31#include <unordered_map>
86static wxString
netChainKeyFor(
const wxString& aRawNetName,
long aSubgraphCode )
88 if( !aRawNetName.IsEmpty() && aRawNetName.Find( wxS(
"<NO NET>" ) ) == wxNOT_FOUND )
139 if( old_conn && new_conn )
141 new_conn->
Clone( *old_conn );
189 return pa > pb ? -1 : 1;
196 if( b_in_a && !a_in_b )
199 if( a_in_b && !b_in_a )
214 if( aGlobal != bGlobal )
215 return aGlobal ? -1 : 1;
220 if( aLocal != bLocal )
221 return aLocal ? -1 : 1;
239 bool aLowQuality = aAName.Contains( wxS(
"-Pad" ) );
240 bool bLowQuality = aBName.Contains( wxS(
"-Pad" ) );
242 if( aLowQuality != bLowQuality )
243 return aLowQuality ? 1 : -1;
245 if( aAName < aBName )
248 if( aBName < aAName )
263 std::vector<SCH_ITEM*> candidates;
264 std::set<SCH_ITEM*> strong_drivers;
288 strong_drivers.insert( item );
290 if( item_priority > highest_priority )
293 candidates.push_back( item );
294 highest_priority = item_priority;
296 else if( !candidates.empty() && ( item_priority == highest_priority ) )
298 candidates.push_back( item );
308 if( !candidates.empty() )
318 std::sort( candidates.begin(), candidates.end(), candidate_cmp );
323 if( strong_drivers.size() > 1 )
330 m_drivers.insert( strong_drivers.begin(), strong_drivers.end() );
352 std::set<CONNECTION_SUBGRAPH*>& aSubgraphs )
364 if( aSubgraphs.insert( sg ).second ==
false )
370 aItems.emplace(
m_sheet, item );
384#ifdef CONNECTIVITY_DEBUG
385 wxASSERT_MSG(
false, wxS(
"Tried to get the net name of an item with no connection" ) );
397 std::vector<SCH_ITEM*> labels;
401 switch( item->Type() )
411 labels.push_back( item );
427 std::vector<SCH_ITEM*> labels;
431 switch( item->Type() )
441 labels.push_back( item );
457 switch( aItem->
Type() )
464 return pin->GetDefaultNetName(
m_sheet, forceNoConnect );
491 wxFAIL_MSG( wxS(
"Unhandled item type in GetNameForDriver" ) );
492 return wxEmptyString;
512const std::vector<std::pair<wxString, SCH_ITEM*>>
515 std::vector<std::pair<wxString, SCH_ITEM*>> foundNetclasses;
517 const std::unordered_set<SCH_RULE_AREA*>& ruleAreaCache = aItem->
GetRuleAreaCache();
522 const std::vector<std::pair<wxString, SCH_ITEM*>> ruleAreaNetclasses =
523 ruleArea->GetResolvedNetclasses( &
m_sheet );
525 if( ruleAreaNetclasses.size() > 0 )
527 foundNetclasses.insert( foundNetclasses.end(), ruleAreaNetclasses.begin(),
528 ruleAreaNetclasses.end() );
544 if( netclass != wxEmptyString )
545 foundNetclasses.push_back( { netclass, aItem } );
552 foundNetclasses.begin(), foundNetclasses.end(),
553 [](
const std::pair<wxString, SCH_ITEM*>& i1,
const std::pair<wxString, SCH_ITEM*>& i2 )
555 return i1.first < i2.first;
558 return foundNetclasses;
584 child->m_absorbed_by =
this;
587 set_absorbed_by( subchild );
595 set_absorbed_by( aOther );
645 if(
const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef() )
646 return part->GetReferenceField().GetText();
648 return wxEmptyString;
651 switch( aDriver->
Type() )
682 std::back_inserter(
m_items ) );
772 wxCHECK2( aOldItem->
Type() == aNewItem->
Type(),
return );
807 wxCHECK2( oldPins.size() == newPins.size(),
return );
809 for(
size_t ii = 0; ii < oldPins.size(); ii++ )
811 exchange( oldPins[ii], newPins[ii] );
822 if( subgraph->m_graph ==
this )
849 chain->ClearSymbols();
858 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler,
862 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
863 monitorTrans.
Start();
868 monitorTrans.
StartSpan(
"updateItemConnectivity",
"" );
869 PROF_TIMER update_items(
"updateItemConnectivity" );
872 std::set<SCH_ITEM*> dirty_items;
874 int count = aSheetList.size() * 2;
879 if( aProgressReporter )
885 std::vector<SCH_ITEM*> items;
888 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
890 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
892 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
894 wxLogTrace(
ConnTrace, wxT(
"Adding item %s to connectivity graph update" ),
895 item->GetTypeDesc() );
896 items.push_back( item );
897 dirty_items.insert( item );
906 if(
pin->IsConnectivityDirty() )
908 dirty_items.insert(
pin );
921 if(
pin->IsConnectivityDirty() )
923 items.push_back(
pin );
924 dirty_items.insert(
pin );
934 if(
pin->IsConnectivityDirty() )
936 items.push_back(
pin );
937 dirty_items.insert(
pin );
950 if( symbol->
GetUnit() != new_unit )
951 symbolsChanged.push_back( { symbol, symbol->
GetUnit() } );
961 if( aProgressReporter )
968 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
971 for(
const auto& [ symbol, originalUnit ] : symbolsChanged )
972 symbol->SetUnit( originalUnit );
983 item->SetConnectivityDirty(
false );
990 PROF_TIMER build_graph(
"buildConnectionGraph" );
991 monitorTrans.
StartSpan(
"BuildConnectionGraph",
"" );
1010 const std::set<SCH_ITEM*> &aItems )
1012 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> retvals;
1013 std::set<CONNECTION_SUBGRAPH*> subgraphs;
1018 while( aSubgraph->m_absorbed_by )
1021 wxASSERT( aSubgraph->m_graph == aSubgraph->m_absorbed_by->m_graph );
1022 aSubgraph = aSubgraph->m_absorbed_by;
1026 while( aSubgraph->m_hier_parent )
1029 wxASSERT( aSubgraph->m_graph == aSubgraph->m_hier_parent->m_graph );
1030 aSubgraph = aSubgraph->m_hier_parent;
1034 aSubgraph->getAllConnectedItems( retvals, subgraphs );
1037 auto extract_element = [&](
SCH_ITEM* aItem )
1043 wxLogTrace(
ConnTrace, wxT(
"Item %s not found in connection graph" ),
1044 aItem->GetTypeDesc() );
1050 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld (%p) has no driver" ),
1051 aItem->GetTypeDesc(), item_sg->
m_code, item_sg );
1056 if( sg_to_scan.empty() )
1058 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld with net %s has no neighbors" ),
1060 sg_to_scan.push_back( item_sg );
1064 wxT(
"Removing all item %s connections from subgraph %ld with net %s: Found "
1067 sg_to_scan.size() );
1071 traverse_subgraph( sg );
1073 for(
auto& bus_it : sg->m_bus_neighbors )
1076 traverse_subgraph( bus_sg );
1079 for(
auto& bus_it : sg->m_bus_parents )
1082 traverse_subgraph( bus_sg );
1096 extract_element(
pin );
1103 extract_element(
pin );
1107 extract_element( item );
1113 for(
const auto& [
path, item] : retvals )
1140 wxLogTrace(
ConnTrace, wxT(
"Removing %zu subgraphs" ), aSubgraphs.size() );
1143 std::set<int> codes_to_remove;
1147 std::sort( el.second.begin(), el.second.end() );
1152 for(
auto& it : sg->m_bus_neighbors )
1158 for(
auto test = parents.begin();
test != parents.end(); )
1166 if( parents.empty() )
1171 for(
auto& it : sg->m_bus_parents )
1177 for(
auto test = neighbors.begin();
test != neighbors.end(); )
1185 if( neighbors.empty() )
1206 auto it = std::lower_bound( el.second.begin(), el.second.end(), sg );
1208 while( it != el.second.end() && *it == sg )
1209 it = el.second.erase( it );
1212 auto remove_sg = [sg](
auto it ) ->
bool
1225 if( remove_sg( it ) )
1233 if( remove_sg( it ) )
1242 if( remove_sg( it ) )
1244 codes_to_remove.insert( it->first.Netcode );
1256 if( remove_sg( it ) )
1264 if( it->second == sg )
1275 if( codes_to_remove.contains( it->second ) )
1283 if( codes_to_remove.contains( it->second ) )
1292 sg->m_graph =
nullptr;
1299 std::map<
VECTOR2I, std::vector<SCH_ITEM*>>& aConnectionMap )
1310 aConn->SetName(
name );
1315 std::map<wxString, std::vector<SCH_PIN*>> pinNumberMap;
1321 updatePin(
pin, conn );
1322 aConnectionMap[
pin->GetPosition() ].push_back(
pin );
1323 pinNumberMap[
pin->GetNumber()].emplace_back(
pin );
1326 auto linkPinsInVec =
1327 [&](
const std::vector<SCH_PIN*>& aVec )
1329 for(
size_t i = 0; i < aVec.size(); ++i )
1331 for(
size_t j = i + 1; j < aVec.size(); ++j )
1333 aVec[i]->AddConnectionTo( aSheet, aVec[j] );
1334 aVec[j]->AddConnectionTo( aSheet, aVec[i] );
1343 for(
const auto& [number,
group] : pinNumberMap )
1344 linkPinsInVec(
group );
1349 std::vector<SCH_PIN*> pins;
1351 for(
const wxString& pinNumber :
group )
1354 pins.emplace_back(
pin );
1357 linkPinsInVec( pins );
1380 std::map<
VECTOR2I, std::vector<SCH_ITEM*>>& aConnectionMap )
1385 m_items.emplace_back( aItem );
1388 switch( aItem->
Type() )
1401 if( points.empty() )
1402 points = {
static_cast<SCH_PIN*
>( aItem )->GetPosition() };
1415 for(
const VECTOR2I& point : points )
1416 aConnectionMap[point].push_back( aItem );
1421 const std::vector<SCH_ITEM*>& aItemList )
1423 wxLogTrace( wxT(
"Updating connectivity for sheet %s with %zu items" ),
1425 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
1429 std::vector<VECTOR2I> points = item->GetConnectionPoints();
1430 item->ClearConnectedItems( aSheet );
1435 pin->InitializeConnection( aSheet,
this );
1437 pin->ClearConnectedItems( aSheet );
1439 connection_map[
pin->GetTextPos() ].push_back(
pin );
1456 VECTOR2I point = item->GetPosition();
1459 std::vector<SCH_ITEM*> overlapping_items;
1461 std::copy_if( items.begin(), items.end(), std::back_inserter( overlapping_items ),
1464 return test_item->Type() == SCH_LINE_T
1465 && test_item->HitTest( point, -1 );
1470 if( overlapping_items.size() < 2 )
continue;
1472 for(
SCH_ITEM* test_item : overlapping_items )
1473 connection_map[point].push_back( test_item );
1482 VECTOR2I point = item->GetPosition();
1486 connection_map[point].push_back( wire );
1491 for(
auto& [point, connection_vec] : connection_map )
1493 std::sort( connection_vec.begin(), connection_vec.end() );
1499 for(
SCH_ITEM* connected_item : connection_vec )
1513 if( connection_vec.size() == 1 )
1529 if( point == bus_entry->GetPosition() )
1532 bus_entry->m_connected_bus_items[1] = busLine;
1545 for(
SCH_ITEM* test_item : connection_vec )
1547 bool bus_connection_ok =
true;
1549 if( test_item == connected_item )
1555 if( test_item->GetLayer() ==
LAYER_BUS )
1574 if( connected_item->ConnectionPropagatesTo( test_item )
1575 && test_item->ConnectionPropagatesTo( connected_item )
1576 && bus_connection_ok )
1578 connected_item->AddConnectionTo( aSheet, test_item );
1589 if( !bus_entry->m_connected_bus_item )
1595 bus_entry->m_connected_bus_item = bus;
1606 wxCHECK_RET(
m_schematic, wxS(
"Connection graph cannot be built without schematic pointer" ) );
1610 for(
const std::shared_ptr<BUS_ALIAS>& alias :
m_schematic->GetAllBusAliases() )
1619 for(
const auto& [sheet, connection] : item->m_connection_map )
1621 if( connection->SubgraphCode() == 0 )
1630 connection->SetSubgraphCode( subgraph->
m_code );
1633 std::list<SCH_ITEM*> memberlist;
1638 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet,
this );
1644 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
1647 std::copy_if( item->ConnectedItems( sheet ).begin(),
1648 item->ConnectedItems( sheet ).end(),
1649 std::back_inserter( memberlist ), get_items );
1651 for(
SCH_ITEM* connected_item : memberlist )
1656 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
1658 wxCHECK2( connected_conn,
continue );
1664 subgraph->
AddItem( connected_item );
1665 const SCH_ITEM_VEC& citemset = connected_item->ConnectedItems( sheet );
1672 if( get_items( citem ) )
1673 memberlist.push_back( citem );
1678 for(
SCH_ITEM* connected_item : memberlist )
1692 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
1697 return candidate->m_dirty;
1700 wxLogTrace(
ConnTrace, wxT(
"Resolving drivers for %zu subgraphs" ), dirty_graphs.size() );
1702 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
1704 auto update_lambda =
1707 if( !subgraph->m_dirty )
1711 for(
SCH_ITEM* item : subgraph->m_items )
1713 switch( item->
Type() )
1716 subgraph->m_no_connect = item;
1720 subgraph->m_bus_entry = item;
1728 subgraph->m_no_connect = item;
1738 subgraph->ResolveDrivers(
true );
1739 subgraph->m_dirty =
false;
1746 auto results =
tp.submit_loop( 0, dirty_graphs.size(),
1749 update_lambda( dirty_graphs[ii] );
1758 return candidate->m_driver;
1771 wxString full_name = subgraph->m_driver_connection->Name();
1772 wxString
name = subgraph->m_driver_connection->Name(
true );
1781 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
1785 subgraph->m_dirty =
true;
1787 if( subgraph->m_strong_driver )
1789 SCH_ITEM* driver = subgraph->m_driver;
1792 switch( driver->
Type() )
1808 if(
pin->IsGlobalPower() )
1812 else if(
pin->IsLocalPower() )
1819 wxLogTrace(
ConnTrace, wxS(
"Unexpected normal pin %s" ),
1829 wxLogTrace(
ConnTrace, wxS(
"Unexpected strong driver %s" ),
1841 std::vector<CONNECTION_SUBGRAPH*> new_subgraphs;
1852 dummy.SetGraph(
this );
1855 wxLogTrace(
ConnTrace, wxS(
"new bus label (%s)" ),
1858 for(
const auto& conn :
dummy.Members() )
1861 if( !conn->IsNet() )
1864 wxString
name = conn->FullLocalName();
1871 auto new_conn = std::make_unique<SCH_CONNECTION>( item, subgraph->m_sheet );
1872 new_conn->SetGraph(
this );
1873 new_conn->SetName(
name );
1876 SCH_CONNECTION* new_conn_ptr = subgraph->StoreImplicitConnection( std::move( new_conn ) );
1879 wxLogTrace(
ConnTrace, wxS(
"SG(%ld), Adding full local name (%s) with sg (%d) on subsheet %s" ),
1880 subgraph->m_code,
name, code, subgraph->m_sheet.PathHumanReadable() );
1893 new_subgraphs.push_back( new_sg );
1898 std::copy( new_subgraphs.begin(), new_subgraphs.end(),
1914 [](
const std::pair<SCH_SHEET_PATH, SCH_PIN*>& a,
1915 const std::pair<SCH_SHEET_PATH, SCH_PIN*>& b )
1917 int pathCmp = a.first.Cmp( b.first );
1922 const SCH_SYMBOL* symA = static_cast<const SCH_SYMBOL*>( a.second->GetParentSymbol() );
1923 const SCH_SYMBOL* symB = static_cast<const SCH_SYMBOL*>( b.second->GetParentSymbol() );
1925 wxString refA = symA ? symA->GetRef( &a.first, false ) : wxString();
1926 wxString refB = symB ? symB->GetRef( &b.first, false ) : wxString();
1928 int refCmp = refA.Cmp( refB );
1933 return a.second->GetNumber().Cmp( b.second->GetNumber() ) < 0;
1936 std::unordered_map<int, CONNECTION_SUBGRAPH*> global_power_pin_subgraphs;
1940 SYMBOL* libParent =
pin->GetLibPin() ?
pin->GetLibPin()->GetParentSymbol() :
nullptr;
1942 if( !
pin->ConnectedItems( sheet ).empty()
1959 connection->
SetName(
pin->GetParentSymbol()->GetValue(
true, &sheet,
false ) );
1968 auto jj = global_power_pin_subgraphs.find( code );
1970 if( jj != global_power_pin_subgraphs.end() )
1972 subgraph = jj->second;
1990 global_power_pin_subgraphs[code] = subgraph;
2007 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
2011 if( subgraph->m_absorbed )
2016 wxString
name = connection->
Name();
2019 unsigned suffix = 1;
2021 auto create_new_name =
2025 wxString suffixStr = std::to_wstring( suffix );
2032 wxString prefix = aConn->BusPrefix();
2034 if( prefix.empty() )
2035 prefix = wxT(
"BUS" );
2040 wxString members = aConn->Name().Mid( aConn->BusPrefix().length() );
2042 newName << prefix << wxT(
"_" ) << suffixStr << members;
2044 aConn->ConfigureFromLabel( newName );
2048 newName << aConn->Name() << wxT(
"_" ) << suffixStr;
2049 aConn->SetSuffix( wxString( wxT(
"_" ) ) << suffixStr );
2056 if( !subgraph->m_strong_driver )
2058 std::vector<CONNECTION_SUBGRAPH*> vec_empty;
2059 std::vector<CONNECTION_SUBGRAPH*>* vec = &vec_empty;
2068 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
2074 if( vec->size() > 1 )
2076 wxString new_name = create_new_name( connection );
2079 new_name = create_new_name( connection );
2081 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
2082 subgraph->m_code,
name, new_name );
2084 std::erase( *vec, subgraph );
2090 else if( subgraph->m_driver )
2102 bool conflict =
false;
2103 wxString global_name = connection->
Name(
true );
2110 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
2114 if( candidate->m_sheet == sheet )
2121 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) skipped for promotion due to potential conflict" ),
2122 subgraph->m_code,
name );
2128 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) weakly driven by unique sheet pin %s, promoting" ),
2129 subgraph->m_code,
name,
2130 subgraph->m_driver->GetItemDescription( &unitsProvider,
true ) );
2132 subgraph->m_strong_driver =
true;
2139 if( connection->
IsBus() )
2163 subgraph->m_dirty =
true;
2171 if( !subgraph->m_strong_driver )
2178 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
2181 std::back_inserter( candidate_subgraphs ),
2184 return ( !candidate->m_absorbed &&
2185 candidate->m_strong_driver &&
2186 candidate != subgraph );
2192 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
2195 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
2197 auto add_connections_to_check =
2200 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
2202 if( possible_driver == aSubgraph->m_driver )
2209 if( c->Type() != aSubgraph->m_driver_connection->Type() )
2212 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
2215 connections_to_check.push_back( c );
2216 wxLogTrace(
ConnTrace, wxS(
"%lu (%s): Adding secondary driver %s" ),
2218 aSubgraph->m_driver_connection->Name(
true ),
2227 add_connections_to_check( subgraph );
2229 std::set<SCH_CONNECTION*> checked_connections;
2231 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2233 auto member = connections_to_check[i];
2236 if( !checked_connections.insert( member.get() ).second )
2239 if( member->IsBus() )
2241 connections_to_check.insert( connections_to_check.end(),
2242 member->Members().begin(),
2243 member->Members().end() );
2246 wxString test_name = member->Name(
true );
2250 if( candidate->
m_absorbed || candidate == subgraph )
2266 if( driver == candidate->
m_driver )
2278 &&
pin->GetDefaultNetName( sheet ) == test_name )
2291 if( subgraph->GetNameForDriver( driver ) == test_name )
2304 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has bus child %lu (%s)" ),
2305 subgraph->m_code, connection->
Name(),
2306 candidate->
m_code, member->Name() );
2308 subgraph->m_bus_neighbors[member].insert( candidate );
2311 else if( ( !connection->
IsBus()
2315 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) absorbs neighbor %lu (%s)" ),
2316 subgraph->m_code, connection->
Name(),
2320 add_connections_to_check( candidate );
2322 subgraph->Absorb( candidate );
2323 invalidated_subgraphs.insert( subgraph );
2333 if( subgraph->m_absorbed )
2336 if( !subgraph->ResolveDrivers() )
2339 if( subgraph->m_driver_connection->IsBus() )
2344 wxLogTrace(
ConnTrace, wxS(
"Re-resolving drivers for %lu (%s)" ),
2345 subgraph->m_code, subgraph->m_driver_connection->Name() );
2364 bool aUnconditional )
2367 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
2371 for(
const std::shared_ptr<BUS_ALIAS>& alias :
m_schematic->GetAllBusAliases() )
2377 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
2396 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
2400 proc_sub_graph.
Show();
2409 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
2411 std::back_inserter( global_subgraphs ),
2414 return !candidate->m_local_driver;
2428 m_driver_subgraphs[ii]->UpdateItemConnections();
2450 if( !global_subgraphs.empty() )
2452 std::unordered_map<CONNECTION_SUBGRAPH*, CONNECTION_SUBGRAPH*> sg_root;
2461 auto it = sg_root.find( cur );
2463 if( it == sg_root.end() || it->second == cur )
2468 auto parent_it = sg_root.find( it->second );
2470 if( parent_it != sg_root.end() && parent_it->second != it->second )
2471 it->second = parent_it->second;
2481 auto prefer_as_representative =
2486 aB->m_driver, aB->m_driver_connection,
2487 aB->m_driver_connection->Name() ) < 0;
2493 sg_root.try_emplace( aA, aA );
2494 sg_root.try_emplace( aB, aB );
2499 if( root_a == root_b )
2502 if( prefer_as_representative( root_a, root_b ) )
2503 sg_root[root_b] = root_a;
2505 sg_root[root_a] = root_b;
2508 std::unordered_map<wxString, std::vector<CONNECTION_SUBGRAPH*>> name_to_sgs;
2512 for(
SCH_ITEM* driver : subgraph->m_drivers )
2520 name_to_sgs[subgraph->GetNameForDriver( driver )].push_back( subgraph );
2524 for(
auto& [
name, sgs] : name_to_sgs )
2526 if( sgs.size() < 2 )
2529 for(
size_t ii = 1; ii < sgs.size(); ++ii )
2530 union_sgs( sgs[0], sgs[ii] );
2536 for(
const auto& entry : sg_root )
2547 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) canonicalized to %lu (%s)" ),
2560 if( !subgraph->m_dirty )
2563 wxLogTrace(
ConnTrace, wxS(
"Processing %lu (%s) for propagation" ),
2564 subgraph->m_code, subgraph->m_driver_connection->Name() );
2570 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
2572 for(
SCH_ITEM* driver : subgraph->m_drivers )
2574 if( driver == subgraph->m_driver )
2577 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
2579 if( secondary_name == subgraph->m_driver_connection->Name() )
2587 if( candidate == subgraph )
2590 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
2597 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) promoted to %s" ),
2599 subgraph->m_driver_connection->Name() );
2621 if( subgraph->m_dirty )
2638 wxASSERT_MSG( !subgraph->m_dirty,
2639 wxS(
"Subgraph not processed by propagateToNeighbors!" ) );
2641 if( subgraph->m_bus_parents.size() < 2 )
2646 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has multiple bus parents" ),
2647 subgraph->m_code, conn->
Name() );
2650 wxCHECK2( conn->
IsNet(),
continue );
2652 for(
const auto& ii : subgraph->m_bus_parents )
2665 wxLogTrace(
ConnTrace, wxS(
"Warning: could not match %s inside %lu (%s)" ),
2670 if( conn->
Name() != match->
Name() )
2672 wxString old_name = match->
Name();
2674 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ),
2677 match->
Clone( *conn );
2685 std::vector<CONNECTION_SUBGRAPH*> old_subgraphs = jj->second;
2689 while( old_sg->m_absorbed )
2690 old_sg = old_sg->m_absorbed_by;
2692 wxString old_sg_name = old_sg->m_driver_connection->Name();
2693 old_sg->m_driver_connection->Clone( *conn );
2695 if( old_sg_name != old_sg->m_driver_connection->Name() )
2706 auto propagateConnectionsTask =
2710 if( !subgraph->m_strong_driver
2711 && subgraph->m_drivers.size() == 1
2712 && subgraph->m_driver->Type() ==
SCH_PIN_T )
2715 wxString
name =
pin->GetDefaultNetName( subgraph->m_sheet,
true );
2717 subgraph->m_driver_connection->ConfigureFromLabel(
name );
2720 subgraph->m_dirty =
false;
2721 subgraph->UpdateItemConnections();
2727 propagateConnectionsTask( m_driver_subgraphs[ii] );
2736 if( subgraph->m_driver_connection->IsBus() )
2739 if( !subgraph->m_driver || subgraph->m_driver->Type() !=
SCH_SHEET_PIN_T )
2748 wxString pinText =
pin->GetShownText(
false );
2755 if( label->
GetShownText( &subgraph->m_sheet,
false ) == pinText )
2758 path.push_back( sheet );
2762 if( parent_conn && parent_conn->
IsBus() )
2776 subgraph->m_driver_connection->NetCode() };
2782 std::shared_ptr<NET_SETTINGS>& netSettings =
m_schematic->Project().GetProjectFile().m_NetSettings;
2783 std::map<wxString, std::set<wxString>> oldAssignments = netSettings->GetNetclassLabelAssignments();
2784 std::set<wxString> affectedNetclassNetAssignments;
2786 netSettings->ClearNetclassLabelAssignments();
2788 auto dirtySubgraphs =
2789 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2791 if( aChangedItemHandler )
2795 for(
SCH_ITEM* item : subgraph->m_items )
2796 (*aChangedItemHandler)( item );
2801 auto checkNetclassDrivers =
2802 [&](
const wxString& netName,
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2804 wxCHECK_RET( !subgraphs.empty(), wxS(
"Invalid empty subgraph" ) );
2806 std::set<wxString> netclasses;
2811 for(
SCH_ITEM* item : subgraph->m_items )
2813 for(
const auto& [
name, provider] : subgraph->GetNetclassesForDriver( item ) )
2814 netclasses.insert(
name );
2821 if( subgraph->m_driver_connection->IsBus() )
2823 auto processBusMember = [&,
this](
const SCH_CONNECTION* member )
2825 if( !netclasses.empty() )
2827 netSettings->AppendNetclassLabelAssignment( member->Name(), netclasses );
2832 if( oldAssignments.count( member->Name() ) )
2834 if( oldAssignments[member->Name()] != netclasses )
2836 affectedNetclassNetAssignments.insert( member->Name() );
2839 dirtySubgraphs( ii->second );
2842 else if( !netclasses.empty() )
2844 affectedNetclassNetAssignments.insert( member->Name() );
2847 dirtySubgraphs( ii->second );
2851 for(
const std::shared_ptr<SCH_CONNECTION>& member : subgraph->m_driver_connection->Members() )
2855 if( member->IsBus() )
2857 for(
const std::shared_ptr<SCH_CONNECTION>& nestedMember : member->Members() )
2858 processBusMember( nestedMember.get() );
2862 processBusMember( member.get() );
2869 if( !netclasses.empty() )
2871 netSettings->AppendNetclassLabelAssignment( netName, netclasses );
2874 if( oldAssignments.count( netName ) )
2876 if( oldAssignments[netName] != netclasses )
2878 affectedNetclassNetAssignments.insert( netName );
2879 dirtySubgraphs( subgraphs );
2882 else if( !netclasses.empty() )
2884 affectedNetclassNetAssignments.insert( netName );
2885 dirtySubgraphs( subgraphs );
2891 checkNetclassDrivers( netname, subgraphs );
2893 if( !aUnconditional )
2895 for(
auto& [netname, netclasses] : oldAssignments )
2897 if( netSettings->GetNetclassLabelAssignments().count( netname )
2898 || affectedNetclassNetAssignments.count( netname ) )
2903 netSettings->SetNetclassLabelAssignment( netname, netclasses );
2921 auto getSubgraphNet = [&](
SCH_PIN* aPin ) -> wxString
2934 result.edges.reserve( 256 );
2943 auto findWireOnScreen = [&](
SCH_PIN* aPin,
SCH_LINE*& aWire ) ->
bool
2947 auto consider = [&](
SCH_ITEM* cand ) ->
bool
2960 if( s.
y == e.
y && p.
y == s.
y )
2962 int minx = std::min( s.
x, e.
x );
2963 int maxx = std::max( s.
x, e.
x );
2965 if( p.
x >= minx && p.
x <= maxx )
2971 else if( s.
x == e.
x && p.
x == s.
x )
2973 int miny = std::min( s.
y, e.
y );
2974 int maxy = std::max( s.
y, e.
y );
2976 if( p.
y >= miny && p.
y <= maxy )
3000 std::vector<SCH_PIN*> pins = symbol->
GetPins( &sheetPath );
3002 if( pins.size() != 2 )
3011 if( !findWireOnScreen( pins[0], wireA ) || !findWireOnScreen( pins[1], wireB ) )
3022 if( pins[0]->IsPower() || pins[1]->IsPower() )
3030 if( aS.
x == aE.
x && bS.
x == bE.
x && aS.
x == bS.
x )
3032 else if( aS.
y == aE.
y && bS.
y == bE.
y && aS.
y == bS.
y )
3039 wxString netA = getSubgraphNet( pins[0] );
3040 wxString netB = getSubgraphNet( pins[1] );
3042 if( netA.IsEmpty() || netB.IsEmpty() || netA == netB )
3045 result.edges.push_back( { netA, netB, symbol } );
3053 std::set<long> powerSubgraphs;
3054 std::map<wxString, long> netToCode;
3066 std::vector<SCH_PIN*> pins = sym->
GetPins( &sheetPath );
3072 netToCode[
netChainKeyFor( sg->GetNetName(), sg->m_code )] = sg->m_code;
3075 || ( p->GetParentSymbol() && p->GetParentSymbol()->IsPower() ) )
3077 powerSubgraphs.insert( sg->m_code );
3088 std::set<wxString> powerAdjacentNets;
3095 if(
auto it = netToCode.find( be.
a ); it != netToCode.end() )
3098 if(
auto it = netToCode.find( be.
b ); it != netToCode.end() )
3101 if( ca == -1 || cb == -1 )
3104 if( powerSubgraphs.contains( ca ) || powerSubgraphs.contains( cb ) )
3106 if( !powerSubgraphs.contains( ca ) )
3107 powerAdjacentNets.insert( be.
a );
3109 if( !powerSubgraphs.contains( cb ) )
3110 powerAdjacentNets.insert( be.
b );
3115 result.adjacency[be.
a].push_back( { be.
b, be.
sym } );
3116 result.adjacency[be.
b].push_back( { be.
a, be.
sym } );
3122 std::map<wxString, int> degree;
3124 for(
const auto&
kv :
result.adjacency )
3125 degree[
kv.first] =
static_cast<int>(
kv.second.size() );
3127 if(
result.adjacency.size() <= 2 )
3128 powerAdjacentNets.clear();
3130 if( powerAdjacentNets.size() <= 2 )
3131 powerAdjacentNets.clear();
3133 std::queue<wxString> q;
3134 std::set<wxString> removed;
3136 for(
const auto&
kv : degree )
3138 if(
kv.second <= 1 && powerAdjacentNets.contains(
kv.first ) )
3144 wxString n = q.front();
3147 if( removed.contains( n ) )
3150 removed.insert( n );
3154 if( removed.contains( e.other ) )
3157 if( degree.count( e.other ) )
3161 if( degree[e.other] <= 1 && powerAdjacentNets.contains( e.other ) )
3167 if( !removed.empty() )
3169 std::map<wxString, std::vector<BRIDGE_NEIGHBOR>> newAdj;
3171 for(
const auto&
kv :
result.adjacency )
3173 if( removed.contains(
kv.first ) )
3178 if( removed.contains( e.
other ) )
3181 newAdj[
kv.first].push_back( e );
3185 result.adjacency.swap( newAdj );
3201 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: begin (items=%zu, schematic=%p)",
3211 std::map<wxString, SCH_NETCHAIN*> netToNetChain;
3215 std::vector<SCH_SCREEN*> allScreens;
3220 allScreens.push_back( sc );
3227 static_cast<SCH_SYMBOL*
>( item )->SetNetChainName( wxEmptyString );
3229 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: screens=%zu (global build)", allScreens.size() );
3238 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 1 (per-sheet 2-pin symbols)" );
3240 auto getSubgraphNet = [&](
SCH_PIN* aPin ) -> wxString
3251 auto& bridgeEdges = bridgeGraph.
edges;
3252 auto& adjacency = bridgeGraph.
adjacency;
3254 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: bridgeEdges=%zu adjacency=%zu",
3255 bridgeEdges.size(), adjacency.size() );
3261 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: targeted stub pruning start (adj=%zu)", adjacency.size() );
3262 std::map<wxString,std::vector<BRIDGE_NEIGHBOR>> snapshot = adjacency;
3263 std::set<wxString> seen;
3264 std::set<wxString> globalPrune;
3265 for(
const auto&
kv : snapshot )
3267 const wxString& start =
kv.first;
3268 if( seen.contains( start ) )
continue;
3270 std::vector<wxString>
comp; std::queue<wxString> q; q.push( start ); seen.insert( start );
3273 wxString cur = q.front(); q.pop();
comp.push_back( cur );
3274 for(
const BRIDGE_NEIGHBOR& e : snapshot[cur] )
if( !seen.contains( e.other ) ) { seen.insert( e.other ); q.push( e.other ); }
3277 if(
comp.size() <= 4 )
continue;
3278 std::map<wxString,int> degree;
3279 for(
const wxString& n :
comp ) degree[n] = (int) snapshot[n].size();
3280 std::vector<wxString> candidates;
3281 for(
const wxString& n :
comp )
3283 const auto& nbrs = snapshot[n];
3284 if( nbrs.size() == 1 )
3286 const wxString neigh = nbrs[0].other;
3287 if( degree.count( neigh ) && degree[neigh] > 2 ) candidates.push_back( n );
3291 if( candidates.empty() )
continue;
3292 std::sort( candidates.begin(), candidates.end(), [](
const wxString& a,
const wxString& b ){ return a.CmpNoCase( b ) < 0; } );
3293 size_t needPrune =
comp.size() - 4;
if( needPrune > candidates.size() ) needPrune = candidates.size();
3295 for(
size_t i = 0; i < needPrune; ++i ) globalPrune.insert( candidates[i] );
3297 if( !globalPrune.empty() )
3299 std::map<wxString,std::vector<BRIDGE_NEIGHBOR>> newAdj;
3300 for(
const auto& kv2 : adjacency )
3302 if( globalPrune.contains( kv2.first ) )
continue;
3305 if( globalPrune.contains( e.
other ) )
continue;
3306 newAdj[kv2.first].push_back( e );
3309 adjacency.swap( newAdj );
3310 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pruned %zu targeted stub nets", globalPrune.size() );
3315 auto neighbors_of = [&](
const wxString& n ) ->
const std::vector<BRIDGE_NEIGHBOR>*
3317 if(
auto it = adjacency.find(n); it != adjacency.end() )
return &it->second;
3326 std::set<wxString> netsAll;
3327 for(
const auto&
kv : adjacency ) netsAll.insert(
kv.first );
3330 std::set<wxString> visited;
3331 for(
const wxString& start : netsAll )
3333 if( visited.contains( start ) )
continue;
3334 std::queue<wxString> q; q.push( start );
3335 std::set<wxString>
comp;
comp.insert( start ); visited.insert( start );
3338 wxString cur = q.front(); q.pop();
3339 if(
auto nbrs = neighbors_of( cur ) )
3343 if( visited.contains( e.other ) )
continue;
3344 visited.insert( e.other );
3345 comp.insert( e.other );
3350 if(
comp.size() >= 2 )
3352 auto sig = std::make_unique<SCH_NETCHAIN>();
3353 for(
const wxString& n :
comp ) sig->AddNet( n );
3355 if(
comp.contains( be.a ) &&
comp.contains( be.b ) && be.sym )
3356 sig->AddSymbol( be.sym );
3361 netToNetChain.clear();
3363 if( sigUP )
for(
const wxString& n : sigUP->GetNets() ) netToNetChain[n] = sigUP.get();
3369 if( !sigUP )
continue;
3372 for(
const wxString& n : sigUP->GetNets() )
3377 netsStr += wxS(
" ");
3381 netsStr += wxS(
"...");
3386 wxLogTrace(
traceSchNetChain,
" chain %p name='%s' nets=%zu [%s]", (
void*) sigUP.get(),
3387 sigUP->GetName(), sigUP->GetNets().size(), netsStr );
3395 std::set<wxString> committedNames;
3400 committedNames.insert(
chain->GetName() );
3412 net = sg->GetNetName();
3415 if( !net.IsEmpty() && net.Length() < 2048 && netToNetChain.count( net ) )
3418 if(
name.Length() > 512 )
3419 name.Truncate( 512 );
3420 if(
name.StartsWith( wxS(
"/" ) ) )
3425 if( !committedNames.count(
name ) )
3426 netToNetChain[net]->SetName(
name );
3432 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 3 (default naming)" );
3435 if( sig->GetName().IsEmpty() )
3437 sig->SetName( wxString::Format( wxT(
"NetChain%d" ), idx ) );
3442 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 4 (terminal pins)" );
3451 std::vector<PIN_INFO> pins;
3455 SCH_SCREEN* sc = sheetPath.LastScreen();
if( !sc )
continue;
3461 wxString net = getSubgraphNet( p );
3462 if( sig->GetNets().count( net ) )
3463 pins.push_back( { p, sym, &sheetPath } );
3470 size_t bestI = 0, bestJ = 0;
3472 for(
size_t i = 0; i < pins.size(); ++i )
3474 for(
size_t j = i + 1; j < pins.size(); ++j )
3476 VECTOR2I pa = pins[i].pin->GetPosition();
3477 VECTOR2I pb = pins[j].pin->GetPosition();
3478 int64_t dx = pa.
x - pb.
x;
3479 int64_t dy = pa.
y - pb.
y;
3480 int64_t d = dx * dx + dy * dy;
3485 a = pins[i].pin->m_Uuid;
3486 b = pins[j].pin->m_Uuid;
3493 sig->SetTerminalPins( a, b );
3495 if( best >= 0 && bestI < pins.size() && bestJ < pins.size() )
3497 sig->SetTerminalRefs( pins[bestI].sym->GetRef( pins[bestI].sheet ), pins[bestI].pin->GetNumber(),
3498 pins[bestJ].sym->GetRef( pins[bestJ].sheet ), pins[bestJ].pin->GetNumber() );
3504 sig->SetTerminalPins( ov.first, ov.second );
3508 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 5 (apply symbol names)" );
3515 sym->SetNetChainName( sig->
GetName() );
3518 for(
const wxString& n : sig->
GetNets() ) { netsStr += n + wxS(
" "); }
3528 std::set<wxString> alreadyCommitted;
3533 alreadyCommitted.insert(
chain->GetName() );
3537 std::map<std::pair<wxString, wxString>, wxString> refPinToNet;
3549 wxString ref = sym->
GetRef( &sp );
3559 refPinToNet[{ ref,
pin->GetNumber() }] =
3568 std::unordered_map<wxString, SCH_NETCHAIN*> committedByName;
3573 committedByName[
chain->GetName()] =
chain.get();
3578 std::set<wxString> refreshedThisPass;
3588 if( alreadyCommitted.count( chainName ) )
3590 auto it = committedByName.find( chainName );
3592 if( it != committedByName.end() && it->second )
3595 refreshedThisPass.insert( chainName );
3602 alreadyCommitted.insert( chainName );
3603 refreshedThisPass.insert( chainName );
3610 if( memberNets.empty() )
3615 if( alreadyCommitted.count( chainName ) && refreshedThisPass.count( chainName ) )
3625 SCH_PIN* terminalPinA =
nullptr;
3626 SCH_PIN* terminalPinB =
nullptr;
3627 std::set<SCH_SYMBOL*> symbols;
3639 wxString ref = sym->
GetRef( &sp );
3640 bool symContributes =
false;
3650 symContributes =
true;
3652 if( ref == termRefs.first.ref &&
pin->GetNumber() == termRefs.first.pin )
3655 if( ref == termRefs.second.ref &&
pin->GetNumber() == termRefs.second.pin )
3659 if( symContributes )
3660 symbols.insert( sym );
3664 if( !terminalPinA || !terminalPinB || symbols.empty() )
3667 "RebuildNetChains: cannot restore manual chain '%s' "
3668 "(terminals or member nets unresolved)",
3673 if( alreadyCommitted.count( chainName ) )
3675 auto it = committedByName.find( chainName );
3677 if( it != committedByName.end() && it->second )
3681 termRefs.first.ref, termRefs.first.pin,
3682 termRefs.second.ref, termRefs.second.pin );
3689 terminalPinB->
m_Uuid, termRefs.first.ref, termRefs.first.pin,
3690 termRefs.second.ref, termRefs.second.pin );
3691 alreadyCommitted.insert( chainName );
3703 sym->SetNetChainName(
chain->GetName() );
3716 catch(
const std::exception& e )
3718 wxFAIL_MSG( wxString::Format(
"RebuildNetChains threw: %s", e.what() ) );
3719 wxLogError(
_(
"Net chain rebuild failed: %s. The schematic may have stale chain "
3720 "data; reload to recover." ),
3721 wxString( e.what() ) );
3732 wxFAIL_MSG(
"RebuildNetChains threw an unknown exception" );
3733 wxLogError(
_(
"Net chain rebuild failed with an unknown error. The schematic may "
3734 "have stale chain data; reload to recover." ) );
3747 const std::map<std::pair<wxString, wxString>, wxString>& aRefPinToNet,
3748 const std::vector<std::unique_ptr<SCH_NETCHAIN>>& aPotentials,
3749 const wxString& aChainName )
3751 auto itFrom = aRefPinToNet.find( { aTermRefs.first.ref, aTermRefs.first.pin } );
3752 auto itTo = aRefPinToNet.find( { aTermRefs.second.ref, aTermRefs.second.pin } );
3754 if( itFrom == aRefPinToNet.end() || itTo == aRefPinToNet.end() )
3757 "RebuildNetChains: cannot restore chain '%s' (terminal %s.%s/%s.%s unresolved)",
3758 aChainName, aTermRefs.first.ref, aTermRefs.first.pin,
3759 aTermRefs.second.ref, aTermRefs.second.pin );
3763 for(
const auto& pot : aPotentials )
3765 if( pot && pot->GetNets().count( itFrom->second ) && pot->GetNets().count( itTo->second ) )
3770 "RebuildNetChains: no potential chain spans both terminals of '%s' (%s/%s)",
3771 aChainName, itFrom->second, itTo->second );
3778 if( !aPinA || !aPinB )
3790 if( netA.IsEmpty() || netB.IsEmpty() )
3795 if( sigUP && sigUP->GetNets().contains( netA ) && sigUP->GetNets().contains( netB ) )
3804 if( aName.IsEmpty() )
3808 [&](
const std::unique_ptr<SCH_NETCHAIN>& aChain )
3810 return aChain && aChain->GetName() == aName;
3821 sym->SetNetChainName( wxEmptyString );
3839 if( aOld.IsEmpty() || aNew.IsEmpty() || aOld == aNew )
3842 auto findByName = [&](
const wxString& aName ) ->
SCH_NETCHAIN*
3860 if( findByName( aNew ) )
3868 sym->SetNetChainName( aNew );
3882 auto rekey = [&](
auto& aMap )
3884 auto it = aMap.find( aOld );
3886 if( it != aMap.end() )
3888 auto val = std::move( it->second );
3890 aMap[aNew] = std::move( val );
3903 const std::set<wxString>& aNets,
3904 const std::set<SCH_SYMBOL*>& aSymbols,
3905 const KIID& aTerminalPinA,
3906 const KIID& aTerminalPinB,
3907 const wxString& aRefA,
3908 const wxString& aPinNumA,
3909 const wxString& aRefB,
3910 const wxString& aPinNumB )
3915 std::set<wxString> filtered;
3917 for(
const wxString& net : aNets )
3919 if( !net.IsEmpty() )
3920 filtered.insert( net );
3936 aTarget->
SetTerminalPins( termOverride->second.first, termOverride->second.second );
3943 sym->SetNetChainName( aTarget->
GetName() );
3961 auto sig = std::make_unique<SCH_NETCHAIN>();
3962 for(
const wxString& n : aPotential->
GetNets() )
3965 sig->AddSymbol( sym );
3966 sig->SetName( aName );
3975 sig->SetNetClass( ncIt->second );
3981 sig->SetColor( colIt->second );
3985 sym->SetNetChainName( sig->GetName() );
4000 std::set<wxString> persistableNets;
4002 for(
const wxString& net : sig->GetNets() )
4010 persistableNets.insert( net );
4013 if( !persistableNets.empty() )
4025 const std::set<SCH_SYMBOL*>& aSymbols,
4026 const std::set<wxString>& aNets,
4027 const KIID& aTerminalPinA,
4028 const KIID& aTerminalPinB,
4029 const wxString& aRefA,
4030 const wxString& aPinNumA,
4031 const wxString& aRefB,
4032 const wxString& aPinNumB )
4042 for(
const wxString& net : aNets )
4051 auto sig = std::make_unique<SCH_NETCHAIN>();
4052 sig->SetName( aName );
4054 for(
const wxString& net : aNets )
4063 sig->AddSymbol( sym );
4065 sig->SetTerminalPins( aTerminalPinA, aTerminalPinB );
4066 sig->SetTerminalRefs( aRefA, aPinNumA, aRefB, aPinNumB );
4071 sig->SetNetClass( ncIt->second );
4076 sig->SetColor( colIt->second );
4079 sym->SetNetChainName( sig->GetName() );
4096 wxLogTrace(
traceSchNetChain,
"CONNECTION_GRAPH::GetNetChainForNet(%s)", aNet );
4102 if( sig->GetNets().count( aNet ) )
4104 wxLogTrace(
traceSchNetChain,
"GetNetChainForNet: found chain '%s'", sig->GetName() );
4116 wxLogTrace(
traceSchNetChain,
"CONNECTION_GRAPH::GetNetChainByName(%s)", aName );
4119 if( sig->GetName() == aName )
4134 wxLogTrace(
traceSchNetChain,
"ReplaceNetChainTerminalPin: chain='%s' prev=%s new=%s",
4138 sig->ReplaceTerminalPin( aPrev, aNew );
4140 sig->GetTerminalPinB() );
4141 wxLogTrace(
traceSchNetChain,
"ReplaceNetChainTerminalPin: updated overrides to (%s,%s)",
4142 sig->GetTerminalPinA().AsString(), sig->GetTerminalPinB().AsString() );
4148 std::pair<KIID, KIID>>& aOverrides )
4188 std::vector<std::shared_ptr<SCH_CONNECTION>> connections_to_check( aConnection->
Members() );
4190 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
4192 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
4194 if( member->IsBus() )
4196 connections_to_check.insert( connections_to_check.end(),
4197 member->Members().begin(),
4198 member->Members().end() );
4210 std::vector<CONNECTION_SUBGRAPH*> search_list;
4211 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
4212 std::unordered_set<SCH_CONNECTION*> stale_bus_members;
4219 path.push_back(
pin->GetParent() );
4230 || visited.contains( candidate ) )
4239 wxLogTrace(
ConnTrace, wxS(
"%lu: found child %lu (%s)" ), aParent->m_code,
4247 wxASSERT( candidate->
m_graph == aParent->m_graph );
4249 search_list.push_back( candidate );
4269 || visited.contains( candidate )
4275 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
4280 if(
pin->GetParent()->m_Uuid != last_parent_uuid )
4286 if( pin_path != aParent->m_sheet )
4291 wxLogTrace(
ConnTrace, wxS(
"%lu: found additional parent %lu (%s)" ),
4294 aParent->m_hier_children.insert( candidate );
4295 search_list.push_back( candidate );
4309 std::vector<std::shared_ptr<SCH_CONNECTION>> sortedMembers;
4311 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
4312 sortedMembers.push_back(
kv.first );
4314 std::sort( sortedMembers.begin(), sortedMembers.end(),
4315 [](
const std::shared_ptr<SCH_CONNECTION>& a,
4316 const std::shared_ptr<SCH_CONNECTION>& b )
4318 return a->Name() < b->Name();
4321 for(
const std::shared_ptr<SCH_CONNECTION>& member_conn : sortedMembers )
4323 const auto& kv_it = aParentGraph->m_bus_neighbors.find( member_conn );
4325 if( kv_it == aParentGraph->m_bus_neighbors.end() )
4368 wxLogTrace(
ConnTrace, wxS(
"Could not match bus member %s in %s" ),
4369 member_conn->Name(), parent->
Name() );
4375 wxCHECK2( neighbor_conn,
continue );
4377 wxString neighbor_name = neighbor_conn->
Name();
4380 if( neighbor_name == member->
Name() )
4390 if( neighbor_conn->
Sheet() != parent->
Sheet() )
4401 bool alreadyUpdatedByBusMember =
false;
4403 for(
const auto& m : parent->
Members() )
4405 if( m->Name() == neighbor_name )
4407 alreadyUpdatedByBusMember =
true;
4412 if( alreadyUpdatedByBusMember )
4417 wxCHECK2_MSG( neighbor_conn->
IsNet(),
continue,
4418 wxS(
"\"" ) + neighbor_name + wxS(
"\" is not a net." ) );
4420 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) connected to bus member %s (local %s)" ),
4427 member->
Clone( *neighbor_conn );
4428 stale_bus_members.insert( member );
4432 neighbor_conn->
Clone( *member );
4445 if( neighbor_conn->
Name() != member->
Name() )
4447 member->
Clone( *neighbor_conn );
4448 stale_bus_members.insert( member );
4457 propagate_bus_neighbors( aSubgraph );
4464 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has both hier ports and pins; deferring processing" ),
4470 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has no hier pins or ports on sheet %s; marking clean" ),
4476 visited.insert( aSubgraph );
4478 wxLogTrace(
ConnTrace, wxS(
"Propagating %lu (%s) to subsheets" ),
4483 for(
unsigned i = 0; i < search_list.size(); i++ )
4485 auto child = search_list[i];
4487 if( visited.insert( child ).second )
4490 child->m_dirty =
false;
4504 if( subgraph == aSubgraph )
4511 wxString candidateName = subgraph->m_driver_connection->Name();
4512 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
4513 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
4523 ( !bestIsStrong && candidateStrong ) ||
4524 ( priority > highest && candidateStrong ) ||
4525 ( priority == highest && candidateStrong && shorterPath ) ||
4526 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
4527 ( candidateName < bestName ) ) )
4529 bestDriver = subgraph;
4531 bestIsStrong = candidateStrong;
4532 bestName = candidateName;
4537 if( bestDriver != aSubgraph )
4539 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) overridden by new driver %lu (%s)" ),
4548 wxString old_name = subgraph->m_driver_connection->Name();
4550 subgraph->m_driver_connection->Clone( *conn );
4552 if( old_name != conn->
Name() )
4556 propagate_bus_neighbors( subgraph );
4562 if( conn->
IsBus() && !stale_bus_members.empty() )
4564 std::unordered_set<SCH_CONNECTION*> cached_members = stale_bus_members;
4574 wxLogTrace(
ConnTrace, wxS(
"WARNING: failed to match stale member %s in %s." ),
4575 stale_member->Name(), subgraph->m_driver_connection->Name() );
4579 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
4580 subgraph->m_driver_connection->Name(), member->
LocalName(), stale_member->Name() );
4582 member->
Clone( *stale_member );
4584 propagate_bus_neighbors( subgraph );
4596 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
4598 switch( aItem->
Type() )
4601 if(
static_cast<SCH_PIN*
>( aItem )->IsPower() )
4602 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
4609 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
4618 c->SetGraph(
this );
4629 if( !aBusConnection->
IsBus() )
4639 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
4641 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
4643 match = bus_member.get();
4651 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
4658 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
4660 if( bus_member->LocalName() == aSearch->
LocalName() )
4662 match = bus_member.get();
4667 else if( c->LocalName() == aSearch->
LocalName() )
4678 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
4682 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
4686 match = bus_member.get();
4720 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
4721 std::erase( vec, aSubgraph );
4724 wxLogTrace(
ConnTrace, wxS(
"recacheSubgraphName: %s => %s" ), aOldName,
4741 std::vector<const CONNECTION_SUBGRAPH*> ret;
4747 wxASSERT( !subgraph->m_dirty );
4749 if( !subgraph->m_driver )
4755 if( !connection->
IsBus() )
4758 auto labels = subgraph->GetVectorBusLabels();
4760 if( labels.size() > 1 )
4762 bool different =
false;
4765 for(
unsigned i = 1; i < labels.size(); ++i )
4777 wxLogTrace(
ConnTrace, wxS(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
4778 connection->
Name() );
4780 ret.push_back( subgraph );
4801 if( graph == aSubGraph )
4844 wxASSERT( !it->second.empty() );
4846 return it->second[0];
4862const std::vector<CONNECTION_SUBGRAPH*>&
4865 static const std::vector<CONNECTION_SUBGRAPH*> subgraphs;
4878 int error_count = 0;
4880 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
4886 std::set<SCH_ITEM*> seenDriverInstances;
4891 wxCHECK2( subgraph,
continue );
4895 wxASSERT( !subgraph->m_dirty );
4897 if( subgraph->m_absorbed )
4900 if( seenDriverInstances.count( subgraph->m_driver ) )
4903 if( subgraph->m_driver )
4904 seenDriverInstances.insert( subgraph->m_driver );
4922 subgraph->ResolveDrivers(
false );
4993 wxCHECK( aSubgraph,
false );
4999 if( driver == aSubgraph->
m_driver )
5010 if( primaryName == secondaryName )
5013 wxString msg = wxString::Format(
_(
"Both %s and %s are attached to the same "
5014 "items; %s will be used in the netlist" ),
5015 primaryName, secondaryName, primaryName );
5018 ercItem->SetItems( aSubgraph->
m_driver, driver );
5019 ercItem->SetSheetSpecificPath( aSubgraph->
GetSheet() );
5020 ercItem->SetItemsSheetPaths( aSubgraph->
GetSheet(), aSubgraph->
m_sheet );
5021 ercItem->SetErrorMessage( msg );
5046 switch( item->
Type() )
5051 bus_item = ( !bus_item ) ? item : bus_item;
5053 net_item = ( !net_item ) ? item : net_item;
5067 bus_item = ( !bus_item ) ? item : bus_item;
5069 net_item = ( !net_item ) ? item : net_item;
5079 if( net_item && bus_item )
5082 ercItem->SetSheetSpecificPath( sheet );
5083 ercItem->SetItems( net_item, bus_item );
5086 screen->
Append( marker );
5105 switch( item->
Type() )
5132 if(
test != member && member->Name() ==
test->Name() )
5146 ercItem->SetSheetSpecificPath( sheet );
5147 ercItem->SetItems( label, port );
5150 screen->
Append( marker );
5162 bool conflict =
false;
5178 switch( item->
Type() )
5208 std::set<wxString> test_names;
5220 for(
const auto& sub_member : member->Members() )
5222 if( test_names.count( sub_member->FullLocalName() ) )
5226 else if( test_names.count( member->FullLocalName() ) )
5245 wxString msg = wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
5246 " member of that bus" ),
5250 ercItem->SetSheetSpecificPath( sheet );
5251 ercItem->SetItems( bus_entry, bus_wire );
5252 ercItem->SetErrorMessage( msg );
5255 screen->
Append( marker );
5272 std::set<SCH_PIN*> unique_pins;
5273 std::set<SCH_LABEL_BASE*> unique_labels;
5281 for(
SCH_ITEM* item : aProcessGraph->m_items )
5283 switch( item->
Type() )
5290 if( aProcessGraph == aSubgraph )
5293 if( std::none_of( unique_pins.begin(), unique_pins.end(),
5296 return test_pin->IsStacked( aPin );
5300 unique_pins.insert( test_pin );
5323 process_subgraph( subgraph );
5328 process_subgraph( aSubgraph );
5344 switch( item->
Type() )
5391 ercItem->SetSheetSpecificPath( sheet );
5392 ercItem->SetItemsSheetPaths( sheet );
5399 pos =
pin->GetPosition();
5408 screen->
Append( marker );
5413 if( unique_pins.empty() && unique_labels.empty() &&
5418 ercItem->SetSheetSpecificPath( sheet );
5419 ercItem->SetItemsSheetPaths( sheet );
5422 screen->
Append( marker );
5429 bool has_other_connections =
false;
5430 std::vector<SCH_PIN*> pins;
5437 switch( item->
Type() )
5444 if( !has_other_connections && !pins.empty()
5447 for(
SCH_PIN* other_pin : pins )
5451 has_other_connections =
true;
5457 pins.emplace_back(
static_cast<SCH_PIN*
>( item ) );
5464 has_other_connections =
true;
5471 pin = pins.empty() ? nullptr : pins[0];
5474 for(
SCH_PIN* test_pin : pins )
5491 ?
pin->GetLibPin()->GetParentSymbol() :
nullptr;
5493 if(
pin && !has_other_connections
5495 && ( !pinLibParent || !pinLibParent->
IsPower() ) )
5497 wxString
name =
pin->Connection( &sheet )->Name();
5498 wxString local_name =
pin->Connection( &sheet )->Name(
true );
5503 has_other_connections =
true;
5508 if(
pin && !has_other_connections
5514 ercItem->SetSheetSpecificPath( sheet );
5515 ercItem->SetItemsSheetPaths( sheet );
5516 ercItem->SetItems(
pin );
5519 screen->
Append( marker );
5527 if( pins.size() > 1 )
5529 for(
SCH_PIN* testPin : pins )
5534 SYMBOL* testLibParent = testPin->GetLibPin()
5538 if( testLibParent && testLibParent->
IsPower()
5539 && testPin->ConnectedItems( sheet ).empty()
5543 ercItem->SetSheetSpecificPath( sheet );
5544 ercItem->SetItemsSheetPaths( sheet );
5545 ercItem->SetItems( testPin );
5548 screen->
Append( marker );
5581 ercItem->SetItems( line );
5582 ercItem->SetSheetSpecificPath( sheet );
5583 ercItem->SetErrorMessage(
_(
"Unconnected wire endpoint" ) );
5605 ercItem->SetItems( entry );
5606 ercItem->SetSheetSpecificPath( sheet );
5607 ercItem->SetErrorMessage(
_(
"Unconnected wire to bus entry" ) );
5624 return err_count > 0;
5634 std::vector<SCH_ITEM*> wires;
5641 wires.emplace_back( item );
5643 wires.emplace_back( item );
5646 if( !wires.empty() )
5651 ercItem->SetSheetSpecificPath( sheet );
5652 ercItem->SetItems( wires[0],
5653 wires.size() > 1 ? wires[1] :
nullptr,
5654 wires.size() > 2 ? wires[2] :
nullptr,
5655 wires.size() > 3 ? wires[3] :
nullptr );
5658 screen->
Append( marker );
5686 size_t pinCount = 0;
5689 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
5695 return std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(),
5698 return item->Type() == SCH_PIN_T;
5703 [&](
SCH_TEXT* aText,
int errCode )
5708 ercItem->SetSheetSpecificPath( sheet );
5709 ercItem->SetItems( aText );
5716 pinCount =
hasPins( aSubgraph );
5720 switch( item->
Type() )
5728 label_map[item->
Type()].push_back(
text );
5733 if(
text->IsDangling() )
5747 if( label_map.empty() )
5752 for(
auto& [ connection, subgraphs ] : aSubgraph->
m_bus_parents )
5756 if( busParent->m_no_connect )
5779 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
5786 for(
auto& [type, label_vec] : label_map )
5790 size_t allPins = pinCount;
5791 size_t localPins = pinCount;
5792 bool hasLocalHierarchy =
false;
5800 std::set<wxString> uniquePortNames;
5804 if( aSubgraph->
m_hier_pins.size() + uniquePortNames.size() > 1 )
5806 hasLocalHierarchy =
true;
5811 for(
auto& [connection, busParents] : aSubgraph->
m_bus_parents )
5815 if( busParent->m_sheet == sheet
5816 && ( !busParent->m_hier_pins.empty()
5817 || !busParent->m_hier_ports.empty() ) )
5819 hasLocalHierarchy =
true;
5824 if( hasLocalHierarchy )
5835 if( neighbor == aSubgraph )
5841 size_t neighborPins =
hasPins( neighbor );
5842 allPins += neighborPins;
5844 if( neighbor->
m_sheet == sheet )
5846 localPins += neighborPins;
5851 hasLocalHierarchy =
true;
5857 if( allPins == 1 && !has_nc )
5868 || ( type ==
SCH_LABEL_T && localPins == 0 && allPins > 1
5869 && !has_nc && !hasLocalHierarchy ) )
5885 std::map<wxString, std::tuple<int, const SCH_ITEM*, SCH_SHEET_PATH>> labelData;
5892 wxString resolvedLabelText =
5895 if( labelData.find( resolvedLabelText ) == labelData.end() )
5897 labelData[resolvedLabelText] = { 1, item, sheet };
5901 std::get<0>( labelData[resolvedLabelText] ) += 1;
5902 std::get<1>( labelData[resolvedLabelText] ) =
nullptr;
5903 std::get<2>( labelData[resolvedLabelText] ) = sheet;
5908 for(
const auto& label : labelData )
5910 if( std::get<0>( label.second ) == 1 )
5913 const SCH_ITEM* item = std::get<1>( label.second );
5916 ercItem->SetItems( std::get<1>( label.second ) );
5917 ercItem->SetSheetSpecificPath( sheet );
5918 ercItem->SetItemsSheetPaths( sheet );
5933 int error_count = 0;
5945 ercItem->SetSheetSpecificPath( sheet );
5946 ercItem->SetItems(
text );
5949 sheet.LastScreen()->Append( marker );
5969 if( sheet.Last()->IsTopLevelSheet() )
5975 wxCHECK2( label,
continue );
5977 msg.Printf(
_(
"Hierarchical label '%s' in root sheet cannot be connected to non-existent "
5981 ercItem->SetItems( item );
5982 ercItem->SetErrorMessage( msg );
5985 sheet.LastScreen()->Append( marker );
5996 parentSheetPath.
push_back( parentSheet );
5998 std::map<wxString, SCH_SHEET_PIN*> pins;
5999 std::map<wxString, SCH_HIERLABEL*> labels;
6004 pins[
pin->GetShownText( &parentSheetPath,
false ) ] =
pin;
6009 ercItem->SetItems(
pin );
6010 ercItem->SetSheetSpecificPath( sheet );
6011 ercItem->SetItemsSheetPaths( sheet );
6014 sheet.LastScreen()->Append( marker );
6022 std::set<wxString> matchedPins;
6029 wxString labelText = label->
GetShownText( &parentSheetPath,
false );
6031 if( !pins.contains( labelText ) )
6032 labels[ labelText ] = label;
6034 matchedPins.insert( labelText );
6038 for(
const wxString& matched : matchedPins )
6039 pins.erase( matched );
6041 for(
const auto& [
name,
pin] : pins )
6043 msg.Printf(
_(
"Sheet pin %s has no matching hierarchical label inside the sheet" ),
6047 ercItem->SetItems(
pin );
6048 ercItem->SetErrorMessage( msg );
6049 ercItem->SetSheetSpecificPath( sheet );
6050 ercItem->SetItemsSheetPaths( sheet );
6053 sheet.LastScreen()->Append( marker );
6058 for(
const auto& [
name, label] : labels )
6060 msg.Printf(
_(
"Hierarchical label %s has no matching sheet pin in the parent sheet" ),
6064 ercItem->SetItems( label );
6065 ercItem->SetErrorMessage( msg );
6066 ercItem->SetSheetSpecificPath( parentSheetPath );
6067 ercItem->SetItemsSheetPaths( parentSheetPath );
constexpr EDA_IU_SCALE schIUScale
This represents a sentry transaction which is used for time-performance metrics You start a transacti...
void StartSpan(const std::string &aOperation, const std::string &aDescription)
static SCH_NETCHAIN * resolvePotentialChainByTerminals(const CHAIN_TERMINAL_REFS &aTermRefs, const std::map< std::pair< wxString, wxString >, wxString > &aRefPinToNet, const std::vector< std::unique_ptr< SCH_NETCHAIN > > &aPotentials, const wxString &aChainName)
Disambiguate the saved (refA.pinA, refB.pinB) terminal pair against the current set of potential net ...
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.
void refreshCommittedChainFromPotential(SCH_NETCHAIN *aTarget, const SCH_NETCHAIN &aSource)
Thin forwarder over refreshCommittedChainPayload that pulls payload fields from an inferred potential...
std::map< wxString, wxString > m_netChainNetClassOverrides
std::pair< CHAIN_TERMINAL_REF, CHAIN_TERMINAL_REF > CHAIN_TERMINAL_REFS
SCH_NETCHAIN * GetNetChainByName(const wxString &aName)
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Check one subgraph for proper connection of labels.
void RemoveItem(SCH_ITEM *aItem)
std::map< wxString, COLOR4D > m_netChainColorOverrides
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.
void updateGenericItemConnectivity(const SCH_SHEET_PATH &aSheet, SCH_ITEM *aItem, std::map< VECTOR2I, std::vector< SCH_ITEM * > > &aConnectionMap)
Update the connectivity of items that are not pins or symbols.
std::vector< std::unique_ptr< SCH_NETCHAIN > > m_committedNetChains
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.
void updateSymbolConnectivity(const SCH_SHEET_PATH &aSheet, SCH_SYMBOL *aSymbol, std::map< VECTOR2I, std::vector< SCH_ITEM * > > &aConnectionMap)
Update the connectivity of a symbol and its pins.
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.
SCH_NETCHAIN * GetNetChainForNet(const wxString &aNet)
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::map< wxString, CHAIN_TERMINAL_REFS > m_netChainTerminalRefOverrides
BRIDGE_GRAPH buildBridgeAdjacency()
Build the bridge graph used for net-chain discovery.
SCH_NETCHAIN * CreateNetChainFromPotential(SCH_NETCHAIN *aPotential, const wxString &aName)
Promote a potential net chain to an actual user net chain with the provided name.
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.
static std::function< void(CONNECTION_GRAPH &)> & RebuildNetChainsTestHook()
Test-only hook fired inside RebuildNetChains() after the restore passes have finished but before the ...
bool RenameCommittedNetChain(const wxString &aOld, const wxString &aNew)
Rename a committed net chain.
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration()
Determine which subgraphs have more than one conflicting bus label.
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
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 refreshCommittedChainPayload(SCH_NETCHAIN *aTarget, const std::set< wxString > &aNets, const std::set< class SCH_SYMBOL * > &aSymbols, const KIID &aTerminalPinA, const KIID &aTerminalPinB, const wxString &aRefA, const wxString &aPinNumA, const wxString &aRefB, const wxString &aPinNumB)
Replace the derived-view payload on aTarget with explicitly supplied member nets, symbols,...
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
SCH_NETCHAIN * CreateManualNetChain(const wxString &aName, const std::set< class SCH_SYMBOL * > &aSymbols, const std::set< wxString > &aNets, const KIID &aTerminalPinA, const KIID &aTerminalPinB, const wxString &aRefA, const wxString &aPinNumA, const wxString &aRefB, const wxString &aPinNumB)
Commit a manually-defined net chain that the inferred-potential pass did not produce.
CONNECTION_GRAPH(SCHEMATIC *aSchematic=nullptr)
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.
void SetNetChainTerminalOverrides(const std::map< wxString, std::pair< KIID, KIID > > &aOverrides)
std::vector< std::unique_ptr< SCH_NETCHAIN > > m_potentialNetChains
last built potential (uncommitted) net chains
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.
SCH_NETCHAIN * FindPotentialNetChainBetweenPins(SCH_PIN *aPinA, SCH_PIN *aPinB)
Locate a potential net chain that contains both pins (by subgraph net membership).
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.
void ReplaceNetChainTerminalPin(const wxString &aNetChain, const KIID &aPrev, const KIID &aNew)
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 rekeyOverrideMaps(const wxString &aOld, const wxString &aNew)
Move every net-chain override map entry keyed by aOld to aNew.
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 updatePinConnectivity(const SCH_SHEET_PATH &aSheet, SCH_PIN *aPin, SCH_CONNECTION *aConnection)
Update the connectivity of a pin and its connections.
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 generateBusAliasMembers()
Iterate through labels to create placeholders for bus elements.
bool DeleteCommittedNetChain(const wxString &aName)
Delete a committed net chain by name.
std::map< wxString, std::set< wxString > > m_netChainMemberNetOverrides
std::map< wxString, std::pair< KIID, KIID > > m_netChainTerminalOverrides
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).
CONNECTION_SUBGRAPH(CONNECTION_GRAPH *aGraph)
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.
virtual const wxString & GetText() const
Return the string associated with the text 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
wxString AsString() const
bool GetDuplicatePinNumbersAreJumpers() const
std::vector< std::set< wxString > > & JumperPinGroups()
Each jumper pin group is a set of pin numbers that should be treated as internally connected.
A small class to help profiling.
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
void Stop()
Save the time when this function was called, and set the counter stane to stop.
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
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)
SCH_SHEET_PATH Sheet() const
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
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) 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.
SCH_CONNECTION * InitializeConnection(const SCH_SHEET_PATH &aPath, CONNECTION_GRAPH *aGraph)
Create a new connection object associated with this object.
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 void SetUnit(int aUnit)
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.
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
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
VECTOR2I GetEndPoint() const
VECTOR2I GetStartPoint() const
bool IsEndDangling() const
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
A net chain is a collection of nets that are connected together through passive components.
const KIID & GetTerminalPinB() const
const std::set< wxString > & GetNets() const
void AddSymbol(class SCH_SYMBOL *aSymbol)
const wxString & GetTerminalRef(int aIdx) const
const wxString & GetName() const
static constexpr char SYNTHETIC_NET_PREFIX[]
Prefix used when synthesising net names for unnamed subgraphs.
static bool IsValidName(const wxString &aName)
void SetTerminalPins(const KIID &aPinA, const KIID &aPinB)
void ReplaceNets(const std::set< wxString > &aNew)
const std::set< class SCH_SYMBOL * > & GetSymbols() const
const wxString & GetTerminalPinNum(int aIdx) const
const KIID & GetTerminalPinA() const
void SetName(const wxString &aName)
void SetTerminalRefs(const wxString &aRefA, const wxString &aPinA, const wxString &aRefB, const wxString &aPinB)
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
VECTOR2I GetPosition() const override
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
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr, std::function< void(SCH_ITEM *)> *aChangedHandler=nullptr) const
Test all of the connectable objects in the schematic for unused connection points.
std::vector< SCH_LINE * > GetBusesAndWires(const VECTOR2I &aPosition, bool aIgnoreEndpoints=false) const
Return buses and wires passing through aPosition.
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
SCH_SCREEN * LastScreen()
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
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()
PASSTHROUGH_MODE GetPassthroughMode() const
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
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()
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
VECTOR2I GetPosition() const override
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
A base class for LIB_SYMBOL and SCH_SYMBOL.
virtual bool IsGlobalPower() const =0
virtual bool IsLocalPower() const =0
virtual bool IsPower() const =0
static int compareDrivers(SCH_ITEM *aA, SCH_CONNECTION *aAConn, const wxString &aAName, SCH_ITEM *aB, SCH_CONNECTION *aBConn, const wxString &aBName)
Unified driver ranking used by CONNECTION_SUBGRAPH::ResolveDrivers (within a single subgraph) and by ...
static wxString netChainKeyFor(const wxString &aRawNetName, long aSubgraphCode)
#define CONNECTIVITY_CANDIDATE
flag indicating that the structure is connected for connectivity
@ 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 any pins.
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
@ ERCE_LABEL_SINGLE_PIN
A label is connected only to a single pin.
@ 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_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 label only exists once in the schematic.
static const wxChar DanglingProfileMask[]
Flag to enable connectivity profiling.
const wxChar *const traceSchNetChain
Flag to enable tracing of schematic net chain rebuild and ERC cross-chain checks.
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 remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
@ PT_NC
not connected (must be left open)
@ PT_NIC
not internally connected (may be connected to anything)
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ BUS
This item represents a bus vector.
@ NET
This item represents a net.
@ BUS_GROUP
This item represents a bus group.
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:...
std::vector< BRIDGE_EDGE > edges
std::map< wxString, std::vector< BRIDGE_NEIGHBOR > > adjacency
const SHAPE_LINE_CHAIN chain
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< int32_t > VECTOR2I