Fix handling of SCH_PINs on multi-unit parts

Fixes https://gitlab.com/kicad/code/kicad/issues/3770
This commit is contained in:
Jon Evans 2020-01-16 21:33:16 -05:00
parent 0645442704
commit ac875e26a8
19 changed files with 191 additions and 126 deletions

View File

@ -396,20 +396,14 @@ void CONNECTION_GRAPH::Recalculate( const SCH_SHEET_LIST& aSheetList, bool aUnco
} }
updateItemConnectivity( sheet, items ); updateItemConnectivity( sheet, items );
// UpdateDanglingState() also adds connected items for SCH_TEXT
sheet.LastScreen()->TestDanglingEnds( &sheet );
} }
update_items.Stop(); update_items.Stop();
wxLogTrace( "CONN_PROFILE", "UpdateItemConnectivity() %0.4f ms", update_items.msecs() ); 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; PROF_COUNTER build_graph;
buildConnectionGraph(); buildConnectionGraph();
@ -442,7 +436,7 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
{ {
std::vector< wxPoint > points; std::vector< wxPoint > points;
item->GetConnectionPoints( points ); item->GetConnectionPoints( points );
item->ConnectedItems().clear(); item->ConnectedItems( aSheet ).clear();
if( item->Type() == SCH_SHEET_T ) if( item->Type() == SCH_SHEET_T )
{ {
@ -453,7 +447,7 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
pin->InitializeConnection( aSheet ); pin->InitializeConnection( aSheet );
} }
pin->ConnectedItems().clear(); pin->ConnectedItems( aSheet ).clear();
pin->Connection( aSheet )->Reset(); pin->Connection( aSheet )->Reset();
connection_map[ pin->GetTextPos() ].push_back( pin ); connection_map[ pin->GetTextPos() ].push_back( pin );
@ -465,26 +459,31 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item ); SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
TRANSFORM t = component->GetTransform(); TRANSFORM t = component->GetTransform();
// Assumption: we don't need to call UpdatePins() here because anything // TODO(JE) right now this relies on GetSchPins() returning good SCH_PIN pointers
// that would change the pins of the component will have called it already // 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 // because calling the first time is not thread-safe
pin.GetDefaultNetName( aSheet ); pin->GetDefaultNetName( aSheet );
pin.ConnectedItems().clear(); pin->ConnectedItems( aSheet ).clear();
// Invisible power pins need to be post-processed later // Invisible power pins need to be post-processed later
if( pin.IsPowerConnection() && !pin.IsVisible() ) if( pin->IsPowerConnection() && !pin->IsVisible() )
m_invisible_power_pins.emplace_back( std::make_pair( aSheet, &pin ) ); m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) );
connection_map[ pos ].push_back( &pin ); connection_map[ pos ].push_back( pin );
m_items.insert( &pin ); m_items.insert( pin );
} }
} }
else else
@ -580,8 +579,8 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
else else
bus_entry->m_connected_bus_items[1] = bus; bus_entry->m_connected_bus_items[1] = bus;
bus_entry->ConnectedItems().insert( bus ); bus_entry->ConnectedItems( aSheet ).insert( bus );
bus->ConnectedItems().insert( bus_entry ); bus->ConnectedItems( aSheet ).insert( bus_entry );
} }
} }
} }
@ -594,8 +593,8 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet,
connected_item->ConnectionPropagatesTo( test_item ) && connected_item->ConnectionPropagatesTo( test_item ) &&
test_item->ConnectionPropagatesTo( connected_item ) ) test_item->ConnectionPropagatesTo( connected_item ) )
{ {
connected_item->ConnectedItems().insert( test_item ); connected_item->ConnectedItems( aSheet ).insert( test_item );
test_item->ConnectedItems().insert( connected_item ); test_item->ConnectedItems( aSheet ).insert( connected_item );
} }
// Set up the link between the bus entry net and the bus // Set up the link between the bus entry net and the bus
@ -688,8 +687,8 @@ void CONNECTION_GRAPH::buildConnectionGraph()
return ( conn->SubgraphCode() == 0 ); return ( conn->SubgraphCode() == 0 );
}; };
std::copy_if( item->ConnectedItems().begin(), std::copy_if( item->ConnectedItems( sheet ).begin(),
item->ConnectedItems().end(), item->ConnectedItems( sheet ).end(),
std::back_inserter( members ), get_items ); std::back_inserter( members ), get_items );
for( auto connected_item : members ) for( auto connected_item : members )
@ -706,8 +705,8 @@ void CONNECTION_GRAPH::buildConnectionGraph()
connected_conn->SetSubgraphCode( subgraph->m_code ); connected_conn->SetSubgraphCode( subgraph->m_code );
subgraph->AddItem( connected_item ); subgraph->AddItem( connected_item );
std::copy_if( connected_item->ConnectedItems().begin(), std::copy_if( connected_item->ConnectedItems( sheet ).begin(),
connected_item->ConnectedItems().end(), connected_item->ConnectedItems( sheet ).end(),
std::back_inserter( members ), get_items ); std::back_inserter( members ), get_items );
} }
} }
@ -913,15 +912,15 @@ void CONNECTION_GRAPH::buildConnectionGraph()
for( const auto& it : m_invisible_power_pins ) 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 // ERC will warn about this: user has wired up an invisible pin
continue; continue;
} }
SCH_SHEET_PATH sheet = it.first;
SCH_CONNECTION* connection = pin->Connection( sheet ); SCH_CONNECTION* connection = pin->Connection( sheet );
if( !connection ) if( !connection )

