27#include <unordered_map>
108 if( old_conn && new_conn )
110 new_conn->
Clone( *old_conn );
158 return pa > pb ? -1 : 1;
165 if( b_in_a && !a_in_b )
168 if( a_in_b && !b_in_a )
183 if( aGlobal != bGlobal )
184 return aGlobal ? -1 : 1;
189 if( aLocal != bLocal )
190 return aLocal ? -1 : 1;
208 bool aLowQuality = aAName.Contains( wxS(
"-Pad" ) );
209 bool bLowQuality = aBName.Contains( wxS(
"-Pad" ) );
211 if( aLowQuality != bLowQuality )
212 return aLowQuality ? 1 : -1;
214 if( aAName < aBName )
217 if( aBName < aAName )
232 std::vector<SCH_ITEM*> candidates;
233 std::set<SCH_ITEM*> strong_drivers;
257 strong_drivers.insert( item );
259 if( item_priority > highest_priority )
262 candidates.push_back( item );
263 highest_priority = item_priority;
265 else if( !candidates.empty() && ( item_priority == highest_priority ) )
267 candidates.push_back( item );
277 if( !candidates.empty() )
287 std::sort( candidates.begin(), candidates.end(), candidate_cmp );
292 if( strong_drivers.size() > 1 )
299 m_drivers.insert( strong_drivers.begin(), strong_drivers.end() );
321 std::set<CONNECTION_SUBGRAPH*>& aSubgraphs )
333 if( aSubgraphs.insert( sg ).second ==
false )
339 aItems.emplace(
m_sheet, item );
353#ifdef CONNECTIVITY_DEBUG
354 wxASSERT_MSG(
false, wxS(
"Tried to get the net name of an item with no connection" ) );
366 std::vector<SCH_ITEM*> labels;
370 switch( item->Type() )
380 labels.push_back( item );
396 std::vector<SCH_ITEM*> labels;
400 switch( item->Type() )
410 labels.push_back( item );
426 switch( aItem->
Type() )
433 return pin->GetDefaultNetName(
m_sheet, forceNoConnect );
460 wxFAIL_MSG( wxS(
"Unhandled item type in GetNameForDriver" ) );
461 return wxEmptyString;
481const std::vector<std::pair<wxString, SCH_ITEM*>>
484 std::vector<std::pair<wxString, SCH_ITEM*>> foundNetclasses;
486 const std::unordered_set<SCH_RULE_AREA*>& ruleAreaCache = aItem->
GetRuleAreaCache();
491 const std::vector<std::pair<wxString, SCH_ITEM*>> ruleAreaNetclasses =
492 ruleArea->GetResolvedNetclasses( &
m_sheet );
494 if( ruleAreaNetclasses.size() > 0 )
496 foundNetclasses.insert( foundNetclasses.end(), ruleAreaNetclasses.begin(),
497 ruleAreaNetclasses.end() );
513 if( netclass != wxEmptyString )
514 foundNetclasses.push_back( { netclass, aItem } );
521 foundNetclasses.begin(), foundNetclasses.end(),
522 [](
const std::pair<wxString, SCH_ITEM*>& i1,
const std::pair<wxString, SCH_ITEM*>& i2 )
524 return i1.first < i2.first;
527 return foundNetclasses;
553 child->m_absorbed_by =
this;
556 set_absorbed_by( subchild );
564 set_absorbed_by( aOther );
614 if(
const std::unique_ptr<LIB_SYMBOL>& part = symbol->GetLibSymbolRef() )
615 return part->GetReferenceField().GetText();
617 return wxEmptyString;
620 switch( aDriver->
Type() )
651 std::back_inserter(
m_items ) );
706 wxCHECK2( aOldItem->
Type() == aNewItem->
Type(),
return );
741 wxCHECK2( oldPins.size() == newPins.size(),
return );
743 for(
size_t ii = 0; ii < oldPins.size(); ii++ )
745 exchange( oldPins[ii], newPins[ii] );
756 if( subgraph->m_graph ==
this )
780 std::function<
void(
SCH_ITEM* )>* aChangedItemHandler,
784 PROF_TIMER recalc_time(
"CONNECTION_GRAPH::Recalculate" );
785 monitorTrans.
Start();
790 monitorTrans.
StartSpan(
"updateItemConnectivity",
"" );
791 PROF_TIMER update_items(
"updateItemConnectivity" );
794 std::set<SCH_ITEM*> dirty_items;
796 int count = aSheetList.size() * 2;
801 if( aProgressReporter )
807 std::vector<SCH_ITEM*> items;
810 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
812 for(
SCH_ITEM* item : sheet.LastScreen()->Items() )
814 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
816 wxLogTrace(
ConnTrace, wxT(
"Adding item %s to connectivity graph update" ),
817 item->GetTypeDesc() );
818 items.push_back( item );
819 dirty_items.insert( item );
828 if(
pin->IsConnectivityDirty() )
830 dirty_items.insert(
pin );
843 if(
pin->IsConnectivityDirty() )
845 items.push_back(
pin );
846 dirty_items.insert(
pin );
856 if(
pin->IsConnectivityDirty() )
858 items.push_back(
pin );
859 dirty_items.insert(
pin );
872 if( symbol->
GetUnit() != new_unit )
873 symbolsChanged.push_back( { symbol, symbol->
GetUnit() } );
883 if( aProgressReporter )
890 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
893 for(
const auto& [ symbol, originalUnit ] : symbolsChanged )
894 symbol->SetUnit( originalUnit );
905 item->SetConnectivityDirty(
false );
912 PROF_TIMER build_graph(
"buildConnectionGraph" );
913 monitorTrans.
StartSpan(
"BuildConnectionGraph",
"" );
932 const std::set<SCH_ITEM*> &aItems )
934 std::set<std::pair<SCH_SHEET_PATH, SCH_ITEM*>> retvals;
935 std::set<CONNECTION_SUBGRAPH*> subgraphs;
940 while( aSubgraph->m_absorbed_by )
943 wxASSERT( aSubgraph->m_graph == aSubgraph->m_absorbed_by->m_graph );
944 aSubgraph = aSubgraph->m_absorbed_by;
948 while( aSubgraph->m_hier_parent )
951 wxASSERT( aSubgraph->m_graph == aSubgraph->m_hier_parent->m_graph );
952 aSubgraph = aSubgraph->m_hier_parent;
956 aSubgraph->getAllConnectedItems( retvals, subgraphs );
959 auto extract_element = [&](
SCH_ITEM* aItem )
965 wxLogTrace(
ConnTrace, wxT(
"Item %s not found in connection graph" ),
966 aItem->GetTypeDesc() );
972 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld (%p) has no driver" ),
973 aItem->GetTypeDesc(), item_sg->
m_code, item_sg );
978 if( sg_to_scan.empty() )
980 wxLogTrace(
ConnTrace, wxT(
"Item %s in subgraph %ld with net %s has no neighbors" ),
982 sg_to_scan.push_back( item_sg );
986 wxT(
"Removing all item %s connections from subgraph %ld with net %s: Found "
993 traverse_subgraph( sg );
995 for(
auto& bus_it : sg->m_bus_neighbors )
998 traverse_subgraph( bus_sg );
1001 for(
auto& bus_it : sg->m_bus_parents )
1004 traverse_subgraph( bus_sg );
1018 extract_element(
pin );
1025 extract_element(
pin );
1029 extract_element( item );
1035 for(
const auto& [
path, item] : retvals )
1062 wxLogTrace(
ConnTrace, wxT(
"Removing %zu subgraphs" ), aSubgraphs.size() );
1065 std::set<int> codes_to_remove;
1069 std::sort( el.second.begin(), el.second.end() );
1074 for(
auto& it : sg->m_bus_neighbors )
1080 for(
auto test = parents.begin();
test != parents.end(); )
1088 if( parents.empty() )
1093 for(
auto& it : sg->m_bus_parents )
1099 for(
auto test = neighbors.begin();
test != neighbors.end(); )
1107 if( neighbors.empty() )
1128 auto it = std::lower_bound( el.second.begin(), el.second.end(), sg );
1130 while( it != el.second.end() && *it == sg )
1131 it = el.second.erase( it );
1134 auto remove_sg = [sg](
auto it ) ->
bool
1147 if( remove_sg( it ) )
1155 if( remove_sg( it ) )
1164 if( remove_sg( it ) )
1166 codes_to_remove.insert( it->first.Netcode );
1178 if( remove_sg( it ) )
1186 if( it->second == sg )
1197 if( codes_to_remove.contains( it->second ) )
1205 if( codes_to_remove.contains( it->second ) )
1214 sg->m_graph =
nullptr;
1221 std::map<
VECTOR2I, std::vector<SCH_ITEM*>>& aConnectionMap )
1232 aConn->SetName(
name );
1237 std::map<wxString, std::vector<SCH_PIN*>> pinNumberMap;
1243 updatePin(
pin, conn );
1244 aConnectionMap[
pin->GetPosition() ].push_back(
pin );
1245 pinNumberMap[
pin->GetNumber()].emplace_back(
pin );
1248 auto linkPinsInVec =
1249 [&](
const std::vector<SCH_PIN*>& aVec )
1251 for(
size_t i = 0; i < aVec.size(); ++i )
1253 for(
size_t j = i + 1; j < aVec.size(); ++j )
1255 aVec[i]->AddConnectionTo( aSheet, aVec[j] );
1256 aVec[j]->AddConnectionTo( aSheet, aVec[i] );
1265 for(
const auto& [number,
group] : pinNumberMap )
1266 linkPinsInVec(
group );
1271 std::vector<SCH_PIN*> pins;
1273 for(
const wxString& pinNumber :
group )
1276 pins.emplace_back(
pin );
1279 linkPinsInVec( pins );
1302 std::map<
VECTOR2I, std::vector<SCH_ITEM*>>& aConnectionMap )
1307 m_items.emplace_back( aItem );
1310 switch( aItem->
Type() )
1323 if( points.empty() )
1324 points = {
static_cast<SCH_PIN*
>( aItem )->GetPosition() };
1337 for(
const VECTOR2I& point : points )
1338 aConnectionMap[point].push_back( aItem );
1343 const std::vector<SCH_ITEM*>& aItemList )
1345 wxLogTrace( wxT(
"Updating connectivity for sheet %s with %zu items" ),
1347 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
1351 std::vector<VECTOR2I> points = item->GetConnectionPoints();
1352 item->ClearConnectedItems( aSheet );
1358 pin->InitializeConnection( aSheet,
this );
1360 pin->ClearConnectedItems( aSheet );
1362 connection_map[
pin->GetTextPos() ].push_back(
pin );
1379 VECTOR2I point = item->GetPosition();
1382 std::vector<SCH_ITEM*> overlapping_items;
1384 std::copy_if( items.begin(), items.end(), std::back_inserter( overlapping_items ),
1387 return test_item->Type() == SCH_LINE_T
1388 && test_item->HitTest( point, -1 );
1393 if( overlapping_items.size() < 2 )
continue;
1395 for(
SCH_ITEM* test_item : overlapping_items )
1396 connection_map[point].push_back( test_item );
1405 VECTOR2I point = item->GetPosition();
1409 connection_map[point].push_back( wire );
1414 for(
auto& [point, connection_vec] : connection_map )
1416 std::sort( connection_vec.begin(), connection_vec.end() );
1422 for(
SCH_ITEM* connected_item : connection_vec )
1436 if( connection_vec.size() == 1 )
1452 if( point == bus_entry->GetPosition() )
1455 bus_entry->m_connected_bus_items[1] = busLine;
1468 for(
SCH_ITEM* test_item : connection_vec )
1470 bool bus_connection_ok =
true;
1472 if( test_item == connected_item )
1478 if( test_item->GetLayer() ==
LAYER_BUS )
1497 if( connected_item->ConnectionPropagatesTo( test_item )
1498 && test_item->ConnectionPropagatesTo( connected_item )
1499 && bus_connection_ok )
1501 connected_item->AddConnectionTo( aSheet, test_item );
1512 if( !bus_entry->m_connected_bus_item )
1518 bus_entry->m_connected_bus_item = bus;
1529 wxCHECK_RET(
m_schematic, wxS(
"Connection graph cannot be built without schematic pointer" ) );
1533 for(
const std::shared_ptr<BUS_ALIAS>& alias :
m_schematic->GetAllBusAliases() )
1542 for(
const auto& [sheet, connection] : item->m_connection_map )
1544 if( connection->SubgraphCode() == 0 )
1553 connection->SetSubgraphCode( subgraph->
m_code );
1556 std::list<SCH_ITEM*> memberlist;
1561 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet,
this );
1567 return ( unique && conn && ( conn->
SubgraphCode() == 0 ) );
1570 std::copy_if( item->ConnectedItems( sheet ).begin(),
1571 item->ConnectedItems( sheet ).end(),
1572 std::back_inserter( memberlist ), get_items );
1574 for(
SCH_ITEM* connected_item : memberlist )
1579 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
1581 wxCHECK2( connected_conn,
continue );
1587 subgraph->
AddItem( connected_item );
1588 const SCH_ITEM_VEC& citemset = connected_item->ConnectedItems( sheet );
1595 if( get_items( citem ) )
1596 memberlist.push_back( citem );
1601 for(
SCH_ITEM* connected_item : memberlist )
1615 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
1620 return candidate->m_dirty;
1623 wxLogTrace(
ConnTrace, wxT(
"Resolving drivers for %zu subgraphs" ), dirty_graphs.size() );
1625 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
1627 auto update_lambda =
1630 if( !subgraph->m_dirty )
1634 for(
SCH_ITEM* item : subgraph->m_items )
1636 switch( item->
Type() )
1639 subgraph->m_no_connect = item;
1643 subgraph->m_bus_entry = item;
1651 subgraph->m_no_connect = item;
1661 subgraph->ResolveDrivers(
true );
1662 subgraph->m_dirty =
false;
1669 auto results =
tp.submit_loop( 0, dirty_graphs.size(),
1672 update_lambda( dirty_graphs[ii] );
1681 return candidate->m_driver;
1694 wxString full_name = subgraph->m_driver_connection->Name();
1695 wxString
name = subgraph->m_driver_connection->Name(
true );
1704 wxString prefixOnly = full_name.BeforeFirst(
'[' ) + wxT(
"[]" );
1708 subgraph->m_dirty =
true;
1710 if( subgraph->m_strong_driver )
1712 SCH_ITEM* driver = subgraph->m_driver;
1715 switch( driver->
Type() )
1731 if(
pin->IsGlobalPower() )
1735 else if(
pin->IsLocalPower() )
1742 wxLogTrace(
ConnTrace, wxS(
"Unexpected normal pin %s" ),
1752 wxLogTrace(
ConnTrace, wxS(
"Unexpected strong driver %s" ),
1764 std::vector<CONNECTION_SUBGRAPH*> new_subgraphs;
1775 dummy.SetGraph(
this );
1778 wxLogTrace(
ConnTrace, wxS(
"new bus label (%s)" ),
1781 for(
const auto& conn :
dummy.Members() )
1784 if( !conn->IsNet() )
1787 wxString
name = conn->FullLocalName();
1794 auto new_conn = std::make_unique<SCH_CONNECTION>( item, subgraph->m_sheet );
1795 new_conn->SetGraph(
this );
1796 new_conn->SetName(
name );
1799 SCH_CONNECTION* new_conn_ptr = subgraph->StoreImplicitConnection( std::move( new_conn ) );
1802 wxLogTrace(
ConnTrace, wxS(
"SG(%ld), Adding full local name (%s) with sg (%d) on subsheet %s" ),
1803 subgraph->m_code,
name, code, subgraph->m_sheet.PathHumanReadable() );
1816 new_subgraphs.push_back( new_sg );
1821 std::copy( new_subgraphs.begin(), new_subgraphs.end(),
1837 [](
const std::pair<SCH_SHEET_PATH, SCH_PIN*>& a,
1838 const std::pair<SCH_SHEET_PATH, SCH_PIN*>& b )
1840 int pathCmp = a.first.Cmp( b.first );
1845 const SCH_SYMBOL* symA = static_cast<const SCH_SYMBOL*>( a.second->GetParentSymbol() );
1846 const SCH_SYMBOL* symB = static_cast<const SCH_SYMBOL*>( b.second->GetParentSymbol() );
1848 wxString refA = symA ? symA->GetRef( &a.first, false ) : wxString();
1849 wxString refB = symB ? symB->GetRef( &b.first, false ) : wxString();
1851 int refCmp = refA.Cmp( refB );
1856 return a.second->GetNumber().Cmp( b.second->GetNumber() ) < 0;
1859 std::unordered_map<int, CONNECTION_SUBGRAPH*> global_power_pin_subgraphs;
1863 SYMBOL* libParent =
pin->GetLibPin() ?
pin->GetLibPin()->GetParentSymbol() :
nullptr;
1865 if( !
pin->ConnectedItems( sheet ).empty()
1882 connection->
SetName(
pin->GetParentSymbol()->GetValue(
true, &sheet,
false ) );
1891 auto jj = global_power_pin_subgraphs.find( code );
1893 if( jj != global_power_pin_subgraphs.end() )
1895 subgraph = jj->second;
1913 global_power_pin_subgraphs[code] = subgraph;
1930 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1934 if( subgraph->m_absorbed )
1939 wxString
name = connection->
Name();
1942 unsigned suffix = 1;
1944 auto create_new_name =
1948 wxString suffixStr = std::to_wstring( suffix );
1955 wxString prefix = aConn->BusPrefix();
1957 if( prefix.empty() )
1958 prefix = wxT(
"BUS" );
1963 wxString members = aConn->Name().Mid( aConn->BusPrefix().length() );
1965 newName << prefix << wxT(
"_" ) << suffixStr << members;
1967 aConn->ConfigureFromLabel( newName );
1971 newName << aConn->Name() << wxT(
"_" ) << suffixStr;
1972 aConn->SetSuffix( wxString( wxT(
"_" ) ) << suffixStr );
1979 if( !subgraph->m_strong_driver )
1981 std::vector<CONNECTION_SUBGRAPH*> vec_empty;
1982 std::vector<CONNECTION_SUBGRAPH*>* vec = &vec_empty;
1991 wxString prefixOnly =
name.BeforeFirst(
'[' ) + wxT(
"[]" );
1997 if( vec->size() > 1 )
1999 wxString new_name = create_new_name( connection );
2002 new_name = create_new_name( connection );
2004 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) is weakly driven and not unique. Changing to %s." ),
2005 subgraph->m_code,
name, new_name );
2007 std::erase( *vec, subgraph );
2013 else if( subgraph->m_driver )
2025 bool conflict =
false;
2026 wxString global_name = connection->
Name(
true );
2033 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
2037 if( candidate->m_sheet == sheet )
2044 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) skipped for promotion due to potential conflict" ),
2045 subgraph->m_code,
name );
2051 wxLogTrace(
ConnTrace, wxS(
"%ld (%s) weakly driven by unique sheet pin %s, promoting" ),
2052 subgraph->m_code,
name,
2053 subgraph->m_driver->GetItemDescription( &unitsProvider,
true ) );
2055 subgraph->m_strong_driver =
true;
2062 if( connection->
IsBus() )
2086 subgraph->m_dirty =
true;
2094 if( !subgraph->m_strong_driver )
2101 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
2104 std::back_inserter( candidate_subgraphs ),
2107 return ( !candidate->m_absorbed &&
2108 candidate->m_strong_driver &&
2109 candidate != subgraph );
2115 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
2118 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
2120 auto add_connections_to_check =
2123 for(
SCH_ITEM* possible_driver : aSubgraph->m_items )
2125 if( possible_driver == aSubgraph->m_driver )
2132 if( c->Type() != aSubgraph->m_driver_connection->Type() )
2135 if( c->Name(
true ) == aSubgraph->m_driver_connection->Name(
true ) )
2138 connections_to_check.push_back( c );
2139 wxLogTrace(
ConnTrace, wxS(
"%lu (%s): Adding secondary driver %s" ),
2141 aSubgraph->m_driver_connection->Name(
true ),
2150 add_connections_to_check( subgraph );
2152 std::set<SCH_CONNECTION*> checked_connections;
2154 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2156 auto member = connections_to_check[i];
2159 if( !checked_connections.insert( member.get() ).second )
2162 if( member->IsBus() )
2164 connections_to_check.insert( connections_to_check.end(),
2165 member->Members().begin(),
2166 member->Members().end() );
2169 wxString test_name = member->Name(
true );
2173 if( candidate->
m_absorbed || candidate == subgraph )
2189 if( driver == candidate->
m_driver )
2201 &&
pin->GetDefaultNetName( sheet ) == test_name )
2214 if( subgraph->GetNameForDriver( driver ) == test_name )
2227 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has bus child %lu (%s)" ),
2228 subgraph->m_code, connection->
Name(),
2229 candidate->
m_code, member->Name() );
2231 subgraph->m_bus_neighbors[member].insert( candidate );
2234 else if( ( !connection->
IsBus()
2238 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) absorbs neighbor %lu (%s)" ),
2239 subgraph->m_code, connection->
Name(),
2243 add_connections_to_check( candidate );
2245 subgraph->Absorb( candidate );
2246 invalidated_subgraphs.insert( subgraph );
2256 if( subgraph->m_absorbed )
2259 if( !subgraph->ResolveDrivers() )
2262 if( subgraph->m_driver_connection->IsBus() )
2267 wxLogTrace(
ConnTrace, wxS(
"Re-resolving drivers for %lu (%s)" ),
2268 subgraph->m_code, subgraph->m_driver_connection->Name() );
2287 bool aUnconditional )
2290 wxCHECK_RET(
m_schematic, wxT(
"Connection graph cannot be built without schematic pointer" ) );
2294 for(
const std::shared_ptr<BUS_ALIAS>& alias :
m_schematic->GetAllBusAliases() )
2300 PROF_TIMER sub_graph(
"buildItemSubGraphs" );
2319 PROF_TIMER proc_sub_graph(
"ProcessSubGraphs" );
2323 proc_sub_graph.
Show();
2332 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
2334 std::back_inserter( global_subgraphs ),
2337 return !candidate->m_local_driver;
2351 m_driver_subgraphs[ii]->UpdateItemConnections();
2373 if( !global_subgraphs.empty() )
2375 std::unordered_map<CONNECTION_SUBGRAPH*, CONNECTION_SUBGRAPH*> sg_root;
2384 auto it = sg_root.find( cur );
2386 if( it == sg_root.end() || it->second == cur )
2391 auto parent_it = sg_root.find( it->second );
2393 if( parent_it != sg_root.end() && parent_it->second != it->second )
2394 it->second = parent_it->second;
2404 auto prefer_as_representative =
2409 aB->m_driver, aB->m_driver_connection,
2410 aB->m_driver_connection->Name() ) < 0;
2416 sg_root.try_emplace( aA, aA );
2417 sg_root.try_emplace( aB, aB );
2422 if( root_a == root_b )
2425 if( prefer_as_representative( root_a, root_b ) )
2426 sg_root[root_b] = root_a;
2428 sg_root[root_a] = root_b;
2431 std::unordered_map<wxString, std::vector<CONNECTION_SUBGRAPH*>> name_to_sgs;
2435 for(
SCH_ITEM* driver : subgraph->m_drivers )
2443 name_to_sgs[subgraph->GetNameForDriver( driver )].push_back( subgraph );
2447 for(
auto& [
name, sgs] : name_to_sgs )
2449 if( sgs.size() < 2 )
2452 for(
size_t ii = 1; ii < sgs.size(); ++ii )
2453 union_sgs( sgs[0], sgs[ii] );
2459 for(
const auto& entry : sg_root )
2470 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) canonicalized to %lu (%s)" ),
2483 if( !subgraph->m_dirty )
2486 wxLogTrace(
ConnTrace, wxS(
"Processing %lu (%s) for propagation" ),
2487 subgraph->m_code, subgraph->m_driver_connection->Name() );
2493 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
2495 for(
SCH_ITEM* driver : subgraph->m_drivers )
2497 if( driver == subgraph->m_driver )
2500 const wxString& secondary_name = subgraph->GetNameForDriver( driver );
2502 if( secondary_name == subgraph->m_driver_connection->Name() )
2510 if( candidate == subgraph )
2513 if( !secondary_is_global && candidate->
m_sheet != subgraph->m_sheet )
2520 wxLogTrace(
ConnTrace, wxS(
"Global %lu (%s) promoted to %s" ),
2522 subgraph->m_driver_connection->Name() );
2544 if( subgraph->m_dirty )
2561 wxASSERT_MSG( !subgraph->m_dirty,
2562 wxS(
"Subgraph not processed by propagateToNeighbors!" ) );
2564 if( subgraph->m_bus_parents.size() < 2 )
2569 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has multiple bus parents" ),
2570 subgraph->m_code, conn->
Name() );
2573 wxCHECK2( conn->
IsNet(),
continue );
2575 for(
const auto& ii : subgraph->m_bus_parents )
2588 wxLogTrace(
ConnTrace, wxS(
"Warning: could not match %s inside %lu (%s)" ),
2593 if( conn->
Name() != match->
Name() )
2595 wxString old_name = match->
Name();
2597 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ),
2600 match->
Clone( *conn );
2608 std::vector<CONNECTION_SUBGRAPH*> old_subgraphs = jj->second;
2612 while( old_sg->m_absorbed )
2613 old_sg = old_sg->m_absorbed_by;
2615 wxString old_sg_name = old_sg->m_driver_connection->Name();
2616 old_sg->m_driver_connection->Clone( *conn );
2618 if( old_sg_name != old_sg->m_driver_connection->Name() )
2626 auto updateItemConnectionsTask =
2630 if( !subgraph->m_strong_driver
2631 && subgraph->m_drivers.size() == 1
2632 && subgraph->m_driver->Type() ==
SCH_PIN_T )
2635 wxString
name =
pin->GetDefaultNetName( subgraph->m_sheet,
true );
2637 subgraph->m_driver_connection->ConfigureFromLabel(
name );
2640 subgraph->m_dirty =
false;
2641 subgraph->UpdateItemConnections();
2644 if( subgraph->m_driver_connection->IsBus() )
2649 if( subgraph->m_driver && subgraph->m_driver->Type() ==
SCH_SHEET_PIN_T )
2655 wxString pinText =
pin->GetShownText(
false );
2662 if( label->
GetShownText( &subgraph->m_sheet,
false ) == pinText )
2665 path.push_back( sheet );
2669 if( parent_conn && parent_conn->
IsBus() )
2676 if( subgraph->m_driver_connection->IsBus() )
2687 updateItemConnectionsTask( m_driver_subgraphs[ii] );
2697 subgraph->m_driver_connection->NetCode() };
2703 std::shared_ptr<NET_SETTINGS>& netSettings =
m_schematic->Project().GetProjectFile().m_NetSettings;
2704 std::map<wxString, std::set<wxString>> oldAssignments = netSettings->GetNetclassLabelAssignments();
2705 std::set<wxString> affectedNetclassNetAssignments;
2707 netSettings->ClearNetclassLabelAssignments();
2709 auto dirtySubgraphs =
2710 [&](
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2712 if( aChangedItemHandler )
2716 for(
SCH_ITEM* item : subgraph->m_items )
2717 (*aChangedItemHandler)( item );
2722 auto checkNetclassDrivers =
2723 [&](
const wxString& netName,
const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
2725 wxCHECK_RET( !subgraphs.empty(), wxS(
"Invalid empty subgraph" ) );
2727 std::set<wxString> netclasses;
2732 for(
SCH_ITEM* item : subgraph->m_items )
2734 for(
const auto& [
name, provider] : subgraph->GetNetclassesForDriver( item ) )
2735 netclasses.insert(
name );
2742 if( subgraph->m_driver_connection->IsBus() )
2744 auto processBusMember = [&,
this](
const SCH_CONNECTION* member )
2746 if( !netclasses.empty() )
2748 netSettings->AppendNetclassLabelAssignment( member->Name(), netclasses );
2753 if( oldAssignments.count( member->Name() ) )
2755 if( oldAssignments[member->Name()] != netclasses )
2757 affectedNetclassNetAssignments.insert( member->Name() );
2760 dirtySubgraphs( ii->second );
2763 else if( !netclasses.empty() )
2765 affectedNetclassNetAssignments.insert( member->Name() );
2768 dirtySubgraphs( ii->second );
2772 for(
const std::shared_ptr<SCH_CONNECTION>& member : subgraph->m_driver_connection->Members() )
2776 if( member->IsBus() )
2778 for(
const std::shared_ptr<SCH_CONNECTION>& nestedMember : member->Members() )
2779 processBusMember( nestedMember.get() );
2783 processBusMember( member.get() );
2790 if( !netclasses.empty() )
2792 netSettings->AppendNetclassLabelAssignment( netName, netclasses );
2795 if( oldAssignments.count( netName ) )
2797 if( oldAssignments[netName] != netclasses )
2799 affectedNetclassNetAssignments.insert( netName );
2800 dirtySubgraphs( subgraphs );
2803 else if( !netclasses.empty() )
2805 affectedNetclassNetAssignments.insert( netName );
2806 dirtySubgraphs( subgraphs );
2812 checkNetclassDrivers( netname, subgraphs );
2814 if( !aUnconditional )
2816 for(
auto& [netname, netclasses] : oldAssignments )
2818 if( netSettings->GetNetclassLabelAssignments().count( netname )
2819 || affectedNetclassNetAssignments.count( netname ) )
2824 netSettings->SetNetclassLabelAssignment( netname, netclasses );
2862 std::vector<std::shared_ptr<SCH_CONNECTION>> connections_to_check( aConnection->
Members() );
2864 for(
unsigned i = 0; i < connections_to_check.size(); i++ )
2866 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
2868 if( member->IsBus() )
2870 connections_to_check.insert( connections_to_check.end(),
2871 member->Members().begin(),
2872 member->Members().end() );
2884 std::vector<CONNECTION_SUBGRAPH*> search_list;
2885 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
2886 std::unordered_set<SCH_CONNECTION*> stale_bus_members;
2893 path.push_back(
pin->GetParent() );
2904 || visited.contains( candidate ) )
2913 wxLogTrace(
ConnTrace, wxS(
"%lu: found child %lu (%s)" ), aParent->m_code,
2921 wxASSERT( candidate->
m_graph == aParent->m_graph );
2923 search_list.push_back( candidate );
2943 || visited.contains( candidate )
2949 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
2954 if(
pin->GetParent()->m_Uuid != last_parent_uuid )
2960 if( pin_path != aParent->m_sheet )
2965 wxLogTrace(
ConnTrace, wxS(
"%lu: found additional parent %lu (%s)" ),
2968 aParent->m_hier_children.insert( candidate );
2969 search_list.push_back( candidate );
2983 std::vector<std::shared_ptr<SCH_CONNECTION>> sortedMembers;
2985 for(
const auto&
kv : aParentGraph->m_bus_neighbors )
2986 sortedMembers.push_back(
kv.first );
2988 std::sort( sortedMembers.begin(), sortedMembers.end(),
2989 [](
const std::shared_ptr<SCH_CONNECTION>& a,
2990 const std::shared_ptr<SCH_CONNECTION>& b )
2992 return a->Name() < b->Name();
2995 for(
const std::shared_ptr<SCH_CONNECTION>& member_conn : sortedMembers )
2997 const auto& kv_it = aParentGraph->m_bus_neighbors.find( member_conn );
2999 if( kv_it == aParentGraph->m_bus_neighbors.end() )
3042 wxLogTrace(
ConnTrace, wxS(
"Could not match bus member %s in %s" ),
3043 member_conn->Name(), parent->
Name() );
3049 wxCHECK2( neighbor_conn,
continue );
3051 wxString neighbor_name = neighbor_conn->
Name();
3054 if( neighbor_name == member->
Name() )
3064 if( neighbor_conn->
Sheet() != parent->
Sheet() )
3075 bool alreadyUpdatedByBusMember =
false;
3077 for(
const auto& m : parent->
Members() )
3079 if( m->Name() == neighbor_name )
3081 alreadyUpdatedByBusMember =
true;
3086 if( alreadyUpdatedByBusMember )
3091 wxCHECK2_MSG( neighbor_conn->
IsNet(),
continue,
3092 wxS(
"\"" ) + neighbor_name + wxS(
"\" is not a net." ) );
3094 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) connected to bus member %s (local %s)" ),
3101 member->
Clone( *neighbor_conn );
3102 stale_bus_members.insert( member );
3106 neighbor_conn->
Clone( *member );
3119 if( neighbor_conn->
Name() != member->
Name() )
3121 member->
Clone( *neighbor_conn );
3122 stale_bus_members.insert( member );
3131 propagate_bus_neighbors( aSubgraph );
3138 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has both hier ports and pins; deferring processing" ),
3144 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) has no hier pins or ports on sheet %s; marking clean" ),
3150 visited.insert( aSubgraph );
3152 wxLogTrace(
ConnTrace, wxS(
"Propagating %lu (%s) to subsheets" ),
3157 for(
unsigned i = 0; i < search_list.size(); i++ )
3159 auto child = search_list[i];
3161 if( visited.insert( child ).second )
3164 child->m_dirty =
false;
3178 if( subgraph == aSubgraph )
3185 wxString candidateName = subgraph->m_driver_connection->Name();
3186 bool shorterPath = subgraph->m_sheet.size() < bestDriver->
m_sheet.
size();
3187 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->
m_sheet.
size();
3197 ( !bestIsStrong && candidateStrong ) ||
3198 ( priority > highest && candidateStrong ) ||
3199 ( priority == highest && candidateStrong && shorterPath ) ||
3200 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
3201 ( candidateName < bestName ) ) )
3203 bestDriver = subgraph;
3205 bestIsStrong = candidateStrong;
3206 bestName = candidateName;
3211 if( bestDriver != aSubgraph )
3213 wxLogTrace(
ConnTrace, wxS(
"%lu (%s) overridden by new driver %lu (%s)" ),
3222 wxString old_name = subgraph->m_driver_connection->Name();
3224 subgraph->m_driver_connection->Clone( *conn );
3226 if( old_name != conn->
Name() )
3230 propagate_bus_neighbors( subgraph );
3236 if( conn->
IsBus() && !stale_bus_members.empty() )
3238 std::unordered_set<SCH_CONNECTION*> cached_members = stale_bus_members;
3248 wxLogTrace(
ConnTrace, wxS(
"WARNING: failed to match stale member %s in %s." ),
3249 stale_member->Name(), subgraph->m_driver_connection->Name() );
3253 wxLogTrace(
ConnTrace, wxS(
"Updating %lu (%s) member %s to %s" ), subgraph->m_code,
3254 subgraph->m_driver_connection->Name(), member->
LocalName(), stale_member->Name() );
3256 member->
Clone( *stale_member );
3258 propagate_bus_neighbors( subgraph );
3270 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>(
nullptr );
3272 switch( aItem->
Type() )
3275 if(
static_cast<SCH_PIN*
>( aItem )->IsPower() )
3276 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
3283 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->
m_sheet );
3292 c->SetGraph(
this );
3303 if( !aBusConnection->
IsBus() )
3313 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->
Members() )
3315 if( bus_member->VectorIndex() == aSearch->
VectorIndex() )
3317 match = bus_member.get();
3325 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
3332 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
3334 if( bus_member->LocalName() == aSearch->
LocalName() )
3336 match = bus_member.get();
3341 else if( c->LocalName() == aSearch->
LocalName() )
3352 for(
const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->
Members() )
3356 for(
const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
3360 match = bus_member.get();
3394 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
3395 std::erase( vec, aSubgraph );
3398 wxLogTrace(
ConnTrace, wxS(
"recacheSubgraphName: %s => %s" ), aOldName,
3415 std::vector<const CONNECTION_SUBGRAPH*> ret;
3421 wxASSERT( !subgraph->m_dirty );
3423 if( !subgraph->m_driver )
3429 if( !connection->
IsBus() )
3432 auto labels = subgraph->GetVectorBusLabels();
3434 if( labels.size() > 1 )
3436 bool different =
false;
3439 for(
unsigned i = 1; i < labels.size(); ++i )
3451 wxLogTrace(
ConnTrace, wxS(
"SG %ld (%s) has multiple bus labels" ), subgraph->m_code,
3452 connection->
Name() );
3454 ret.push_back( subgraph );
3475 if( graph == aSubGraph )
3518 wxASSERT( !it->second.empty() );
3520 return it->second[0];
3536const std::vector<CONNECTION_SUBGRAPH*>&
3539 static const std::vector<CONNECTION_SUBGRAPH*> subgraphs;
3552 int error_count = 0;
3554 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::RunERC" ) );
3560 std::set<SCH_ITEM*> seenDriverInstances;
3565 wxCHECK2( subgraph,
continue );
3569 wxASSERT( !subgraph->m_dirty );
3571 if( subgraph->m_absorbed )
3574 if( seenDriverInstances.count( subgraph->m_driver ) )
3577 if( subgraph->m_driver )
3578 seenDriverInstances.insert( subgraph->m_driver );
3596 subgraph->ResolveDrivers(
false );
3667 wxCHECK( aSubgraph,
false );
3673 if( driver == aSubgraph->
m_driver )
3684 if( primaryName == secondaryName )
3687 wxString msg = wxString::Format(
_(
"Both %s and %s are attached to the same "
3688 "items; %s will be used in the netlist" ),
3689 primaryName, secondaryName, primaryName );
3692 ercItem->SetItems( aSubgraph->
m_driver, driver );
3693 ercItem->SetSheetSpecificPath( aSubgraph->
GetSheet() );
3694 ercItem->SetItemsSheetPaths( aSubgraph->
GetSheet(), aSubgraph->
m_sheet );
3695 ercItem->SetErrorMessage( msg );
3720 switch( item->
Type() )
3725 bus_item = ( !bus_item ) ? item : bus_item;
3727 net_item = ( !net_item ) ? item : net_item;
3741 bus_item = ( !bus_item ) ? item : bus_item;
3743 net_item = ( !net_item ) ? item : net_item;
3753 if( net_item && bus_item )
3756 ercItem->SetSheetSpecificPath( sheet );
3757 ercItem->SetItems( net_item, bus_item );
3760 screen->
Append( marker );
3779 switch( item->
Type() )
3806 if(
test != member && member->Name() ==
test->Name() )
3820 ercItem->SetSheetSpecificPath( sheet );
3821 ercItem->SetItems( label, port );
3824 screen->
Append( marker );
3836 bool conflict =
false;
3852 switch( item->
Type() )
3882 std::set<wxString> test_names;
3894 for(
const auto& sub_member : member->Members() )
3896 if( test_names.count( sub_member->FullLocalName() ) )
3900 else if( test_names.count( member->FullLocalName() ) )
3919 wxString msg = wxString::Format(
_(
"Net %s is graphically connected to bus %s but is not a"
3920 " member of that bus" ),
3924 ercItem->SetSheetSpecificPath( sheet );
3925 ercItem->SetItems( bus_entry, bus_wire );
3926 ercItem->SetErrorMessage( msg );
3929 screen->
Append( marker );
3946 std::set<SCH_PIN*> unique_pins;
3947 std::set<SCH_LABEL_BASE*> unique_labels;
3955 for(
SCH_ITEM* item : aProcessGraph->m_items )
3957 switch( item->
Type() )
3964 if( aProcessGraph == aSubgraph )
3967 if( std::none_of( unique_pins.begin(), unique_pins.end(),
3970 return test_pin->IsStacked( aPin );
3974 unique_pins.insert( test_pin );
3997 process_subgraph( subgraph );
4002 process_subgraph( aSubgraph );
4037 ercItem->SetSheetSpecificPath( sheet );
4038 ercItem->SetItemsSheetPaths( sheet );
4045 pos =
pin->GetPosition();
4054 screen->
Append( marker );
4059 if( unique_pins.empty() && unique_labels.empty() &&
4064 ercItem->SetSheetSpecificPath( sheet );
4065 ercItem->SetItemsSheetPaths( sheet );
4068 screen->
Append( marker );
4075 bool has_other_connections =
false;
4076 std::vector<SCH_PIN*> pins;
4083 switch( item->
Type() )
4090 if( !has_other_connections && !pins.empty()
4093 for(
SCH_PIN* other_pin : pins )
4097 has_other_connections =
true;
4103 pins.emplace_back(
static_cast<SCH_PIN*
>( item ) );
4110 has_other_connections =
true;
4117 pin = pins.empty() ? nullptr : pins[0];
4120 for(
SCH_PIN* test_pin : pins )
4137 ?
pin->GetLibPin()->GetParentSymbol() :
nullptr;
4139 if(
pin && !has_other_connections
4141 && ( !pinLibParent || !pinLibParent->
IsPower() ) )
4143 wxString
name =
pin->Connection( &sheet )->Name();
4144 wxString local_name =
pin->Connection( &sheet )->Name(
true );
4149 has_other_connections =
true;
4154 if(
pin && !has_other_connections
4160 ercItem->SetSheetSpecificPath( sheet );
4161 ercItem->SetItemsSheetPaths( sheet );
4162 ercItem->SetItems(
pin );
4165 screen->
Append( marker );
4173 if( pins.size() > 1 )
4175 for(
SCH_PIN* testPin : pins )
4180 SYMBOL* testLibParent = testPin->GetLibPin()
4184 if( testLibParent && testLibParent->
IsPower()
4185 && testPin->ConnectedItems( sheet ).empty()
4189 ercItem->SetSheetSpecificPath( sheet );
4190 ercItem->SetItemsSheetPaths( sheet );
4191 ercItem->SetItems( testPin );
4194 screen->
Append( marker );
4227 ercItem->SetItems( line );
4228 ercItem->SetSheetSpecificPath( sheet );
4229 ercItem->SetErrorMessage(
_(
"Unconnected wire endpoint" ) );
4251 ercItem->SetItems( entry );
4252 ercItem->SetSheetSpecificPath( sheet );
4253 ercItem->SetErrorMessage(
_(
"Unconnected wire to bus entry" ) );
4270 return err_count > 0;
4280 std::vector<SCH_ITEM*> wires;
4287 wires.emplace_back( item );
4289 wires.emplace_back( item );
4292 if( !wires.empty() )
4297 ercItem->SetSheetSpecificPath( sheet );
4298 ercItem->SetItems( wires[0],
4299 wires.size() > 1 ? wires[1] :
nullptr,
4300 wires.size() > 2 ? wires[2] :
nullptr,
4301 wires.size() > 3 ? wires[3] :
nullptr );
4304 screen->
Append( marker );
4332 size_t pinCount = 0;
4335 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
4341 return std::count_if( aLocSubgraph->m_items.begin(), aLocSubgraph->m_items.end(),
4344 return item->Type() == SCH_PIN_T;
4349 [&](
SCH_TEXT* aText,
int errCode )
4354 ercItem->SetSheetSpecificPath( sheet );
4355 ercItem->SetItems( aText );
4362 pinCount =
hasPins( aSubgraph );
4366 switch( item->
Type() )
4374 label_map[item->
Type()].push_back(
text );
4379 if(
text->IsDangling() )
4393 if( label_map.empty() )
4398 for(
auto& [ connection, subgraphs ] : aSubgraph->
m_bus_parents )
4402 if( busParent->m_no_connect )
4425 wxCHECK_MSG(
m_schematic,
true, wxS(
"Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" ) );
4432 for(
auto& [type, label_vec] : label_map )
4436 size_t allPins = pinCount;
4437 size_t localPins = pinCount;
4438 bool hasLocalHierarchy =
false;
4446 std::set<wxString> uniquePortNames;
4450 if( aSubgraph->
m_hier_pins.size() + uniquePortNames.size() > 1 )
4452 hasLocalHierarchy =
true;
4457 for(
auto& [connection, busParents] : aSubgraph->
m_bus_parents )
4461 if( busParent->m_sheet == sheet
4462 && ( !busParent->m_hier_pins.empty()
4463 || !busParent->m_hier_ports.empty() ) )
4465 hasLocalHierarchy =
true;
4470 if( hasLocalHierarchy )
4481 if( neighbor == aSubgraph )
4487 size_t neighborPins =
hasPins( neighbor );
4488 allPins += neighborPins;
4490 if( neighbor->
m_sheet == sheet )
4492 localPins += neighborPins;
4497 hasLocalHierarchy =
true;
4503 if( allPins == 1 && !has_nc )
4514 || ( type ==
SCH_LABEL_T && localPins == 0 && allPins > 1
4515 && !has_nc && !hasLocalHierarchy ) )
4531 std::map<wxString, std::tuple<int, const SCH_ITEM*, SCH_SHEET_PATH>> labelData;
4538 wxString resolvedLabelText =
4541 if( labelData.find( resolvedLabelText ) == labelData.end() )
4543 labelData[resolvedLabelText] = { 1, item, sheet };
4547 std::get<0>( labelData[resolvedLabelText] ) += 1;
4548 std::get<1>( labelData[resolvedLabelText] ) =
nullptr;
4549 std::get<2>( labelData[resolvedLabelText] ) = sheet;
4554 for(
const auto& label : labelData )
4556 if( std::get<0>( label.second ) == 1 )
4559 const SCH_ITEM* item = std::get<1>( label.second );
4562 ercItem->SetItems( std::get<1>( label.second ) );
4563 ercItem->SetSheetSpecificPath( sheet );
4564 ercItem->SetItemsSheetPaths( sheet );
4579 int error_count = 0;
4591 ercItem->SetSheetSpecificPath( sheet );
4592 ercItem->SetItems(
text );
4595 sheet.LastScreen()->Append( marker );
4615 if( sheet.Last()->IsTopLevelSheet() )
4621 wxCHECK2( label,
continue );
4623 msg.Printf(
_(
"Hierarchical label '%s' in root sheet cannot be connected to non-existent "
4627 ercItem->SetItems( item );
4628 ercItem->SetErrorMessage( msg );
4631 sheet.LastScreen()->Append( marker );
4642 parentSheetPath.
push_back( parentSheet );
4644 std::map<wxString, SCH_SHEET_PIN*> pins;
4645 std::map<wxString, SCH_HIERLABEL*> labels;
4650 pins[
pin->GetShownText( &parentSheetPath,
false ) ] =
pin;
4655 ercItem->SetItems(
pin );
4656 ercItem->SetSheetSpecificPath( sheet );
4657 ercItem->SetItemsSheetPaths( sheet );
4660 sheet.LastScreen()->Append( marker );
4668 std::set<wxString> matchedPins;
4675 wxString labelText = label->
GetShownText( &parentSheetPath,
false );
4677 if( !pins.contains( labelText ) )
4678 labels[ labelText ] = label;
4680 matchedPins.insert( labelText );
4684 for(
const wxString& matched : matchedPins )
4685 pins.erase( matched );
4687 for(
const auto& [
name,
pin] : pins )
4689 msg.Printf(
_(
"Sheet pin %s has no matching hierarchical label inside the sheet" ),
4693 ercItem->SetItems(
pin );
4694 ercItem->SetErrorMessage( msg );
4695 ercItem->SetSheetSpecificPath( sheet );
4696 ercItem->SetItemsSheetPaths( sheet );
4699 sheet.LastScreen()->Append( marker );
4704 for(
const auto& [
name, label] : labels )
4706 msg.Printf(
_(
"Hierarchical label %s has no matching sheet pin in the parent sheet" ),
4710 ercItem->SetItems( label );
4711 ercItem->SetErrorMessage( msg );
4712 ercItem->SetSheetSpecificPath( parentSheetPath );
4713 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)
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.
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::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.
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.
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 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
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.
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 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.
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.
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
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
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
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()
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()
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 ...
#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.
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:...
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< int32_t > VECTOR2I