KiCad PCB EDA Suite
CONNECTION_GRAPH Class Reference

Calculates the connectivity of a schematic and generates netlists. More...

#include <connection_graph.h>

Public Member Functions

 CONNECTION_GRAPH (SCHEMATIC *aSchematic=nullptr)
 
 ~CONNECTION_GRAPH ()
 
void Reset ()
 
void SetSchematic (SCHEMATIC *aSchematic)
 
void Recalculate (const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr)
 Updates the connection graph for the given list of sheets. More...
 
std::shared_ptr< BUS_ALIASGetBusAlias (const wxString &aName)
 Returns a bus alias pointer for the given name if it exists (from cache) More...
 
std::vector< const CONNECTION_SUBGRAPH * > GetBusesNeedingMigration ()
 Determines which subgraphs have more than one conflicting bus label. More...
 
int RunERC ()
 Runs electrical rule checks on the connectivity graph. More...
 
const NET_MAPGetNetMap () const
 
CONNECTION_SUBGRAPHFindSubgraphByName (const wxString &aNetName, const SCH_SHEET_PATH &aPath)
 Returns the subgraph for a given net name on a given sheet. More...
 
CONNECTION_SUBGRAPHFindFirstSubgraphByName (const wxString &aNetName)
 Retrieves a subgraph for the given net name, if one exists. More...
 
CONNECTION_SUBGRAPHGetSubgraphForItem (SCH_ITEM *aItem)
 

Static Public Attributes

static bool m_allowRealTime = true
 

Private Member Functions