View File

@ -551,7 +551,7 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets( bool aUseGraph )
} }
// Netlist ordering: Net name, then ref des, then pin name // 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_a = a.first->GetParentComponent()->GetRef( &a.second );
auto ref_b = b.first->GetParentComponent()->GetRef( &b.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; 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 ) for( const auto& pair : sorted_items )
{ {
SCH_PIN* pin = pair.first; SCH_PIN* pin = pair.first;

View File

@ -187,7 +187,8 @@ void SCH_BUS_ENTRY_BASE::Rotate( wxPoint aPosition )
} }
bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{ {
bool previousStateStart = m_isDanglingStart; bool previousStateStart = m_isDanglingStart;
bool previousStateEnd = m_isDanglingEnd; bool previousStateEnd = m_isDanglingEnd;
@ -249,7 +250,8 @@ bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aI
} }
bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{ {
bool previousStateStart = m_isDanglingStart; bool previousStateStart = m_isDanglingStart;
bool previousStateEnd = m_isDanglingEnd; bool previousStateEnd = m_isDanglingEnd;

View File

@ -157,7 +157,8 @@ public:
BITMAP_DEF GetMenuImage() const override; BITMAP_DEF GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
/** /**
* Pointer to the bus item (usually a bus wire) connected to this bus-wire * Pointer to the bus item (usually a bus wire) connected to this bus-wire
@ -201,7 +202,8 @@ public:
BITMAP_DEF GetMenuImage() const override; BITMAP_DEF GetMenuImage() const override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
/** /**
* Pointer to the bus items (usually bus wires) connected to this bus-bus * Pointer to the bus items (usually bus wires) connected to this bus-bus

View File

@ -456,31 +456,26 @@ void SCH_COMPONENT::ResolveAll(
} }
void SCH_COMPONENT::UpdatePins( SCH_SHEET_PATH* aSheet ) void SCH_COMPONENT::UpdatePins()
{ {
m_pins.clear(); m_pins.clear();
m_pinMap.clear(); m_pinMap.clear();
if( m_part ) if( m_part )
{ {
SCH_PIN_MAP map;
unsigned i = 0; unsigned i = 0;
for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) ) for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) )
{ {
wxASSERT( libPin->Type() == LIB_PIN_T ); 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() ) ) if( libPin->GetConvert() && m_convert && ( m_convert != libPin->GetConvert() ) )
continue; continue;
m_pins.emplace_back( SCH_PIN( libPin, this ) ); m_pins.push_back( std::unique_ptr<SCH_PIN>( new SCH_PIN( libPin, this ) ) );
m_pinMap[ libPin ] = i; m_pinMap[ libPin ] = i;
if( aSheet )
m_pins[ i ].InitializeConnection( *aSheet );
++i; ++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 ) SCH_CONNECTION* SCH_COMPONENT::GetConnectionForPin( LIB_PIN* aPin, const SCH_SHEET_PATH& aSheet )
{ {
if( m_pinMap.count( aPin ) ) if( m_pinMap.count( aPin ) )
return m_pins[ m_pinMap.at( aPin ) ].Connection( aSheet ); return m_pins[ m_pinMap[aPin] ]->Connection( aSheet );
return nullptr; 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 path = GetPath( aSheet );
wxString h_path, h_multi; 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 ); wxString path = GetPath( aSheet );
@ -978,6 +973,27 @@ void SCH_COMPONENT::GetPins( std::vector<LIB_PIN*>& 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 ) void SCH_COMPONENT::SwapData( SCH_ITEM* aItem )
{ {
wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T), wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T),
@ -1508,16 +1524,17 @@ void SCH_COMPONENT::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_COMPONENT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) bool SCH_COMPONENT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{ {
bool changed = false; bool changed = false;
for( SCH_PIN& pin : m_pins ) for( auto& pin : m_pins )
{ {
bool previousState = pin.IsDangling(); bool previousState = pin->IsDangling();
pin.SetIsDangling( true ); 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 ) for( DANGLING_END_ITEM& each_item : aItemList )
{ {
@ -1539,7 +1556,7 @@ bool SCH_COMPONENT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemLi
case JUNCTION_END: case JUNCTION_END:
if( pos == each_item.GetPosition() ) if( pos == each_item.GetPosition() )
pin.SetIsDangling( false ); pin->SetIsDangling( false );
break; break;
@ -1547,11 +1564,11 @@ bool SCH_COMPONENT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemLi
break; break;
} }
if( !pin.IsDangling() ) if( !pin->IsDangling() )
break; break;
} }
changed = ( changed || ( previousState != pin.IsDangling() ) ); changed = ( changed || ( previousState != pin->IsDangling() ) );
} }
return changed; return changed;
@ -1569,8 +1586,8 @@ wxPoint SCH_COMPONENT::GetPinPhysicalPosition( const LIB_PIN* Pin ) const
void SCH_COMPONENT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const void SCH_COMPONENT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const
{ {
for( const SCH_PIN& pin : m_pins ) for( const auto& pin : m_pins )
aPoints.push_back( m_transform.TransformCoordinate( pin.GetPosition() ) + m_Pos ); 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 ) 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; 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 ); 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; return true;
} }
@ -1858,9 +1875,9 @@ void SCH_COMPONENT::Plot( PLOTTER* aPlotter )
bool SCH_COMPONENT::HasBrightenedPins() 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; return true;
} }
@ -1870,30 +1887,30 @@ bool SCH_COMPONENT::HasBrightenedPins()
void SCH_COMPONENT::ClearBrightenedPins() void SCH_COMPONENT::ClearBrightenedPins()
{ {
for( SCH_PIN& pin : m_pins ) for( auto& pin : m_pins )
pin.ClearBrightened(); pin->ClearBrightened();
} }
void SCH_COMPONENT::BrightenPin( LIB_PIN* aPin ) void SCH_COMPONENT::BrightenPin( LIB_PIN* aPin )
{ {
if( m_pinMap.count( aPin ) ) if( m_pinMap.count( aPin ) )
m_pins[ m_pinMap.at( aPin ) ].SetBrightened(); m_pins[ m_pinMap.at( aPin ) ]->SetBrightened();
} }
void SCH_COMPONENT::ClearHighlightedPins() void SCH_COMPONENT::ClearHighlightedPins()
{ {
for( SCH_PIN& pin : m_pins ) for( auto& pin : m_pins )
pin.ClearHighlighted(); pin->ClearHighlighted();
} }
bool SCH_COMPONENT::HasHighlightedPins() 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; return true;
} }
@ -1904,7 +1921,7 @@ bool SCH_COMPONENT::HasHighlightedPins()
void SCH_COMPONENT::HighlightPin( LIB_PIN* aPin ) void SCH_COMPONENT::HighlightPin( LIB_PIN* aPin )
{ {
if( m_pinMap.count( aPin ) ) if( m_pinMap.count( aPin ) )
m_pins[ m_pinMap.at( aPin ) ].SetHighlighted(); m_pins[ m_pinMap.at( aPin ) ]->SetHighlighted();
} }

View File

@ -68,7 +68,9 @@ class SYMBOL_LIB_TABLE;
/// A container for several SCH_PIN items /// A container for several SCH_PIN items
typedef std::vector<SCH_PIN> SCH_PINS; typedef std::vector<std::unique_ptr<SCH_PIN>> SCH_PINS;
typedef std::vector<SCH_PIN*> SCH_PIN_PTRS;
/// A map from the library pin pointer to the SCH_PIN's index /// A map from the library pin pointer to the SCH_PIN's index
typedef std::unordered_map<LIB_PIN*, unsigned> SCH_PIN_MAP; typedef std::unordered_map<LIB_PIN*, unsigned> 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. ///< A flattened copy of a LIB_PART found in the PROJECT's libraries to for this component.
std::unique_ptr< LIB_PART > m_part; std::unique_ptr< LIB_PART > m_part;
SCH_PINS m_pins; ///< the component's pins 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*. SCH_PIN_MAP m_pinMap; ///< the component's pins mapped by LIB_PIN*
AUTOPLACED m_fieldsAutoplaced; ///< indicates status of field autoplacement AUTOPLACED m_fieldsAutoplaced; ///< indicates status of field autoplacement
@ -225,9 +227,9 @@ public:
int GetUnit() const { return m_unit; } 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 * Retrieves the connection for a given pin of the component
@ -475,7 +477,13 @@ public:
*/ */
void GetPins( std::vector<LIB_PIN*>& aPinsList ); void GetPins( std::vector<LIB_PIN*>& 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 * Print a component
@ -537,10 +545,10 @@ public:
int aMulti ); int aMulti );
// returns the unit selection, for the given sheet path. // 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. // 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): // Geometric transforms (used in block operations):
@ -576,7 +584,8 @@ public:
* *
* @return true if any pin's state has changed. * @return true if any pin's state has changed.
*/ */
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
wxPoint GetPinPhysicalPosition( const LIB_PIN* Pin ) const; wxPoint GetPinPhysicalPosition( const LIB_PIN* Pin ) const;

View File

@ -1039,7 +1039,7 @@ void SCH_EDIT_FRAME::AddItemToScreenAndUndoList( SCH_ITEM* aItem, bool aUndoAppe
TestDanglingEnds(); TestDanglingEnds();
for( SCH_ITEM* item : aItem->ConnectedItems() ) for( SCH_ITEM* item : aItem->ConnectedItems( *g_CurrentSheet ) )
RefreshItem( item ); RefreshItem( item );
} }
@ -1172,14 +1172,15 @@ void SCH_EDIT_FRAME::FixupJunctions()
GetCurrentSheet().UpdateAllScreenReferences(); GetCurrentSheet().UpdateAllScreenReferences();
auto screen = GetCurrentSheet().LastScreen(); auto screen = GetCurrentSheet().LastScreen();
for( auto aItem : screen->Items().OfType( SCH_COMPONENT_T ) ) for( auto aItem : screen->Items().OfType( SCH_COMPONENT_T ) )
{ {
auto cmp = static_cast<SCH_COMPONENT*>( aItem ); auto cmp = static_cast<SCH_COMPONENT*>( aItem );
auto xform = cmp->GetTransform(); 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 // Test if a _new_ junction is needed, and add it if missing
if( screen->IsJunctionNeeded( pos, true ) ) if( screen->IsJunctionNeeded( pos, true ) )

View File

@ -85,8 +85,8 @@ SCH_ITEM* SCH_ITEM::Duplicate( bool doClone )
{ {
SCH_COMPONENT* component = (SCH_COMPONENT*) newItem; SCH_COMPONENT* component = (SCH_COMPONENT*) newItem;
for( SCH_PIN& pin : component->GetPins() ) for( SCH_PIN* pin : component->GetSchPins() )
pin.ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED ); pin->ClearFlags( SELECTED | HIGHLIGHTED | BRIGHTENED );
std::vector<SCH_FIELD*> fields; std::vector<SCH_FIELD*> fields;
component->GetFields( fields, false ); component->GetFields( fields, false );
@ -135,15 +135,15 @@ SCH_CONNECTION* SCH_ITEM::Connection( const SCH_SHEET_PATH& aSheet ) const
} }
std::unordered_set<SCH_ITEM*>& 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 );
} }

View File

@ -126,6 +126,8 @@ public:
}; };
typedef std::unordered_set<SCH_ITEM*> ITEM_SET;
/** /**
* SCH_ITEM * SCH_ITEM
* is a base class for any item which can be embedded within the SCHEMATIC * 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 wxPoint m_storedPos; ///< a temporary variable used in some move commands
///> to store a initial pos (of the item or mouse cursor) ///> to store a initial pos (of the item or mouse cursor)
/// Stores pointers to other items that are connected to this one (schematic only) /// Stores pointers to other items that are connected to this one, per sheet
std::unordered_set<SCH_ITEM*> m_connected_items; std::unordered_map<SCH_SHEET_PATH, ITEM_SET> m_connected_items;
/// Stores connectivity information, per sheet /// Stores connectivity information, per sheet
std::unordered_map<SCH_SHEET_PATH, SCH_CONNECTION*> m_connection_map; std::unordered_map<SCH_SHEET_PATH, SCH_CONNECTION*> m_connection_map;
@ -301,10 +303,18 @@ public:
* always returns false. Only override the method if the item can be tested for a * always returns false. Only override the method if the item can be tested for a
* dangling state. * 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 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. * @return True if the dangling state has changed from it's current setting.
*/ */
virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) { return false; } virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr )
{
return false;
}
virtual bool IsDangling() const { return false; } virtual bool IsDangling() const { return false; }
@ -351,14 +361,14 @@ public:
SCH_CONNECTION* Connection( const SCH_SHEET_PATH& aPath ) const; 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<SCH_ITEM*>& ConnectedItems(); ITEM_SET& ConnectedItems( const SCH_SHEET_PATH& aPath );
/** /**
* Adds a connection link between this item and another * 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 * Creates a new connection object associated with this object

View File

@ -534,7 +534,8 @@ void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{ {
bool previousStartState = m_startIsDangling; bool previousStartState = m_startIsDangling;
bool previousEndState = m_endIsDangling; bool previousEndState = m_endIsDangling;
@ -559,7 +560,7 @@ bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
if( m_end == item.GetPosition() ) if( m_end == item.GetPosition() )
m_endIsDangling = false; m_endIsDangling = false;
if( (m_startIsDangling == false) && (m_endIsDangling == false) ) if( !m_startIsDangling && !m_endIsDangling )
break; break;
} }
} }

View File

@ -178,7 +178,8 @@ public:
void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override; void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsStartDangling() const { return m_startIsDangling; } bool IsStartDangling() const { return m_startIsDangling; }
bool IsEndDangling() const { return m_endIsDangling; } bool IsEndDangling() const { return m_endIsDangling; }

View File

@ -1329,17 +1329,17 @@ void SCH_PAINTER::draw( SCH_COMPONENT *aComp, int aLayer )
// Copy the pin info from the component to the temp pins // Copy the pin info from the component to the temp pins
LIB_PINS tempPins; LIB_PINS tempPins;
tempPart.GetPins( tempPins, aComp->GetUnit(), aComp->GetConvert() ); 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 ) for( unsigned i = 0; i < tempPins.size() && i < compPins.size(); ++ i )
{ {
LIB_PIN* tempPin = tempPins[ i ]; LIB_PIN* tempPin = tempPins[ i ];
const SCH_PIN& compPin = compPins[ i ]; const SCH_PIN* compPin = compPins[ i ];
tempPin->ClearFlags(); 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 ); tempPin->SetFlags( IS_DANGLING );
} }

View File

@ -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; std::vector< DANGLING_END_ITEM > endPoints;
bool hasStateChanged = false; bool hasStateChanged = false;
@ -795,7 +795,7 @@ bool SCH_SCREEN::TestDanglingEnds()
for( auto item : Items() ) for( auto item : Items() )
{ {
if( item->UpdateDanglingState( endPoints ) ) if( item->UpdateDanglingState( endPoints, aPath ) )
hasStateChanged = true; hasStateChanged = true;
} }

View File

@ -285,9 +285,10 @@ public:
/** /**
* Test all of the connectable objects in the schematic for unused connection points. * 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. * @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 * Return all wires and junctions connected to \a aSegment which are not connected any

View File

@ -757,7 +757,8 @@ void SCH_SHEET::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_SHEET::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) bool SCH_SHEET::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{ {
bool changed = false; bool changed = false;

View File

@ -509,7 +509,8 @@ public:
void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList ) override; void GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsConnectable() const override { return true; } bool IsConnectable() const override { return true; }

View File

@ -328,7 +328,8 @@ void SCH_TEXT::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
} }
bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath )
{ {
// Normal text labels cannot be tested for dangling ends. // Normal text labels cannot be tested for dangling ends.
if( Type() == SCH_TEXT_T ) if( Type() == SCH_TEXT_T )
@ -355,8 +356,8 @@ bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
{ {
m_isDangling = false; m_isDangling = false;
if( item.GetType() != PIN_END ) if( aPath && item.GetType() != PIN_END )
m_connected_items.insert( static_cast< SCH_ITEM* >( item.GetItem() ) ); m_connected_items[ *aPath ].insert( static_cast<SCH_ITEM*>( item.GetItem() ) );
} }
break; break;
@ -385,9 +386,12 @@ bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList )
// Add the line to the connected items, since it won't be picked // Add the line to the connected items, since it won't be picked
// up by a search of intersecting connection points // up by a search of intersecting connection points
auto sch_item = static_cast< SCH_ITEM* >( item.GetItem() ); if( aPath )
AddConnectionTo( sch_item ); {
sch_item->AddConnectionTo( this ); auto sch_item = static_cast<SCH_ITEM*>( item.GetItem() );
AddConnectionTo( *aPath, sch_item );
sch_item->AddConnectionTo( *aPath, this );
}
} }
} }
break; break;
@ -669,7 +673,9 @@ bool SCH_LABEL::IsType( const KICAD_T aScanTypes[] ) const
{ {
if( *p == SCH_LABEL_LOCATE_WIRE_T ) 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 ) ) if( connection->IsType( wireTypes ) )
return true; return true;
@ -677,7 +683,9 @@ bool SCH_LABEL::IsType( const KICAD_T aScanTypes[] ) const
} }
else if ( *p == SCH_LABEL_LOCATE_BUS_T ) 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 ) ) if( connection->IsType( busTypes ) )
return true; return true;

View File

@ -299,7 +299,8 @@ public:
void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override; void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) override;
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList ) override; bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
const SCH_SHEET_PATH* aPath = nullptr ) override;
bool IsDangling() const override { return m_isDangling; } bool IsDangling() const override { return m_isDangling; }
void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; } void SetIsDangling( bool aIsDangling ) { m_isDangling = aIsDangling; }

View File

@ -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.) // represented in the LIB_PART and will inherit the settings of the parent component.)
if( itemType == SCH_COMPONENT_T ) if( itemType == SCH_COMPONENT_T )
{ {
SCH_PINS& pins = static_cast<SCH_COMPONENT*>( aItem )->GetPins(); SCH_PIN_PTRS pins = static_cast<SCH_COMPONENT*>( aItem )->GetSchPins( g_CurrentSheet );
for( SCH_PIN& pin : pins ) for( SCH_PIN* pin : pins )
{ {
if( aMode == SELECTED ) if( aMode == SELECTED )
pin.SetSelected(); pin->SetSelected();
else if( aMode == BRIGHTENED ) else if( aMode == BRIGHTENED )
pin.SetBrightened(); pin->SetBrightened();
} }
std::vector<SCH_FIELD*> fields; std::vector<SCH_FIELD*> fields;
@ -1256,14 +1256,14 @@ void EE_SELECTION_TOOL::unhighlight( EDA_ITEM* aItem, int aMode, EE_SELECTION* a
// represented in the LIB_PART.) // represented in the LIB_PART.)
if( itemType == SCH_COMPONENT_T ) if( itemType == SCH_COMPONENT_T )
{ {
SCH_PINS& pins = static_cast<SCH_COMPONENT*>( aItem )->GetPins(); SCH_PIN_PTRS pins = static_cast<SCH_COMPONENT*>( aItem )->GetSchPins( g_CurrentSheet );
for( SCH_PIN& pin : pins ) for( SCH_PIN* pin : pins )
{ {
if( aMode == SELECTED ) if( aMode == SELECTED )
pin.ClearSelected(); pin->ClearSelected();
else if( aMode == BRIGHTENED ) else if( aMode == BRIGHTENED )
pin.ClearBrightened(); pin->ClearBrightened();
} }
std::vector<SCH_FIELD*> fields; std::vector<SCH_FIELD*> fields;