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 } );
484 foundNetclasses.begin(), foundNetclasses.end(),
485 [](
const std::pair<wxString, SCH_ITEM*>& i1,
const std::pair<wxString, SCH_ITEM*>& i2 )
487 return i1.first < i2.first;
490 return foundNetclasses;
516 child->m_absorbed_by =
this;
519 set_absorbed_by( subchild );
527 set_absorbed_by( aOther );
577 switch( aDriver->
Type() )
593 || sym->
GetLibSymbolRef()->GetReferenceField().GetText().StartsWith(
'#' ) )
607 std::back_inserter(
m_items ) );
664 wxCHECK2( aOldItem->
Type() == aNewItem->
Type(),
return );
699 wxCHECK2( oldPins.size() == newPins.size(),
return );
701 for(
size_t ii = 0; ii < oldPins.size(); ii++ )
703 exchange( oldPins[ii], newPins[ii] );
714 if( subgraph->m_graph ==
this )
738 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler )
740 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
745 PROF_TIMER update_items(
"updateItemConnectivity" );
748 std::set<SCH_ITEM*> dirty_items;
752 std::vector<SCH_ITEM*> items;
755 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
757 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
759 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
761 wxLogTrace(
ConnTrace, wxT(
"Adding item %s to connectivity graph update" ),
762 item->GetTypeDesc() );
763 items.push_back( item );
764 dirty_items.insert( item );
773 if(
pin->IsConnectivityDirty() )
775 dirty_items.insert(
pin );
788 if(
pin->IsConnectivityDirty() )
790 items.push_back(
pin );
791 dirty_items.insert(
pin );
801 if(
pin->IsConnectivityDirty() )
803 items.push_back(
pin );
804 dirty_items.insert(
pin );
817 if( symbol->
GetUnit() != new_unit )
818 symbolsChanged.push_back( { symbol, symbol->
GetUnit() } );
820 symbol->SetUnit( new_unit );
829 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
832 for(
const auto& [ symbol, originalUnit ] : symbolsChanged )
833 symbol->SetUnit( originalUnit );
838 m_schematic->CurrentSheet().LastScreen()->TestDanglingEnds( &m_schematic->CurrentSheet(),
839 aChangedItemHandler );
842 item->SetConnectivityDirty(
false );
847 PROF_TIMER build_graph(
"buildConnectionGraph" );
849 buildConnectionGraph( aChangedItemHandler, aUnconditional );
862 const std::set<SCH_ITEM*> &aItems )
864 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> retvals;
865 std::set<CONNECTION_SUBGRAPH*> subgraphs;
870 while( aSubgraph->m_absorbed_by )
872 wxASSERT( aSubgraph->m_graph == aSubgraph->m_absorbed_by->m_graph );
873 aSubgraph = aSubgraph->m_absorbed_by;
877 while( aSubgraph->m_hier_parent )
879 wxASSERT( aSubgraph->m_graph == aSubgraph->m_hier_parent->m_graph );
880 aSubgraph = aSubgraph->m_hier_parent;
884 aSubgraph->getAllConnectedItems( retvals, subgraphs );
887 auto extract_element = [&](
SCH_ITEM* aItem )
893 wxLogTrace(
ConnTrace, wxT(
"Item %s not found in connection graph" ),
894 aItem->GetTypeDesc() );
900 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld (%p) has no driver" ),
901 aItem->GetTypeDesc(), item_sg->
m_code, item_sg );
906 if( sg_to_scan.empty() )
908 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld with net %s has no neighbors" ),
910 sg_to_scan.push_back( item_sg );
914 wxT(
"Removing all item %s connections from subgraph %ld with net %s: Found "
921 traverse_subgraph( sg );
923 for(
auto& bus_it : sg->m_bus_neighbors )
926 traverse_subgraph( bus_sg );
929 for(
auto& bus_it : sg->m_bus_parents )
932 traverse_subgraph( bus_sg );
946 extract_element(
pin );
953 extract_element(
pin );
957 extract_element( item );
963 for(
const auto& [
path, item] : retvals )
990 wxLogTrace(
ConnTrace, wxT(
"Removing %zu subgraphs" ), aSubgraphs.size() );
993 std::set<int> codes_to_remove;
997 std::sort( el.second.begin(), el.second.end() );
1002 for(
auto& it : sg->m_bus_neighbors )
1008 for(
auto test = parents.begin();
test != parents.end(); )
1016 if( parents.empty() )
1021 for(
auto& it : sg->m_bus_parents )
1027 for(
auto test = neighbors.begin();
test != neighbors.end(); )
1035 if( neighbors.empty() )
1056 auto it = std::lower_bound( el.second.begin(), el.second.end(), sg );
1058 while( it != el.second.end() && *it == sg )
1059 it = el.second.erase( it );
1062 auto remove_sg = [sg](
auto it ) ->
bool
1075 if( remove_sg( it ) )
1083 if( remove_sg( it ) )
1092 if( remove_sg( it ) )
1094 codes_to_remove.insert( it->first.Netcode );
1106 if( remove_sg( it ) )
1114 if( it->second == sg )
1125 if( codes_to_remove.contains( it->second ) )
1133 if( codes_to_remove.contains( it->second ) )
1142 sg->m_graph =
nullptr;
1149 const std::vector<SCH_ITEM*>& aItemList )
1151 wxLogTrace( wxT(
"Updating connectivity for sheet %s with %zu items" ),
1153 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
1157 aConn->SetType( CONNECTION_TYPE::NET );
1166 aConn->SetName(
name );
1173 std::vector<VECTOR2I> points = item->GetConnectionPoints();
1174 item->ClearConnectedItems( aSheet );
1180 pin->InitializeConnection( aSheet,
this );
1182 pin->ClearConnectedItems( aSheet );
1184 connection_map[
pin->GetTextPos() ].push_back(
pin );
1196 updatePin(
pin, conn );
1197 connection_map[
pin->GetPosition() ].push_back(
pin );
1203 SCH_CONNECTION* conn = item->InitializeConnection( aSheet,
this );
1206 switch( item->Type() )
1210 CONNECTION_TYPE::NET );
1214 conn->
SetType( CONNECTION_TYPE::BUS );
1222 if( points.empty() )
1223 points = {
static_cast<SCH_PIN*
>( item )->GetPosition() };
1225 updatePin(
static_cast<SCH_PIN*
>( item ), conn );
1229 conn->
SetType( CONNECTION_TYPE::NET );
1239 for(
const VECTOR2I& point : points )
1240 connection_map[ point ].push_back( item );
1244 for(
const auto& it : connection_map )
1246 std::vector<SCH_ITEM*> connection_vec = it.second;
1247 std::sort( connection_vec.begin(), connection_vec.end() );
1253 std::mutex update_mutex;
1255 auto update_lambda = [&](
SCH_ITEM* connected_item ) ->
size_t
1269 if( connection_vec.size() == 1 )
1282 if( connection_vec.size() < 2 )
1288 if( it.first == bus_entry->GetPosition() )
1291 bus_entry->m_connected_bus_items[1] = busLine;
1293 std::lock_guard<std::mutex> lock( update_mutex );
1306 for(
SCH_ITEM* test_item : connection_vec )
1308 bool bus_connection_ok =
true;
1310 if( test_item == connected_item )
1316 if( test_item->GetLayer() ==
LAYER_BUS )
1335 if( connected_item->ConnectionPropagatesTo( test_item ) &&
1336 test_item->ConnectionPropagatesTo( connected_item ) &&
1339 connected_item->AddConnectionTo( aSheet, test_item );
1350 if( !bus_entry->m_connected_bus_item )
1356 bus_entry->m_connected_bus_item = bus;
1365 tp.push_loop( connection_vec.size(),
1366 [&](
const int a,
const int b)
1368 for( int ii = a; ii < b; ++ii )
1369 update_lambda( connection_vec[ii] );
1371 tp.wait_for_tasks();
1379 wxCHECK_RET(
m_schematic, wxS(
"Connection graph cannot be built without schematic pointer" ) );
1385 for(
const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
1392 for(
const auto& it : item->m_connection_map )
1409 std::list<SCH_ITEM*> memberlist;
1414 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet,
this );
1415 bool unique = !( aItem->GetFlags() &
CANDIDATE );
1420 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
1423 std::copy_if( item->ConnectedItems( sheet ).begin(),
1424 item->ConnectedItems( sheet ).end(),
1425 std::back_inserter( memberlist ), get_items );
1427 for(
SCH_ITEM* connected_item : memberlist )
1432 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
1434 wxASSERT( connected_conn );
1440 subgraph->
AddItem( connected_item );
1441 const SCH_ITEM_VEC& citemset = connected_item->ConnectedItems( sheet );
1448 if( get_items( citem ) )
1449 memberlist.push_back( citem );
1454 for(
SCH_ITEM* connected_item : memberlist )
1455 connected_item->ClearFlags(
CANDIDATE );
1469 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
1474 return candidate->m_dirty;
1477 wxLogTrace(
ConnTrace, wxT(
"Resolving drivers for %zu subgraphs" ), dirty_graphs.size() );
1479 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
1483 if( !subgraph->m_dirty )
1487 for(
SCH_ITEM* item : subgraph->m_items )
1489 switch( item->
Type() )
1492 subgraph->m_no_connect = item;
1496 subgraph->m_bus_entry = item;
1503 if(
pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
1504 subgraph->m_no_connect = item;
1514 subgraph->ResolveDrivers(
true );
1515 subgraph->m_dirty =
false;
1522 tp.push_loop( dirty_graphs.size(),
1523 [&](
const int a,
const int b)
1525 for( int ii = a; ii < b; ++ii )
1526 update_lambda( dirty_graphs[ii] );
1528 tp.wait_for_tasks();
1535 return candidate->m_driver;
1548 wxString full_name = subgraph->m_driver_connection->Name();
1549 wxString
name = subgraph->m_driver_connection->Name(
true );
1556 if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1558 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
1562 subgraph->m_dirty =
true;
1564 if( subgraph->m_strong_driver )
1566 SCH_ITEM* driver = subgraph->m_driver;
1569 switch( driver->
Type() )
1585 if(
pin->IsGlobalPower() )
1589 else if(
pin->IsLocalPower() )
1596 wxLogTrace(
ConnTrace, wxS(
"Unexpected normal pin %s" ),
1606 wxLogTrace(
ConnTrace, wxS(
"Unexpected strong driver %s" ),
1618 std::vector<CONNECTION_SUBGRAPH*> new_subgraphs;
1629 dummy.SetGraph(
this );
1632 wxLogTrace(
ConnTrace, wxS(
"new bus label (%s)" ),
1635 for(
const auto& conn :
dummy.Members() )
1637 wxString
name = conn->FullLocalName();
1647 new_conn->
SetType( CONNECTION_TYPE::NET );
1648 subgraph->StoreImplicitConnection( new_conn );
1651 wxLogTrace(
ConnTrace, wxS(
"SG(%ld), Adding full local name (%s) with sg (%d) "
1653 subgraph->m_code,
name, code, subgraph->m_sheet.PathHumanReadable() );
1666 new_subgraphs.push_back( new_sg );
1671 std::copy( new_subgraphs.begin(), new_subgraphs.end(),
1683 std::unordered_map<int, CONNECTION_SUBGRAPH*> global_power_pin_subgraphs;
1690 if( !
pin->ConnectedItems( sheet ).empty()
1691 && !
pin->GetLibPin()->GetParentSymbol()->IsGlobalPower() )
1706 if(
pin->GetLibPin()->GetParentSymbol()->IsGlobalPower() )
1707 connection->
SetName(
pin->GetParentSymbol()->GetValue(
true, &sheet,
false ) );
1716 auto jj = global_power_pin_subgraphs.find( code );
1718 if( jj != global_power_pin_subgraphs.end() )
1720 subgraph = jj->second;
1738 global_power_pin_subgraphs[code] = subgraph;
1755 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1759 if( subgraph->m_absorbed )
1764 wxString
name = connection->
Name();
1767 unsigned suffix = 1;
1769 auto create_new_name =
1773 wxString suffixStr = std::to_wstring( suffix );
1778 if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1780 wxString prefix = aConn->BusPrefix();
1782 if( prefix.empty() )
1783 prefix = wxT(
"BUS" );
1785 wxString oldName = aConn->Name().AfterFirst(
'{' );
1787 newName << prefix << wxT(
"_" ) << suffixStr << wxT(
"{" ) << oldName;
1789 aConn->ConfigureFromLabel( newName );
1793 newName << aConn->Name() << wxT(
"_" ) << suffixStr;
1794 aConn->SetSuffix( wxString( wxT(
"_" ) ) << suffixStr );
1801 if( !subgraph->m_strong_driver )
1803 std::vector<CONNECTION_SUBGRAPH*> vec_empty;
1804 std::vector<CONNECTION_SUBGRAPH*>* vec = &vec_empty;
1811 if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1813 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1819 if( vec->size() > 1 )
1821 wxString new_name = create_new_name( connection );
1824 new_name = create_new_name( connection );
1827 wxS(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
1828 subgraph->m_code,
name, new_name );
1836 else if( subgraph->m_driver )
1848 bool conflict =
false;
1849 wxString global_name = connection->
Name(
true );
1856 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1860 if( candidate->m_sheet == sheet )
1868 wxS(
"%ld (%s) skipped for promotion due to potential "
1870 subgraph->m_code,
name );
1877 wxS(
"%ld (%s) weakly driven by unique sheet pin %s, "
1879 subgraph->m_code,
name,
1880 subgraph->m_driver->GetItemDescription( &unitsProvider,
1883 subgraph->m_strong_driver =
true;
1890 if( connection->
IsBus() )
1914 subgraph->m_dirty =
true;
1922 if( !subgraph->m_strong_driver )
1929 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1932 std::back_inserter( candidate_subgraphs ),
1935 return ( !candidate->m_absorbed &&
1936 candidate->m_strong_driver &&
1937 candidate != subgraph );
1943 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1946 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1948 auto add_connections_to_check =
1951 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
1953 if( possible_driver == aSubgraph->m_driver )
1960 if( c->Type() != aSubgraph->m_driver_connection->Type() )
1963 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
1966 connections_to_check.push_back( c );
1968 wxS(
"%lu (%s): Adding secondary driver %s" ),
1970 aSubgraph->m_driver_connection->Name(
true ),
1979 add_connections_to_check( subgraph );
1981 std::set<SCH_CONNECTION*> checked_connections;
1983 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
1985 auto member = connections_to_check[i];
1988 if( !checked_connections.insert( member.get() ).second )
1991 if( member->IsBus() )
1993 connections_to_check.insert( connections_to_check.end(),
1994 member->Members().begin(),
1995 member->Members().end() );
1998 wxString test_name = member->Name(
true );
2002 if( candidate->
m_absorbed || candidate == subgraph )
2018 if( driver == candidate->
m_driver )
2030 &&
pin->GetDefaultNetName( sheet ) == test_name )
2042 if( subgraph->GetNameForDriver( driver ) == test_name )
2055 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has bus child %lu (%s)" ),
2056 subgraph->m_code, connection->
Name(),
2057 candidate->
m_code, member->Name() );
2059 subgraph->m_bus_neighbors[member].insert( candidate );
2062 else if( !connection->
IsBus()
2065 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) absorbs neighbor %lu (%s)" ),
2066 subgraph->m_code, connection->
Name(),
2070 add_connections_to_check( candidate );
2072 subgraph->Absorb( candidate );
2073 invalidated_subgraphs.insert( subgraph );
2083 if( subgraph->m_absorbed )
2086 if( !subgraph->ResolveDrivers() )
2089 if( subgraph->m_driver_connection->IsBus() )
2094 wxLogTrace(
ConnTrace, wxS(
"Re-resolving drivers for %lu (%s)" ), subgraph->m_code,
2095 subgraph->m_driver_connection->Name() );
2114 bool aUnconditional )
2117 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
2123 for(
const std::shared_ptr<BUS_ALIAS>& alias : screen->GetBusAliases() )
2127 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
2146 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
2150 proc_sub_graph.
Show();
2159 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
2161 std::back_inserter( global_subgraphs ),
2164 return !candidate->m_local_driver;
2176 [&](
const int a,
const int b)
2178 for( int ii = a; ii < b; ++ii )
2179 m_driver_subgraphs[ii]->UpdateItemConnections();
2182 tp.wait_for_tasks();
2189 if( !subgraph->m_dirty )
2192 wxLogTrace(
ConnTrace, wxS(
"Processing %lu (%s) for propagation" ), subgraph->m_code,
2193 subgraph->m_driver_connection->Name() );
2199 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
2201 for(
SCH_ITEM* driver : subgraph->m_drivers )
2203 if( driver == subgraph->m_driver )
2206 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
2208 if( secondary_name == subgraph->m_driver_connection->Name() )
2216 if( candidate == subgraph )
2219 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
2226 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) promoted to %s" ),
2228 subgraph->m_driver_connection->Name() );
2250 if( subgraph->m_dirty )
2266 wxASSERT_MSG( !subgraph->m_dirty,
2267 wxS(
"Subgraph not processed by propagateToNeighbors!" ) );
2269 if( subgraph->m_bus_parents.size() < 2 )
2274 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has multiple bus parents" ),
2275 subgraph->m_code, conn->
Name() );
2277 wxASSERT( conn->
IsNet() );
2279 for(
const auto& ii : subgraph->m_bus_parents )
2292 wxLogTrace(
ConnTrace, wxS(
"Warning: could not match %s inside %lu (%s)" ),
2297 if( conn->
Name() != match->
Name() )
2299 wxString old_name = match->
Name();
2301 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ),
2303 old_name, conn->
Name() );
2305 match->
Clone( *conn );
2324 auto updateItemConnectionsTask =
2328 if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
2329 subgraph->m_driver->Type() ==
SCH_PIN_T )
2332 wxString
name =
pin->GetDefaultNetName( subgraph->m_sheet,
true );
2334 subgraph->m_driver_connection->ConfigureFromLabel(
name );
2337 subgraph->m_dirty =
false;
2338 subgraph->UpdateItemConnections();
2341 if( subgraph->m_driver_connection->IsBus() )
2346 if( subgraph->m_driver && subgraph->m_driver->Type() ==
SCH_SHEET_PIN_T )
2352 wxString pinText =
pin->GetShownText(
false );
2359 if( label->
GetShownText( &subgraph->m_sheet,
false ) == pinText )
2362 path.push_back( sheet );
2366 if( parent_conn && parent_conn->
IsBus() )
2367 subgraph->m_driver_connection->
SetType( CONNECTION_TYPE::BUS );
2373 if( subgraph->m_driver_connection->IsBus() )
2382 [&](
const int a,
const int b)
2384 for(
int ii = a; ii < b; ++ii )
2387 tp.wait_for_tasks();
2395 subgraph->m_driver_connection->NetCode() };
2402 std::map<wxString, std::set<wxString>> oldAssignments =
2403 netSettings->GetNetclassLabelAssignments();
2404 std::set<wxString> affectedNetclassNetAssignments;
2406 netSettings->ClearNetclassLabelAssignments();
2408 auto dirtySubgraphs =
2409 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2411 if( aChangedItemHandler )
2415 for(
SCH_ITEM* item : subgraph->m_items )
2416 (*aChangedItemHandler)( item );
2421 auto checkNetclassDrivers =
2422 [&](
const wxString& netName,
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2424 wxCHECK_RET( !subgraphs.empty(), wxS(
"Invalid empty subgraph" ) );
2426 std::set<wxString> netclasses;
2431 for(
SCH_ITEM* item : subgraph->m_items )
2433 std::vector<std::pair<wxString, SCH_ITEM*>> netclassesWithProviders =
2434 subgraph->GetNetclassesForDriver( item );
2436 for( std::pair<wxString, SCH_ITEM*>& ncPair : netclassesWithProviders )
2437 netclasses.insert( std::move( ncPair.first ) );
2444 if( subgraph->m_driver_connection->IsBus() )
2446 auto processBusMember = [&,
this](
const SCH_CONNECTION* member )
2448 if( !netclasses.empty() )
2450 netSettings->AppendNetclassLabelAssignment( member->Name(), netclasses );
2455 if( oldAssignments.count( member->Name() ) )
2457 if( oldAssignments[member->Name()] != netclasses )
2459 affectedNetclassNetAssignments.insert( member->Name() );
2462 dirtySubgraphs( ii->second );
2465 else if( !netclasses.empty() )
2467 affectedNetclassNetAssignments.insert( member->Name() );
2470 dirtySubgraphs( ii->second );
2474 for(
const std::shared_ptr<SCH_CONNECTION>& member :
2475 subgraph->m_driver_connection->Members() )
2480 if( member->IsBus() )
2482 for(
const std::shared_ptr<SCH_CONNECTION>& nestedMember :
2485 processBusMember( nestedMember.get() );
2490 processBusMember( member.get() );
2497 if( !netclasses.empty() )
2499 netSettings->AppendNetclassLabelAssignment( netName, netclasses );
2502 if( oldAssignments.count( netName ) )
2504 if( oldAssignments[netName] != netclasses )
2506 affectedNetclassNetAssignments.insert( netName );
2507 dirtySubgraphs( subgraphs );
2510 else if( !netclasses.empty() )
2512 affectedNetclassNetAssignments.insert( netName );
2513 dirtySubgraphs( subgraphs );
2519 checkNetclassDrivers( netname, subgraphs );
2521 if( !aUnconditional )
2523 for(
auto& [netname, netclasses] : oldAssignments )
2525 if( netSettings->GetNetclassLabelAssignments().count( netname )
2526 || affectedNetclassNetAssignments.count( netname ) )
2531 netSettings->SetNetclassLabelAssignment( netname, netclasses );
2569 std::vector<std::shared_ptr<SCH_CONNECTION>> connections_to_check( aConnection->
Members() );
2571 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2573 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
2575 if( member->IsBus() )
2577 connections_to_check.insert( connections_to_check.end(),
2578 member->Members().begin(),
2579 member->Members().end() );
2591 std::vector<CONNECTION_SUBGRAPH*> search_list;
2592 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
2593 std::unordered_set<SCH_CONNECTION*> stale_bus_members;
2600 path.push_back(
pin->GetParent() );
2611 || visited.contains( candidate ) )
2620 wxLogTrace(
ConnTrace, wxS(
"%lu: found child %lu (%s)" ), aParent->m_code,
2626 wxASSERT( candidate->
m_graph == aParent->m_graph );
2628 search_list.push_back( candidate );
2648 || visited.contains( candidate )
2654 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
2659 if(
pin->GetParent()->m_Uuid != last_parent_uuid )
2665 if( pin_path != aParent->m_sheet )
2670 wxLogTrace(
ConnTrace, wxS(
"%lu: found additional parent %lu (%s)" ),
2671 aParent->m_code, candidate->
m_code,
2674 aParent->m_hier_children.insert( candidate );
2675 search_list.push_back( candidate );
2685 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
2727 wxLogTrace(
ConnTrace, wxS(
"Could not match bus member %s in %s" ),
2728 kv.first->Name(), parent->
Name() );
2733 auto neighbor_name = neighbor_conn->
Name();
2736 if( neighbor_name == member->
Name() )
2740 if( neighbor_conn->Sheet() != neighbor->
m_sheet )
2744 wxASSERT( neighbor_conn->IsNet() );
2746 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) connected to bus member %s (local %s)" ),
2753 member->
Clone( *neighbor_conn );
2754 stale_bus_members.insert( member );
2758 neighbor_conn->Clone( *member );
2772 propagate_bus_neighbors( aSubgraph );
2779 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has both hier ports and pins; deferring processing" ),
2786 wxS(
"%lu (%s) has no hier pins or ports on sheet %s; marking clean" ),
2792 visited.insert( aSubgraph );
2794 wxLogTrace(
ConnTrace, wxS(
"Propagating %lu (%s) to subsheets" ),
2799 for(
unsigned i = 0; i < search_list.size(); i++ )
2801 auto child = search_list[i];
2803 if( visited.insert( child ).second )
2806 child->m_dirty =
false;
2821 if( subgraph == aSubgraph )
2828 wxString candidateName = subgraph->m_driver_connection->Name();
2829 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
2830 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
2840 ( !bestIsStrong && candidateStrong ) ||
2841 ( priority > highest && candidateStrong ) ||
2842 ( priority == highest && candidateStrong && shorterPath ) ||
2843 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
2844 ( candidateName < bestName ) ) )
2846 bestDriver = subgraph;
2848 bestIsStrong = candidateStrong;
2849 bestName = candidateName;
2854 if( bestDriver != aSubgraph )
2856 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) overridden by new driver %lu (%s)" ),
2865 wxString old_name = subgraph->m_driver_connection->
Name();
2867 subgraph->m_driver_connection->Clone( *conn );
2869 if( old_name != conn->
Name() )
2873 propagate_bus_neighbors( subgraph );
2879 if( conn->
IsBus() && !stale_bus_members.empty() )
2881 std::unordered_set<SCH_CONNECTION*> cached_members = stale_bus_members;
2892 wxLogTrace(
ConnTrace, wxS(
"WARNING: failed to match stale member %s in %s." ),
2893 stale_member->Name(), subgraph->m_driver_connection->Name() );
2897 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
2898 subgraph->m_driver_connection->Name(), member->
LocalName(),
2899 stale_member->Name() );
2901 member->
Clone( *stale_member );
2903 propagate_bus_neighbors( subgraph );
2915 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
2917 switch( aItem->
Type() )
2923 if(
pin->IsPower() )
2924 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2933 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
2943 c->SetGraph(
this );
2954 wxASSERT( aBusConnection->
IsBus() );
2958 if( aBusConnection->
Type() == CONNECTION_TYPE::BUS )
2963 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
2965 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
2967 match = bus_member.get();
2975 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
2980 if( c->Type() == CONNECTION_TYPE::BUS )
2982 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
2984 if( bus_member->LocalName() == aSearch->
LocalName() )
2986 match = bus_member.get();
2991 else if( c->LocalName() == aSearch->
LocalName() )
3004 const wxString& aOldName )
3010 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
3014 wxLogTrace(
ConnTrace, wxS(
"recacheSubgraphName: %s => %s" ), aOldName,
3031 std::vector<const CONNECTION_SUBGRAPH*> ret;
3036 wxASSERT( !subgraph->m_dirty );
3038 if( !subgraph->m_driver )
3044 if( !connection->
IsBus() )
3047 auto labels = subgraph->GetVectorBusLabels();
3049 if( labels.size() > 1 )
3051 bool different =
false;
3052 wxString first =
static_cast<SCH_TEXT*
>( labels.at( 0 ) )->GetShownText( sheet,
false );
3054 for(
unsigned i = 1; i < labels.size(); ++i )
3067 wxLogTrace(
ConnTrace, wxS(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
3068 connection->
Name() );
3070 ret.push_back( subgraph );
3091 if( graph == aSubGraph )
3132 wxASSERT( !it->second.empty() );
3134 return it->second[0];
3150const std::vector<CONNECTION_SUBGRAPH*>&
3153 static const std::vector<CONNECTION_SUBGRAPH*> subgraphs;
3166 int error_count = 0;
3168 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
3174 std::set<SCH_ITEM*> seenDriverInstances;
3179 wxCHECK2( subgraph,
continue );
3182 wxASSERT( !subgraph->m_dirty );
3184 if( subgraph->m_absorbed )
3187 if( seenDriverInstances.count( subgraph->m_driver ) )
3190 if( subgraph->m_driver )
3191 seenDriverInstances.insert( subgraph->m_driver );
3209 subgraph->ResolveDrivers(
false );
3280 wxCHECK( aSubgraph,
false );
3286 if( driver == aSubgraph->
m_driver )
3298 if( primaryName == secondaryName )
3301 wxString msg = wxString::Format(
_(
"Both %s and %s are attached to the same "
3302 "items; %s will be used in the netlist" ),
3303 primaryName, secondaryName, primaryName );
3306 ercItem->SetItems( aSubgraph->
m_driver, driver );
3307 ercItem->SetSheetSpecificPath( aSubgraph->
GetSheet() );
3308 ercItem->SetItemsSheetPaths( aSubgraph->
GetSheet(), aSubgraph->
m_sheet );
3309 ercItem->SetErrorMessage( msg );
3334 switch( item->
Type() )
3339 bus_item = ( !bus_item ) ? item : bus_item;
3341 net_item = ( !net_item ) ? item : net_item;
3356 bus_item = ( !bus_item ) ? item : bus_item;
3358 net_item = ( !net_item ) ? item : net_item;
3368 if( net_item && bus_item )
3371 ercItem->SetSheetSpecificPath( sheet );
3372 ercItem->SetItems( net_item, bus_item );
3375 screen->
Append( marker );
3394 switch( item->
Type() )
3425 if(
test != member && member->Name() ==
test->Name() )
3439 ercItem->SetSheetSpecificPath( sheet );
3440 ercItem->SetItems( label, port );
3443 screen->
Append( marker );
3455 bool conflict =
false;
3471 switch( item->
Type() )
3501 std::set<wxString> test_names;
3511 if( member->Type() == CONNECTION_TYPE::BUS )
3513 for(
const auto& sub_member : member->Members() )
3515 if( test_names.count( sub_member->FullLocalName() ) )
3519 else if( test_names.count( member->FullLocalName() ) )
3538 wxString msg = wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
3539 " member of that bus" ),
3543 ercItem->SetSheetSpecificPath( sheet );
3544 ercItem->SetItems( bus_entry, bus_wire );
3545 ercItem->SetErrorMessage( msg );
3548 screen->
Append( marker );
3565 std::set<SCH_PIN*> unique_pins;
3566 std::set<SCH_LABEL_BASE*> unique_labels;
3574 for(
SCH_ITEM* item : aProcessGraph->m_items )
3576 switch( item->
Type() )
3583 if( aProcessGraph == aSubgraph )
3586 if( std::none_of( unique_pins.begin(), unique_pins.end(),
3593 unique_pins.insert( test_pin );
3616 process_subgraph( subgraph );
3621 process_subgraph( aSubgraph );
3649 if( test_pin && test_pin->
GetType() == ELECTRICAL_PINTYPE::PT_NC )
3656 ercItem->SetSheetSpecificPath( sheet );
3657 ercItem->SetItemsSheetPaths( sheet );
3664 pos =
pin->GetPosition();
3673 screen->
Append( marker );
3678 if( unique_pins.empty() && unique_labels.empty() &&
3683 ercItem->SetSheetSpecificPath( sheet );
3684 ercItem->SetItemsSheetPaths( sheet );
3687 screen->
Append( marker );
3694 bool has_other_connections =
false;
3695 std::vector<SCH_PIN*> pins;
3702 switch( item->
Type() )
3709 if( !has_other_connections && !pins.empty()
3712 for(
SCH_PIN* other_pin : pins )
3716 has_other_connections =
true;
3722 pins.emplace_back(
static_cast<SCH_PIN*
>( item ) );
3729 has_other_connections =
true;
3736 pin = pins.empty() ? nullptr : pins[0];
3739 for(
SCH_PIN* test_pin : pins )
3744 if( test_pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
3745 && !test_pin->IsPower() )
3756 if(
pin && !has_other_connections
3758 && !
pin->GetLibPin()->GetParentSymbol()->IsPower() )
3760 wxString
name =
pin->Connection( &sheet )->Name();
3761 wxString local_name =
pin->Connection( &sheet )->Name(
true );
3766 has_other_connections =
true;
3771 if(
pin && !has_other_connections
3772 &&
pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
3773 &&
pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
3777 ercItem->SetSheetSpecificPath( sheet );
3778 ercItem->SetItemsSheetPaths( sheet );
3779 ercItem->SetItems(
pin );
3782 screen->
Append( marker );
3790 if( pins.size() > 1 )
3792 for(
SCH_PIN* testPin : pins )
3797 if( testPin->GetLibPin()->GetParentSymbol()->IsPower()
3798 && testPin->ConnectedItems( sheet ).empty()
3802 ercItem->SetSheetSpecificPath( sheet );
3803 ercItem->SetItemsSheetPaths( sheet );
3804 ercItem->SetItems( testPin );
3807 screen->
Append( marker );
3838 std::shared_ptr<ERC_ITEM> ercItem =
3841 ercItem->SetItems( line );
3842 ercItem->SetSheetSpecificPath( sheet );
3843 ercItem->SetErrorMessage(
_(
"Unconnected wire endpoint" ) );
3863 std::shared_ptr<ERC_ITEM> ercItem =
3866 ercItem->SetItems( entry );
3867 ercItem->SetSheetSpecificPath( sheet );
3868 ercItem->SetErrorMessage(
_(
"Unconnected wire to bus entry" ) );
3885 return err_count > 0;
3895 std::vector<SCH_ITEM*> wires;
3902 wires.emplace_back( item );
3904 wires.emplace_back( item );
3907 if( !wires.empty() )
3912 ercItem->SetSheetSpecificPath( sheet );
3913 ercItem->SetItems( wires[0],
3914 wires.size() > 1 ? wires[1] :
nullptr,
3915 wires.size() > 2 ? wires[2] :
nullptr,
3916 wires.size() > 3 ? wires[3] :
nullptr );
3919 screen->
Append( marker );
3947 size_t pinCount = 0;
3950 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
3956 return std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(),
3959 return item->Type() == SCH_PIN_T;
3964 [&](
SCH_TEXT* aText,
int errCode )
3969 ercItem->SetSheetSpecificPath( sheet );
3970 ercItem->SetItems( aText );
3977 pinCount =
hasPins( aSubgraph );
3981 switch( item->
Type() )
3989 label_map[item->
Type()].push_back(
text );
3994 if(
text->IsDangling() )
4010 if( label_map.empty() )
4015 for(
auto& [ connection, subgraphs ] : aSubgraph->
m_bus_parents )
4019 if( busParent->m_no_connect )
4042 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
4049 for(
auto& [type, label_vec] : label_map )
4067 size_t allPins = pinCount;
4075 if( neighbor == aSubgraph )
4081 allPins +=
hasPins( neighbor );
4085 if( allPins == 1 && !has_nc )
4109 std::map<wxString, std::tuple<int, const SCH_ITEM*, SCH_SHEET_PATH>> labelData;
4116 wxString resolvedLabelText =
4119 if( labelData.find( resolvedLabelText ) == labelData.end() )
4121 labelData[resolvedLabelText] = { 1, item, sheet };
4125 std::get<0>( labelData[resolvedLabelText] ) += 1;
4126 std::get<1>( labelData[resolvedLabelText] ) =
nullptr;
4127 std::get<2>( labelData[resolvedLabelText] ) = sheet;
4132 for(
const auto& label : labelData )
4134 if( std::get<0>( label.second ) == 1 )
4137 const SCH_ITEM* item = std::get<1>( label.second );
4140 ercItem->SetItems( std::get<1>( label.second ) );
4141 ercItem->SetSheetSpecificPath( sheet );
4142 ercItem->SetItemsSheetPaths( sheet );
4157 int error_count = 0;
4169 ercItem->SetSheetSpecificPath( sheet );
4170 ercItem->SetItems(
text );
4173 sheet.LastScreen()->Append( marker );
4196 parentSheetPath.
push_back( parentSheet );
4198 std::map<wxString, SCH_SHEET_PIN*> pins;
4199 std::map<wxString, SCH_HIERLABEL*> labels;
4204 pins[
pin->GetShownText( &parentSheetPath,
false ) ] =
pin;
4209 ercItem->SetItems(
pin );
4210 ercItem->SetSheetSpecificPath( sheet );
4211 ercItem->SetItemsSheetPaths( sheet );
4214 sheet.LastScreen()->Append( marker );
4222 std::set<wxString> matchedPins;
4229 wxString labelText = label->
GetShownText( &parentSheetPath,
false );
4231 if( !pins.count( labelText ) )
4232 labels[ labelText ] = label;
4234 matchedPins.insert( labelText );
4238 for(
const wxString& matched : matchedPins )
4239 pins.erase( matched );
4241 for(
const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
4243 wxString msg = wxString::Format(
_(
"Sheet pin %s has no matching hierarchical "
4244 "label inside the sheet" ),
4248 ercItem->SetItems( unmatched.second );
4249 ercItem->SetErrorMessage( msg );
4250 ercItem->SetSheetSpecificPath( sheet );
4251 ercItem->SetItemsSheetPaths( sheet );
4254 sheet.LastScreen()->Append( marker );
4259 for(
const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
4261 wxString msg = wxString::Format(
_(
"Hierarchical label %s has no matching "
4262 "sheet pin in the parent sheet" ),
4266 ercItem->SetItems( unmatched.second );
4267 ercItem->SetErrorMessage( msg );
4268 ercItem->SetSheetSpecificPath( parentSheetPath );
4269 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.
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.
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction)
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.