void updateItemConnectivity (const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
 Updates the graphical connectivity between items (i.e. More...
 
void buildConnectionGraph (std::function< void(SCH_ITEM *)> *aChangedItemHandler)
 Generates the connection graph (after all item connectivity has been updated) More...
 
void buildItemSubGraphs ()
 Generates individual item subgraphs on a per-sheet basis. More...
 
void resolveAllDrivers ()
 Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel. More...
 
void collectAllDriverValues ()
 Maps the driver values for each subgraph. More...
 
void generateInvisiblePinSubGraphs ()
 Iterate through the invisible power pins to collect the global labels as drivers. More...
 
void processSubGraphs ()
 Process all subgraphs to assign netcodes and merge subgraphs based on labels. More...
 
int assignNewNetCode (SCH_CONNECTION &aConnection)
 Helper to assign a new net code to a connection. More...
 
void assignNetCodesToBus (SCH_CONNECTION *aConnection)
 Ensures all members of the bus connection have a valid net code assigned. More...
 
void propagateToNeighbors (CONNECTION_SUBGRAPH *aSubgraph)
 Updates all neighbors of a subgraph with this one's connectivity info. More...
 
std::shared_ptr< SCH_CONNECTIONgetDefaultConnection (SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
 Builds a new default connection for the given item based on its properties. More...
 
void recacheSubgraphName (CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
 
bool ercCheckMultipleDrivers (const CONNECTION_SUBGRAPH *aSubgraph)
 If the subgraph has multiple drivers of equal priority that are graphically connected, ResolveDrivers() will have stored the second driver for use by this function, which actually creates the markers. More...
 
bool ercCheckNetclassConflicts (const std::vector< CONNECTION_SUBGRAPH * > &subgraphs)
 
bool ercCheckBusToNetConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting connections between net and bus labels. More...
 
bool ercCheckBusToBusConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting connections between two bus items. More...
 
bool ercCheckBusToBusEntryConflicts (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for conflicting bus entry to bus connections. More...
 
bool ercCheckNoConnects (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for proper presence or absence of no-connect symbols. More...
 
bool ercCheckFloatingWires (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for floating wires. More...
 
bool ercCheckLabels (const CONNECTION_SUBGRAPH *aSubgraph)
 Checks one subgraph for proper connection of labels. More...
 
int ercCheckHierSheets ()
 Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on the parent sheet object. More...
 

Static Private Member Functions

static SCH_CONNECTIONmatchBusMember (SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
 Search for a matching bus member inside a bus connection. More...
 

Private Attributes

SCH_SHEET_LIST m_sheetList
 
std::vector< SCH_ITEM * > m_items
 
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
 
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
 
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
 
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
 
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
 
std::unordered_map< wxString, int > m_net_name_to_code_map
 
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::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
 
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
 
std::unordered_map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
 
NET_MAP m_net_code_to_subgraphs_map
 
int m_last_net_code
 
int m_last_bus_code
 
int m_last_subgraph_code
 
SCHEMATICm_schematic
 The schematic this graph represents. More...
 

Detailed Description

Calculates the connectivity of a schematic and generates netlists.

Definition at line 272 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCHEMATIC aSchematic = nullptr)
inline

Definition at line 275 of file connection_graph.h.

275 :
276 m_last_net_code( 1 ),
277 m_last_bus_code( 1 ),
279 m_schematic( aSchematic )
280 {}
SCHEMATIC * m_schematic
The schematic this graph represents.

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 282 of file connection_graph.h.

283 {
284 Reset();
285 }

References Reset().

Member Function Documentation

◆ assignNetCodesToBus()

void CONNECTION_GRAPH::assignNetCodesToBus ( SCH_CONNECTION aConnection)
private

Ensures all members of the bus connection have a valid net code assigned.

Parameters
aConnectionis a bus connection

Definition at line 1749 of file connection_graph.cpp.

1750{
1751 std::vector< std::shared_ptr<SCH_CONNECTION>>& connections_to_check( aConnection->Members() );
1752
1753 for( unsigned i = 0; i < connections_to_check.size(); i++ )
1754 {
1755 const std::shared_ptr<SCH_CONNECTION>& member = connections_to_check[i];
1756
1757 if( member->IsBus() )
1758 {
1759 connections_to_check.insert( connections_to_check.end(),
1760 member->Members().begin(),
1761 member->Members().end() );
1762 continue;
1763 }
1764
1765 assignNewNetCode( *member );
1766 }
1767}
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()

References assignNewNetCode(), and SCH_CONNECTION::Members().

Referenced by processSubGraphs().

◆ assignNewNetCode()

int CONNECTION_GRAPH::assignNewNetCode ( SCH_CONNECTION aConnection)
private

Helper to assign a new net code to a connection.

Returns
the assigned code

Definition at line 1727 of file connection_graph.cpp.

1728{
1729 int code;
1730
1731 auto it = m_net_name_to_code_map.find( aConnection.Name() );
1732
1733 if( it == m_net_name_to_code_map.end() )
1734 {
1735 code = m_last_net_code++;
1736 m_net_name_to_code_map[ aConnection.Name() ] = code;
1737 }
1738 else
1739 {
1740 code = it->second;
1741 }
1742
1743 aConnection.SetNetCode( code );
1744
1745 return code;
1746}
std::unordered_map< wxString, int > m_net_name_to_code_map
void SetNetCode(int aCode)
wxString Name(bool aIgnoreSheet=false) const

References m_last_net_code, m_net_name_to_code_map, SCH_CONNECTION::Name(), and SCH_CONNECTION::SetNetCode().

Referenced by assignNetCodesToBus(), generateInvisiblePinSubGraphs(), and processSubGraphs().

◆ buildConnectionGraph()

void CONNECTION_GRAPH::buildConnectionGraph ( std::function< void(SCH_ITEM *)> *  aChangedItemHandler)
private

Generates the connection graph (after all item connectivity has been updated)

In the first phase, the algorithm iterates over all items, and then over all items that are connected (graphically) to each item, placing them into CONNECTION_SUBGRAPHs. Items that can potentially drive connectivity (i.e. labels, pins, etc.) are added to the m_drivers vector of the subgraph.

In the second phase, each subgraph is resolved. To resolve a subgraph, the driver is first selected by CONNECTION_SUBGRAPH::ResolveDrivers(), and then the connection for the chosen driver is propagated to all the other items in the subgraph.

TODO(JE): Net codes are non-deterministic. Fortunately, they are also not really used for anything. We should consider removing them entirely and just using net names everywhere.

Definition at line 1410 of file connection_graph.cpp.

1411{
1412 // Recache all bus aliases for later use
1413 wxCHECK_RET( m_schematic, wxT( "Connection graph cannot be built without schematic pointer" ) );
1414
1415 SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
1416
1417 for( unsigned i = 0; i < all_sheets.size(); i++ )
1418 {
1419 for( const std::shared_ptr<BUS_ALIAS>& alias : all_sheets[i].LastScreen()->GetBusAliases() )
1420 m_bus_alias_cache[ alias->GetName() ] = alias;
1421 }
1422
1423 PROF_TIMER sub_graph( "buildItemSubGraphs" );
1425
1426 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
1427 sub_graph.Show();
1428
1429
1436
1438
1440
1441 PROF_TIMER proc_sub_graph( "ProcessSubGraphs" );
1443
1444 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
1445 proc_sub_graph.Show();
1446
1447 // Absorbed subgraphs should no longer be considered
1448 alg::delete_if( m_driver_subgraphs, [&]( const CONNECTION_SUBGRAPH* candidate ) -> bool
1449 {
1450 return candidate->m_absorbed;
1451 } );
1452
1453 // Store global subgraphs for later reference
1454 std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1455 std::copy_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1456 std::back_inserter( global_subgraphs ),
1457 [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1458 {
1459 return !candidate->m_local_driver;
1460 } );
1461
1462 // Recache remaining valid subgraphs by sheet path
1464
1465 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1466 m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1467
1468 GetKiCadThreadPool().parallelize_loop( 0, m_driver_subgraphs.size(),
1469 [&]( const int a, const int b)
1470 {
1471 for( int ii = a; ii < b; ++ii )
1472 m_driver_subgraphs[ii]->UpdateItemConnections();
1473 }).wait();
1474
1475 // Next time through the subgraphs, we do some post-processing to handle things like
1476 // connecting bus members to their neighboring subgraphs, and then propagate connections
1477 // through the hierarchy
1478
1479 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1480 {
1481 if( !subgraph->m_dirty )
1482 continue;
1483
1484 wxLogTrace( ConnTrace, "Processing %lu (%s) for propagation", subgraph->m_code,
1485 subgraph->m_driver_connection->Name() );
1486
1487 // For subgraphs that are driven by a global (power port or label) and have more
1488 // than one global driver, we need to seek out other subgraphs driven by the
1489 // same name as the non-chosen driver and update them to match the chosen one.
1490
1491 if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1492 {
1493 for( SCH_ITEM* driver : subgraph->m_drivers )
1494 {
1495 if( driver == subgraph->m_driver )
1496 continue;
1497
1498 wxString secondary_name = subgraph->GetNameForDriver( driver );
1499
1500 if( secondary_name == subgraph->m_driver_connection->Name() )
1501 continue;
1502
1503 bool secondary_is_global = CONNECTION_SUBGRAPH::GetDriverPriority( driver )
1505
1506 for( CONNECTION_SUBGRAPH* candidate : global_subgraphs )
1507 {
1508 if( candidate == subgraph )
1509 continue;
1510
1511 if( !secondary_is_global && candidate->m_sheet != subgraph->m_sheet )
1512 continue;
1513
1514 SCH_CONNECTION* conn = candidate->m_driver_connection;
1515
1516 if( conn->Name() == secondary_name )
1517 {
1518 wxLogTrace( ConnTrace, "Global %lu (%s) promoted to %s", candidate->m_code,
1519 conn->Name(), subgraph->m_driver_connection->Name() );
1520
1521 conn->Clone( *subgraph->m_driver_connection );
1522
1523 candidate->m_dirty = false;
1524 }
1525 }
1526 }
1527 }
1528
1529 // This call will handle descending the hierarchy and updating child subgraphs
1530 propagateToNeighbors( subgraph );
1531 }
1532
1533 // Handle buses that have been linked together somewhere by member (net) connections.
1534 // This feels a bit hacky, perhaps this algorithm should be revisited in the future.
1535
1536 // For net subgraphs that have more than one bus parent, we need to ensure that those
1537 // buses are linked together in the final netlist. The final name of each bus might not
1538 // match the local name that was used to establish the parent-child relationship, because
1539 // the bus may have been renamed by a hierarchical connection. So, for each of these cases,
1540 // we need to identify the appropriate bus members to link together (and their final names),
1541 // and then update all instances of the old name in the hierarchy.
1542
1543 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1544 {
1545 // All SGs should have been processed by propagateToNeighbors above
1546 wxASSERT_MSG( !subgraph->m_dirty, "Subgraph not processed by propagateToNeighbors!" );
1547
1548 if( subgraph->m_bus_parents.size() < 2 )
1549 continue;
1550
1551 SCH_CONNECTION* conn = subgraph->m_driver_connection;
1552
1553 wxLogTrace( ConnTrace, "%lu (%s) has multiple bus parents",
1554 subgraph->m_code, conn->Name() );
1555
1556 wxASSERT( conn->IsNet() );
1557
1558 for( const auto& ii : subgraph->m_bus_parents )
1559 {
1560 SCH_CONNECTION* link_member = ii.first.get();
1561
1562 for( CONNECTION_SUBGRAPH* parent : ii.second )
1563 {
1564 while( parent->m_absorbed )
1565 parent = parent->m_absorbed_by;
1566
1567 SCH_CONNECTION* match = matchBusMember( parent->m_driver_connection, link_member );
1568
1569 if( !match )
1570 {
1571 wxLogTrace( ConnTrace, "Warning: could not match %s inside %lu (%s)",
1572 conn->Name(), parent->m_code, parent->m_driver_connection->Name() );
1573 continue;
1574 }
1575
1576 if( conn->Name() != match->Name() )
1577 {
1578 wxString old_name = match->Name();
1579
1580 wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", parent->m_code,
1581 parent->m_driver_connection->Name(), old_name, conn->Name() );
1582
1583 match->Clone( *conn );
1584
1585 auto jj = m_net_name_to_subgraphs_map.find( old_name );
1586
1587 if( jj == m_net_name_to_subgraphs_map.end() )
1588 continue;
1589
1590 for( CONNECTION_SUBGRAPH* old_sg : jj->second )
1591 {
1592 while( old_sg->m_absorbed )
1593 old_sg = old_sg->m_absorbed_by;
1594
1595 old_sg->m_driver_connection->Clone( *conn );
1596 }
1597 }
1598 }
1599 }
1600 }
1601
1602
1603 auto updateItemConnectionsTask =
1604 [&]( CONNECTION_SUBGRAPH* subgraph ) -> size_t
1605 {
1606 // Make sure weakly-driven single-pin nets get the unconnected_ prefix
1607 if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
1608 subgraph->m_driver->Type() == SCH_PIN_T )
1609 {
1610 SCH_PIN* pin = static_cast<SCH_PIN*>( subgraph->m_driver );
1611 wxString name = pin->GetDefaultNetName( subgraph->m_sheet, true );
1612
1613 subgraph->m_driver_connection->ConfigureFromLabel( name );
1614 }
1615
1616 subgraph->m_dirty = false;
1617 subgraph->UpdateItemConnections();
1618
1619 // No other processing to do on buses
1620 if( subgraph->m_driver_connection->IsBus() )
1621 return 0;
1622
1623 // As a visual aid, we can check sheet pins that are driven by themselves to see
1624 // if they should be promoted to buses
1625
1626 if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1627 {
1628 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( subgraph->m_driver );
1629
1630 if( SCH_SHEET* sheet = pin->GetParent() )
1631 {
1632 wxString pinText = pin->GetText();
1633 SCH_SCREEN* screen = sheet->GetScreen();
1634
1635 for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
1636 {
1637 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
1638
1639 if( label->GetText() == pinText )
1640 {
1641 SCH_SHEET_PATH path = subgraph->m_sheet;
1642 path.push_back( sheet );
1643
1644 SCH_CONNECTION* parent_conn = label->Connection( &path );
1645
1646 if( parent_conn && parent_conn->IsBus() )
1647 subgraph->m_driver_connection->SetType( CONNECTION_TYPE::BUS );
1648
1649 break;
1650 }
1651 }
1652
1653 if( subgraph->m_driver_connection->IsBus() )
1654 return 0;
1655 }
1656 }
1657
1658 return 1;
1659 };
1660
1661 GetKiCadThreadPool().parallelize_loop( 0, m_driver_subgraphs.size(),
1662 [&]( const int a, const int b)
1663 {
1664 for( int ii = a; ii < b; ++ii )
1665 updateItemConnectionsTask( m_driver_subgraphs[ii] );
1666 }).wait();
1667
1670
1671 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1672 {
1673 NET_NAME_CODE_CACHE_KEY key = { subgraph->GetNetName(),
1674 subgraph->m_driver_connection->NetCode() };
1675 m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1676
1677 m_net_name_to_subgraphs_map[subgraph->m_driver_connection->Name()].push_back( subgraph );
1678 }
1679
1680 std::shared_ptr<NET_SETTINGS>& netSettings = m_schematic->Prj().GetProjectFile().m_NetSettings;
1681 std::map<wxString, wxString> oldAssignments = netSettings->m_NetClassLabelAssignments;
1682
1683 netSettings->m_NetClassLabelAssignments.clear();
1684
1685 auto dirtySubgraphs =
1686 [&]( const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
1687 {
1688 if( aChangedItemHandler )
1689 {
1690 for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
1691 {
1692 for( SCH_ITEM* item : subgraph->m_items )
1693 (*aChangedItemHandler)( item );
1694 }
1695 }
1696 };
1697
1698 auto checkNetclassDrivers =
1699 [&]( const std::vector<CONNECTION_SUBGRAPH*>& subgraphs )
1700 {
1701 for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
1702 {
1703 for( SCH_ITEM* item : subgraph->m_items )
1704 {
1705 const wxString netclass = subgraph->GetNetclassForDriver( item );
1706
1707 if( !netclass.IsEmpty() )
1708 {
1709 const wxString netname = subgraph->GetNetName();
1710
1711 netSettings->m_NetClassLabelAssignments[ netname ] = netclass;
1712
1713 if( oldAssignments[ netname ] != netclass )
1714 dirtySubgraphs( subgraphs );
1715
1716 return;
1717 }
1718 }
1719 }
1720 };
1721
1722 for( const auto& [ netname, subgraphs ] : m_net_name_to_subgraphs_map )
1723 checkNetclassDrivers( subgraphs );
1724}
const char * name
Definition: DXF_plotter.cpp:56
void processSubGraphs()
Process all subgraphs to assign netcodes and merge subgraphs based on labels.
void collectAllDriverValues()
Maps the driver values for each subgraph.
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
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
void buildItemSubGraphs()
Generates individual item subgraphs on a per-sheet basis.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void generateInvisiblePinSubGraphs()
Iterate through the invisible power pins to collect the global labels as drivers.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
NET_MAP m_net_code_to_subgraphs_map
void resolveAllDrivers()
Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel.
A subgraph is a set of items that are electrically connected on a single sheet.
PRIORITY GetDriverPriority()
SCH_SHEET_PATH m_sheet
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.
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
A small class to help profiling.
Definition: profile.h:47
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
Definition: project_file.h:168
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:148
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:85
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:75
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsNet() const
void SetType(CONNECTION_TYPE aType)
bool IsBus() const
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:146
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
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...
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:55
static const wxChar ConnProfileMask[]
static const wxChar ConnTrace[]
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
Definition: kicad_algo.h:173
@ BUS
This item represents a bus vector.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:32
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:152
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:156
@ SCH_PIN_T
Definition: typeinfo.h:158

References buildItemSubGraphs(), BUS, SCH_CONNECTION::Clone(), collectAllDriverValues(), SCH_ITEM::Connection(), ConnProfileMask, ConnTrace, alg::delete_if(), generateInvisiblePinSubGraphs(), CONNECTION_SUBGRAPH::GetDriverPriority(), GetKiCadThreadPool(), PROJECT::GetProjectFile(), SCHEMATIC::GetSheets(), EDA_TEXT::GetText(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::IsNet(), SCH_SCREEN::Items(), CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, m_bus_alias_cache, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver_connection, m_driver_subgraphs, m_net_code_to_subgraphs_map, m_net_name_to_subgraphs_map, PROJECT_FILE::m_NetSettings, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, matchBusMember(), name, SCH_CONNECTION::Name(), EE_RTREE::OfType(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, SCHEMATIC::Prj(), processSubGraphs(), propagateToNeighbors(), resolveAllDrivers(), SCH_HIER_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, SCH_CONNECTION::SetType(), and PROF_TIMER::Show().

◆ buildItemSubGraphs()

void CONNECTION_GRAPH::buildItemSubGraphs ( )
private

Generates individual item subgraphs on a per-sheet basis.

Definition at line 778 of file connection_graph.cpp.

779{
780 // Recache all bus aliases for later use
781 wxCHECK_RET( m_schematic, "Connection graph cannot be built without schematic pointer" );
782
783 SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
784
785 for( unsigned i = 0; i < all_sheets.size(); i++ )
786 {
787 for( const std::shared_ptr<BUS_ALIAS>& alias : all_sheets[i].LastScreen()->GetBusAliases() )
788 m_bus_alias_cache[ alias->GetName() ] = alias;
789 }
790
791 // Build subgraphs from items (on a per-sheet basis)
792
793 for( SCH_ITEM* item : m_items )
794 {
795 for( const auto& it : item->m_connection_map )
796 {
797 const SCH_SHEET_PATH& sheet = it.first;
798 SCH_CONNECTION* connection = it.second;
799
800 if( connection->SubgraphCode() == 0 )
801 {
802 CONNECTION_SUBGRAPH* subgraph = new CONNECTION_SUBGRAPH( this );
803
804 subgraph->m_code = m_last_subgraph_code++;
805 subgraph->m_sheet = sheet;
806
807 subgraph->AddItem( item );
808
809 connection->SetSubgraphCode( subgraph->m_code );
810 m_item_to_subgraph_map[item] = subgraph;
811
812 std::list<SCH_ITEM*> memberlist;
813
814 auto get_items =
815 [&]( SCH_ITEM* aItem ) -> bool
816 {
817 SCH_CONNECTION* conn = aItem->GetOrInitConnection( sheet, this );
818 bool unique = !( aItem->GetFlags() & CANDIDATE );
819
820 if( conn && !conn->SubgraphCode() )
821 aItem->SetFlags( CANDIDATE );
822
823 return ( unique && conn && ( conn->SubgraphCode() == 0 ) );
824 };
825
826 std::copy_if( item->ConnectedItems( sheet ).begin(),
827 item->ConnectedItems( sheet ).end(),
828 std::back_inserter( memberlist ), get_items );
829
830 for( SCH_ITEM* connected_item : memberlist )
831 {
832 if( connected_item->Type() == SCH_NO_CONNECT_T )
833 subgraph->m_no_connect = connected_item;
834
835 SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
836
837 wxASSERT( connected_conn );
838
839 if( connected_conn->SubgraphCode() == 0 )
840 {
841 connected_conn->SetSubgraphCode( subgraph->m_code );
842 m_item_to_subgraph_map[connected_item] = subgraph;
843 subgraph->AddItem( connected_item );
844 SCH_ITEM_SET& citemset = connected_item->ConnectedItems( sheet );
845
846 for( SCH_ITEM* citem : citemset )
847 {
848 if( citem->HasFlag( CANDIDATE ) )
849 continue;
850
851 if( get_items( citem ) )
852 memberlist.push_back( citem );
853 }
854 }
855 }
856
857 for( SCH_ITEM* connected_item : memberlist )
858 connected_item->ClearFlags( CANDIDATE );
859
860 subgraph->m_dirty = true;
861 m_subgraphs.push_back( subgraph );
862 }
863 }
864 }
865
866}
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
std::vector< SCH_ITEM * > m_items
std::unordered_map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
void SetSubgraphCode(int aCode)
int SubgraphCode() const
#define CANDIDATE
flag indicating that the structure is connected
std::vector< SCH_ITEM * > SCH_ITEM_SET
Definition: sch_item.h:136
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:142

References CONNECTION_SUBGRAPH::AddItem(), CANDIDATE, SCHEMATIC::GetSheets(), m_bus_alias_cache, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, m_item_to_subgraph_map, m_items, m_last_subgraph_code, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_subgraphs, SCH_NO_CONNECT_T, SCH_CONNECTION::SetSubgraphCode(), and SCH_CONNECTION::SubgraphCode().

Referenced by buildConnectionGraph().

◆ collectAllDriverValues()

void CONNECTION_GRAPH::collectAllDriverValues ( )
private

Maps the driver values for each subgraph.

Definition at line 937 of file connection_graph.cpp.

938{
939 // Check for subgraphs with the same net name but only weak drivers.
940 // For example, two wires that are both connected to hierarchical
941 // sheet pins that happen to have the same name, but are not the same.
942
943 for( auto&& subgraph : m_driver_subgraphs )
944 {
945 wxString full_name = subgraph->m_driver_connection->Name();
946 wxString name = subgraph->m_driver_connection->Name( true );
947 m_net_name_to_subgraphs_map[full_name].emplace_back( subgraph );
948
949 // For vector buses, we need to cache the prefix also, as two different instances of the
950 // weakly driven pin may have the same prefix but different vector start and end. We need
951 // to treat those as needing renaming also, because otherwise if they end up on a sheet with
952 // common usage, they will be incorrectly merged.
953 if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
954 {
955 wxString prefixOnly = full_name.BeforeFirst( '[' ) + wxT( "[]" );
956 m_net_name_to_subgraphs_map[prefixOnly].emplace_back( subgraph );
957 }
958
959 subgraph->m_dirty = true;
960
961 if( subgraph->m_strong_driver )
962 {
963 SCH_ITEM* driver = subgraph->m_driver;
964 SCH_SHEET_PATH sheet = subgraph->m_sheet;
965
966 switch( driver->Type() )
967 {
968 case SCH_LABEL_T:
969 case SCH_HIER_LABEL_T:
970 {
971 m_local_label_cache[std::make_pair( sheet, name )].push_back( subgraph );
972 break;
973 }
975 {
976 m_global_label_cache[name].push_back( subgraph );
977 break;
978 }
979 case SCH_PIN_T:
980 {
981 SCH_PIN* pin = static_cast<SCH_PIN*>( driver );
982 wxASSERT( pin->IsPowerConnection() );
983 m_global_label_cache[name].push_back( subgraph );
984 break;
985 }
986 default:
987 {
989
990 wxLogTrace( ConnTrace, "Unexpected strong driver %s",
991 driver->GetSelectMenuText( &unitsProvider ) );
992 break;
993 }
994 }
995 }
996 }
997}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
std::unordered_map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:111
virtual wxString GetSelectMenuText(UNITS_PROVIDER *aUnitsProvider) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:108
@ SCH_LABEL_T
Definition: typeinfo.h:150
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:151

References BUS, ConnTrace, EDA_ITEM::GetSelectMenuText(), m_driver_subgraphs, m_global_label_cache, m_local_label_cache, m_net_name_to_subgraphs_map, MILLIMETRES, name, pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, schIUScale, and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ ercCheckBusToBusConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting connections between two bus items.

For example, a labeled bus wire connected to a hierarchical sheet pin where the labeled bus doesn't contain any of the same bus members as the sheet pin

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2573 of file connection_graph.cpp.

2574{
2575 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2576 SCH_SCREEN* screen = sheet.LastScreen();
2577
2578 SCH_ITEM* label = nullptr;
2579 SCH_ITEM* port = nullptr;
2580
2581 for( SCH_ITEM* item : aSubgraph->m_items )
2582 {
2583 switch( item->Type() )
2584 {
2585 case SCH_TEXT_T:
2586 case SCH_GLOBAL_LABEL_T:
2587 {
2588 if( !label && item->Connection( &sheet )->IsBus() )
2589 label = item;
2590 break;
2591 }
2592
2593 case SCH_SHEET_PIN_T:
2594 case SCH_HIER_LABEL_T:
2595 {
2596 if( !port && item->Connection( &sheet )->IsBus() )
2597 port = item;
2598 break;
2599 }
2600
2601 default:
2602 break;
2603 }
2604 }
2605
2606 if( label && port )
2607 {
2608 bool match = false;
2609
2610 for( const auto& member : label->Connection( &sheet )->Members() )
2611 {
2612 for( const auto& test : port->Connection( &sheet )->Members() )
2613 {
2614 if( test != member && member->Name() == test->Name() )
2615 {
2616 match = true;
2617 break;
2618 }
2619 }
2620
2621 if( match )
2622 break;
2623 }
2624
2625 if( !match )
2626 {
2627 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
2628 ercItem->SetItems( label, port );
2629
2630 SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
2631 screen->Append( marker );
2632
2633 return false;
2634 }
2635 }
2636
2637 return true;
2638}
std::vector< SCH_ITEM * > m_items
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:263
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:202
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:139
SCH_SCREEN * LastScreen()
@ ERCE_BUS_TO_BUS_CONFLICT
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:60
@ SCH_TEXT_T
Definition: typeinfo.h:149

References SCH_SCREEN::Append(), SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_TO_BUS_CONFLICT, EDA_ITEM::GetPosition(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_SHEET_PIN_T, SCH_TEXT_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckBusToBusEntryConflicts()

bool CONNECTION_GRAPH::ercCheckBusToBusEntryConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting bus entry to bus connections.

For example, a wire with label "A0" is connected to a bus labeled "D[8..0]"

Will also check for mistakes related to bus group names, for example: A bus group named "USB{DP DM}" should have bus entry connections like "USB.DP" but someone might accidentally just enter "DP"

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2641 of file connection_graph.cpp.

2642{
2643 bool conflict = false;
2644 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2645 SCH_SCREEN* screen = sheet.LastScreen();
2646
2647 SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2648 SCH_ITEM* bus_wire = nullptr;
2649 wxString bus_name;
2650
2651 if( !aSubgraph->m_driver_connection )
2652 {
2653 // Incomplete bus entry. Let the unconnected tests handle it.
2654 return true;
2655 }
2656
2657 for( SCH_ITEM* item : aSubgraph->m_items )
2658 {
2659 switch( item->Type() )
2660 {
2662 {
2663 if( !bus_entry )
2664 bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2665 break;
2666 }
2667
2668 default:
2669 break;
2670 }
2671 }
2672
2673 if( bus_entry && bus_entry->m_connected_bus_item )
2674 {
2675 bus_wire = bus_entry->m_connected_bus_item;
2676
2677 wxASSERT( bus_wire->Type() == SCH_LINE_T );
2678
2679 // In some cases, the connection list (SCH_CONNECTION*) can be null.
2680 // Skip null connections.
2681 if( bus_entry->Connection( &sheet )
2682 && bus_wire->Type() == SCH_LINE_T
2683 && bus_wire->Connection( &sheet ) )
2684 {
2685 conflict = true; // Assume a conflict; we'll reset if we find it's OK
2686
2687 bus_name = bus_wire->Connection( &sheet )->Name();
2688
2689 wxString test_name = bus_entry->Connection( &sheet )->Name();
2690
2691 for( const auto& member : bus_wire->Connection( &sheet )->Members() )
2692 {
2693 if( member->Type() == CONNECTION_TYPE::BUS )
2694 {
2695 for( const auto& sub_member : member->Members() )
2696 {
2697 if( sub_member->Name() == test_name )
2698 conflict = false;
2699 }
2700 }
2701 else if( member->Name() == test_name )
2702 {
2703 conflict = false;
2704 }
2705 }
2706 }
2707 }
2708
2709 // Don't report warnings if this bus member has been overridden by a higher priority power pin
2710 // or global label
2711 if( conflict && CONNECTION_SUBGRAPH::GetDriverPriority( aSubgraph->m_driver )
2713 {
2714 conflict = false;
2715 }
2716
2717 if( conflict )
2718 {
2719 wxString netName = aSubgraph->m_driver_connection->Name();
2720 wxString msg = wxString::Format( _( "Net %s is graphically connected to bus %s but is not a"
2721 " member of that bus" ),
2722 UnescapeString( netName ),
2723 UnescapeString( bus_name ) );
2724 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
2725 ercItem->SetItems( bus_entry, bus_wire );
2726 ercItem->SetErrorMessage( msg );
2727
2728 SCH_MARKER* marker = new SCH_MARKER( ercItem, bus_entry->GetPosition() );
2729 screen->Append( marker );
2730
2731 return false;
2732 }
2733
2734 return true;
2735}
VECTOR2I GetPosition() const override
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 ...
#define _(s)
@ ERCE_BUS_ENTRY_CONFLICT
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:58
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxString UnescapeString(const wxString &aSource)
@ SCH_LINE_T
Definition: typeinfo.h:145
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:143

References _, SCH_SCREEN::Append(), BUS, SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_BUS_ENTRY_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetDriverPriority(), SCH_BUS_ENTRY_BASE::GetPosition(), SCH_SHEET_PATH::LastScreen(), SCH_BUS_WIRE_ENTRY::m_connected_bus_item, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_CONNECTION::Members(), SCH_CONNECTION::Name(), CONNECTION_SUBGRAPH::POWER_PIN, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, EDA_ITEM::Type(), and UnescapeString().

Referenced by RunERC().

◆ ercCheckBusToNetConflicts()

bool CONNECTION_GRAPH::ercCheckBusToNetConflicts ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for conflicting connections between net and bus labels.

For example, a net wire connected to a bus port/pin, or vice versa

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2516 of file connection_graph.cpp.

2517{
2518 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2519 SCH_SCREEN* screen = sheet.LastScreen();
2520
2521 SCH_ITEM* net_item = nullptr;
2522 SCH_ITEM* bus_item = nullptr;
2523 SCH_CONNECTION conn( this );
2524
2525 for( SCH_ITEM* item : aSubgraph->m_items )
2526 {
2527 switch( item->Type() )
2528 {
2529 case SCH_LINE_T:
2530 {
2531 if( item->GetLayer() == LAYER_BUS )
2532 bus_item = ( !bus_item ) ? item : bus_item;
2533 else
2534 net_item = ( !net_item ) ? item : net_item;
2535 break;
2536 }
2537
2538 case SCH_LABEL_T:
2539 case SCH_GLOBAL_LABEL_T:
2540 case SCH_SHEET_PIN_T:
2541 case SCH_HIER_LABEL_T:
2542 {
2543 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2544 conn.ConfigureFromLabel( EscapeString( text->GetShownText(), CTX_NETNAME ) );
2545
2546 if( conn.IsBus() )
2547 bus_item = ( !bus_item ) ? item : bus_item;
2548 else
2549 net_item = ( !net_item ) ? item : net_item;
2550 break;
2551 }
2552
2553 default:
2554 break;
2555 }
2556 }
2557
2558 if( net_item && bus_item )
2559 {
2560 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
2561 ercItem->SetItems( net_item, bus_item );
2562
2563 SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
2564 screen->Append( marker );
2565
2566 return false;
2567 }
2568
2569 return true;
2570}
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:246
@ ERCE_BUS_TO_NET_CONFLICT
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:62
@ LAYER_BUS
Definition: layer_ids.h:345
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
Definition: string_utils.h:54

References SCH_SCREEN::Append(), SCH_CONNECTION::ConfigureFromLabel(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_BUS_TO_NET_CONFLICT, EscapeString(), SCH_ITEM::GetLayer(), EDA_ITEM::GetPosition(), SCH_CONNECTION::IsBus(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_LINE_T, SCH_SHEET_PIN_T, text, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckFloatingWires()

bool CONNECTION_GRAPH::ercCheckFloatingWires ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for floating wires.

Will throw an error for any subgraph that consists of just wires with no driver

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2921 of file connection_graph.cpp.

2922{
2923 if( aSubgraph->m_driver )
2924 return true;
2925
2926 std::vector<SCH_ITEM*> wires;
2927
2928 // We've gotten this far, so we know we have no valid driver. All we need to do is check
2929 // for a wire that we can place the error on.
2930
2931 for( SCH_ITEM* item : aSubgraph->m_items )
2932 {
2933 if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
2934 wires.emplace_back( item );
2935 else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
2936 wires.emplace_back( item );
2937 }
2938
2939 if( !wires.empty() )
2940 {
2941 SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2942
2943 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
2944 ercItem->SetItems( wires[0],
2945 wires.size() > 1 ? wires[1] : nullptr,
2946 wires.size() > 2 ? wires[2] : nullptr,
2947 wires.size() > 3 ? wires[3] : nullptr );
2948
2949 SCH_MARKER* marker = new SCH_MARKER( ercItem, wires[0]->GetPosition() );
2950 screen->Append( marker );
2951
2952 return false;
2953 }
2954
2955 return true;
2956}
@ ERCE_WIRE_DANGLING
Some wires are not connected to anything else.
Definition: erc_settings.h:67
@ LAYER_WIRE
Definition: layer_ids.h:344

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_WIRE_DANGLING, SCH_ITEM::GetLayer(), SCH_SHEET_PATH::LastScreen(), LAYER_WIRE, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_items, CONNECTION_SUBGRAPH::m_sheet, SCH_BUS_WIRE_ENTRY_T, SCH_LINE_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckHierSheets()

int CONNECTION_GRAPH::ercCheckHierSheets ( )
private

Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on the parent sheet object.

Parameters
aSubgraphis the subgraph to examine
Returns
the number of errors found

Definition at line 3125 of file connection_graph.cpp.

3126{
3127 int errors = 0;
3128
3129 ERC_SETTINGS& settings = m_schematic->ErcSettings();
3130
3131 for( const SCH_SHEET_PATH& sheet : m_sheetList )
3132 {
3133 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
3134 {
3135 if( item->Type() != SCH_SHEET_T )
3136 continue;
3137
3138 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
3139
3140 std::map<wxString, SCH_SHEET_PIN*> pins;
3141 std::map<wxString, SCH_HIERLABEL*> labels;
3142
3143 for( SCH_SHEET_PIN* pin : parentSheet->GetPins() )
3144 {
3145 if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
3146 pins[pin->GetText()] = pin;
3147
3148 if( pin->IsDangling() && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
3149 {
3150 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
3151 ercItem->SetItems( pin );
3152
3153 SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
3154 sheet.LastScreen()->Append( marker );
3155
3156 errors++;
3157 }
3158 }
3159
3160 if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
3161 {
3162 std::set<wxString> matchedPins;
3163
3164 for( SCH_ITEM* subItem : parentSheet->GetScreen()->Items() )
3165 {
3166 if( subItem->Type() == SCH_HIER_LABEL_T )
3167 {
3168 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
3169
3170 if( !pins.count( label->GetText() ) )
3171 labels[label->GetText()] = label;
3172 else
3173 matchedPins.insert( label->GetText() );
3174 }
3175 }
3176
3177 for( const wxString& matched : matchedPins )
3178 pins.erase( matched );
3179
3180 for( const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
3181 {
3182 wxString msg = wxString::Format( _( "Sheet pin %s has no matching hierarchical "
3183 "label inside the sheet" ),
3184 UnescapeString( unmatched.first ) );
3185
3186 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
3187 ercItem->SetItems( unmatched.second );
3188 ercItem->SetErrorMessage( msg );
3189 ercItem->SetIsSheetSpecific();
3190
3191 SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
3192 sheet.LastScreen()->Append( marker );
3193
3194 errors++;
3195 }
3196
3197 for( const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
3198 {
3199 wxString msg = wxString::Format( _( "Hierarchical label %s has no matching "
3200 "sheet pin in the parent sheet" ),
3201 UnescapeString( unmatched.first ) );
3202
3203 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
3204 ercItem->SetItems( unmatched.second );
3205 ercItem->SetErrorMessage( msg );
3206 ercItem->SetIsSheetSpecific();
3207
3208 SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
3209 parentSheet->GetScreen()->Append( marker );
3210
3211 errors++;
3212 }
3213 }
3214 }
3215 }
3216
3217 return errors;
3218}
SCH_SHEET_LIST m_sheetList
Container for ERC settings.
Definition: erc_settings.h:109
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:125
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:179
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:103
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:172
@ ERCE_PIN_NOT_CONNECTED
Pin not connected and not no connect symbol.
Definition: erc_settings.h:42
@ ERCE_HIERACHICAL_LABEL
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:47
@ SCH_SHEET_T
Definition: typeinfo.h:157

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_HIERACHICAL_LABEL, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), Format(), SCH_SHEET::GetPins(), SCH_SHEET::GetScreen(), EDA_TEXT::GetText(), ERC_SETTINGS::IsTestEnabled(), SCH_SCREEN::Items(), m_schematic, m_sheetList, pin, SCH_HIER_LABEL_T, SCH_SHEET_T, and UnescapeString().

Referenced by RunERC().

◆ ercCheckLabels()

bool CONNECTION_GRAPH::ercCheckLabels ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for proper connection of labels.

Labels should be connected to something

Parameters
aSubgraphis the subgraph to examine
aCheckGlobalLabelsis true if global labels should be checked for loneliness
Returns
true for no errors, false for errors

Definition at line 2959 of file connection_graph.cpp.

2960{
2961 // Label connection rules:
2962 // Any label without a no-connect needs to have at least 2 pins, otherwise it is invalid
2963 // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2964 // Global labels are flagged if they appear only once, don't connect to any local labels,
2965 // and don't have a no-connect marker
2966
2967
2968 if( !aSubgraph->m_driver_connection )
2969 return true;
2970
2971 // Buses are excluded from this test: many users create buses with only a single instance
2972 // and it's not really a problem as long as the nets in the bus pass ERC
2973 if( aSubgraph->m_driver_connection->IsBus() )
2974 return true;
2975
2976 ERC_SETTINGS& settings = m_schematic->ErcSettings();
2977 bool ok = true;
2978 int pinCount = 0;
2979
2980 std::map<KICAD_T, std::vector<SCH_TEXT*>> label_map;
2981
2982
2983 auto hasPins =
2984 []( const CONNECTION_SUBGRAPH* aLocSubgraph ) -> int
2985 {
2986 int retval = 0;
2987
2988 for( const SCH_ITEM* item : aLocSubgraph->m_items )
2989 {
2990 switch( item->Type() )
2991 {
2992 case SCH_PIN_T:
2993 case SCH_SHEET_PIN_T:
2994 ++retval;
2995 break;
2996
2997 default: break;
2998 }
2999 }
3000
3001 return retval;
3002 };
3003
3004 auto reportError = [&]( SCH_TEXT* aText, int errCode )
3005 {
3006 if( settings.IsTestEnabled( errCode ) )
3007 {
3008 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
3009 ercItem->SetItems( aText );
3010
3011 SCH_MARKER* marker = new SCH_MARKER( ercItem, aText->GetPosition() );
3012 aSubgraph->m_sheet.LastScreen()->Append( marker );
3013 }
3014 };
3015
3016 pinCount = hasPins( aSubgraph );
3017
3018 for( SCH_ITEM* item : aSubgraph->m_items )
3019 {
3020 switch( item->Type() )
3021 {
3022 case SCH_LABEL_T:
3023 case SCH_GLOBAL_LABEL_T:
3024 case SCH_HIER_LABEL_T:
3025 {
3026 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
3027
3028 label_map[item->Type()].push_back( text );
3029
3030 // Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
3031 // we want to error if an individual label in the subgraph is floating, even if it's
3032 // connected to other valid things by way of another label on the same sheet.
3033 if( text->IsDangling() )
3034 {
3035 reportError( text, ERCE_LABEL_NOT_CONNECTED );
3036 return false;
3037 }
3038
3039 break;
3040 }
3041
3042 // If this subgraph has a no-connect, do not continue processing as we do not
3043 // submit no-connect errors for nets explicitly designated as no-connect
3044 case SCH_NO_CONNECT_T:
3045 return true;
3046
3047 default:
3048 break;
3049 }
3050 }
3051
3052 if( label_map.empty() )
3053 return true;
3054
3055 wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" );
3056
3057 // Labels that have multiple pins connected are not dangling (may be used for naming segments)
3058 // so leave them without errors here
3059 if( pinCount > 1 )
3060 return true;
3061
3062 for( auto& [type, label_vec] : label_map )
3063 {
3064
3065 switch( type )
3066 {
3067 case SCH_GLOBAL_LABEL_T:
3068 if( !settings.IsTestEnabled( ERCE_GLOBLABEL ) )
3069 continue;
3070
3071 break;
3072 default:
3073 if( !settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
3074 continue;
3075
3076 break;
3077 }
3078
3079 for( SCH_TEXT* text : label_vec )
3080 {
3081 int allPins = pinCount;
3082
3083 // Labels are connected if there are at least 2 pins on their net
3084 const CONNECTION_SUBGRAPH* subgraph = aSubgraph;
3085
3086 // If there is a hierarchical connection, walk up the hierarchy
3087 // to get the top-most subgraph
3088 while( subgraph->m_hier_parent )
3089 subgraph = subgraph->m_hier_parent;
3090
3091 wxString name = subgraph->m_driver_connection->Name();
3092
3093 // If there are local bus connections (a label with the same name as a bus element)
3094 // Then get the name from the SCH_CONNECTION element used to map the bus connection
3095 // as this is the "true" connection name
3096 if( !subgraph->m_bus_parents.empty() )
3097 name = subgraph->m_bus_parents.begin()->first->Name();
3098
3099 auto it = m_net_name_to_subgraphs_map.find( name );
3100
3101 if( it != m_net_name_to_subgraphs_map.end() )
3102 {
3103 for( const CONNECTION_SUBGRAPH* neighbor : it->second )
3104 {
3105 if( neighbor == aSubgraph )
3106 continue;
3107
3108 allPins += hasPins( neighbor );
3109 }
3110 }
3111
3112 if( allPins < 2 )
3113 {
3114 reportError( text,
3116 ok = false;
3117 }
3118 }
3119 }
3120
3121 return ok;
3122}
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.
CONNECTION_SUBGRAPH * m_hier_parent
VECTOR2I GetPosition() const override
Definition: sch_text.h:205
@ ERCE_LABEL_NOT_CONNECTED
Label not connected to anything.
Definition: erc_settings.h:50
@ ERCE_GLOBLABEL
A global label is unique.
Definition: erc_settings.h:65

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, SCHEMATIC::ErcSettings(), SCH_TEXT::GetPosition(), SCH_CONNECTION::IsBus(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_bus_parents, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_items, m_net_name_to_subgraphs_map, m_schematic, CONNECTION_SUBGRAPH::m_sheet, name, SCH_CONNECTION::Name(), SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_NO_CONNECT_T, SCH_PIN_T, SCH_SHEET_PIN_T, text, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckMultipleDrivers()

bool CONNECTION_GRAPH::ercCheckMultipleDrivers ( const CONNECTION_SUBGRAPH aSubgraph)
private

If the subgraph has multiple drivers of equal priority that are graphically connected, ResolveDrivers() will have stored the second driver for use by this function, which actually creates the markers.

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2405 of file connection_graph.cpp.

2406{
2407 wxCHECK( aSubgraph, false );
2408 /*
2409 * This was changed late in 6.0 to fix https://gitlab.com/kicad/code/kicad/-/issues/9367
2410 * so I'm going to leave the original code in for just a little while. If anyone comes
2411 * across this in 7.0 development (or later), feel free to delete.
2412 */
2413#if 0
2414 if( aSubgraph->m_second_driver )
2415 {
2416 SCH_ITEM* primary = aSubgraph->m_first_driver;
2417 SCH_ITEM* secondary = aSubgraph->m_second_driver;
2418
2419 wxPoint pos = primary->Type() == SCH_PIN_T ?
2420 static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2421 primary->GetPosition();
2422
2423 wxString primaryName = aSubgraph->GetNameForDriver( primary );
2424 wxString secondaryName = aSubgraph->GetNameForDriver( secondary );
2425
2426 wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2427 "items; %s will be used in the netlist" ),
2428 primaryName, secondaryName, primaryName );
2429
2430 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2431 ercItem->SetItems( primary, secondary );
2432 ercItem->SetErrorMessage( msg );
2433
2434 SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2435 aSubgraph->m_sheet.LastScreen()->Append( marker );
2436
2437 return false;
2438 }
2439#else
2440 if( aSubgraph->m_multiple_drivers )
2441 {
2442 for( SCH_ITEM* driver : aSubgraph->m_drivers )
2443 {
2444 if( driver == aSubgraph->m_driver )
2445 continue;
2446
2447 if( driver->Type() == SCH_GLOBAL_LABEL_T
2448 || driver->Type() == SCH_HIER_LABEL_T
2449 || driver->Type() == SCH_LABEL_T )
2450 {
2451 wxString primaryName = aSubgraph->GetNameForDriver( aSubgraph->m_driver );
2452 wxString secondaryName = aSubgraph->GetNameForDriver( driver );
2453
2454 if( primaryName == secondaryName )
2455 continue;
2456
2457 wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2458 "items; %s will be used in the netlist" ),
2459 primaryName, secondaryName, primaryName );
2460
2461 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2462 ercItem->SetItems( aSubgraph->m_driver, driver );
2463 ercItem->SetErrorMessage( msg );
2464
2465 SCH_MARKER* marker = new SCH_MARKER( ercItem, driver->GetPosition() );
2466 aSubgraph->m_sheet.LastScreen()->Append( marker );
2467
2468 return false;
2469 }
2470 }
2471 }
2472#endif
2473
2474 return true;
2475}
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
std::vector< SCH_ITEM * > m_drivers
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
@ ERCE_DRIVER_CONFLICT
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:57

References _, SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_DRIVER_CONFLICT, Format(), CONNECTION_SUBGRAPH::GetNameForDriver(), EDA_ITEM::GetPosition(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_first_driver, CONNECTION_SUBGRAPH::m_multiple_drivers, CONNECTION_SUBGRAPH::m_second_driver, CONNECTION_SUBGRAPH::m_sheet, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckNetclassConflicts()

bool CONNECTION_GRAPH::ercCheckNetclassConflicts ( const std::vector< CONNECTION_SUBGRAPH * > &  subgraphs)
private

Definition at line 2478 of file connection_graph.cpp.

2479{
2480 wxString firstNetclass;
2481 SCH_ITEM* firstNetclassDriver = nullptr;
2482
2483 for( const CONNECTION_SUBGRAPH* subgraph : subgraphs )
2484 {
2485 for( SCH_ITEM* item : subgraph->m_items )
2486 {
2487 const wxString netclass = subgraph->GetNetclassForDriver( item );
2488
2489 if( netclass.IsEmpty() )
2490 continue;
2491
2492 if( netclass != firstNetclass )
2493 {
2494 if( !firstNetclassDriver )
2495 {
2496 firstNetclass = netclass;
2497 firstNetclassDriver = item;
2498 continue;
2499 }
2500
2501 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NETCLASS_CONFLICT );
2502 ercItem->SetItems( firstNetclassDriver, item );
2503
2504 SCH_MARKER* marker = new SCH_MARKER( ercItem, item->GetPosition() );
2505 subgraph->m_sheet.LastScreen()->Append( marker );
2506
2507 return false;
2508 }
2509 }
2510 }
2511
2512 return true;
2513}
@ ERCE_NETCLASS_CONFLICT
Multiple labels assign different netclasses to same net.
Definition: erc_settings.h:64

References ERC_ITEM::Create(), ERCE_NETCLASS_CONFLICT, and EDA_ITEM::GetPosition().

Referenced by RunERC().

◆ ercCheckNoConnects()

bool CONNECTION_GRAPH::ercCheckNoConnects ( const CONNECTION_SUBGRAPH aSubgraph)
private

Checks one subgraph for proper presence or absence of no-connect symbols.

A pin with a no-connect symbol should not have any connections A pin without a no-connect symbol should have at least one connection

Parameters
aSubgraphis the subgraph to examine
Returns
true for no errors, false for errors

Definition at line 2739 of file connection_graph.cpp.

2740{
2741 ERC_SETTINGS& settings = m_schematic->ErcSettings();
2742 const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2743 SCH_SCREEN* screen = sheet.LastScreen();
2744 bool ok = true;
2745
2746 if( aSubgraph->m_no_connect != nullptr )
2747 {
2748 SCH_PIN* pin = nullptr;
2749 std::set<SCH_ITEM*> unique_items;
2750
2751 // Any subgraph that contains both a pin and a no-connect should not
2752 // contain any other driving items.
2753
2754 for( SCH_ITEM* item : aSubgraph->m_items )
2755 {
2756 switch( item->Type() )
2757 {
2758 case SCH_PIN_T:
2759 {
2760 pin = static_cast<SCH_PIN*>( item );
2761
2762 // Insert the pin's parent so that we don't flag stacked pins
2763 if( auto [existing, success] = unique_items.insert(
2764 static_cast<SCH_ITEM*>( pin->GetParent() ) ); !success )
2765 {
2766 SCH_PIN* ex_pin = static_cast<SCH_PIN*>( *existing );
2767
2768 // Stacked pins don't count as connected
2769 // but if they are not stacked, but still in the same symbol
2770 // flag this for an error
2771 if( !pin->IsStacked( ex_pin ) )
2772 unique_items.insert( ex_pin );
2773 }
2774
2775 break;
2776 }
2777
2778 case SCH_LINE_T:
2779 case SCH_JUNCTION_T:
2780 case SCH_NO_CONNECT_T:
2781 break;
2782
2783 default:
2784 unique_items.insert( item );
2785 }
2786 }
2787
2788 if( unique_items.size() > 1 && pin && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
2789 {
2790 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
2791 ercItem->SetItems( pin );
2792
2793 SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2794 screen->Append( marker );
2795
2796 ok = false;
2797 }
2798
2799 if( unique_items.empty() && settings.IsTestEnabled( ERCE_NOCONNECT_NOT_CONNECTED ) )
2800 {
2801 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
2802 ercItem->SetItems( aSubgraph->m_no_connect );
2803
2804 SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
2805 screen->Append( marker );
2806
2807 ok = false;
2808 }
2809 }
2810 else
2811 {
2812 bool has_other_connections = false;
2813 std::vector<SCH_PIN*> pins;
2814
2815 // Any subgraph that lacks a no-connect and contains a pin should also
2816 // contain at least one other potential driver
2817
2818 for( SCH_ITEM* item : aSubgraph->m_items )
2819 {
2820 switch( item->Type() )
2821 {
2822 case SCH_PIN_T:
2823 {
2824 // Stacked pins do not count as other connections but non-stacked pins do
2825 if( !has_other_connections && !pins.empty() )
2826 {
2827 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
2828
2829 for( SCH_PIN* other_pin : pins )
2830 {
2831 if( other_pin->GetParent() != pin->GetParent()
2832 || other_pin->GetPosition() != pin->GetPosition() )
2833 {
2834 has_other_connections = true;
2835 break;
2836 }
2837 }
2838 }
2839
2840 pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2841
2842 break;
2843 }
2844
2845 default:
2846 if( aSubgraph->GetDriverPriority( item ) != CONNECTION_SUBGRAPH::PRIORITY::NONE )
2847 has_other_connections = true;
2848
2849 break;
2850 }
2851 }
2852
2853 // For many checks, we can just use the first pin
2854 SCH_PIN* pin = pins.empty() ? nullptr : pins[0];
2855
2856 // Check if invisible power input pins connect to anything else via net name,
2857 // but not for power symbols as the ones in the standard library all have invisible pins
2858 // and we want to throw unconnected errors for those even if they are connected to other
2859 // net items by name, because usually failing to connect them graphically is a mistake
2860 if( pin && !has_other_connections
2861 && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
2862 && !pin->IsVisible()
2863 && !pin->GetLibPin()->GetParent()->IsPower() )
2864 {
2865 wxString name = pin->Connection( &sheet )->Name();
2866 wxString local_name = pin->Connection( &sheet )->Name( true );
2867
2868 if( m_global_label_cache.count( name )
2869 || m_local_label_cache.count( std::make_pair( sheet, local_name ) ) )
2870 {
2871 has_other_connections = true;
2872 }
2873 }
2874
2875 // Only one pin, and it's not a no-connect pin
2876 if( pin && !has_other_connections
2877 && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
2878 && pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
2879 && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2880 {
2881 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2882 ercItem->SetItems( pin );
2883
2884 SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2885 screen->Append( marker );
2886
2887 ok = false;
2888 }
2889
2890 // If there are multiple pins in this SG, they might be indirectly connected (by netname)
2891 // rather than directly connected (by wires). We want to flag dangling pins even if they
2892 // join nets with another pin, as it's often a mistake
2893 if( pins.size() > 1 )
2894 {
2895 for( SCH_PIN* testPin : pins )
2896 {
2897 // We only apply this test to power symbols, because other symbols have invisible
2898 // pins that are meant to be dangling, but the KiCad standard library power symbols
2899 // have invisible pins that are *not* meant to be dangling.
2900 if( testPin->GetLibPin()->GetParent()->IsPower()
2901 && testPin->ConnectedItems( sheet ).empty()
2902 && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2903 {
2904 std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2905 ercItem->SetItems( testPin );
2906
2907 SCH_MARKER* marker = new SCH_MARKER( ercItem,
2908 testPin->GetTransformedPosition() );
2909 screen->Append( marker );
2910
2911 ok = false;
2912 }
2913 }
2914 }
2915 }
2916
2917 return ok;
2918}
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
@ ERCE_NOCONNECT_NOT_CONNECTED
A no connect symbol is not connected to anything.
Definition: erc_settings.h:49
@ ERCE_NOCONNECT_CONNECTED
A no connect symbol is connected to more than 1 pin.
Definition: erc_settings.h:48
@ 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.
@ SCH_JUNCTION_T
Definition: typeinfo.h:141

References SCH_SCREEN::Append(), ERC_ITEM::Create(), ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), CONNECTION_SUBGRAPH::GetDriverPriority(), EDA_ITEM::GetPosition(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), m_global_label_cache, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, name, CONNECTION_SUBGRAPH::NONE, pin, PT_NC, PT_NIC, PT_POWER_IN, SCH_JUNCTION_T, SCH_LINE_T, SCH_NO_CONNECT_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by RunERC().

◆ FindFirstSubgraphByName()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::FindFirstSubgraphByName ( const wxString &  aNetName)

Retrieves a subgraph for the given net name, if one exists.

Searches every sheet

Parameters
aNetNameis the full net name to search for
Returns
the subgraph matching the query, or nullptr if none is found

Definition at line 2273 of file connection_graph.cpp.

2274{
2275 auto it = m_net_name_to_subgraphs_map.find( aNetName );
2276
2277 if( it == m_net_name_to_subgraphs_map.end() )
2278 return nullptr;
2279
2280 wxASSERT( !it->second.empty() );
2281
2282 return it->second[0];
2283}

References m_net_name_to_subgraphs_map.

◆ FindSubgraphByName()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::FindSubgraphByName ( const wxString &  aNetName,
const SCH_SHEET_PATH aPath 
)

Returns the subgraph for a given net name on a given sheet.

Parameters
aNetNameis the local net name to look for
aPathis a sheet path to look on
Returns
the subgraph matching the query, or nullptr if none is found

Definition at line 2252 of file connection_graph.cpp.

2254{
2255 auto it = m_net_name_to_subgraphs_map.find( aNetName );
2256
2257 if( it == m_net_name_to_subgraphs_map.end() )
2258 return nullptr;
2259
2260 for( CONNECTION_SUBGRAPH* sg : it->second )
2261 {
2262 // Cache is supposed to be valid by now
2263 wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
2264
2265 if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
2266 return sg;
2267 }
2268
2269 return nullptr;
2270}

References CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_driver_connection, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_sheet, and SCH_CONNECTION::Name().

Referenced by NETLIST_EXPORTER_BASE::CreatePinList(), and NETLIST_EXPORTER_BASE::findAllUnitsOfSymbol().

◆ generateInvisiblePinSubGraphs()

void CONNECTION_GRAPH::generateInvisiblePinSubGraphs ( )
private

Iterate through the invisible power pins to collect the global labels as drivers.

Definition at line 1000 of file connection_graph.cpp.

1001{
1002 // Generate subgraphs for invisible power pins. These will be merged with other subgraphs
1003 // on the same sheet in the next loop.
1004
1005 std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
1006
1007 for( const auto& it : m_invisible_power_pins )
1008 {
1009 SCH_SHEET_PATH sheet = it.first;
1010 SCH_PIN* pin = it.second;
1011
1012 if( !pin->ConnectedItems( sheet ).empty() && !pin->GetLibPin()->GetParent()->IsPower() )
1013 {
1014 // ERC will warn about this: user has wired up an invisible pin
1015 continue;
1016 }
1017
1018 SCH_CONNECTION* connection = pin->GetOrInitConnection( sheet, this );
1019
1020 // If this pin already has a subgraph, don't need to process
1021 if( !connection || connection->SubgraphCode() > 0 )
1022 continue;
1023
1024 connection->SetName( pin->GetShownName() );
1025
1026 int code = assignNewNetCode( *connection );
1027
1028 connection->SetNetCode( code );
1029
1030 CONNECTION_SUBGRAPH* subgraph;
1031 auto jj = invisible_pin_subgraphs.find( code );
1032
1033 if( jj != invisible_pin_subgraphs.end() )
1034 {
1035 subgraph = jj->second;
1036 subgraph->AddItem( pin );
1037 }
1038 else
1039 {
1040 subgraph = new CONNECTION_SUBGRAPH( this );
1041
1042 subgraph->m_code = m_last_subgraph_code++;
1043 subgraph->m_sheet = sheet;
1044
1045 subgraph->AddItem( pin );
1046 subgraph->ResolveDrivers();
1047
1048 NET_NAME_CODE_CACHE_KEY key = { subgraph->GetNetName(), code };
1049 m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1050 m_subgraphs.push_back( subgraph );
1051 m_driver_subgraphs.push_back( subgraph );
1052
1053 invisible_pin_subgraphs[code] = subgraph;
1054 }
1055
1056 connection->SetSubgraphCode( subgraph->m_code );
1057 }
1058}
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
void SetName(const wxString &aName)

References CONNECTION_SUBGRAPH::AddItem(), assignNewNetCode(), CONNECTION_SUBGRAPH::GetNetName(), CONNECTION_SUBGRAPH::m_code, m_driver_subgraphs, m_invisible_power_pins, m_last_subgraph_code, m_net_code_to_subgraphs_map, CONNECTION_SUBGRAPH::m_sheet, m_subgraphs, pin, CONNECTION_SUBGRAPH::ResolveDrivers(), SCH_CONNECTION::SetName(), SCH_CONNECTION::SetNetCode(), SCH_CONNECTION::SetSubgraphCode(), and SCH_CONNECTION::SubgraphCode().

Referenced by buildConnectionGraph().

◆ GetBusAlias()

std::shared_ptr< BUS_ALIAS > CONNECTION_GRAPH::GetBusAlias ( const wxString &  aName)

Returns a bus alias pointer for the given name if it exists (from cache)

CONNECTION_GRAPH caches these, they are owned by the SCH_SCREEN that the alias was defined on. The cache is only used to update the graph.

Definition at line 2197 of file connection_graph.cpp.

2198{
2199 auto it = m_bus_alias_cache.find( aName );
2200
2201 return it != m_bus_alias_cache.end() ? it->second : nullptr;
2202}

References m_bus_alias_cache.

Referenced by SCH_CONNECTION::AppendInfoToMsgPanel(), and SCH_CONNECTION::ConfigureFromLabel().

◆ GetBusesNeedingMigration()

std::vector< const CONNECTION_SUBGRAPH * > CONNECTION_GRAPH::GetBusesNeedingMigration ( )

Determines which subgraphs have more than one conflicting bus label.

See also
DIALOG_MIGRATE_BUSES
Returns
a list of subgraphs that need migration

Definition at line 2205 of file connection_graph.cpp.

2206{
2207 std::vector<const CONNECTION_SUBGRAPH*> ret;
2208
2209 for( CONNECTION_SUBGRAPH* subgraph : m_subgraphs )
2210 {
2211 // Graph is supposed to be up-to-date before calling this
2212 wxASSERT( !subgraph->m_dirty );
2213
2214 if( !subgraph->m_driver )
2215 continue;
2216
2217 SCH_CONNECTION* connection = subgraph->m_driver->Connection( &subgraph->m_sheet );
2218
2219 if( !connection->IsBus() )
2220 continue;
2221
2222 auto labels = subgraph->GetBusLabels();
2223
2224 if( labels.size() > 1 )
2225 {
2226 bool different = false;
2227 wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2228
2229 for( unsigned i = 1; i < labels.size(); ++i )
2230 {
2231 if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2232 {
2233 different = true;
2234 break;
2235 }
2236 }
2237
2238 if( !different )
2239 continue;
2240
2241 wxLogTrace( ConnTrace, "SG %ld (%s) has multiple bus labels", subgraph->m_code,
2242 connection->Name() );
2243
2244 ret.push_back( subgraph );
2245 }
2246 }
2247
2248 return ret;
2249}
SCH_ITEM * m_driver
The SCH_ITEM that drives this connection's net.
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: sch_text.cpp:337

References SCH_ITEM::Connection(), ConnTrace, SCH_TEXT::GetShownText(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::m_driver, m_subgraphs, and SCH_CONNECTION::Name().

Referenced by DIALOG_MIGRATE_BUSES::loadGraphData().

◆ getDefaultConnection()

std::shared_ptr< SCH_CONNECTION > CONNECTION_GRAPH::getDefaultConnection ( SCH_ITEM aItem,
CONNECTION_SUBGRAPH aSubgraph 
)
private

Builds a new default connection for the given item based on its properties.

Handles strong drivers (power pins and labels) only

Parameters
aItemis an item that can generate a connection name
aSubgraphis used to determine the sheet to use and retrieve the cached name
Returns
a connection generated from the item, or nullptr if item is not valid

Definition at line 2088 of file connection_graph.cpp.

2090{
2091 std::shared_ptr<SCH_CONNECTION> c = std::shared_ptr<SCH_CONNECTION>( nullptr );
2092
2093 switch( aItem->Type() )
2094 {
2095 case SCH_PIN_T:
2096 {
2097 SCH_PIN* pin = static_cast<SCH_PIN*>( aItem );
2098
2099 if( pin->IsPowerConnection() )
2100 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
2101
2102 break;
2103 }
2104
2105 case SCH_GLOBAL_LABEL_T:
2106 case SCH_HIER_LABEL_T:
2107 case SCH_LABEL_T:
2108 {
2109 c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
2110 break;
2111 }
2112
2113 default:
2114 break;
2115 }
2116
2117 if( c )
2118 {
2119 c->SetGraph( this );
2120 c->ConfigureFromLabel( aSubgraph->GetNameForDriver( aItem ) );
2121 }
2122
2123 return c;
2124}

References CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::m_sheet, pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by processSubGraphs(), and propagateToNeighbors().

◆ GetNetMap()

◆ GetSubgraphForItem()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::GetSubgraphForItem ( SCH_ITEM aItem)

Definition at line 2286 of file connection_graph.cpp.

2287{
2288 auto it = m_item_to_subgraph_map.find( aItem );
2289 CONNECTION_SUBGRAPH* ret = it != m_item_to_subgraph_map.end() ? it->second : nullptr;
2290
2291 while( ret && ret->m_absorbed )
2292 ret = ret->m_absorbed_by;
2293
2294 return ret;
2295}

References CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, and m_item_to_subgraph_map.

Referenced by SCH_EDITOR_CONTROL::UpdateNetHighlighting().

◆ matchBusMember()

SCH_CONNECTION * CONNECTION_GRAPH::matchBusMember ( SCH_CONNECTION aBusConnection,
SCH_CONNECTION aSearch 
)
staticprivate

Search for a matching bus member inside a bus connection.

For bus groups, this returns a bus member that matches aSearch by name. For bus vectors, this returns a bus member that matches by vector index.

Parameters
aBusConnectionis the bus connection to search
aSearchis the net connection to search for
Returns
a member of aBusConnection that matches aSearch

Definition at line 2127 of file connection_graph.cpp.

2129{
2130 wxASSERT( aBusConnection->IsBus() );
2131
2132 SCH_CONNECTION* match = nullptr;
2133
2134 if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
2135 {
2136 // Vector bus: compare against index, because we allow the name
2137 // to be different
2138
2139 for( const std::shared_ptr<SCH_CONNECTION>& bus_member : aBusConnection->Members() )
2140 {
2141 if( bus_member->VectorIndex() == aSearch->VectorIndex() )
2142 {
2143 match = bus_member.get();
2144 break;
2145 }
2146 }
2147 }
2148 else
2149 {
2150 // Group bus
2151 for( const std::shared_ptr<SCH_CONNECTION>& c : aBusConnection->Members() )
2152 {
2153 // Vector inside group: compare names, because for bus groups
2154 // we expect the naming to be consistent across all usages
2155 // TODO(JE) explain this in the docs
2156 if( c->Type() == CONNECTION_TYPE::BUS )
2157 {
2158 for( const std::shared_ptr<SCH_CONNECTION>& bus_member : c->Members() )
2159 {
2160 if( bus_member->LocalName() == aSearch->LocalName() )
2161 {
2162 match = bus_member.get();
2163 break;
2164 }
2165 }
2166 }
2167 else if( c->LocalName() == aSearch->LocalName() )
2168 {
2169 match = c.get();
2170 break;
2171 }
2172 }
2173 }
2174
2175 return match;
2176}
CONNECTION_TYPE Type() const
wxString LocalName() const
long VectorIndex() const

References BUS, SCH_CONNECTION::IsBus(), SCH_CONNECTION::LocalName(), SCH_CONNECTION::Members(), SCH_CONNECTION::Type(), and SCH_CONNECTION::VectorIndex().

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ processSubGraphs()

void CONNECTION_GRAPH::processSubGraphs ( )
private

Process all subgraphs to assign netcodes and merge subgraphs based on labels.

Definition at line 1061 of file connection_graph.cpp.

1062{
1063 // Here we do all the local (sheet) processing of each subgraph, including assigning net
1064 // codes, merging subgraphs together that use label connections, etc.
1065
1066 // Cache remaining valid subgraphs by sheet path
1067 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1068 m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1069
1070 std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
1071
1072 for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1073 {
1074 if( subgraph->m_absorbed )
1075 continue;
1076
1077 SCH_CONNECTION* connection = subgraph->m_driver_connection;
1078 SCH_SHEET_PATH sheet = subgraph->m_sheet;
1079 wxString name = connection->Name();
1080
1081 // Test subgraphs with weak drivers for net name conflicts and fix them
1082 unsigned suffix = 1;
1083
1084 auto create_new_name =
1085 [&suffix]( SCH_CONNECTION* aConn ) -> wxString
1086 {
1087 wxString newName;
1088 wxString suffixStr = std::to_wstring( suffix );
1089
1090 // For group buses with a prefix, we can add the suffix to the prefix.
1091 // If they don't have a prefix, we force the creation of a prefix so that
1092 // two buses don't get inadvertently shorted together.
1093 if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1094 {
1095 wxString prefix = aConn->BusPrefix();
1096
1097 if( prefix.empty() )
1098 prefix = wxT( "BUS" ); // So result will be "BUS_1{...}"
1099
1100 wxString oldName = aConn->Name().AfterFirst( '{' );
1101
1102 newName << prefix << wxT( "_" ) << suffixStr << wxT( "{" ) << oldName;
1103
1104 aConn->ConfigureFromLabel( newName );
1105 }
1106 else
1107 {
1108 newName << aConn->Name() << wxT( "_" ) << suffixStr;
1109 aConn->SetSuffix( wxString( wxT( "_" ) ) << suffixStr );
1110 }
1111
1112 suffix++;
1113 return newName;
1114 };
1115
1116 if( !subgraph->m_strong_driver )
1117 {
1118 std::vector<CONNECTION_SUBGRAPH*>* vec = &m_net_name_to_subgraphs_map.at( name );
1119
1120 // If we are a unique bus vector, check if we aren't actually unique because of another
1121 // subgraph with a similar bus vector
1122 if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1123 {
1124 wxString prefixOnly = name.BeforeFirst( '[' ) + wxT( "[]" );
1125 vec = &m_net_name_to_subgraphs_map.at( prefixOnly );
1126 }
1127
1128 if( vec->size() > 1 )
1129 {
1130 wxString new_name = create_new_name( connection );
1131
1132 while( m_net_name_to_subgraphs_map.count( new_name ) )
1133 new_name = create_new_name( connection );
1134
1135 wxLogTrace( ConnTrace, "%ld (%s) is weakly driven and not unique. Changing to %s.",
1136 subgraph->m_code, name, new_name );
1137
1138 alg::delete_matching( *vec, subgraph );
1139
1140 m_net_name_to_subgraphs_map[new_name].emplace_back( subgraph );
1141
1142 name = new_name;
1143 }
1144 else
1145 {
1146 // If there is no conflict, promote sheet pins to be strong drivers so that they
1147 // will be considered below for propagation/merging.
1148
1149 // It is possible for this to generate a conflict if the sheet pin has the same
1150 // name as a global label on the same sheet, because global merging will then treat
1151 // this subgraph as if it had a matching local label. So, for those cases, we
1152 // don't apply this promotion
1153
1154 if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1155 {
1156 bool conflict = false;
1157 wxString global_name = connection->Name( true );
1158 auto kk = m_net_name_to_subgraphs_map.find( global_name );
1159
1160 if( kk != m_net_name_to_subgraphs_map.end() )
1161 {
1162 // A global will conflict if it is on the same sheet as this subgraph, since
1163 // it would be connected by implicit local label linking
1164 std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1165
1166 for( const CONNECTION_SUBGRAPH* candidate : candidates )
1167 {
1168 if( candidate->m_sheet == sheet )
1169 conflict = true;
1170 }
1171 }
1172
1173 if( conflict )
1174 {
1175 wxLogTrace( ConnTrace,
1176 "%ld (%s) skipped for promotion due to potential conflict",
1177 subgraph->m_code, name );
1178 }
1179 else
1180 {
1182
1183 wxLogTrace( ConnTrace,
1184 "%ld (%s) weakly driven by unique sheet pin %s, promoting",
1185 subgraph->m_code, name,
1186 subgraph->m_driver->GetSelectMenuText( &unitsProvider ) );
1187
1188 subgraph->m_strong_driver = true;
1189 }
1190 }
1191 }
1192 }
1193
1194 // Assign net codes
1195
1196 if( connection->IsBus() )
1197 {
1198 int code = -1;
1199 auto it = m_bus_name_to_code_map.find( name );
1200
1201 if( it != m_bus_name_to_code_map.end() )
1202 {
1203 code = it->second;
1204 }
1205 else
1206 {
1207 code = m_last_bus_code++;
1208 m_bus_name_to_code_map[ name ] = code;
1209 }
1210
1211 connection->SetBusCode( code );
1212 assignNetCodesToBus( connection );
1213 }
1214 else
1215 {
1216 assignNewNetCode( *connection );
1217 }
1218
1219 // Reset the flag for the next loop below
1220 subgraph->m_dirty = true;
1221
1222 // Next, we merge together subgraphs that have label connections, and create
1223 // neighbor links for subgraphs that are part of a bus on the same sheet.
1224 // For merging, we consider each possible strong driver.
1225
1226 // If this subgraph doesn't have a strong driver, let's skip it, since there is no
1227 // way it will be merged with anything.
1228
1229 if( !subgraph->m_strong_driver )
1230 continue;
1231
1232 // candidate_subgraphs will contain each valid, non-bus subgraph on the same sheet
1233 // as the subgraph we are considering that has a strong driver.
1234 // Weakly driven subgraphs are not considered since they will never be absorbed or
1235 // form neighbor links.
1236
1237 std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1238 std::copy_if( m_sheet_to_subgraphs_map[ subgraph->m_sheet ].begin(),
1239 m_sheet_to_subgraphs_map[ subgraph->m_sheet ].end(),
1240 std::back_inserter( candidate_subgraphs ),
1241 [&] ( const CONNECTION_SUBGRAPH* candidate )
1242 {
1243 return ( !candidate->m_absorbed &&
1244 candidate->m_strong_driver &&
1245 candidate != subgraph );
1246 } );
1247
1248 // This is a list of connections on the current subgraph to compare to the
1249 // drivers of each candidate subgraph. If the current subgraph is a bus,
1250 // we should consider each bus member.
1251 std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1252
1253 // Also check the main driving connection
1254 connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1255
1256 auto add_connections_to_check =
1257 [&] ( CONNECTION_SUBGRAPH* aSubgraph )
1258 {
1259 for( SCH_ITEM* possible_driver : aSubgraph->m_items )
1260 {
1261 if( possible_driver == aSubgraph->m_driver )
1262 continue;
1263
1264 auto c = getDefaultConnection( possible_driver, aSubgraph );
1265
1266 if( c )
1267 {
1268 if( c->Type() != aSubgraph->m_driver_connection->Type() )
1269 continue;
1270
1271 if( c->Name( true ) == aSubgraph->m_driver_connection->Name( true ) )
1272 continue;
1273
1274 connections_to_check.push_back( c );
1275 wxLogTrace( ConnTrace,
1276 "%lu (%s): Adding secondary driver %s", aSubgraph->m_code,
1277 aSubgraph->m_driver_connection->Name( true ),
1278 c->Name( true ) );
1279 }
1280 }
1281 };
1282
1283 // Now add other strong drivers
1284 // The actual connection attached to these items will have been overwritten
1285 // by the chosen driver of the subgraph, so we need to create a dummy connection
1286 add_connections_to_check( subgraph );
1287
1288 for( unsigned i = 0; i < connections_to_check.size(); i++ )
1289 {
1290 auto member = connections_to_check[i];
1291
1292 if( member->IsBus() )
1293 {
1294 connections_to_check.insert( connections_to_check.end(),
1295 member->Members().begin(),
1296 member->Members().end() );
1297 }
1298
1299 wxString test_name = member->Name( true );
1300
1301 for( CONNECTION_SUBGRAPH* candidate : candidate_subgraphs )
1302 {
1303 if( candidate->m_absorbed )
1304 continue;
1305
1306 bool match = false;
1307
1308 if( candidate->m_driver_connection->Name( true ) == test_name )
1309 {
1310 match = true;
1311 }
1312 else
1313 {
1314 if( !candidate->m_multiple_drivers )
1315 continue;
1316
1317 for( SCH_ITEM *driver : candidate->m_drivers )
1318 {
1319 if( driver == candidate->m_driver )
1320 continue;
1321
1322 // Sheet pins are not candidates for merging
1323 if( driver->Type() == SCH_SHEET_PIN_T )
1324 continue;
1325
1326 if( driver->Type() == SCH_PIN_T )
1327 {
1328 auto pin = static_cast<SCH_PIN*>( driver );
1329
1330 if( pin->IsPowerConnection() && pin->GetShownName() == test_name )
1331 {
1332 match = true;
1333 break;
1334 }
1335 }
1336 else
1337 {
1338 wxASSERT( driver->Type() == SCH_LABEL_T ||
1339 driver->Type() == SCH_GLOBAL_LABEL_T ||
1340 driver->Type() == SCH_HIER_LABEL_T );
1341
1342 if( subgraph->GetNameForDriver( driver ) == test_name )
1343 {
1344 match = true;
1345 break;
1346 }
1347 }
1348 }
1349 }
1350
1351 if( match )
1352 {
1353 if( connection->IsBus() && candidate->m_driver_connection->IsNet() )
1354 {
1355 wxLogTrace( ConnTrace, "%lu (%s) has bus child %lu (%s)", subgraph->m_code,
1356 connection->Name(), candidate->m_code, member->Name() );
1357
1358 subgraph->m_bus_neighbors[member].insert( candidate );
1359 candidate->m_bus_parents[member].insert( subgraph );
1360 }
1361 else
1362 {
1363 wxLogTrace( ConnTrace, "%lu (%s) absorbs neighbor %lu (%s)",
1364 subgraph->m_code, connection->Name(),
1365 candidate->m_code, candidate->m_driver_connection->Name() );
1366
1367 // Candidate may have other non-chosen drivers we need to follow
1368 add_connections_to_check( candidate );
1369
1370 subgraph->Absorb( candidate );
1371 invalidated_subgraphs.insert( subgraph );
1372 }
1373 }
1374 }
1375 }
1376 }
1377
1378 // Update any subgraph that was invalidated above
1379 for( CONNECTION_SUBGRAPH* subgraph : invalidated_subgraphs )
1380 {
1381 if( subgraph->m_absorbed )
1382 continue;
1383
1384 subgraph->ResolveDrivers();
1385
1386 if( subgraph->m_driver_connection->IsBus() )
1387 assignNetCodesToBus( subgraph->m_driver_connection );
1388 else
1389 assignNewNetCode( *subgraph->m_driver_connection );
1390
1391 wxLogTrace( ConnTrace, "Re-resolving drivers for %lu (%s)", subgraph->m_code,
1392 subgraph->m_driver_connection->Name() );
1393 }
1394
1395}
std::shared_ptr< SCH_CONNECTION > getDefaultConnection(SCH_ITEM *aItem, CONNECTION_SUBGRAPH *aSubgraph)
Builds a new default connection for the given item based on its properties.
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensures all members of the bus connection have a valid net code assigned.
std::unordered_map< wxString, int > m_bus_name_to_code_map
void SetBusCode(int aCode)
void delete_matching(_Container &__c, _Value __value)
Covers for the horrifically named std::remove and std::remove_if (neither of which remove anything).
Definition: kicad_algo.h:164
@ BUS_GROUP
This item represents a bus group.

References assignNetCodesToBus(), assignNewNetCode(), BUS, BUS_GROUP, ConnTrace, alg::delete_matching(), getDefaultConnection(), SCH_CONNECTION::IsBus(), SCH_CONNECTION::IsNet(), CONNECTION_SUBGRAPH::m_absorbed, m_bus_name_to_code_map, CONNECTION_SUBGRAPH::m_bus_parents, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, m_driver_subgraphs, CONNECTION_SUBGRAPH::m_drivers, m_last_bus_code, CONNECTION_SUBGRAPH::m_multiple_drivers, m_net_name_to_subgraphs_map, m_sheet_to_subgraphs_map, MILLIMETRES, name, SCH_CONNECTION::Name(), pin, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, schIUScale, SCH_CONNECTION::SetBusCode(), and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ propagateToNeighbors()

void CONNECTION_GRAPH::propagateToNeighbors ( CONNECTION_SUBGRAPH aSubgraph)
private

Updates all neighbors of a subgraph with this one's connectivity info.

If this subgraph contains hierarchical links, this method will descent the hierarchy and propagate the connectivity across all linked sheets.

Definition at line 1770 of file connection_graph.cpp.

1771{
1772 SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1773 std::vector<CONNECTION_SUBGRAPH*> search_list;
1774 std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1775 std::vector<SCH_CONNECTION*> stale_bus_members;
1776
1777 auto visit =
1778 [&]( CONNECTION_SUBGRAPH* aParent )
1779 {
1780 for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1781 {
1782 SCH_SHEET_PATH path = aParent->m_sheet;
1783 path.push_back( pin->GetParent() );
1784
1785 auto it = m_sheet_to_subgraphs_map.find( path );
1786
1787 if( it == m_sheet_to_subgraphs_map.end() )
1788 continue;
1789
1790 for( CONNECTION_SUBGRAPH* candidate : it->second )
1791 {
1792 if( !candidate->m_strong_driver
1793 || candidate->m_hier_ports.empty()
1794 || visited.count( candidate ) )
1795 {
1796 continue;
1797 }
1798
1799 for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1800 {
1801 if( candidate->GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1802 {
1803 wxLogTrace( ConnTrace, "%lu: found child %lu (%s)", aParent->m_code,
1804 candidate->m_code, candidate->m_driver_connection->Name() );
1805
1806 candidate->m_hier_parent = aParent;
1807
1808 search_list.push_back( candidate );
1809 break;
1810 }
1811 }
1812 }
1813 }
1814
1815 for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1816 {
1817 SCH_SHEET_PATH path = aParent->m_sheet;
1818 path.pop_back();
1819
1820 auto it = m_sheet_to_subgraphs_map.find( path );
1821
1822 if( it == m_sheet_to_subgraphs_map.end() )
1823 continue;
1824
1825 for( CONNECTION_SUBGRAPH* candidate : it->second )
1826 {
1827 if( candidate->m_hier_pins.empty()
1828 || visited.count( candidate )
1829 || candidate->m_driver_connection->Type() != aParent->m_driver_connection->Type() )
1830 {
1831 continue;
1832 }
1833
1834 const KIID& last_parent_uuid = aParent->m_sheet.Last()->m_Uuid;
1835
1836 for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1837 {
1838 // If the last sheet UUIDs won't match, no need to check the full path
1839 if( pin->GetParent()->m_Uuid != last_parent_uuid )
1840 continue;
1841
1842 SCH_SHEET_PATH pin_path = path;
1843 pin_path.push_back( pin->GetParent() );
1844
1845 if( pin_path != aParent->m_sheet )
1846 continue;
1847
1848 if( aParent->GetNameForDriver( label ) == candidate->GetNameForDriver( pin ) )
1849 {
1850 wxLogTrace( ConnTrace, "%lu: found additional parent %lu (%s)",
1851 aParent->m_code, candidate->m_code,
1852 candidate->m_driver_connection->Name() );
1853
1854 search_list.push_back( candidate );
1855 break;
1856 }
1857 }
1858 }
1859 }
1860 };
1861
1862 auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1863 for( const auto& kv : aParentGraph->m_bus_neighbors )
1864 {
1865 for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1866 {
1867 // May have been absorbed but won't have been deleted
1868 while( neighbor->m_absorbed )
1869 neighbor = neighbor->m_absorbed_by;
1870
1871 SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1872
1873 // Now member may be out of date, since we just cloned the
1874 // connection from higher up in the hierarchy. We need to
1875 // figure out what the actual new connection is.
1876 SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1877
1878 if( !member )
1879 {
1880 // Try harder: we might match on a secondary driver
1881 for( CONNECTION_SUBGRAPH* sg : kv.second )
1882 {
1883 if( sg->m_multiple_drivers )
1884 {
1885 SCH_SHEET_PATH sheet = sg->m_sheet;
1886
1887 for( SCH_ITEM* driver : sg->m_drivers )
1888 {
1889 auto c = getDefaultConnection( driver, sg );
1890 member = matchBusMember( parent, c.get() );
1891
1892 if( member )
1893 break;
1894 }
1895 }
1896
1897 if( member )
1898 break;
1899 }
1900 }
1901
1902 // This is bad, probably an ERC error
1903 if( !member )
1904 {
1905 wxLogTrace( ConnTrace, "Could not match bus member %s in %s",
1906 kv.first->Name(), parent->Name() );
1907 continue;
1908 }
1909
1910 auto neighbor_conn = neighbor->m_driver_connection;
1911 auto neighbor_name = neighbor_conn->Name();
1912
1913 // Matching name: no update needed
1914 if( neighbor_name == member->Name() )
1915 continue;
1916
1917 // Was this neighbor already updated from a different sheet? Don't rename it again
1918 if( neighbor_conn->Sheet() != neighbor->m_sheet )
1919 continue;
1920
1921 // Safety check against infinite recursion
1922 wxASSERT( neighbor_conn->IsNet() );
1923
1924 wxLogTrace( ConnTrace, "%lu (%s) connected to bus member %s (local %s)",
1925 neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1926
1927 // Take whichever name is higher priority
1930 {
1931 member->Clone( *neighbor_conn );
1932 stale_bus_members.push_back( member );
1933 }
1934 else
1935 {
1936 neighbor_conn->Clone( *member );
1937
1938 recacheSubgraphName( neighbor, neighbor_name );
1939
1940 // Recurse onto this neighbor in case it needs to re-propagate
1941 neighbor->m_dirty = true;
1942 propagateToNeighbors( neighbor );
1943 }
1944 }
1945 }
1946 };
1947
1948 // If we are a bus, we must propagate to local neighbors and then the hierarchy
1949 if( conn->IsBus() )
1950 propagate_bus_neighbors( aSubgraph );
1951
1952 // If we have both ports and pins, skip processing as we'll be visited by a parent or child.
1953 // If we only have one or the other, process (we can either go bottom-up or top-down depending
1954 // on which subgraph comes up first)
1955 if( !aSubgraph->m_hier_ports.empty() && !aSubgraph->m_hier_pins.empty() )
1956 {
1957 wxLogTrace( ConnTrace, "%lu (%s) has both hier ports and pins; deferring processing",
1958 aSubgraph->m_code, conn->Name() );
1959 return;
1960 }
1961 else if( aSubgraph->m_hier_ports.empty() && aSubgraph->m_hier_pins.empty() )
1962 {
1963 wxLogTrace( ConnTrace, "%lu (%s) has no hier pins or ports; marking clean",
1964 aSubgraph->m_code, conn->Name() );
1965 aSubgraph->m_dirty = false;
1966 return;
1967 }
1968
1969 visited.insert( aSubgraph );
1970
1971 wxLogTrace( ConnTrace, "Propagating %lu (%s) to subsheets",
1972 aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1973
1974 visit( aSubgraph );
1975
1976 for( unsigned i = 0; i < search_list.size(); i++ )
1977 {
1978 auto child = search_list[i];
1979
1980 visited.insert( child );
1981
1982 visit( child );
1983
1984 child->m_dirty = false;
1985 }
1986
1987 // Now, find the best driver for this chain of subgraphs
1988 CONNECTION_SUBGRAPH* bestDriver = aSubgraph;
1991 bool bestIsStrong = ( highest >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1992 wxString bestName = aSubgraph->m_driver_connection->Name();
1993
1994 // Check if a subsheet has a higher-priority connection to the same net
1996 {
1997 for( CONNECTION_SUBGRAPH* subgraph : visited )
1998 {
1999 if( subgraph == aSubgraph )
2000 continue;
2001
2003 CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
2004
2005 bool candidateStrong = ( priority >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
2006 wxString candidateName = subgraph->m_driver_connection->Name();
2007 bool shorterPath = subgraph->m_sheet.size() < bestDriver->m_sheet.size();
2008 bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->m_sheet.size();
2009
2010 // Pick a better driving subgraph if it:
2011 // a) has a power pin or global driver
2012 // b) is a strong driver and we're a weak driver
2013 // c) is a higher priority strong driver
2014 // d) matches our priority, is a strong driver, and has a shorter path
2015 // e) matches our strength and is at least as short, and is alphabetically lower
2016
2017 if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
2018 ( !bestIsStrong && candidateStrong ) ||
2019 ( priority > highest && candidateStrong ) ||
2020 ( priority == highest && candidateStrong && shorterPath ) ||
2021 ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
2022 ( candidateName < bestName ) ) )
2023 {
2024 bestDriver = subgraph;
2025 highest = priority;
2026 bestIsStrong = candidateStrong;
2027 bestName = candidateName;
2028 }
2029 }
2030 }
2031
2032 if( bestDriver != aSubgraph )
2033 {
2034 wxLogTrace( ConnTrace, "%lu (%s) overridden by new driver %lu (%s)",
2035 aSubgraph->m_code, aSubgraph->m_driver_connection->Name(), bestDriver->m_code,
2036 bestDriver->m_driver_connection->Name() );
2037 }
2038
2039 conn = bestDriver->m_driver_connection;
2040
2041 for( CONNECTION_SUBGRAPH* subgraph : visited )
2042 {
2043 wxString old_name = subgraph->m_driver_connection->Name();
2044
2045 subgraph->m_driver_connection->Clone( *conn );
2046
2047 if( old_name != conn->Name() )
2048 recacheSubgraphName( subgraph, old_name );
2049
2050 if( conn->IsBus() )
2051 propagate_bus_neighbors( subgraph );
2052 }
2053
2054 // Somewhere along the way, a bus member may have been upgraded to a global or power label.
2055 // Because this can happen anywhere, we need a second pass to update all instances of that bus
2056 // member to have the correct connection info
2057 if( conn->IsBus() && !stale_bus_members.empty() )
2058 {
2059 for( SCH_CONNECTION* stale_member : stale_bus_members )
2060 {
2061 for( CONNECTION_SUBGRAPH* subgraph : visited )
2062 {
2063 SCH_CONNECTION* member = matchBusMember( subgraph->m_driver_connection,
2064 stale_member );
2065
2066 if( !member )
2067 {
2068 wxLogTrace( ConnTrace, "WARNING: failed to match stale member %s in %s.",
2069 stale_member->Name(), subgraph->m_driver_connection->Name() );
2070 continue;
2071 }
2072
2073 wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", subgraph->m_code,
2074 subgraph->m_driver_connection->Name(), member->LocalName(),
2075 stale_member->Name() );
2076
2077 member->Clone( *stale_member );
2078
2079 propagate_bus_neighbors( subgraph );
2080 }
2081 }
2082 }
2083
2084 aSubgraph->m_dirty = false;
2085}
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_HIERLABEL * > m_hier_ports
std::vector< SCH_SHEET_PIN * > m_hier_pins
Definition: kiid.h:47
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
#define kv

References SCH_CONNECTION::Clone(), ConnTrace, getDefaultConnection(), CONNECTION_SUBGRAPH::GetDriverPriority(), CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::HIER_LABEL, SCH_CONNECTION::IsBus(), kv, SCH_CONNECTION::LocalName(), CONNECTION_SUBGRAPH::m_absorbed, CONNECTION_SUBGRAPH::m_absorbed_by, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_hier_pins, CONNECTION_SUBGRAPH::m_hier_ports, CONNECTION_SUBGRAPH::m_multiple_drivers, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, CONNECTION_SUBGRAPH::m_strong_driver, matchBusMember(), SCH_CONNECTION::Name(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, propagateToNeighbors(), SCH_SHEET_PATH::push_back(), recacheSubgraphName(), SCH_SHEET_PATH::size(), and SCH_CONNECTION::Type().

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ recacheSubgraphName()

void CONNECTION_GRAPH::recacheSubgraphName ( CONNECTION_SUBGRAPH aSubgraph,
const wxString &  aOldName 
)
private

Definition at line 2179 of file connection_graph.cpp.

2181{
2182 auto it = m_net_name_to_subgraphs_map.find( aOldName );
2183
2184 if( it != m_net_name_to_subgraphs_map.end() )
2185 {
2186 std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2187 alg::delete_matching( vec, aSubgraph );
2188 }
2189
2190 wxLogTrace( ConnTrace, "recacheSubgraphName: %s => %s", aOldName,
2191 aSubgraph->m_driver_connection->Name() );
2192
2193 m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
2194}

References ConnTrace, alg::delete_matching(), CONNECTION_SUBGRAPH::m_driver_connection, m_net_name_to_subgraphs_map, and SCH_CONNECTION::Name().

Referenced by propagateToNeighbors().

◆ Recalculate()

void CONNECTION_GRAPH::Recalculate ( const SCH_SHEET_LIST aSheetList,
bool  aUnconditional = false,
std::function< void(SCH_ITEM *)> *  aChangedItemHandler = nullptr 
)

Updates the connection graph for the given list of sheets.

Parameters
aSheetListis the list of possibly modified sheets
aUnconditionalis true if an unconditional full recalculation should be done
aChangedItemHandleran optional handler to receive any changed items

Definition at line 479 of file connection_graph.cpp.

481{
482 PROF_TIMER recalc_time( "CONNECTION_GRAPH::Recalculate" );
483
484 if( aUnconditional )
485 Reset();
486
487 PROF_TIMER update_items( "updateItemConnectivity" );
488
489 m_sheetList = aSheetList;
490
491 for( const SCH_SHEET_PATH& sheet : aSheetList )
492 {
493 std::vector<SCH_ITEM*> items;
494 // Store current unit value, to regenerate it after calculations
495 // (useful in complex hierarchies)
496 std::vector<std::pair<SCH_SYMBOL*, int>> symbolsChanged;
497
498 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
499 {
500 if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
501 items.push_back( item );
502
503 // Ensure the hierarchy info stored in SCREENS is built and up to date
504 // (multi-unit symbols)
505 if( item->Type() == SCH_SYMBOL_T )
506 {
507 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
508 int new_unit = symbol->GetUnitSelection( &sheet );
509
510 // Store the initial unit value, to regenerate it after calculations,
511 // if modified
512 if( symbol->GetUnit() != new_unit )
513 symbolsChanged.push_back( { symbol, symbol->GetUnit() } );
514
515 symbol->UpdateUnit( new_unit );
516 }
517 }
518
519 m_items.reserve( m_items.size() + items.size() );
520
521 updateItemConnectivity( sheet, items );
522
523 // UpdateDanglingState() also adds connected items for SCH_TEXT
524 sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
525
526 // Restore the m_unit member, to avoid changes in current active sheet path
527 // after calculations
528 for( auto& item : symbolsChanged )
529 {
530 item.first->UpdateUnit( item.second );
531 }
532 }
533
534 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
535 update_items.Show();
536
537 PROF_TIMER build_graph( "buildConnectionGraph" );
538
539 buildConnectionGraph( aChangedItemHandler );
540
541 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
542 build_graph.Show();
543
544 recalc_time.Stop();
545
546 if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
547 recalc_time.Show();
548
549#ifndef DEBUG
550 // Pressure relief valve for release builds
551 const double max_recalc_time_msecs = 250.;
552
553 if( m_allowRealTime && ADVANCED_CFG::GetCfg().m_RealTimeConnectivity &&
554 recalc_time.msecs() > max_recalc_time_msecs )
555 {
556 m_allowRealTime = false;
557 }
558#endif
559}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
static bool m_allowRealTime
void buildConnectionGraph(std::function< void(SCH_ITEM *)> *aChangedItemHandler)
Generates the connection graph (after all item connectivity has been updated)
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
Schematic symbol object.
Definition: sch_symbol.h:79
int GetUnit() const
Definition: sch_symbol.h:225
void UpdateUnit(int aUnit)
Change the unit number to aUnit without setting any internal flags.
Definition: sch_symbol.cpp:400
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:609
@ SCH_SYMBOL_T
Definition: typeinfo.h:155

References SCH_SYMBOL::GetUnit(), SCH_SYMBOL::GetUnitSelection(), m_items, m_sheetList, Reset(), SCH_SYMBOL_T, and updateItemConnectivity().

Referenced by SCH_EDIT_FRAME::RecalculateConnections(), and SCH_SCREENS::UpdateSymbolLinks().

◆ Reset()

◆ resolveAllDrivers()

void CONNECTION_GRAPH::resolveAllDrivers ( )
private

Finds all subgraphs in the connection graph and calls ResolveDrivers() in parallel.

Definition at line 868 of file connection_graph.cpp.

869{
870 // Resolve drivers for subgraphs and propagate connectivity info
871 std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
872
873 std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( dirty_graphs ),
874 [&] ( const CONNECTION_SUBGRAPH* candidate )
875 {
876 return candidate->m_dirty;
877 } );
878
879 std::vector<std::future<size_t>> returns( dirty_graphs.size() );
880
881 auto update_lambda = []( CONNECTION_SUBGRAPH* subgraph ) -> size_t
882 {
883 if( !subgraph->m_dirty )
884 return 0;
885
886 // Special processing for some items
887 for( SCH_ITEM* item : subgraph->m_items )
888 {
889 switch( item->Type() )
890 {
891 case SCH_NO_CONNECT_T:
892 subgraph->m_no_connect = item;
893 break;
894
896 subgraph->m_bus_entry = item;
897 break;
898
899 case SCH_PIN_T:
900 {
901 auto pin = static_cast<SCH_PIN*>( item );
902
903 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
904 subgraph->m_no_connect = item;
905
906 break;
907 }
908
909 default:
910 break;
911 }
912 }
913
914 subgraph->ResolveDrivers( true );
915 subgraph->m_dirty = false;
916
917 return 1;
918 };
919
920 GetKiCadThreadPool().parallelize_loop( 0, dirty_graphs.size(),
921 [&]( const int a, const int b)
922 {
923 for( int ii = a; ii < b; ++ii )
924 update_lambda( dirty_graphs[ii] );
925 }).wait();
926
927 // Now discard any non-driven subgraphs from further consideration
928
929 std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( m_driver_subgraphs ),
930 [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
931 {
932 return candidate->m_driver;
933 } );
934}

References GetKiCadThreadPool(), m_driver_subgraphs, m_subgraphs, pin, PT_NC, SCH_BUS_WIRE_ENTRY_T, SCH_NO_CONNECT_T, SCH_PIN_T, and EDA_ITEM::Type().

Referenced by buildConnectionGraph().

◆ RunERC()

int CONNECTION_GRAPH::RunERC ( )

Runs electrical rule checks on the connectivity graph.

Precondition: graph is up-to-date

Returns
the number of errors found

NOTE:

We could check that labels attached to bus subgraphs follow the proper format (i.e. actually define a bus).

This check doesn't need to be here right now because labels won't actually be connected to bus wires if they aren't in the right format due to their TestDanglingEnds() implementation.

Definition at line 2298 of file connection_graph.cpp.

2299{
2300 int error_count = 0;
2301
2302 wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::RunERC" );
2303
2304 ERC_SETTINGS& settings = m_schematic->ErcSettings();
2305
2306 // We don't want to run many ERC checks more than once on a given screen even though it may
2307 // represent multiple sheets with multiple subgraphs. We can tell these apart by drivers.
2308 std::set<SCH_ITEM*> seenDriverInstances;
2309
2310 for( CONNECTION_SUBGRAPH* subgraph : m_subgraphs )
2311 {
2312 // There shouldn't be any null sub-graph pointers.
2313 wxCHECK2( subgraph, continue );
2314
2315 // Graph is supposed to be up-to-date before calling RunERC()
2316 wxASSERT( !subgraph->m_dirty );
2317
2318 if( subgraph->m_absorbed )
2319 continue;
2320
2321 if( seenDriverInstances.count( subgraph->m_driver ) )
2322 continue;
2323
2324 if( subgraph->m_driver )
2325 seenDriverInstances.insert( subgraph->m_driver );
2326
2337 if( settings.IsTestEnabled( ERCE_DRIVER_CONFLICT ) )
2338 {
2339 if( !ercCheckMultipleDrivers( subgraph ) )
2340 error_count++;
2341 }
2342
2343 subgraph->ResolveDrivers( false );
2344
2345 if( settings.IsTestEnabled( ERCE_BUS_TO_NET_CONFLICT ) )
2346 {
2347 if( !ercCheckBusToNetConflicts( subgraph ) )
2348 error_count++;
2349 }
2350
2351 if( settings.IsTestEnabled( ERCE_BUS_ENTRY_CONFLICT ) )
2352 {
2353 if( !ercCheckBusToBusEntryConflicts( subgraph ) )
2354 error_count++;
2355 }
2356
2357 if( settings.IsTestEnabled( ERCE_BUS_TO_BUS_CONFLICT ) )
2358 {
2359 if( !ercCheckBusToBusConflicts( subgraph ) )
2360 error_count++;
2361 }
2362
2363 if( settings.IsTestEnabled( ERCE_WIRE_DANGLING ) )
2364 {
2365 if( !ercCheckFloatingWires( subgraph ) )
2366 error_count++;
2367 }
2368
2371 || settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2372 {
2373 if( !ercCheckNoConnects( subgraph ) )
2374 error_count++;
2375 }
2376
2378 || settings.IsTestEnabled( ERCE_GLOBLABEL ) )
2379 {
2380 if( !ercCheckLabels( subgraph ) )
2381 error_count++;
2382 }
2383 }
2384
2385 // Hierarchical sheet checking is done at the schematic level
2387 || settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2388 {
2389 error_count += ercCheckHierSheets();
2390 }
2391
2392 if( settings.IsTestEnabled( ERCE_NETCLASS_CONFLICT ) )
2393 {
2394 for( const auto& [ netname, subgraphs ] : m_net_name_to_subgraphs_map )
2395 {
2396 if( !ercCheckNetclassConflicts( subgraphs ) )
2397 error_count++;
2398 }
2399 }
2400
2401 return error_count;
2402}
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.
bool ercCheckNetclassConflicts(const std::vector< CONNECTION_SUBGRAPH * > &subgraphs)
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
int ercCheckHierSheets()
Checks that a hierarchical sheet has at least one matching label inside the sheet for each port on th...
bool ercCheckBusToNetConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between net and bus labels.
bool ercCheckNoConnects(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper presence or absence of no-connect symbols.
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.

References ercCheckBusToBusConflicts(), ercCheckBusToBusEntryConflicts(), ercCheckBusToNetConflicts(), ercCheckFloatingWires(), ercCheckHierSheets(), ercCheckLabels(), ercCheckMultipleDrivers(), ercCheckNetclassConflicts(), ercCheckNoConnects(), ERCE_BUS_ENTRY_CONFLICT, ERCE_BUS_TO_BUS_CONFLICT, ERCE_BUS_TO_NET_CONFLICT, ERCE_DRIVER_CONFLICT, ERCE_GLOBLABEL, ERCE_HIERACHICAL_LABEL, ERCE_LABEL_NOT_CONNECTED, ERCE_NETCLASS_CONFLICT, ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, ERCE_WIRE_DANGLING, SCHEMATIC::ErcSettings(), ERC_SETTINGS::IsTestEnabled(), m_net_name_to_subgraphs_map, m_schematic, and m_subgraphs.

Referenced by DIALOG_ERC::testErc().

◆ SetSchematic()

void CONNECTION_GRAPH::SetSchematic ( SCHEMATIC aSchematic)
inline

Definition at line 289 of file connection_graph.h.

290 {
291 m_schematic = aSchematic;
292 }

References m_schematic.

◆ updateItemConnectivity()

void CONNECTION_GRAPH::updateItemConnectivity ( const SCH_SHEET_PATH aSheet,
const std::vector< SCH_ITEM * > &  aItemList 
)
private

Updates the graphical connectivity between items (i.e.

where they touch) The items passed in must be on the same sheet.

In the first phase, all items in aItemList have their connections initialized for the given sheet (since they may have connections on more than one sheet, and each needs to be calculated individually). The graphical connection points for the item are added to a map that stores (x, y) -> [list of items].

Any item that is stored in the list of items that have a connection point at a given (x, y) location will eventually be electrically connected. This means that we can't store SCH_SYMBOLs in this map – we must store a structure that links a specific pin on a symbol back to that symbol: a SCH_PIN_CONNECTION. This wrapper class is a convenience for linking a pin and symbol to a specific (x, y) point.

In the second phase, we iterate over each value in the map, which is a vector of items that have overlapping connection points. After some checks to ensure that the items should actually connect, the items are linked together using ConnectedItems().

As a side effect, items are loaded into m_items for BuildConnectionGraph()

Parameters
aSheetis the path to the sheet of all items in the list
aItemListis a list of items to consider

Definition at line 562 of file connection_graph.cpp.

564{
565 std::map<VECTOR2I, std::vector<SCH_ITEM*>> connection_map;
566
567 for( SCH_ITEM* item : aItemList )
568 {
569 std::vector<VECTOR2I> points = item->GetConnectionPoints();
570 item->ConnectedItems( aSheet ).clear();
571
572 if( item->Type() == SCH_SHEET_T )
573 {
574 for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
575 {
576 pin->InitializeConnection( aSheet, this );
577
578 pin->ConnectedItems( aSheet ).clear();
579
580 connection_map[ pin->GetTextPos() ].push_back( pin );
581 m_items.emplace_back( pin );
582 }
583 }
584 else if( item->Type() == SCH_SYMBOL_T )
585 {
586 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
587
588 for( SCH_PIN* pin : symbol->GetPins( &aSheet ) )
589 {
590 pin->InitializeConnection( aSheet, this );
591
592 VECTOR2I pos = pin->GetPosition();
593
594 // because calling the first time is not thread-safe
595 pin->GetDefaultNetName( aSheet );
596 pin->ConnectedItems( aSheet ).clear();
597
598 // Invisible power pins need to be post-processed later
599
600 if( pin->IsPowerConnection() && !pin->IsVisible() )
601 m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) );
602
603 connection_map[ pos ].push_back( pin );
604 m_items.emplace_back( pin );
605 }
606 }
607 else
608 {
609 m_items.emplace_back( item );
610 SCH_CONNECTION* conn = item->InitializeConnection( aSheet, this );
611
612 // Set bus/net property here so that the propagation code uses it
613 switch( item->Type() )
614 {
615 case SCH_LINE_T:
616 conn->SetType( item->GetLayer() == LAYER_BUS ? CONNECTION_TYPE::BUS :
618 break;
619
622 // clean previous (old) links:
623 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] = nullptr;
624 static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] = nullptr;
625 break;
626
627 case SCH_PIN_T:
629 break;
630
633 // clean previous (old) link:
634 static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item = nullptr;
635 break;
636
637 default:
638 break;
639 }
640
641 for( const VECTOR2I& point : points )
642 connection_map[ point ].push_back( item );
643 }
644
645 item->SetConnectivityDirty( false );
646 }
647
648 for( const auto& it : connection_map )
649 {
650 const std::vector<SCH_ITEM*>& connection_vec = it.second;
651
652 // Pre-scan to see if we have a bus at this location
653 SCH_LINE* busLine = aSheet.LastScreen()->GetBus( it.first );
654
655 std::mutex update_mutex;
656
657 auto update_lambda = [&]( SCH_ITEM* connected_item ) -> size_t
658 {
659 // Bus entries are special: they can have connection points in the
660 // middle of a wire segment, because the junction algo doesn't split
661 // the segment in two where you place a bus entry. This means that
662 // bus entries that don't land on the end of a line segment need to
663 // have "virtual" connection points to the segments they graphically
664 // touch.
665 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
666 {
667 // If this location only has the connection point of the bus
668 // entry itself, this means that either the bus entry is not
669 // connected to anything graphically, or that it is connected to
670 // a segment at some point other than at one of the endpoints.
671 if( connection_vec.size() == 1 )
672 {
673 if( busLine )
674 {
675 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
676 bus_entry->m_connected_bus_item = busLine;
677 }
678 }
679 }
680
681 // Bus-to-bus entries are treated just like bus wires
682 else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
683 {
684 if( connection_vec.size() < 2 )
685 {
686 if( busLine )
687 {
688 auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
689
690 if( it.first == bus_entry->GetPosition() )
691 bus_entry->m_connected_bus_items[0] = busLine;
692 else
693 bus_entry->m_connected_bus_items[1] = busLine;
694
695 std::lock_guard<std::mutex> lock( update_mutex );
696 bus_entry->AddConnectionTo( aSheet, busLine );
697 busLine->AddConnectionTo( aSheet, bus_entry );
698 }
699 }
700 }
701
702 // Change junctions to be on bus junction layer if they are touching a bus
703 else if( connected_item->Type() == SCH_JUNCTION_T )
704 {
705 connected_item->SetLayer( busLine ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
706 }
707
708 SCH_ITEM_SET& connected_set = connected_item->ConnectedItems( aSheet );
709 connected_set.reserve( connection_vec.size() );
710
711 for( SCH_ITEM* test_item : connection_vec )
712 {
713 bool bus_connection_ok = true;
714
715 if( test_item == connected_item )
716 continue;
717
718 // Set up the link between the bus entry net and the bus
719 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
720 {
721 if( test_item->GetLayer() == LAYER_BUS )
722 {
723 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
724 bus_entry->m_connected_bus_item = test_item;
725 }
726 }
727
728 // Bus entries only connect to bus lines on the end that is touching a bus line.
729 // If the user has overlapped another net line with the endpoint of the bus entry
730 // where the entry connects to a bus, we don't want to short-circuit it.
731 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
732 {
733 bus_connection_ok = !busLine || test_item->GetLayer() == LAYER_BUS;
734 }
735 else if( test_item->Type() == SCH_BUS_WIRE_ENTRY_T )
736 {
737 bus_connection_ok = !busLine || connected_item->GetLayer() == LAYER_BUS;
738 }
739
740 if( connected_item->ConnectionPropagatesTo( test_item ) &&
741 test_item->ConnectionPropagatesTo( connected_item ) &&
742 bus_connection_ok )
743 {
744 connected_set.push_back( test_item );
745 }
746 }
747
748 // If we got this far and did not find a connected bus item for a bus entry,
749 // we should do a manual scan in case there is a bus item on this connection
750 // point but we didn't pick it up earlier because there is *also* a net item here.
751 if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
752 {
753 auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
754
755 if( !bus_entry->m_connected_bus_item )
756 {
757 SCH_SCREEN* screen = aSheet.LastScreen();
758 SCH_LINE* bus = screen->GetBus( it.first );
759
760 if( bus )
761 bus_entry->m_connected_bus_item = bus;
762 }
763 }
764
765 return 1;
766 };
767
768 GetKiCadThreadPool().parallelize_loop( 0, connection_vec.size(),
769 [&]( const int a, const int b)
770 {
771 for( int ii = a; ii < b; ++ii )
772 update_lambda( connection_vec[ii] );
773 }).wait();
774 }
775}
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...
void AddConnectionTo(const SCH_SHEET_PATH &aPath, SCH_ITEM *aItem)
Add a connection link between this item and another.
Definition: sch_item.cpp:193
void SetConnectivityDirty(bool aDirty=true)
Definition: sch_item.h:406
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
SCH_LINE * GetBus(const VECTOR2I &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:432
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:972
@ LAYER_JUNCTION
Definition: layer_ids.h:346
@ LAYER_BUS_JUNCTION
Definition: layer_ids.h:384
@ NET
This item represents a net.
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:144

References SCH_ITEM::AddConnectionTo(), BUS, SCH_SCREEN::GetBus(), GetKiCadThreadPool(), SCH_ITEM::GetLayer(), SCH_SYMBOL::GetPins(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, LAYER_BUS_JUNCTION, LAYER_JUNCTION, SCH_BUS_WIRE_ENTRY::m_connected_bus_item, SCH_BUS_BUS_ENTRY::m_connected_bus_items, m_invisible_power_pins, m_items, NET, pin, SCH_BUS_BUS_ENTRY_T, SCH_BUS_WIRE_ENTRY_T, SCH_JUNCTION_T, SCH_LINE_T, SCH_PIN_T, SCH_SHEET_T, SCH_SYMBOL_T, SCH_ITEM::SetConnectivityDirty(), and SCH_CONNECTION::SetType().

Referenced by Recalculate().

Member Data Documentation

◆ m_allowRealTime

◆ m_bus_alias_cache

std::unordered_map<wxString, std::shared_ptr<BUS_ALIAS> > CONNECTION_GRAPH::m_bus_alias_cache
private

Definition at line 581 of file connection_graph.h.

Referenced by buildConnectionGraph(), buildItemSubGraphs(), GetBusAlias(), and Reset().

◆ m_bus_name_to_code_map

std::unordered_map<wxString, int> CONNECTION_GRAPH::m_bus_name_to_code_map
private

Definition at line 585 of file connection_graph.h.

Referenced by processSubGraphs(), and Reset().

◆ m_driver_subgraphs

std::vector<CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_driver_subgraphs
private

◆ m_global_label_cache

std::unordered_map<wxString, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_global_label_cache
private

Definition at line 587 of file connection_graph.h.

Referenced by collectAllDriverValues(), ercCheckNoConnects(), and Reset().

◆ m_invisible_power_pins

std::vector<std::pair<SCH_SHEET_PATH, SCH_PIN*> > CONNECTION_GRAPH::m_invisible_power_pins
private

◆ m_item_to_subgraph_map

std::unordered_map<SCH_ITEM*, CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_item_to_subgraph_map
private

Definition at line 594 of file connection_graph.h.

Referenced by buildItemSubGraphs(), GetSubgraphForItem(), and Reset().

◆ m_items

std::vector<SCH_ITEM*> CONNECTION_GRAPH::m_items
private

Definition at line 568 of file connection_graph.h.

Referenced by buildItemSubGraphs(), Recalculate(), Reset(), and updateItemConnectivity().

◆ m_last_bus_code

int CONNECTION_GRAPH::m_last_bus_code
private

Definition at line 600 of file connection_graph.h.

Referenced by processSubGraphs(), and Reset().

◆ m_last_net_code

int CONNECTION_GRAPH::m_last_net_code
private

Definition at line 598 of file connection_graph.h.

Referenced by assignNewNetCode(), and Reset().

◆ m_last_subgraph_code

int CONNECTION_GRAPH::m_last_subgraph_code
private

Definition at line 602 of file connection_graph.h.

Referenced by buildItemSubGraphs(), generateInvisiblePinSubGraphs(), and Reset().

◆ m_local_label_cache

std::map< std::pair<SCH_SHEET_PATH, wxString>, std::vector<const CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_local_label_cache
private

Definition at line 590 of file connection_graph.h.

Referenced by collectAllDriverValues(), ercCheckNoConnects(), and Reset().

◆ m_net_code_to_subgraphs_map

NET_MAP CONNECTION_GRAPH::m_net_code_to_subgraphs_map
private

◆ m_net_name_to_code_map

std::unordered_map<wxString, int> CONNECTION_GRAPH::m_net_name_to_code_map
private

Definition at line 583 of file connection_graph.h.

Referenced by assignNewNetCode(), and Reset().

◆ m_net_name_to_subgraphs_map

std::unordered_map<wxString, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_net_name_to_subgraphs_map
private

◆ m_schematic

SCHEMATIC* CONNECTION_GRAPH::m_schematic
private

The schematic this graph represents.

Definition at line 604 of file connection_graph.h.

Referenced by buildConnectionGraph(), buildItemSubGraphs(), ercCheckHierSheets(), ercCheckLabels(), ercCheckNoConnects(), RunERC(), and SetSchematic().

◆ m_sheet_to_subgraphs_map

std::unordered_map<SCH_SHEET_PATH, std::vector<CONNECTION_SUBGRAPH*> > CONNECTION_GRAPH::m_sheet_to_subgraphs_map
private

◆ m_sheetList

SCH_SHEET_LIST CONNECTION_GRAPH::m_sheetList
private

Definition at line 565 of file connection_graph.h.

Referenced by ercCheckHierSheets(), and Recalculate().

◆ m_subgraphs

std::vector<CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::m_subgraphs
private

The documentation for this class was generated from the following files: