26#include <unordered_map>
107 if( old_conn && new_conn )
109 new_conn->
Clone( *old_conn );
158 if( aPower && !bPower )
160 else if( bPower && !aPower )
167 if( aPower && !bPower )
169 else if( bPower && !aPower )
175 bool a_lowQualityName = a_name.Contains(
"-Pad" );
176 bool b_lowQualityName = b_name.Contains(
"-Pad" );
178 if( a_lowQualityName && !b_lowQualityName )
180 else if( b_lowQualityName && !a_lowQualityName )
183 return a_name < b_name;
187 std::set<
SCH_ITEM*,
decltype( candidate_cmp )> candidates( candidate_cmp );
188 std::set<SCH_ITEM*> strong_drivers;
212 strong_drivers.insert( item );
214 if( item_priority > highest_priority )
217 candidates.insert( item );
218 highest_priority = item_priority;
220 else if( !candidates.empty() && ( item_priority == highest_priority ) )
222 candidates.insert( item );
232 if( !candidates.empty() )
234 if( candidates.size() > 1 )
245 if( p->
GetShape() == LABEL_FLAG_SHAPE::L_OUTPUT )
258 if( strong_drivers.size() > 1 )
265 m_drivers.insert( strong_drivers.begin(), strong_drivers.end() );
287 std::set<CONNECTION_SUBGRAPH*>& aSubgraphs )
299 if( aSubgraphs.insert( sg ).second ==
false )
305 aItems.emplace(
m_sheet, item );
319#ifdef CONNECTIVITY_DEBUG
320 wxASSERT_MSG(
false, wxS(
"Tried to get the net name of an item with no connection" ) );
332 std::vector<SCH_ITEM*> labels;
336 switch( item->Type() )
344 if( type == CONNECTION_TYPE::BUS || type == CONNECTION_TYPE::BUS_GROUP )
345 labels.push_back( item );
361 std::vector<SCH_ITEM*> labels;
365 switch( item->Type() )
373 if( label_conn->
Type() == CONNECTION_TYPE::BUS )
374 labels.push_back( item );
390 switch( aItem->
Type() )
397 return pin->GetDefaultNetName(
m_sheet, forceNoConnect );
424 wxFAIL_MSG( wxS(
"Unhandled item type in GetNameForDriver" ) );
425 return wxEmptyString;
445const std::vector<std::pair<wxString, SCH_ITEM*>>
448 std::vector<std::pair<wxString, SCH_ITEM*>> foundNetclasses;
450 const std::unordered_set<SCH_RULE_AREA*>& ruleAreaCache = aItem->
GetRuleAreaCache();
455 const std::vector<std::pair<wxString, SCH_ITEM*>> ruleNetclasses =
456 ruleArea->GetResolvedNetclasses();
458 if( ruleNetclasses.size() > 0 )
460 foundNetclasses.insert( foundNetclasses.end(), ruleNetclasses.begin(),
461 ruleNetclasses.end() );
471 SCH_FIELD* field = static_cast<SCH_FIELD*>( aChild );
473 if( field->GetCanonicalName() == wxT(
"Netclass" ) )
475 wxString netclass = field->GetShownText( &m_sheet, false );
477 if( netclass != wxEmptyString )
478 foundNetclasses.push_back( { netclass, aItem } );
485 foundNetclasses.begin(), foundNetclasses.end(),
486 [](
const std::pair<wxString, SCH_ITEM*>& i1,
const std::pair<wxString, SCH_ITEM*>& i2 )
488 return i1.first < i2.first;
491 return foundNetclasses;
517 child->m_absorbed_by =
this;
520 set_absorbed_by( subchild );
528 set_absorbed_by( aOther );
578 switch( aDriver->
Type() )
594 || sym->
GetLibSymbolRef()->GetReferenceField().GetText().StartsWith(
'#' ) )
608 std::back_inserter(
m_items ) );
665 wxCHECK2( aOldItem->
Type() == aNewItem->
Type(),
return );
700 wxCHECK2( oldPins.size() == newPins.size(),
return );
702 for(
size_t ii = 0; ii < oldPins.size(); ii++ )
704 exchange( oldPins[ii], newPins[ii] );
715 if( subgraph->m_graph ==
this )
739 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler )
741 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
746 PROF_TIMER update_items(
"updateItemConnectivity" );
749 std::set<SCH_ITEM*> dirty_items;
753 std::vector<SCH_ITEM*> items;
756 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
758 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
760 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
762 wxLogTrace(
ConnTrace, wxT(
"Adding item %s to connectivity graph update" ),
763 item->GetTypeDesc() );
764 items.push_back( item );
765 dirty_items.insert( item );
774 if(
pin->IsConnectivityDirty() )
776 dirty_items.insert(
pin );
789 if(
pin->IsConnectivityDirty() )
791 items.push_back(
pin );
792 dirty_items.insert(
pin );
802 if(
pin->IsConnectivityDirty() )
804 items.push_back(
pin );
805 dirty_items.insert(
pin );
818 if( symbol->
GetUnit() != new_unit )
819 symbolsChanged.push_back( { symbol, symbol->
GetUnit() } );
821 symbol->SetUnit( new_unit );
830 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
833 for(
const auto& [ symbol, originalUnit ] : symbolsChanged )
834 symbol->SetUnit( originalUnit );
839 m_schematic->CurrentSheet().LastScreen()->TestDanglingEnds( &m_schematic->CurrentSheet(),
840 aChangedItemHandler );
843 item->SetConnectivityDirty(
false );
848 PROF_TIMER build_graph(
"buildConnectionGraph" );
850 buildConnectionGraph( aChangedItemHandler, aUnconditional );
863 const std::set<SCH_ITEM*> &aItems )
865 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> retvals;
866 std::set<CONNECTION_SUBGRAPH*> subgraphs;
871 while( aSubgraph->m_absorbed_by )
874 wxASSERT( aSubgraph->m_graph == aSubgraph->m_absorbed_by->m_graph );
875 aSubgraph = aSubgraph->m_absorbed_by;
879 while( aSubgraph->m_hier_parent )
882 wxASSERT( aSubgraph->m_graph == aSubgraph->m_hier_parent->m_graph );
883 aSubgraph = aSubgraph->m_hier_parent;
887 aSubgraph->getAllConnectedItems( retvals, subgraphs );
890 auto extract_element = [&](
SCH_ITEM* aItem )
896 wxLogTrace(
ConnTrace, wxT(
"Item %s not found in connection graph" ),
897 aItem->GetTypeDesc() );
903 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld (%p) has no driver" ),
904 aItem->GetTypeDesc(), item_sg->
m_code, item_sg );
909 if( sg_to_scan.empty() )
911 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld with net %s has no neighbors" ),
913 sg_to_scan.push_back( item_sg );
917 wxT(
"Removing all item %s connections from subgraph %ld with net %s: Found "
924 traverse_subgraph( sg );
926 for(
auto& bus_it : sg->m_bus_neighbors )
929 traverse_subgraph( bus_sg );
932 for(
auto& bus_it : sg->m_bus_parents )
935 traverse_subgraph( bus_sg );
949 extract_element(
pin );
956 extract_element(
pin );
960 extract_element( item );
966 for(
const auto& [
path, item] : retvals )
993 wxLogTrace(
ConnTrace, wxT(
"Removing %zu subgraphs" ), aSubgraphs.size() );
996 std::set<int> codes_to_remove;
1000 std::sort( el.second.begin(), el.second.end() );
1005 for(
auto& it : sg->m_bus_neighbors )
1011 for(
auto test = parents.begin();
test != parents.end(); )
1019 if( parents.empty() )
1024 for(
auto& it : sg->m_bus_parents )
1030 for(
auto test = neighbors.begin();
test != neighbors.end(); )
1038 if( neighbors.empty() )
1059 auto it = std::lower_bound( el.second.begin(), el.second.end(), sg );
1061 while( it != el.second.end() && *it == sg )
1062 it = el.second.erase( it );
1065 auto remove_sg = [sg](
auto it ) ->
bool
1078 if( remove_sg( it ) )
1086 if( remove_sg( it ) )
1095 if( remove_sg( it ) )
1097 codes_to_remove.insert( it->first.Netcode );
1109 if( remove_sg( it ) )
1117 if( it->second == sg )
1128 if( codes_to_remove.contains( it->second ) )
1136 if( codes_to_remove.contains( it->second ) )
1145 sg->m_graph =
nullptr;
1152 const std::vector<SCH_ITEM*>& aItemList )
1154 wxLogTrace( wxT(
"Updating connectivity for sheet %s with %zu items" ),
1156 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
1160 aConn->SetType( CONNECTION_TYPE::NET );
1169 aConn->SetName(
name );
1176 std::vector<VECTOR2I> points = item->GetConnectionPoints();
1177 item->ClearConnectedItems( aSheet );
1183 pin->InitializeConnection( aSheet,
this );
1185 pin->ClearConnectedItems( aSheet );
1187 connection_map[
pin->GetTextPos() ].push_back(
pin );
1195 std::map<wxString, std::vector<SCH_PIN*>> pinNumberMap;
1201 updatePin(
pin, conn );
1202 connection_map[
pin->GetPosition() ].push_back(
pin );
1203 pinNumberMap[
pin->GetNumber()].emplace_back(
pin );
1206 auto linkPinsInVec =
1207 [&](
const std::vector<SCH_PIN*>& aVec )
1209 for(
size_t i = 0; i < aVec.size(); ++i )
1211 for(
size_t j = i + 1; j < aVec.size(); ++j )
1213 aVec[i]->AddConnectionTo( aSheet, aVec[j] );
1214 aVec[j]->AddConnectionTo( aSheet, aVec[i] );
1223 for(
const std::vector<SCH_PIN*>&
group : pinNumberMap | std::views::values )
1224 linkPinsInVec(
group );
1229 std::vector<SCH_PIN*> pins;
1231 for(
const wxString& pinNumber :
group )
1232 pins.emplace_back( symbol->
GetPin( pinNumber ) );
1234 linkPinsInVec( pins );
1241 SCH_CONNECTION* conn = item->InitializeConnection( aSheet,
this );
1244 switch( item->Type() )
1248 CONNECTION_TYPE::NET );
1252 conn->
SetType( CONNECTION_TYPE::BUS );
1260 if( points.empty() )
1261 points = {
static_cast<SCH_PIN*
>( item )->GetPosition() };
1263 updatePin(
static_cast<SCH_PIN*
>( item ), conn );
1267 conn->
SetType( CONNECTION_TYPE::NET );
1277 for(
const VECTOR2I& point : points )
1278 connection_map[ point ].push_back( item );
1282 for(
const auto& it : connection_map )
1284 std::vector<SCH_ITEM*> connection_vec = it.second;
1285 std::sort( connection_vec.begin(), connection_vec.end() );
1291 std::mutex update_mutex;
1293 auto update_lambda = [&](
SCH_ITEM* connected_item ) ->
size_t
1307 if( connection_vec.size() == 1 )
1320 if( connection_vec.size() < 2 )
1326 if( it.first == bus_entry->GetPosition() )
1329 bus_entry->m_connected_bus_items[1] = busLine;
1331 std::lock_guard<std::mutex> lock( update_mutex );
1344 for(
SCH_ITEM* test_item : connection_vec )
1346 bool bus_connection_ok =
true;
1348 if( test_item == connected_item )
1354 if( test_item->GetLayer() ==
LAYER_BUS )
1373 if( connected_item->ConnectionPropagatesTo( test_item ) &&
1374 test_item->ConnectionPropagatesTo( connected_item ) &&
1377 connected_item->AddConnectionTo( aSheet, test_item );
1388 if( !bus_entry->m_connected_bus_item )
1394 bus_entry->m_connected_bus_item = bus;
1403 auto results =
tp.parallelize_loop( connection_vec.size(),
1404 [&](
const int a,
const int b)
1406 for( int ii = a; ii < b; ++ii )
1407 update_lambda( connection_vec[ii] );
1417 wxCHECK_RET(
m_schematic, wxS(
"Connection graph cannot be built without schematic pointer" ) );
1423 for(
const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
1430 for(
const auto& it : item->m_connection_map )
1447 std::list<SCH_ITEM*> memberlist;
1452 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet,
this );
1453 bool unique = !( aItem->GetFlags() &
CANDIDATE );
1458 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
1461 std::copy_if( item->ConnectedItems( sheet ).begin(),
1462 item->ConnectedItems( sheet ).end(),
1463 std::back_inserter( memberlist ), get_items );
1465 for(
SCH_ITEM* connected_item : memberlist )
1470 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
1472 wxCHECK2( connected_conn,
continue );
1478 subgraph->
AddItem( connected_item );
1479 const SCH_ITEM_VEC& citemset = connected_item->ConnectedItems( sheet );
1486 if( get_items( citem ) )
1487 memberlist.push_back( citem );
1492 for(
SCH_ITEM* connected_item : memberlist )
1493 connected_item->ClearFlags(
CANDIDATE );
1507 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
1512 return candidate->m_dirty;
1515 wxLogTrace(
ConnTrace, wxT(
"Resolving drivers for %zu subgraphs" ), dirty_graphs.size() );
1517 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
1521 if( !subgraph->m_dirty )
1525 for(
SCH_ITEM* item : subgraph->m_items )
1527 switch( item->
Type() )
1530 subgraph->m_no_connect = item;
1534 subgraph->m_bus_entry = item;
1541 if(
pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
1542 subgraph->m_no_connect = item;
1552 subgraph->ResolveDrivers(
true );
1553 subgraph->m_dirty =
false;
1560 auto results =
tp.parallelize_loop( dirty_graphs.size(),
1561 [&](
const int a,
const int b)
1563 for( int ii = a; ii < b; ++ii )
1564 update_lambda( dirty_graphs[ii] );
1573 return candidate->m_driver;
1586 wxString full_name = subgraph->m_driver_connection->Name();
1587 wxString
name = subgraph->m_driver_connection->Name(
true );
1594 if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1596 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
1600 subgraph->m_dirty =
true;
1602 if( subgraph->m_strong_driver )
1604 SCH_ITEM* driver = subgraph->m_driver;
1607 switch( driver->
Type() )
1623 if(
pin->IsGlobalPower() )
1627 else if(
pin->IsLocalPower() )
1634 wxLogTrace(
ConnTrace, wxS(
"Unexpected normal pin %s" ),
1644 wxLogTrace(
ConnTrace, wxS(
"Unexpected strong driver %s" ),
1656 std::vector<CONNECTION_SUBGRAPH*> new_subgraphs;
1667 dummy.SetGraph(
this );
1670 wxLogTrace(
ConnTrace, wxS(
"new bus label (%s)" ),
1673 for(
const auto& conn :
dummy.Members() )
1675 wxString
name = conn->FullLocalName();
1685 new_conn->
SetType( CONNECTION_TYPE::NET );
1686 subgraph->StoreImplicitConnection( new_conn );
1689 wxLogTrace(
ConnTrace, wxS(
"SG(%ld), Adding full local name (%s) with sg (%d) "
1691 subgraph->m_code,
name, code, subgraph->m_sheet.PathHumanReadable() );
1704 new_subgraphs.push_back( new_sg );
1709 std::copy( new_subgraphs.begin(), new_subgraphs.end(),
1721 std::unordered_map<int, CONNECTION_SUBGRAPH*> global_power_pin_subgraphs;
1728 if( !
pin->ConnectedItems( sheet ).empty()
1729 && !
pin->GetLibPin()->GetParentSymbol()->IsGlobalPower() )
1744 if(
pin->GetLibPin()->GetParentSymbol()->IsGlobalPower() )
1745 connection->
SetName(
pin->GetParentSymbol()->GetValue(
true, &sheet,
false ) );
1754 auto jj = global_power_pin_subgraphs.find( code );
1756 if( jj != global_power_pin_subgraphs.end() )
1758 subgraph = jj->second;
1776 global_power_pin_subgraphs[code] = subgraph;
1793 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1797 if( subgraph->m_absorbed )
1802 wxString
name = connection->
Name();
1805 unsigned suffix = 1;
1807 auto create_new_name =
1811 wxString suffixStr = std::to_wstring( suffix );
1816 if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1818 wxString prefix = aConn->BusPrefix();
1820 if( prefix.empty() )
1821 prefix = wxT(
"BUS" );
1823 wxString oldName = aConn->Name().AfterFirst(
'{' );
1825 newName << prefix << wxT(
"_" ) << suffixStr << wxT(
"{" ) << oldName;
1827 aConn->ConfigureFromLabel( newName );
1831 newName << aConn->Name() << wxT(
"_" ) << suffixStr;
1832 aConn->SetSuffix( wxString( wxT(
"_" ) ) << suffixStr );
1839 if( !subgraph->m_strong_driver )
1841 std::vector<CONNECTION_SUBGRAPH*> vec_empty;
1842 std::vector<CONNECTION_SUBGRAPH*>* vec = &vec_empty;
1849 if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1851 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1857 if( vec->size() > 1 )
1859 wxString new_name = create_new_name( connection );
1862 new_name = create_new_name( connection );
1865 wxS(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
1866 subgraph->m_code,
name, new_name );
1874 else if( subgraph->m_driver )
1886 bool conflict =
false;
1887 wxString global_name = connection->
Name(
true );
1894 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1898 if( candidate->m_sheet == sheet )
1906 wxS(
"%ld (%s) skipped for promotion due to potential "
1908 subgraph->m_code,
name );
1915 wxS(
"%ld (%s) weakly driven by unique sheet pin %s, "
1917 subgraph->m_code,
name,
1918 subgraph->m_driver->GetItemDescription( &unitsProvider,
1921 subgraph->m_strong_driver =
true;
1928 if( connection->
IsBus() )
1952 subgraph->m_dirty =
true;
1960 if( !subgraph->m_strong_driver )
1967 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1970 std::back_inserter( candidate_subgraphs ),
1973 return ( !candidate->m_absorbed &&
1974 candidate->m_strong_driver &&
1975 candidate != subgraph );
1981 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1984 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1986 auto add_connections_to_check =
1989 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
1991 if( possible_driver == aSubgraph->m_driver )
1998 if( c->Type() != aSubgraph->m_driver_connection->Type() )
2001 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
2004 connections_to_check.push_back( c );
2006 wxS(
"%lu (%s): Adding secondary driver %s" ),
2008 aSubgraph->m_driver_connection->Name(
true ),
2017 add_connections_to_check( subgraph );
2019 std::set<SCH_CONNECTION*> checked_connections;
2021 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2023 auto member = connections_to_check[i];
2026 if( !checked_connections.insert( member.get() ).second )
2029 if( member->IsBus() )
2031 connections_to_check.insert( connections_to_check.end(),
2032 member->Members().begin(),
2033 member->Members().end() );
2036 wxString test_name = member->Name(
true );
2040 if( candidate->
m_absorbed || candidate == subgraph )
2056 if( driver == candidate->
m_driver )
2068 &&
pin->GetDefaultNetName( sheet ) == test_name )
2081 if( subgraph->GetNameForDriver( driver ) == test_name )
2094 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has bus child %lu (%s)" ),
2095 subgraph->m_code, connection->
Name(),
2096 candidate->
m_code, member->Name() );
2098 subgraph->m_bus_neighbors[member].insert( candidate );
2101 else if( !connection->
IsBus()
2104 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) absorbs neighbor %lu (%s)" ),
2105 subgraph->m_code, connection->
Name(),
2109 add_connections_to_check( candidate );
2111 subgraph->Absorb( candidate );
2112 invalidated_subgraphs.insert( subgraph );
2122 if( subgraph->m_absorbed )
2125 if( !subgraph->ResolveDrivers() )
2128 if( subgraph->m_driver_connection->IsBus() )
2133 wxLogTrace(
ConnTrace, wxS(
"Re-resolving drivers for %lu (%s)" ), subgraph->m_code,
2134 subgraph->m_driver_connection->Name() );
2153 bool aUnconditional )
2156 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
2162 for(
const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
2166 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
2185 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
2189 proc_sub_graph.
Show();
2198 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
2200 std::back_inserter( global_subgraphs ),
2203 return !candidate->m_local_driver;
2215 [&](
const int a,
const int b)
2217 for( int ii = a; ii < b; ++ii )
2218 m_driver_subgraphs[ii]->UpdateItemConnections();
2228 if( !subgraph->m_dirty )
2231 wxLogTrace(
ConnTrace, wxS(
"Processing %lu (%s) for propagation" ), subgraph->m_code,
2232 subgraph->m_driver_connection->Name() );
2238 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
2240 for(
SCH_ITEM* driver : subgraph->m_drivers )
2242 if( driver == subgraph->m_driver )
2245 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
2247 if( secondary_name == subgraph->m_driver_connection->Name() )
2255 if( candidate == subgraph )
2258 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
2265 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) promoted to %s" ),
2267 subgraph->m_driver_connection->Name() );
2289 if( subgraph->m_dirty )
2306 wxASSERT_MSG( !subgraph->m_dirty,
2307 wxS(
"Subgraph not processed by propagateToNeighbors!" ) );
2309 if( subgraph->m_bus_parents.size() < 2 )
2314 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has multiple bus parents" ),
2315 subgraph->m_code, conn->
Name() );
2318 wxASSERT( conn->
IsNet() );
2320 for(
const auto& ii : subgraph->m_bus_parents )
2333 wxLogTrace(
ConnTrace, wxS(
"Warning: could not match %s inside %lu (%s)" ),
2338 if( conn->
Name() != match->
Name() )
2340 wxString old_name = match->
Name();
2342 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ),
2344 old_name, conn->
Name() );
2346 match->
Clone( *conn );
2365 auto updateItemConnectionsTask =
2369 if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
2370 subgraph->m_driver->Type() ==
SCH_PIN_T )
2373 wxString
name =
pin->GetDefaultNetName( subgraph->m_sheet,
true );
2375 subgraph->m_driver_connection->ConfigureFromLabel(
name );
2378 subgraph->m_dirty =
false;
2379 subgraph->UpdateItemConnections();
2382 if( subgraph->m_driver_connection->IsBus() )
2387 if( subgraph->m_driver && subgraph->m_driver->Type() ==
SCH_SHEET_PIN_T )
2393 wxString pinText =
pin->GetShownText(
false );
2400 if( label->
GetShownText( &subgraph->m_sheet,
false ) == pinText )
2403 path.push_back( sheet );
2407 if( parent_conn && parent_conn->
IsBus() )
2408 subgraph->m_driver_connection->
SetType( CONNECTION_TYPE::BUS );
2414 if( subgraph->m_driver_connection->IsBus() )
2423 [&](
const int a,
const int b)
2425 for(
int ii = a; ii < b; ++ii )
2436 subgraph->m_driver_connection->NetCode() };
2443 std::map<wxString, std::set<wxString>> oldAssignments =
2444 netSettings->GetNetclassLabelAssignments();
2445 std::set<wxString> affectedNetclassNetAssignments;
2447 netSettings->ClearNetclassLabelAssignments();
2449 auto dirtySubgraphs =
2450 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2452 if( aChangedItemHandler )
2456 for(
SCH_ITEM* item : subgraph->m_items )
2457 (*aChangedItemHandler)( item );
2462 auto checkNetclassDrivers =
2463 [&](
const wxString& netName,
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2465 wxCHECK_RET( !subgraphs.empty(), wxS(
"Invalid empty subgraph" ) );
2467 std::set<wxString> netclasses;
2472 for(
SCH_ITEM* item : subgraph->m_items )
2474 std::vector<std::pair<wxString, SCH_ITEM*>> netclassesWithProviders =
2475 subgraph->GetNetclassesForDriver( item );
2477 for( std::pair<wxString, SCH_ITEM*>& ncPair : netclassesWithProviders )
2478 netclasses.insert( std::move( ncPair.first ) );
2485 if( subgraph->m_driver_connection->IsBus() )
2487 auto processBusMember = [&,
this](
const SCH_CONNECTION* member )
2489 if( !netclasses.empty() )
2491 netSettings->AppendNetclassLabelAssignment( member->Name(), netclasses );
2496 if( oldAssignments.count( member->Name() ) )
2498 if( oldAssignments[member->Name()] != netclasses )
2500 affectedNetclassNetAssignments.insert( member->Name() );
2503 dirtySubgraphs( ii->second );
2506 else if( !netclasses.empty() )
2508 affectedNetclassNetAssignments.insert( member->Name() );
2511 dirtySubgraphs( ii->second );
2515 for(
const std::shared_ptr<SCH_CONNECTION>& member :
2516 subgraph->m_driver_connection->Members() )
2521 if( member->IsBus() )
2523 for(
const std::shared_ptr<SCH_CONNECTION>& nestedMember :
2526 processBusMember( nestedMember.get() );
2531 processBusMember( member.get() );
2538 if( !netclasses.empty() )
2540 netSettings->AppendNetclassLabelAssignment( netName, netclasses );
2543 if( oldAssignments.count( netName ) )
2545 if( oldAssignments[netName] != netclasses )
2547 affectedNetclassNetAssignments.insert( netName );
2548 dirtySubgraphs( subgraphs );
2551 else if( !netclasses.empty() )
2553 affectedNetclassNetAssignments.insert( netName );
2554 dirtySubgraphs( subgraphs );
2560 checkNetclassDrivers( netname, subgraphs );
2562 if( !aUnconditional )
2564 for(
auto& [netname, netclasses] : oldAssignments )
2566 if( netSettings->GetNetclassLabelAssignments().count( netname )
2567 || affectedNetclassNetAssignments.count( netname ) )
2572 netSettings->SetNetclassLabelAssignment( netname, netclasses );
2610 std::vector<std::shared_ptr<SCH_CONNECTION>> connections_to_check( aConnection->
Members() );
2612 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2614 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
2616 if( member->IsBus() )
2618 connections_to_check.insert( connections_to_check.end(),
2619 member->Members().begin(),
2620 member->Members().end() );
2632 std::vector<CONNECTION_SUBGRAPH*> search_list;
2633 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
2634 std::unordered_set<SCH_CONNECTION*> stale_bus_members;
2641 path.push_back(
pin->GetParent() );
2652 || visited.contains( candidate ) )
2661 wxLogTrace(
ConnTrace, wxS(
"%lu: found child %lu (%s)" ), aParent->m_code,
2669 wxASSERT( candidate->
m_graph == aParent->m_graph );
2671 search_list.push_back( candidate );
2691 || visited.contains( candidate )
2697 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
2702 if(
pin->GetParent()->m_Uuid != last_parent_uuid )
2708 if( pin_path != aParent->m_sheet )
2713 wxLogTrace(
ConnTrace, wxS(
"%lu: found additional parent %lu (%s)" ),
2714 aParent->m_code, candidate->
m_code,
2717 aParent->m_hier_children.insert( candidate );
2718 search_list.push_back( candidate );
2728 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
2770 wxLogTrace(
ConnTrace, wxS(
"Could not match bus member %s in %s" ),
2771 kv.first->Name(), parent->
Name() );
2776 auto neighbor_name = neighbor_conn->
Name();
2779 if( neighbor_name == member->
Name() )
2783 if( neighbor_conn->Sheet() != neighbor->
m_sheet )
2787 wxCHECK2_MSG( neighbor_conn->IsNet(),
continue,
2788 wxS(
"\"" ) + neighbor_name + wxS(
"\" is not a net." ) );
2790 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) connected to bus member %s (local %s)" ),
2797 member->
Clone( *neighbor_conn );
2798 stale_bus_members.insert( member );
2802 neighbor_conn->Clone( *member );
2816 propagate_bus_neighbors( aSubgraph );
2823 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has both hier ports and pins; deferring processing" ),
2830 wxS(
"%lu (%s) has no hier pins or ports on sheet %s; marking clean" ),
2836 visited.insert( aSubgraph );
2838 wxLogTrace(
ConnTrace, wxS(
"Propagating %lu (%s) to subsheets" ),
2843 for(
unsigned i = 0; i < search_list.size(); i++ )
2845 auto child = search_list[i];
2847 if( visited.insert( child ).second )
2850 child->m_dirty =
false;
2865 if( subgraph == aSubgraph )
2872 wxString candidateName = subgraph->m_driver_connection->Name();
2873 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
2874 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
2884 ( !bestIsStrong && candidateStrong ) ||
2885 ( priority > highest && candidateStrong ) ||
2886 ( priority == highest && candidateStrong && shorterPath ) ||
2887 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
2888 ( candidateName < bestName ) ) )
2890 bestDriver = subgraph;
2892 bestIsStrong = candidateStrong;
2893 bestName = candidateName;
2898 if( bestDriver != aSubgraph )
2900 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) overridden by new driver %lu (%s)" ),
2909 wxString old_name = subgraph->m_driver_connection->
Name();
2911 subgraph->m_driver_connection->Clone( *conn );
2913 if( old_name != conn->
Name() )
2917 propagate_bus_neighbors( subgraph );
2923 if( conn->
IsBus() && !stale_bus_members.empty() )
2925 std::unordered_set<SCH_CONNECTION*> cached_members = stale_bus_members;
2936 wxLogTrace(
ConnTrace, wxS(
"WARNING: failed to match stale member %s in %s." ),
2937 stale_member->Name(), subgraph->m_driver_connection->Name() );
2941 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
2942 subgraph->m_driver_connection->Name(), member->
LocalName(),
2943 stale_member->Name() );
2945 member->
Clone( *stale_member );
2947 propagate_bus_neighbors( subgraph );
2959 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
2961 switch( aItem->
Type() )
2967 if(
pin->IsPower() )
2968 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2977 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2987 c->SetGraph(
this );
2999 wxASSERT( aBusConnection->
IsBus() );
3003 if( aBusConnection->
Type() == CONNECTION_TYPE::BUS )
3008 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
3010 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
3012 match = bus_member.get();
3020 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
3025 if( c->Type() == CONNECTION_TYPE::BUS )
3027 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
3029 if( bus_member->LocalName() == aSearch->
LocalName() )
3031 match = bus_member.get();
3036 else if( c->LocalName() == aSearch->
LocalName() )
3049 const wxString& aOldName )
3055 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
3059 wxLogTrace(
ConnTrace, wxS(
"recacheSubgraphName: %s => %s" ), aOldName,
3076 std::vector<const CONNECTION_SUBGRAPH*> ret;
3082 wxASSERT( !subgraph->m_dirty );
3084 if( !subgraph->m_driver )
3090 if( !connection->
IsBus() )
3093 auto labels = subgraph->GetVectorBusLabels();
3095 if( labels.size() > 1 )
3097 bool different =
false;
3098 wxString first =
static_cast<SCH_TEXT*
>( labels.at( 0 ) )->GetShownText( sheet,
false );
3100 for(
unsigned i = 1; i < labels.size(); ++i )
3113 wxLogTrace(
ConnTrace, wxS(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
3114 connection->
Name() );
3116 ret.push_back( subgraph );
3137 if( graph == aSubGraph )
3180 wxASSERT( !it->second.empty() );
3182 return it->second[0];
3198const std::vector<CONNECTION_SUBGRAPH*>&
3201 static const std::vector<CONNECTION_SUBGRAPH*> subgraphs;
3214 int error_count = 0;
3216 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
3222 std::set<SCH_ITEM*> seenDriverInstances;
3227 wxCHECK2( subgraph,
continue );
3231 wxASSERT( !subgraph->m_dirty );
3233 if( subgraph->m_absorbed )
3236 if( seenDriverInstances.count( subgraph->m_driver ) )
3239 if( subgraph->m_driver )
3240 seenDriverInstances.insert( subgraph->m_driver );
3258 subgraph->ResolveDrivers(
false );
3329 wxCHECK( aSubgraph,
false );
3335 if( driver == aSubgraph->
m_driver )
3347 if( primaryName == secondaryName )
3350 wxString msg = wxString::Format(
_(
"Both %s and %s are attached to the same "
3351 "items; %s will be used in the netlist" ),
3352 primaryName, secondaryName, primaryName );
3355 ercItem->SetItems( aSubgraph->
m_driver, driver );
3356 ercItem->SetSheetSpecificPath( aSubgraph->
GetSheet() );
3357 ercItem->SetItemsSheetPaths( aSubgraph->
GetSheet(), aSubgraph->
m_sheet );
3358 ercItem->SetErrorMessage( msg );
3383 switch( item->
Type() )
3388 bus_item = ( !bus_item ) ? item : bus_item;
3390 net_item = ( !net_item ) ? item : net_item;
3405 bus_item = ( !bus_item ) ? item : bus_item;
3407 net_item = ( !net_item ) ? item : net_item;
3417 if( net_item && bus_item )
3420 ercItem->SetSheetSpecificPath( sheet );
3421 ercItem->SetItems( net_item, bus_item );
3424 screen->
Append( marker );
3443 switch( item->
Type() )
3474 if(
test != member && member->Name() ==
test->Name() )
3488 ercItem->SetSheetSpecificPath( sheet );
3489 ercItem->SetItems( label, port );
3492 screen->
Append( marker );
3504 bool conflict =
false;
3520 switch( item->
Type() )
3551 std::set<wxString> test_names;
3561 if( member->Type() == CONNECTION_TYPE::BUS )
3563 for(
const auto& sub_member : member->Members() )
3565 if( test_names.count( sub_member->FullLocalName() ) )
3569 else if( test_names.count( member->FullLocalName() ) )
3588 wxString msg = wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
3589 " member of that bus" ),
3593 ercItem->SetSheetSpecificPath( sheet );
3594 ercItem->SetItems( bus_entry, bus_wire );
3595 ercItem->SetErrorMessage( msg );
3598 screen->
Append( marker );
3615 std::set<SCH_PIN*> unique_pins;
3616 std::set<SCH_LABEL_BASE*> unique_labels;
3624 for(
SCH_ITEM* item : aProcessGraph->m_items )
3626 switch( item->
Type() )
3633 if( aProcessGraph == aSubgraph )
3636 if( std::none_of( unique_pins.begin(), unique_pins.end(),
3643 unique_pins.insert( test_pin );
3666 process_subgraph( subgraph );
3671 process_subgraph( aSubgraph );
3699 if( test_pin && test_pin->
GetType() == ELECTRICAL_PINTYPE::PT_NC )
3706 ercItem->SetSheetSpecificPath( sheet );
3707 ercItem->SetItemsSheetPaths( sheet );
3714 pos =
pin->GetPosition();
3723 screen->
Append( marker );
3728 if( unique_pins.empty() && unique_labels.empty() &&
3733 ercItem->SetSheetSpecificPath( sheet );
3734 ercItem->SetItemsSheetPaths( sheet );
3737 screen->
Append( marker );
3744 bool has_other_connections =
false;
3745 std::vector<SCH_PIN*> pins;
3752 switch( item->
Type() )
3759 if( !has_other_connections && !pins.empty()
3762 for(
SCH_PIN* other_pin : pins )
3766 has_other_connections =
true;
3772 pins.emplace_back(
static_cast<SCH_PIN*
>( item ) );
3779 has_other_connections =
true;
3786 pin = pins.empty() ? nullptr : pins[0];
3789 for(
SCH_PIN* test_pin : pins )
3794 if( test_pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
3795 && !test_pin->IsPower() )
3806 if(
pin && !has_other_connections
3808 && !
pin->GetLibPin()->GetParentSymbol()->IsPower() )
3810 wxString
name =
pin->Connection( &sheet )->Name();
3811 wxString local_name =
pin->Connection( &sheet )->Name(
true );
3816 has_other_connections =
true;
3821 if(
pin && !has_other_connections
3822 &&
pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
3823 &&
pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
3827 ercItem->SetSheetSpecificPath( sheet );
3828 ercItem->SetItemsSheetPaths( sheet );
3829 ercItem->SetItems(
pin );
3832 screen->
Append( marker );
3840 if( pins.size() > 1 )
3842 for(
SCH_PIN* testPin : pins )
3847 if( testPin->GetLibPin()->GetParentSymbol()->IsPower()
3848 && testPin->ConnectedItems( sheet ).empty()
3852 ercItem->SetSheetSpecificPath( sheet );
3853 ercItem->SetItemsSheetPaths( sheet );
3854 ercItem->SetItems( testPin );
3857 screen->
Append( marker );
3888 std::shared_ptr<ERC_ITEM> ercItem =
3891 ercItem->SetItems( line );
3892 ercItem->SetSheetSpecificPath( sheet );
3893 ercItem->SetErrorMessage(
_(
"Unconnected wire endpoint" ) );
3913 std::shared_ptr<ERC_ITEM> ercItem =
3916 ercItem->SetItems( entry );
3917 ercItem->SetSheetSpecificPath( sheet );
3918 ercItem->SetErrorMessage(
_(
"Unconnected wire to bus entry" ) );
3935 return err_count > 0;
3945 std::vector<SCH_ITEM*> wires;
3952 wires.emplace_back( item );
3954 wires.emplace_back( item );
3957 if( !wires.empty() )
3962 ercItem->SetSheetSpecificPath( sheet );
3963 ercItem->SetItems( wires[0],
3964 wires.size() > 1 ? wires[1] :
nullptr,
3965 wires.size() > 2 ? wires[2] :
nullptr,
3966 wires.size() > 3 ? wires[3] :
nullptr );
3969 screen->
Append( marker );
3997 size_t pinCount = 0;
4000 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
4006 return std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(),
4009 return item->Type() == SCH_PIN_T;
4014 [&](
SCH_TEXT* aText,
int errCode )
4019 ercItem->SetSheetSpecificPath( sheet );
4020 ercItem->SetItems( aText );
4027 pinCount =
hasPins( aSubgraph );
4031 switch( item->
Type() )
4039 label_map[item->
Type()].push_back(
text );
4044 if(
text->IsDangling() )
4060 if( label_map.empty() )
4065 for(
auto& [ connection, subgraphs ] : aSubgraph->
m_bus_parents )
4069 if( busParent->m_no_connect )
4092 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
4099 for(
auto& [type, label_vec] : label_map )
4117 size_t allPins = pinCount;
4125 if( neighbor == aSubgraph )
4131 allPins +=
hasPins( neighbor );
4135 if( allPins == 1 && !has_nc )
4159 std::map<wxString, std::tuple<int, const SCH_ITEM*, SCH_SHEET_PATH>> labelData;
4166 wxString resolvedLabelText =
4169 if( labelData.find( resolvedLabelText ) == labelData.end() )
4171 labelData[resolvedLabelText] = { 1, item, sheet };
4175 std::get<0>( labelData[resolvedLabelText] ) += 1;
4176 std::get<1>( labelData[resolvedLabelText] ) =
nullptr;
4177 std::get<2>( labelData[resolvedLabelText] ) = sheet;
4182 for(
const auto& label : labelData )
4184 if( std::get<0>( label.second ) == 1 )
4187 const SCH_ITEM* item = std::get<1>( label.second );
4190 ercItem->SetItems( std::get<1>( label.second ) );
4191 ercItem->SetSheetSpecificPath( sheet );
4192 ercItem->SetItemsSheetPaths( sheet );
4207 int error_count = 0;
4219 ercItem->SetSheetSpecificPath( sheet );
4220 ercItem->SetItems(
text );
4223 sheet.LastScreen()->Append( marker );
4246 parentSheetPath.
push_back( parentSheet );
4248 std::map<wxString, SCH_SHEET_PIN*> pins;
4249 std::map<wxString, SCH_HIERLABEL*> labels;
4254 pins[
pin->GetShownText( &parentSheetPath,
false ) ] =
pin;
4259 ercItem->SetItems(
pin );
4260 ercItem->SetSheetSpecificPath( sheet );
4261 ercItem->SetItemsSheetPaths( sheet );
4264 sheet.LastScreen()->Append( marker );
4272 std::set<wxString> matchedPins;
4279 wxString labelText = label->
GetShownText( &parentSheetPath,
false );
4281 if( !pins.count( labelText ) )
4282 labels[ labelText ] = label;
4284 matchedPins.insert( labelText );
4288 for(
const wxString& matched : matchedPins )
4289 pins.erase( matched );
4291 for(
const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
4293 wxString msg = wxString::Format(
_(
"Sheet pin %s has no matching hierarchical "
4294 "label inside the sheet" ),
4298 ercItem->SetItems( unmatched.second );
4299 ercItem->SetErrorMessage( msg );
4300 ercItem->SetSheetSpecificPath( sheet );
4301 ercItem->SetItemsSheetPaths( sheet );
4304 sheet.LastScreen()->Append( marker );
4309 for(
const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
4311 wxString msg = wxString::Format(
_(
"Hierarchical label %s has no matching "
4312 "sheet pin in the parent sheet" ),
4316 ercItem->SetItems( unmatched.second );
4317 ercItem->SetErrorMessage( msg );
4318 ercItem->SetSheetSpecificPath( parentSheetPath );
4319 ercItem->SetItemsSheetPaths( parentSheetPath );
constexpr EDA_IU_SCALE schIUScale
Calculate the connectivity of a schematic and generates netlists.
int RunERC()
Run electrical rule checks on the connectivity graph.
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for conflicting connections between two bus items.
void processSubGraphs()
Process all subgraphs to assign netcodes and merge subgraphs based on labels.
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for proper connection of labels.
void RemoveItem(SCH_ITEM *aItem)
void collectAllDriverValues()
Map the driver values for each subgraph.
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Return the subgraph for a given net name on a given sheet.
int ercCheckDirectiveLabels()
Check directive labels should be connected to something.
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
Cache to lookup subgraphs in m_driver_subgraphs by sheet path.
CONNECTION_SUBGRAPH * FindFirstSubgraphByName(const wxString &aNetName)
Retrieve a subgraph for the given net name, if one exists.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph, bool aForce)
Update all neighbors of a subgraph with this one's connectivity info.
void buildItemSubGraphs()
Generate individual item subgraphs on a per-sheet basis.
const std::vector< CONNECTION_SUBGRAPH * > & GetAllSubgraphs(const wxString &aNetName) const
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
SCH_SHEET_LIST m_sheetList
All the sheets in the schematic (as long as we don't have partial updates).
void generateGlobalPowerPinSubGraphs()
Iterate through the global power pins to collect the global labels as drivers.
std::unordered_map< wxString, int > m_net_name_to_code_map
int ercCheckSingleGlobalLabel()
Check that a global label is instantiated more that once across the schematic hierarchy.
int ercCheckHierSheets()
Check that a hierarchical sheet has at least one matching label inside the sheet for each port on the...
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for conflicting connections between net and bus labels.
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Build a new default connection for the given item based on its properties.
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration()
Determine which subgraphs have more than one conflicting bus label.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
int getOrCreateNetCode(const wxString &aNetName)
bool ercCheckDanglingWireEndpoints(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for dangling wire endpoints.
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensure all members of the bus connection have a valid net code assigned.
std::unordered_map< wxString, int > m_bus_name_to_code_map
std::unordered_map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
The owner of all CONNECTION_SUBGRAPH objects.
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_global_power_pins
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for proper presence or absence of no-connect symbols.
size_t hasPins(const CONNECTION_SUBGRAPH *aLocSubgraph)
Get the number of pins in a given subgraph.
std::vector< SCH_ITEM * > m_items
All connectable items in the schematic.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::shared_ptr< BUS_ALIAS > GetBusAlias(const wxString &aName)
Return a bus alias pointer for the given name if it exists (from cache)
void removeSubgraphs(std::set< CONNECTION_SUBGRAPH * > &aSubgraphs)
Remove references to the given subgraphs from all structures in the connection graph.
std::unordered_map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
std::set< std::pair< SCH_SHEET_PATH, SCH_ITEM * > > ExtractAffectedItems(const std::set< SCH_ITEM * > &aItems)
For a set of items, this will remove the connected items and their associated data including subgraph...
wxString GetResolvedSubgraphName(const CONNECTION_SUBGRAPH *aSubGraph) const
Return the fully-resolved netname for a given subgraph.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for conflicting bus entry to bus connections.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
Cache of a subset of m_subgraphs.
void ExchangeItem(SCH_ITEM *aOldItem, SCH_ITEM *aNewItem)
Replace all references to #aOldItem with #aNewItem in the graph.
NET_MAP m_net_code_to_subgraphs_map
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for floating wires.
void buildConnectionGraph(std::function< void(SCH_ITEM *)> *aChangedItemHandler, bool aUnconditional)
Generate the connection graph (after all item connectivity has been updated).
void Merge(CONNECTION_GRAPH &aGraph)
Combine the input graph contents into the current graph.
void resolveAllDrivers()
Find all subgraphs in the connection graph and calls ResolveDrivers() in parallel.
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Update the graphical connectivity between items (i.e.
CONNECTION_SUBGRAPH * GetSubgraphForItem(SCH_ITEM *aItem) const
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
Update the connection graph for the given list of sheets.
void generateBusAliasMembers()
Iterate through labels to create placeholders for bus elements.
A subgraph is a set of items that are electrically connected on a single sheet.
wxString driverName(SCH_ITEM *aItem) const
PRIORITY GetDriverPriority()
bool m_strong_driver
True if the driver is "strong": a label or power object.
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::set< CONNECTION_SUBGRAPH * > m_absorbed_subgraphs
Set of subgraphs that have been absorbed by this subgraph.
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
std::mutex m_driver_name_cache_mutex
A cache of escaped netnames from schematic items.
SCH_SHEET_PATH m_sheet
On which logical sheet is the subgraph contained.
void UpdateItemConnections()
Update all items to match the driver connection.
std::set< SCH_SHEET_PIN * > m_hier_pins
Cache for lookup of any hierarchical (sheet) pins on this subgraph (for referring down).
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_neighbors
If a subgraph is a bus, this map contains links between the bus members and any local sheet neighbors...
CONNECTION_GRAPH * m_graph
std::vector< SCH_ITEM * > GetAllBusLabels() const
Return all the all bus labels attached to this subgraph (if any).
std::unordered_map< SCH_ITEM *, wxString > m_driver_name_cache
const wxString & GetNameForDriver(SCH_ITEM *aItem) const
Return the candidate net name for a driver.
wxString GetNetName() const
Return the fully-qualified net name for this subgraph (if one exists)
std::vector< SCH_ITEM * > GetVectorBusLabels() const
Return all the vector-based bus labels attached to this subgraph (if any).
const SCH_SHEET_PATH & GetSheet() const
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determine which potential driver should drive the subgraph.
std::set< SCH_ITEM * > m_drivers
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
std::unordered_set< CONNECTION_SUBGRAPH * > m_hier_children
If not null, this indicates the subgraph(s) on a lower level sheet that are linked to this one.
void AddItem(SCH_ITEM *aItem)
Add a new item to the subgraph.
const std::vector< std::pair< wxString, SCH_ITEM * > > GetNetclassesForDriver(SCH_ITEM *aItem) const
Return the resolved netclasses for the item, and the source item providing the netclass.
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combine another subgraph on the same sheet into this one.
std::set< SCH_ITEM * > m_items
Contents of the subgraph.
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_parents
If this is a net, this vector contains links to any same-sheet buses that contain it.
SCH_ITEM * m_driver
Fully-resolved driver for the subgraph (might not exist in this subgraph).
std::mutex m_driver_mutex
bool m_is_bus_member
True if the subgraph is not actually part of a net.
void ExchangeItem(SCH_ITEM *aOldItem, SCH_ITEM *aNewItem)
Replaces all references to #aOldItem with #aNewItem in the subgraph.
CONNECTION_SUBGRAPH * m_hier_parent
If not null, this indicates the subgraph on a higher level sheet that is linked to this one.
void RemoveItem(SCH_ITEM *aItem)
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::set< SCH_HIERLABEL * > m_hier_ports
Cache for lookup of any hierarchical ports on this subgraph (for referring up).
void getAllConnectedItems(std::set< std::pair< SCH_SHEET_PATH, SCH_ITEM * > > &aItems, std::set< CONNECTION_SUBGRAPH * > &aSubgraphs)
Find all items in the subgraph as well as child subgraphs recursively.
virtual VECTOR2I GetPosition() const
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
KICAD_T Type() const
Returns the type of object.
EE_TYPE Overlapping(const BOX2I &aRect) const
EE_TYPE OfType(KICAD_T aType) const
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Container for ERC settings.
bool IsTestEnabled(int aErrorCode) const
A small class to help profiling.
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
virtual PROJECT_FILE & GetProjectFile() const
PROJECT & Prj() const
Return a reference to the project this schematic is part of.
SCH_SHEET_PATH & CurrentSheet() const
ERC_SETTINGS & ErcSettings() const
Class for a bus to bus entry.
SCH_ITEM * m_connected_bus_items[2]
Pointer to the bus items (usually bus wires) connected to this bus-bus entry (either or both may be n...
bool IsStartDangling() const
VECTOR2I GetPosition() const override
bool IsEndDangling() const
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Class for a wire to bus entry.
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString FullLocalName() const
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
void SetSubgraphCode(int aCode)
void SetBusCode(int aCode)
void SetName(const wxString &aName)
CONNECTION_TYPE Type() const
void SetNetCode(int aCode)
SCH_ITEM * m_driver
The SCH_ITEM that drives this connection's net.
bool IsDriver() const
Checks if the SCH_ITEM this connection is attached to can drive connections Drivers can be labels,...
void SetType(CONNECTION_TYPE aType)
wxString LocalName() const
wxString Name(bool aIgnoreSheet=false) const
bool IsSubsetOf(SCH_CONNECTION *aOther) const
Returns true if this connection is contained within aOther (but not the same as aOther)
void SetDriver(SCH_ITEM *aItem)
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
void SetGraph(CONNECTION_GRAPH *aGraph)
const std::vector< std::shared_ptr< SCH_CONNECTION > > & Members() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
void ClearConnectedItems(const SCH_SHEET_PATH &aPath)
Clear all connections to this item.
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
const SYMBOL * GetParentSymbol() const
virtual const wxString & GetCachedDriverName() const
const std::unordered_set< SCH_RULE_AREA * > & GetRuleAreaCache() const
Get the cache of rule areas enclosing this item.
void AddConnectionTo(const SCH_SHEET_PATH &aPath, SCH_ITEM *aItem)
Add a connection link between this item and another.
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
void SetConnectionGraph(CONNECTION_GRAPH *aGraph)
Update the connection graph for all connections in this item.
virtual bool HasCachedDriverName() const
SCH_CONNECTION * GetOrInitConnection(const SCH_SHEET_PATH &aPath, CONNECTION_GRAPH *aGraph)
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const override
bool IsDangling() const override
LABEL_FLAG_SHAPE GetShape() const
Segment description base class to describe items which have 2 end points (track, wire,...
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
bool IsStartDangling() const
bool IsEndDangling() const
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
bool IsGlobalPower() const
Return whether this pin forms a global power connection: i.e., is part of a power symbol and of type ...
bool IsLocalPower() const
Local power pin is the same except that it is sheet-local and it does not support the legacy hidden p...
SCH_PIN * GetLibPin() const
bool IsStacked(const SCH_PIN *aPin) const
wxString GetDefaultNetName(const SCH_SHEET_PATH &aPath, bool aForceNoConnect=false)
bool IsPower() const
Check if the pin is either a global or local power pin.
ELECTRICAL_PINTYPE GetType() const
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
const SCH_SHEET * GetSheet(unsigned aIndex) const
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
SCH_SCREEN * LastScreen()
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
wxString GetFileName() const
Return the filename corresponding to this sheet.
SCH_SCREEN * GetScreen() const
std::vector< SCH_SHEET_PIN * > & GetPins()
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
VECTOR2I GetPosition() const override
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
virtual bool IsGlobalPower() const =0
bool GetExcludedFromBoard() const
virtual bool IsLocalPower() const =0
virtual bool IsPower() const =0
#define CANDIDATE
flag indicating that the structure is connected
@ ERCE_DRIVER_CONFLICT
Conflicting drivers (labels, etc) on a subgraph.
@ ERCE_UNCONNECTED_WIRE_ENDPOINT
A label is connected to more than one wire.
@ ERCE_LABEL_NOT_CONNECTED
Label not connected to anything.
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
@ ERCE_BUS_ENTRY_CONFLICT
A wire connected to a bus doesn't match the bus.
@ ERCE_BUS_TO_NET_CONFLICT
A bus wire is graphically connected to a net port/pin (or vice versa).
@ ERCE_NOCONNECT_NOT_CONNECTED
A no connect symbol is not connected to anything.
@ ERCE_PIN_NOT_CONNECTED
Pin not connected and not no connect symbol.
@ ERCE_GLOBLABEL_DANGLING
A global label is dangling.
@ ERCE_NOCONNECT_CONNECTED
A no connect symbol is connected to more than 1 pin.
@ ERCE_HIERACHICAL_LABEL
Mismatch between hierarchical labels and pins sheets.
@ ERCE_WIRE_DANGLING
Some wires are not connected to anything else.
@ ERCE_SINGLE_GLOBAL_LABEL
A global label only exists once in the schematic.
static const wxChar DanglingProfileMask[]
Flag to enable connectivity profiling.
static const wxChar ConnTrace[]
Flag to enable connectivity tracing.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
std::vector< SCH_ITEM * > SCH_ITEM_VEC
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
Functions to provide common constants and other functions to assist in making a consistent UI.