From ac875e26a8e49cf9896b0eb8d2a07f6346e25f25 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Thu, 16 Jan 2020 21:33:16 -0500 Subject: [PATCH] Fix handling of SCH_PINs on multi-unit parts Fixes https://gitlab.com/kicad/code/kicad/issues/3770 --- eeschema/connection_graph.cpp | 65 +++++++------- .../netlist_exporter_generic.cpp | 13 ++- eeschema/sch_bus_entry.cpp | 6 +- eeschema/sch_bus_entry.h | 6 +- eeschema/sch_component.cpp | 87 +++++++++++-------- eeschema/sch_component.h | 27 ++++-- eeschema/sch_edit_frame.cpp | 7 +- eeschema/sch_item.cpp | 12 +-- eeschema/sch_item.h | 22 +++-- eeschema/sch_line.cpp | 5 +- eeschema/sch_line.h | 3 +- eeschema/sch_painter.cpp | 8 +- eeschema/sch_screen.cpp | 4 +- eeschema/sch_screen.h | 3 +- eeschema/sch_sheet.cpp | 3 +- eeschema/sch_sheet.h | 3 +- eeschema/sch_text.cpp | 24 +++-- eeschema/sch_text.h | 3 +- eeschema/tools/ee_selection_tool.cpp | 16 ++-- 19 files changed, 191 insertions(+), 126 deletions(-) diff --git a/eeschema/connection_graph.cpp b/eeschema/connection_graph.cpp index 4b32f44f57..042c9f2189 100644 --- a/eeschema/connection_graph.cpp +++ b/eeschema/connection_graph.cpp @@ -396,20 +396,14 @@ void CONNECTION_GRAPH::Recalculate( const SCH_SHEET_LIST& aSheetList, bool aUnco } updateItemConnectivity( sheet, items ); + + // UpdateDanglingState() also adds connected items for SCH_TEXT + sheet.LastScreen()->TestDanglingEnds( &sheet ); } update_items.Stop(); wxLogTrace( "CONN_PROFILE", "UpdateItemConnectivity() %0.4f ms", update_items.msecs() ); - PROF_COUNTER tde; - - // IsDanglingStateChanged() also adds connected items for things like SCH_TEXT - SCH_SCREENS schematic; - schematic.TestDanglingEnds(); - - tde.Stop(); - wxLogTrace( "CONN_PROFILE", "TestDanglingEnds() %0.4f ms", tde.msecs() ); - PROF_COUNTER build_graph; buildConnectionGraph(); @@ -442,7 +436,7 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, { std::vector< wxPoint > points; item->GetConnectionPoints( points ); - item->ConnectedItems().clear(); + item->ConnectedItems( aSheet ).clear(); if( item->Type() == SCH_SHEET_T ) { @@ -453,7 +447,7 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, pin->InitializeConnection( aSheet ); } - pin->ConnectedItems().clear(); + pin->ConnectedItems( aSheet ).clear(); pin->Connection( aSheet )->Reset(); connection_map[ pin->GetTextPos() ].push_back( pin ); @@ -465,26 +459,31 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, SCH_COMPONENT* component = static_cast( item ); TRANSFORM t = component->GetTransform(); - // Assumption: we don't need to call UpdatePins() here because anything - // that would change the pins of the component will have called it already + // TODO(JE) right now this relies on GetSchPins() returning good SCH_PIN pointers + // that contain good LIB_PIN pointers. Since these get invalidated whenever the + // library component is refreshed, the current solution as of ed025972 is to just + // rebuild the SCH_PIN list when the component is refreshed, and then re-run the + // connectivity calculations. This is slow and should be improved before release. + // See https://gitlab.com/kicad/code/kicad/issues/3784 - for( SCH_PIN& pin : component->GetPins() ) + for( SCH_PIN* pin : component->GetSchPins( &aSheet ) ) { - pin.InitializeConnection( aSheet ); + pin->InitializeConnection( aSheet ); - wxPoint pos = t.TransformCoordinate( pin.GetPosition() ) + component->GetPosition(); + wxPoint pos = t.TransformCoordinate( pin->GetPosition() ) + + component->GetPosition(); // because calling the first time is not thread-safe - pin.GetDefaultNetName( aSheet ); - pin.ConnectedItems().clear(); + pin->GetDefaultNetName( aSheet ); + pin->ConnectedItems( aSheet ).clear(); // Invisible power pins need to be post-processed later - if( pin.IsPowerConnection() && !pin.IsVisible() ) - m_invisible_power_pins.emplace_back( std::make_pair( aSheet, &pin ) ); + if( pin->IsPowerConnection() && !pin->IsVisible() ) + m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) ); - connection_map[ pos ].push_back( &pin ); - m_items.insert( &pin ); + connection_map[ pos ].push_back( pin ); + m_items.insert( pin ); } } else @@ -580,8 +579,8 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, else bus_entry->m_connected_bus_items[1] = bus; - bus_entry->ConnectedItems().insert( bus ); - bus->ConnectedItems().insert( bus_entry ); + bus_entry->ConnectedItems( aSheet ).insert( bus ); + bus->ConnectedItems( aSheet ).insert( bus_entry ); } } } @@ -594,8 +593,8 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, connected_item->ConnectionPropagatesTo( test_item ) && test_item->ConnectionPropagatesTo( connected_item ) ) { - connected_item->ConnectedItems().insert( test_item ); - test_item->ConnectedItems().insert( connected_item ); + connected_item->ConnectedItems( aSheet ).insert( test_item ); + test_item->ConnectedItems( aSheet ).insert( connected_item ); } // Set up the link between the bus entry net and the bus @@ -688,8 +687,8 @@ void CONNECTION_GRAPH::buildConnectionGraph() return ( conn->SubgraphCode() == 0 ); }; - std::copy_if( item->ConnectedItems().begin(), - item->ConnectedItems().end(), + std::copy_if( item->ConnectedItems( sheet ).begin(), + item->ConnectedItems( sheet ).end(), std::back_inserter( members ), get_items ); for( auto connected_item : members ) @@ -706,8 +705,8 @@ void CONNECTION_GRAPH::buildConnectionGraph() connected_conn->SetSubgraphCode( subgraph->m_code ); subgraph->AddItem( connected_item ); - std::copy_if( connected_item->ConnectedItems().begin(), - connected_item->ConnectedItems().end(), + std::copy_if( connected_item->ConnectedItems( sheet ).begin(), + connected_item->ConnectedItems( sheet ).end(), std::back_inserter( members ), get_items ); } } @@ -913,15 +912,15 @@ void CONNECTION_GRAPH::buildConnectionGraph() for( const auto& it : m_invisible_power_pins ) { - SCH_PIN* pin = it.second; + SCH_SHEET_PATH sheet = it.first; + SCH_PIN* pin = it.second; - if( !pin->ConnectedItems().empty() && !pin->GetLibPin()->GetParent()->IsPower() ) + if( !pin->ConnectedItems( sheet ).empty() && !pin->GetLibPin()->GetParent()->IsPower() ) { // ERC will warn about this: user has wired up an invisible pin continue; } - SCH_SHEET_PATH sheet = it.first; SCH_CONNECTION* connection = pin->Connection( sheet ); if( !connection ) diff --git a/eeschema/netlist_exporters/netlist_exporter_generic.cpp b/eeschema/netlist_exporters/netlist_exporter_generic.cpp index c1b0a491e7..aa2df06552 100644 --- a/eeschema/netlist_exporters/netlist_exporter_generic.cpp +++ b/eeschema/netlist_exporters/netlist_exporter_generic.cpp @@ -551,7 +551,7 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets( bool aUseGraph ) } // Netlist ordering: Net name, then ref des, then pin name - std::sort( sorted_items.begin(), sorted_items.end(), []( auto a, auto b ) { + std::sort( sorted_items.begin(), sorted_items.end(), [] ( auto a, auto b ) { auto ref_a = a.first->GetParentComponent()->GetRef( &a.second ); auto ref_b = b.first->GetParentComponent()->GetRef( &b.second ); @@ -561,6 +561,17 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets( bool aUseGraph ) return ref_a < ref_b; } ); + // Some duplicates can exist, for example on multi-unit parts with duplicated + // pins across units. If the user connects the pins on each unit, they will + // appear on separate subgraphs. Remove those here: + sorted_items.erase( std::unique( sorted_items.begin(), sorted_items.end(), + [] ( auto a, auto b ) { + auto ref_a = a.first->GetParentComponent()->GetRef( &a.second ); + auto ref_b = b.first->GetParentComponent()->GetRef( &b.second ); + + return ref_a == ref_b && a.first->GetNumber() == b.first->GetNumber(); + } ), sorted_items.end() ); + for( const auto& pair : sorted_items ) { SCH_PIN* pin = pair.first; diff --git a/eeschema/sch_bus_entry.cpp b/eeschema/sch_bus_entry.cpp index 613dcafd4e..26608b4dd3 100644 --- a/eeschema/sch_bus_entry.cpp +++ b/eeschema/sch_bus_entry.cpp @@ -187,7 +187,8 @@ void SCH_BUS_ENTRY_BASE::Rotate( wxPoint aPosition ) } -bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& aItemList ) +bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath ) { bool previousStateStart = m_isDanglingStart; bool previousStateEnd = m_isDanglingEnd; @@ -249,7 +250,8 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector& aI } -bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector& aItemList ) +bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath ) { bool previousStateStart = m_isDanglingStart; bool previousStateEnd = m_isDanglingEnd; diff --git a/eeschema/sch_bus_entry.h b/eeschema/sch_bus_entry.h index cf726941b3..9e4a470687 100644 --- a/eeschema/sch_bus_entry.h +++ b/eeschema/sch_bus_entry.h @@ -157,7 +157,8 @@ public: BITMAP_DEF GetMenuImage() const override; - bool UpdateDanglingState( std::vector& aItemList ) override; + bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) override; /** * Pointer to the bus item (usually a bus wire) connected to this bus-wire @@ -201,7 +202,8 @@ public: BITMAP_DEF GetMenuImage() const override; - bool UpdateDanglingState( std::vector& aItemList ) override; + bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) override; /** * Pointer to the bus items (usually bus wires) connected to this bus-bus diff --git a/eeschema/sch_component.cpp b/eeschema/sch_component.cpp index 51dbf28449..08074f3927 100644 --- a/eeschema/sch_component.cpp +++ b/eeschema/sch_component.cpp @@ -456,31 +456,26 @@ void SCH_COMPONENT::ResolveAll( } -void SCH_COMPONENT::UpdatePins( SCH_SHEET_PATH* aSheet ) +void SCH_COMPONENT::UpdatePins() { m_pins.clear(); m_pinMap.clear(); if( m_part ) { + SCH_PIN_MAP map; unsigned i = 0; for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) ) { wxASSERT( libPin->Type() == LIB_PIN_T ); - if( libPin->GetUnit() && m_unit && ( m_unit != libPin->GetUnit() ) ) - continue; - if( libPin->GetConvert() && m_convert && ( m_convert != libPin->GetConvert() ) ) continue; - m_pins.emplace_back( SCH_PIN( libPin, this ) ); + m_pins.push_back( std::unique_ptr( new SCH_PIN( libPin, this ) ) ); m_pinMap[ libPin ] = i; - if( aSheet ) - m_pins[ i ].InitializeConnection( *aSheet ); - ++i; } } @@ -490,7 +485,7 @@ void SCH_COMPONENT::UpdatePins( SCH_SHEET_PATH* aSheet ) SCH_CONNECTION* SCH_COMPONENT::GetConnectionForPin( LIB_PIN* aPin, const SCH_SHEET_PATH& aSheet ) { if( m_pinMap.count( aPin ) ) - return m_pins[ m_pinMap.at( aPin ) ].Connection( aSheet ); + return m_pins[ m_pinMap[aPin] ]->Connection( aSheet ); return nullptr; } @@ -757,7 +752,7 @@ void SCH_COMPONENT::SetTimeStamp( timestamp_t aNewTimeStamp ) } -int SCH_COMPONENT::GetUnitSelection( SCH_SHEET_PATH* aSheet ) +int SCH_COMPONENT::GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const { wxString path = GetPath( aSheet ); wxString h_path, h_multi; @@ -785,7 +780,7 @@ int SCH_COMPONENT::GetUnitSelection( SCH_SHEET_PATH* aSheet ) } -void SCH_COMPONENT::SetUnitSelection( SCH_SHEET_PATH* aSheet, int aUnitSelection ) +void SCH_COMPONENT::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection ) { wxString path = GetPath( aSheet ); @@ -978,6 +973,27 @@ void SCH_COMPONENT::GetPins( std::vector& aPinsList ) } +SCH_PIN_PTRS SCH_COMPONENT::GetSchPins( const SCH_SHEET_PATH* aSheet ) const +{ + if( aSheet == nullptr ) + aSheet = g_CurrentSheet; + + // TODO(JE) if this works, consider caching in m_sheet_pins + int unit = GetUnitSelection( aSheet ); + SCH_PIN_PTRS ptrs; + + for( const auto& p : m_pins ) + { + if( unit && p->GetLibPin()->GetUnit() && ( p->GetLibPin()->GetUnit() != unit ) ) + continue; + + ptrs.push_back( p.get() ); + } + + return ptrs; +} + + void SCH_COMPONENT::SwapData( SCH_ITEM* aItem ) { wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T), @@ -1508,16 +1524,17 @@ void SCH_COMPONENT::GetEndPoints( std::vector & aItemList ) } -bool SCH_COMPONENT::UpdateDanglingState( std::vector& aItemList ) +bool SCH_COMPONENT::UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath ) { bool changed = false; - for( SCH_PIN& pin : m_pins ) + for( auto& pin : m_pins ) { - bool previousState = pin.IsDangling(); - pin.SetIsDangling( true ); + bool previousState = pin->IsDangling(); + pin->SetIsDangling( true ); - wxPoint pos = m_transform.TransformCoordinate( pin.GetPosition() ) + m_Pos; + wxPoint pos = m_transform.TransformCoordinate( pin->GetPosition() ) + m_Pos; for( DANGLING_END_ITEM& each_item : aItemList ) { @@ -1539,7 +1556,7 @@ bool SCH_COMPONENT::UpdateDanglingState( std::vector& aItemLi case JUNCTION_END: if( pos == each_item.GetPosition() ) - pin.SetIsDangling( false ); + pin->SetIsDangling( false ); break; @@ -1547,11 +1564,11 @@ bool SCH_COMPONENT::UpdateDanglingState( std::vector& aItemLi break; } - if( !pin.IsDangling() ) + if( !pin->IsDangling() ) break; } - changed = ( changed || ( previousState != pin.IsDangling() ) ); + changed = ( changed || ( previousState != pin->IsDangling() ) ); } return changed; @@ -1569,8 +1586,8 @@ wxPoint SCH_COMPONENT::GetPinPhysicalPosition( const LIB_PIN* Pin ) const void SCH_COMPONENT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const { - for( const SCH_PIN& pin : m_pins ) - aPoints.push_back( m_transform.TransformCoordinate( pin.GetPosition() ) + m_Pos ); + for( const auto& pin : m_pins ) + aPoints.push_back( m_transform.TransformCoordinate( pin->GetPosition() ) + m_Pos ); } @@ -1648,9 +1665,9 @@ SEARCH_RESULT SCH_COMPONENT::Visit( INSPECTOR aInspector, void* aTestData, if( stype == SCH_LOCATE_ANY_T || stype == SCH_PIN_T ) { - for( SCH_PIN& pin : m_pins ) + for( auto& pin : m_pins ) { - if( SEARCH_RESULT::QUIT == aInspector( &pin, (void*) this ) ) + if( SEARCH_RESULT::QUIT == aInspector( pin.get(), (void*) this ) ) return SEARCH_RESULT::QUIT; } } @@ -1821,9 +1838,9 @@ bool SCH_COMPONENT::doIsConnected( const wxPoint& aPosition ) const { wxPoint new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_Pos ); - for( const SCH_PIN& pin : m_pins ) + for( const auto& pin : m_pins ) { - if( pin.GetPosition() == new_pos ) + if( pin->GetPosition() == new_pos ) return true; } @@ -1858,9 +1875,9 @@ void SCH_COMPONENT::Plot( PLOTTER* aPlotter ) bool SCH_COMPONENT::HasBrightenedPins() { - for( const SCH_PIN& pin : m_pins ) + for( const auto& pin : m_pins ) { - if( pin.IsBrightened() ) + if( pin->IsBrightened() ) return true; } @@ -1870,30 +1887,30 @@ bool SCH_COMPONENT::HasBrightenedPins() void SCH_COMPONENT::ClearBrightenedPins() { - for( SCH_PIN& pin : m_pins ) - pin.ClearBrightened(); + for( auto& pin : m_pins ) + pin->ClearBrightened(); } void SCH_COMPONENT::BrightenPin( LIB_PIN* aPin ) { if( m_pinMap.count( aPin ) ) - m_pins[ m_pinMap.at( aPin ) ].SetBrightened(); + m_pins[ m_pinMap.at( aPin ) ]->SetBrightened(); } void SCH_COMPONENT::ClearHighlightedPins() { - for( SCH_PIN& pin : m_pins ) - pin.ClearHighlighted(); + for( auto& pin : m_pins ) + pin->ClearHighlighted(); } bool SCH_COMPONENT::HasHighlightedPins() { - for( const SCH_PIN& pin : m_pins ) + for( const auto& pin : m_pins ) { - if( pin.IsHighlighted() ) + if( pin->IsHighlighted() ) return true; } @@ -1904,7 +1921,7 @@ bool SCH_COMPONENT::HasHighlightedPins() void SCH_COMPONENT::HighlightPin( LIB_PIN* aPin ) { if( m_pinMap.count( aPin ) ) - m_pins[ m_pinMap.at( aPin ) ].SetHighlighted(); + m_pins[ m_pinMap.at( aPin ) ]->SetHighlighted(); } diff --git a/eeschema/sch_component.h b/eeschema/sch_component.h index cc8493af2a..a8443d9fc3 100644 --- a/eeschema/sch_component.h +++ b/eeschema/sch_component.h @@ -68,7 +68,9 @@ class SYMBOL_LIB_TABLE; /// A container for several SCH_PIN items -typedef std::vector SCH_PINS; +typedef std::vector> SCH_PINS; + +typedef std::vector SCH_PIN_PTRS; /// A map from the library pin pointer to the SCH_PIN's index typedef std::unordered_map SCH_PIN_MAP; @@ -112,8 +114,8 @@ private: ///< A flattened copy of a LIB_PART found in the PROJECT's libraries to for this component. std::unique_ptr< LIB_PART > m_part; - SCH_PINS m_pins; ///< the component's pins - SCH_PIN_MAP m_pinMap; ///< the component's pins mapped by LIB_PIN*. + SCH_PINS m_pins; ///< a SCH_PIN for every LIB_PIN (across all units) + SCH_PIN_MAP m_pinMap; ///< the component's pins mapped by LIB_PIN* AUTOPLACED m_fieldsAutoplaced; ///< indicates status of field autoplacement @@ -225,9 +227,9 @@ public: int GetUnit() const { return m_unit; } /** - * Updates the local cache of SCH_PIN_CONNECTION objects for each pin + * Updates the cache of SCH_PIN objects for each pin */ - void UpdatePins( SCH_SHEET_PATH* aSheet = nullptr ); + void UpdatePins(); /** * Retrieves the connection for a given pin of the component @@ -475,7 +477,13 @@ public: */ void GetPins( std::vector& aPinsList ); - SCH_PINS& GetPins() { return m_pins; } + /** + * Retrieves a list of the SCH_PINs for the given sheet path. + * Since a component can have a different unit on a different instance of a sheet, + * this list returns the subset of pins that exist on a given sheet. + * @return a vector of pointers (non-owning) to SCH_PINs + */ + SCH_PIN_PTRS GetSchPins( const SCH_SHEET_PATH* aSheet = nullptr ) const; /** * Print a component @@ -537,10 +545,10 @@ public: int aMulti ); // returns the unit selection, for the given sheet path. - int GetUnitSelection( SCH_SHEET_PATH* aSheet ); + int GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const; // Set the unit selection, for the given sheet path. - void SetUnitSelection( SCH_SHEET_PATH* aSheet, int aUnitSelection ); + void SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection ); // Geometric transforms (used in block operations): @@ -576,7 +584,8 @@ public: * * @return true if any pin's state has changed. */ - bool UpdateDanglingState( std::vector& aItemList ) override; + bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) override; wxPoint GetPinPhysicalPosition( const LIB_PIN* Pin ) const; diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 0ce03ca806..7b789da9c1 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -1039,7 +1039,7 @@ void SCH_EDIT_FRAME::AddItemToScreenAndUndoList( SCH_ITEM* aItem, bool aUndoAppe TestDanglingEnds(); - for( SCH_ITEM* item : aItem->ConnectedItems() ) + for( SCH_ITEM* item : aItem->ConnectedItems( *g_CurrentSheet ) ) RefreshItem( item ); } @@ -1172,14 +1172,15 @@ void SCH_EDIT_FRAME::FixupJunctions() GetCurrentSheet().UpdateAllScreenReferences(); auto screen = GetCurrentSheet().LastScreen(); + for( auto aItem : screen->Items().OfType( SCH_COMPONENT_T ) ) { auto cmp = static_cast( aItem ); auto xform = cmp->GetTransform(); - for( const SCH_PIN& pin : cmp->GetPins() ) + for( const SCH_PIN* pin : cmp->GetSchPins( &sheet ) ) { - auto pos = cmp->GetPosition() + xform.TransformCoordinate( pin.GetPosition() ); + auto pos = cmp->GetPosition() + xform.TransformCoordinate( pin->GetPosition() ); // Test if a _new_ junction is needed, and add it if missing if( screen->IsJunctionNeeded( pos, true ) ) diff --git a/eeschema/sch_item.cpp b/eeschema/sch_item.cpp index 349d4a2ac8..fb0ed35355 100644 --- a/eeschema/sch_item.cpp +++ b/eeschema/sch_item.cpp @@ -85,8 +85,8 @@ SCH_ITEM* SCH_ITEM::Duplicate( bool doClone ) { SCH_COMPONENT* component = (SCH_COMPONENT*) newItem; - for( SCH_PIN& pin : component->GetPins() ) - pin.ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED ); + for( SCH_PIN* pin : component->GetSchPins() ) + pin->ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED ); std::vector fields; component->GetFields( fields, false ); @@ -135,15 +135,15 @@ SCH_CONNECTION* SCH_ITEM::Connection( const SCH_SHEET_PATH& aSheet ) const } -std::unordered_set& SCH_ITEM::ConnectedItems() +ITEM_SET& SCH_ITEM::ConnectedItems( const SCH_SHEET_PATH& aSheet ) { - return m_connected_items; + return m_connected_items[ aSheet ]; } -void SCH_ITEM::AddConnectionTo( SCH_ITEM* aItem ) +void SCH_ITEM::AddConnectionTo( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aItem ) { - m_connected_items.insert( aItem ); + m_connected_items[ aSheet ].insert( aItem ); } diff --git a/eeschema/sch_item.h b/eeschema/sch_item.h index 683f1f4f24..6d0ef8898d 100644 --- a/eeschema/sch_item.h +++ b/eeschema/sch_item.h @@ -126,6 +126,8 @@ public: }; +typedef std::unordered_set ITEM_SET; + /** * SCH_ITEM * is a base class for any item which can be embedded within the SCHEMATIC @@ -143,8 +145,8 @@ protected: wxPoint m_storedPos; ///< a temporary variable used in some move commands ///> to store a initial pos (of the item or mouse cursor) - /// Stores pointers to other items that are connected to this one (schematic only) - std::unordered_set m_connected_items; + /// Stores pointers to other items that are connected to this one, per sheet + std::unordered_map m_connected_items; /// Stores connectivity information, per sheet std::unordered_map m_connection_map; @@ -301,10 +303,18 @@ public: * always returns false. Only override the method if the item can be tested for a * dangling state. * + * If aSheet is passed a non-null pointer to a SCH_SHEET_PATH, the overrided method can + * optionally use it to update sheet-local connectivity information + * * @param aItemList - List of items to test item against. + * @param aSheet - Sheet path to update connections for * @return True if the dangling state has changed from it's current setting. */ - virtual bool UpdateDanglingState( std::vector& aItemList ) { return false; } + virtual bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) + { + return false; + } virtual bool IsDangling() const { return false; } @@ -351,14 +361,14 @@ public: SCH_CONNECTION* Connection( const SCH_SHEET_PATH& aPath ) const; /** - * Retrieves the set of items connected to this item (schematic only) + * Retrieves the set of items connected to this item on the given sheet */ - std::unordered_set& ConnectedItems(); + ITEM_SET& ConnectedItems( const SCH_SHEET_PATH& aPath ); /** * Adds a connection link between this item and another */ - void AddConnectionTo( SCH_ITEM* aItem ); + void AddConnectionTo( const SCH_SHEET_PATH& aPath, SCH_ITEM* aItem ); /** * Creates a new connection object associated with this object diff --git a/eeschema/sch_line.cpp b/eeschema/sch_line.cpp index b58e5a4b34..a56b7f6760 100644 --- a/eeschema/sch_line.cpp +++ b/eeschema/sch_line.cpp @@ -534,7 +534,8 @@ void SCH_LINE::GetEndPoints( std::vector & aItemList ) } -bool SCH_LINE::UpdateDanglingState( std::vector& aItemList ) +bool SCH_LINE::UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath ) { bool previousStartState = m_startIsDangling; bool previousEndState = m_endIsDangling; @@ -559,7 +560,7 @@ bool SCH_LINE::UpdateDanglingState( std::vector& aItemList ) if( m_end == item.GetPosition() ) m_endIsDangling = false; - if( (m_startIsDangling == false) && (m_endIsDangling == false) ) + if( !m_startIsDangling && !m_endIsDangling ) break; } } diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index ebe7be1440..d611dcfb18 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -178,7 +178,8 @@ public: void GetEndPoints( std::vector& aItemList ) override; - bool UpdateDanglingState( std::vector& aItemList ) override; + bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) override; bool IsStartDangling() const { return m_startIsDangling; } bool IsEndDangling() const { return m_endIsDangling; } diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp index 8f79368add..27c52a7f36 100644 --- a/eeschema/sch_painter.cpp +++ b/eeschema/sch_painter.cpp @@ -1329,17 +1329,17 @@ void SCH_PAINTER::draw( SCH_COMPONENT *aComp, int aLayer ) // Copy the pin info from the component to the temp pins LIB_PINS tempPins; tempPart.GetPins( tempPins, aComp->GetUnit(), aComp->GetConvert() ); - const SCH_PINS& compPins = aComp->GetPins(); + const SCH_PIN_PTRS compPins = aComp->GetSchPins(); for( unsigned i = 0; i < tempPins.size() && i < compPins.size(); ++ i ) { LIB_PIN* tempPin = tempPins[ i ]; - const SCH_PIN& compPin = compPins[ i ]; + const SCH_PIN* compPin = compPins[ i ]; tempPin->ClearFlags(); - tempPin->SetFlags( compPin.GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED + tempPin->SetFlags( compPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED - if( compPin.IsDangling() ) + if( compPin->IsDangling() ) tempPin->SetFlags( IS_DANGLING ); } diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index 09c6ad5bd8..53725ec36b 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -785,7 +785,7 @@ void SCH_SCREEN::GetHierarchicalItems( EDA_ITEMS& aItems ) } -bool SCH_SCREEN::TestDanglingEnds() +bool SCH_SCREEN::TestDanglingEnds( const SCH_SHEET_PATH* aPath ) { std::vector< DANGLING_END_ITEM > endPoints; bool hasStateChanged = false; @@ -795,7 +795,7 @@ bool SCH_SCREEN::TestDanglingEnds() for( auto item : Items() ) { - if( item->UpdateDanglingState( endPoints ) ) + if( item->UpdateDanglingState( endPoints, aPath ) ) hasStateChanged = true; } diff --git a/eeschema/sch_screen.h b/eeschema/sch_screen.h index dc30e958bd..770844758c 100644 --- a/eeschema/sch_screen.h +++ b/eeschema/sch_screen.h @@ -285,9 +285,10 @@ public: /** * Test all of the connectable objects in the schematic for unused connection points. + * @param aPath is a sheet path to pass to UpdateDanglingState if desired * @return True if any connection state changes were made. */ - bool TestDanglingEnds(); + bool TestDanglingEnds( const SCH_SHEET_PATH* aPath = nullptr ); /** * Return all wires and junctions connected to \a aSegment which are not connected any diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index c4375f1db8..6d99795ae4 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -757,7 +757,8 @@ void SCH_SHEET::GetEndPoints( std::vector & aItemList ) } -bool SCH_SHEET::UpdateDanglingState( std::vector& aItemList ) +bool SCH_SHEET::UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath ) { bool changed = false; diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index ea64432ce7..fa5e03f077 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -509,7 +509,8 @@ public: void GetEndPoints( std::vector & aItemList ) override; - bool UpdateDanglingState( std::vector& aItemList ) override; + bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) override; bool IsConnectable() const override { return true; } diff --git a/eeschema/sch_text.cpp b/eeschema/sch_text.cpp index 1bf13b6cea..08fc0b5af1 100644 --- a/eeschema/sch_text.cpp +++ b/eeschema/sch_text.cpp @@ -328,7 +328,8 @@ void SCH_TEXT::GetEndPoints( std::vector & aItemList ) } -bool SCH_TEXT::UpdateDanglingState( std::vector& aItemList ) +bool SCH_TEXT::UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath ) { // Normal text labels cannot be tested for dangling ends. if( Type() == SCH_TEXT_T ) @@ -355,8 +356,8 @@ bool SCH_TEXT::UpdateDanglingState( std::vector& aItemList ) { m_isDangling = false; - if( item.GetType() != PIN_END ) - m_connected_items.insert( static_cast< SCH_ITEM* >( item.GetItem() ) ); + if( aPath && item.GetType() != PIN_END ) + m_connected_items[ *aPath ].insert( static_cast( item.GetItem() ) ); } break; @@ -385,9 +386,12 @@ bool SCH_TEXT::UpdateDanglingState( std::vector& aItemList ) // Add the line to the connected items, since it won't be picked // up by a search of intersecting connection points - auto sch_item = static_cast< SCH_ITEM* >( item.GetItem() ); - AddConnectionTo( sch_item ); - sch_item->AddConnectionTo( this ); + if( aPath ) + { + auto sch_item = static_cast( item.GetItem() ); + AddConnectionTo( *aPath, sch_item ); + sch_item->AddConnectionTo( *aPath, this ); + } } } break; @@ -669,7 +673,9 @@ bool SCH_LABEL::IsType( const KICAD_T aScanTypes[] ) const { if( *p == SCH_LABEL_LOCATE_WIRE_T ) { - for( SCH_ITEM* connection : m_connected_items ) + wxASSERT( m_connected_items.count( *g_CurrentSheet ) ); + + for( SCH_ITEM* connection : m_connected_items.at( *g_CurrentSheet ) ) { if( connection->IsType( wireTypes ) ) return true; @@ -677,7 +683,9 @@ bool SCH_LABEL::IsType( const KICAD_T aScanTypes[] ) const } else if ( *p == SCH_LABEL_LOCATE_BUS_T ) { - for( SCH_ITEM* connection : m_connected_items ) + wxASSERT( m_connected_items.count( *g_CurrentSheet ) ); + + for( SCH_ITEM* connection : m_connected_items.at( *g_CurrentSheet ) ) { if( connection->IsType( busTypes ) ) return true; diff --git a/eeschema/sch_text.h b/eeschema/sch_text.h index 39b813883f..77234943cb 100644 --- a/eeschema/sch_text.h +++ b/eeschema/sch_text.h @@ -299,7 +299,8 @@ public: void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override; - bool UpdateDanglingState( std::vector& aItemList ) override; + bool UpdateDanglingState( std::vector& aItemList, + const SCH_SHEET_PATH* aPath = nullptr ) override; bool IsDangling() const override { return m_isDangling; } void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; } diff --git a/eeschema/tools/ee_selection_tool.cpp b/eeschema/tools/ee_selection_tool.cpp index 0a526515b7..cccf6422f6 100644 --- a/eeschema/tools/ee_selection_tool.cpp +++ b/eeschema/tools/ee_selection_tool.cpp @@ -1199,14 +1199,14 @@ void EE_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, EE_SELECTION* aGr // represented in the LIB_PART and will inherit the settings of the parent component.) if( itemType == SCH_COMPONENT_T ) { - SCH_PINS& pins = static_cast( aItem )->GetPins(); + SCH_PIN_PTRS pins = static_cast( aItem )->GetSchPins( g_CurrentSheet ); - for( SCH_PIN& pin : pins ) + for( SCH_PIN* pin : pins ) { if( aMode == SELECTED ) - pin.SetSelected(); + pin->SetSelected(); else if( aMode == BRIGHTENED ) - pin.SetBrightened(); + pin->SetBrightened(); } std::vector fields; @@ -1256,14 +1256,14 @@ void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, EE_SELECTION* a // represented in the LIB_PART.) if( itemType == SCH_COMPONENT_T ) { - SCH_PINS& pins = static_cast( aItem )->GetPins(); + SCH_PIN_PTRS pins = static_cast( aItem )->GetSchPins( g_CurrentSheet ); - for( SCH_PIN& pin : pins ) + for( SCH_PIN* pin : pins ) { if( aMode == SELECTED ) - pin.ClearSelected(); + pin->ClearSelected(); else if( aMode == BRIGHTENED ) - pin.ClearBrightened(); + pin->ClearBrightened(); } std::vector fields;