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 ()
 Generates the connection graph (after all item connectivity has been updated) 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 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::map< wxString, int > m_net_name_to_code_map
 
std::map< wxString, int > m_bus_name_to_code_map
 
std::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::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 248 of file connection_graph.h.

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCHEMATIC aSchematic = nullptr)
inline

Definition at line 251 of file connection_graph.h.

251  :
252  m_last_net_code( 1 ),
253  m_last_bus_code( 1 ),
255  m_schematic( aSchematic )
256  {}
SCHEMATIC * m_schematic
The schematic this graph represents.

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 258 of file connection_graph.h.

259  {
260  Reset();
261  }

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 1602 of file connection_graph.cpp.

1603 {
1604  auto connections_to_check( aConnection->Members() );
1605 
1606  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1607  {
1608  auto member = connections_to_check[i];
1609 
1610  if( member->IsBus() )
1611  {
1612  connections_to_check.insert( connections_to_check.end(),
1613  member->Members().begin(),
1614  member->Members().end() );
1615  continue;
1616  }
1617 
1618  assignNewNetCode( *member );
1619  }
1620 }
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 buildConnectionGraph().

◆ 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 1580 of file connection_graph.cpp.

1581 {
1582  int code;
1583 
1584  auto it = m_net_name_to_code_map.find( aConnection.Name() );
1585 
1586  if( it == m_net_name_to_code_map.end() )
1587  {
1588  code = m_last_net_code++;
1589  m_net_name_to_code_map[ aConnection.Name() ] = code;
1590  }
1591  else
1592  {
1593  code = it->second;
1594  }
1595 
1596  aConnection.SetNetCode( code );
1597 
1598  return code;
1599 }
wxString Name(bool aIgnoreSheet=false) const
std::map< wxString, int > m_net_name_to_code_map
void SetNetCode(int aCode)

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

Referenced by assignNetCodesToBus(), and buildConnectionGraph().

◆ buildConnectionGraph()

void CONNECTION_GRAPH::buildConnectionGraph ( )
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 705 of file connection_graph.cpp.

706 {
707  // Recache all bus aliases for later use
708  wxCHECK_RET( m_schematic, "Connection graph cannot be built without schematic pointer" );
709 
710  SCH_SHEET_LIST all_sheets = m_schematic->GetSheets();
711 
712  for( unsigned i = 0; i < all_sheets.size(); i++ )
713  {
714  for( const auto& alias : all_sheets[i].LastScreen()->GetBusAliases() )
715  m_bus_alias_cache[ alias->GetName() ] = alias;
716  }
717 
718  // Build subgraphs from items (on a per-sheet basis)
719 
720  for( SCH_ITEM* item : m_items )
721  {
722  for( const auto& it : item->m_connection_map )
723  {
724  const auto sheet = it.first;
725  auto connection = it.second;
726 
727  if( connection->SubgraphCode() == 0 )
728  {
729  CONNECTION_SUBGRAPH* subgraph = new CONNECTION_SUBGRAPH( this );
730 
731  subgraph->m_code = m_last_subgraph_code++;
732  subgraph->m_sheet = sheet;
733 
734  subgraph->AddItem( item );
735 
736  connection->SetSubgraphCode( subgraph->m_code );
737  m_item_to_subgraph_map[item] = subgraph;
738 
739  std::list<SCH_ITEM*> members;
740 
741  auto get_items =
742  [&]( SCH_ITEM* aItem ) -> bool
743  {
744  SCH_CONNECTION* conn = aItem->Connection( &sheet );
745 
746  if( !conn )
747  conn = aItem->InitializeConnection( sheet, this );
748 
749  return ( conn->SubgraphCode() == 0 );
750  };
751 
752  std::copy_if( item->ConnectedItems( sheet ).begin(),
753  item->ConnectedItems( sheet ).end(),
754  std::back_inserter( members ), get_items );
755 
756  for( SCH_ITEM* connected_item : members )
757  {
758  if( connected_item->Type() == SCH_NO_CONNECT_T )
759  subgraph->m_no_connect = connected_item;
760 
761  SCH_CONNECTION* connected_conn = connected_item->Connection( &sheet );
762 
763  wxASSERT( connected_conn );
764 
765  if( connected_conn->SubgraphCode() == 0 )
766  {
767  connected_conn->SetSubgraphCode( subgraph->m_code );
768  m_item_to_subgraph_map[connected_item] = subgraph;
769  subgraph->AddItem( connected_item );
770 
771  std::copy_if( connected_item->ConnectedItems( sheet ).begin(),
772  connected_item->ConnectedItems( sheet ).end(),
773  std::back_inserter( members ), get_items );
774  }
775  }
776 
777  subgraph->m_dirty = true;
778  m_subgraphs.push_back( subgraph );
779  }
780  }
781  }
782 
788  // Resolve drivers for subgraphs and propagate connectivity info
789 
790  // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
791  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
792  ( m_subgraphs.size() + 3 ) / 4 );
793 
794  std::atomic<size_t> nextSubgraph( 0 );
795  std::vector<std::future<size_t>> returns( parallelThreadCount );
796  std::vector<CONNECTION_SUBGRAPH*> dirty_graphs;
797 
798  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( dirty_graphs ),
799  [&] ( const CONNECTION_SUBGRAPH* candidate )
800  {
801  return candidate->m_dirty;
802  } );
803 
804  auto update_lambda = [&nextSubgraph, &dirty_graphs]() -> size_t
805  {
806  for( size_t subgraphId = nextSubgraph++; subgraphId < dirty_graphs.size(); subgraphId = nextSubgraph++ )
807  {
808  auto subgraph = dirty_graphs[subgraphId];
809 
810  if( !subgraph->m_dirty )
811  continue;
812 
813  // Special processing for some items
814  for( auto item : subgraph->m_items )
815  {
816  switch( item->Type() )
817  {
818  case SCH_NO_CONNECT_T:
819  subgraph->m_no_connect = item;
820  break;
821 
823  subgraph->m_bus_entry = item;
824  break;
825 
826  case SCH_PIN_T:
827  {
828  auto pin = static_cast<SCH_PIN*>( item );
829 
830  if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
831  subgraph->m_no_connect = item;
832 
833  break;
834  }
835 
836  default:
837  break;
838  }
839  }
840 
841  subgraph->ResolveDrivers( true );
842  subgraph->m_dirty = false;
843  }
844 
845  return 1;
846  };
847 
848  if( parallelThreadCount == 1 )
849  update_lambda();
850  else
851  {
852  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
853  returns[ii] = std::async( std::launch::async, update_lambda );
854 
855  // Finalize the threads
856  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
857  returns[ii].wait();
858  }
859 
860  // Now discard any non-driven subgraphs from further consideration
861 
862  std::copy_if( m_subgraphs.begin(), m_subgraphs.end(), std::back_inserter( m_driver_subgraphs ),
863  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
864  {
865  return candidate->m_driver;
866  } );
867 
868  // Check for subgraphs with the same net name but only weak drivers.
869  // For example, two wires that are both connected to hierarchical
870  // sheet pins that happen to have the same name, but are not the same.
871 
872  for( auto&& subgraph : m_driver_subgraphs )
873  {
874  wxString full_name = subgraph->m_driver_connection->Name();
875  wxString name = subgraph->m_driver_connection->Name( true );
876  m_net_name_to_subgraphs_map[full_name].emplace_back( subgraph );
877 
878  // For vector buses, we need to cache the prefix also, as two different instances of the
879  // weakly driven pin may have the same prefix but different vector start and end. We need
880  // to treat those as needing renaming also, because otherwise if they end up on a sheet with
881  // common usage, they will be incorrectly merged.
882  if( subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
883  {
884  wxString prefixOnly = full_name.BeforeFirst( '[' ) + wxT( "[]" );
885  m_net_name_to_subgraphs_map[prefixOnly].emplace_back( subgraph );
886  }
887 
888  subgraph->m_dirty = true;
889 
890  if( subgraph->m_strong_driver )
891  {
892  SCH_ITEM* driver = subgraph->m_driver;
893  SCH_SHEET_PATH sheet = subgraph->m_sheet;
894 
895  switch( driver->Type() )
896  {
897  case SCH_LABEL_T:
898  case SCH_HIER_LABEL_T:
899  {
900  m_local_label_cache[std::make_pair( sheet, name )].push_back( subgraph );
901  break;
902  }
903  case SCH_GLOBAL_LABEL_T:
904  {
905  m_global_label_cache[name].push_back( subgraph );
906  break;
907  }
908  case SCH_PIN_T:
909  {
910  auto pin = static_cast<SCH_PIN*>( driver );
911  wxASSERT( pin->IsPowerConnection() );
912  m_global_label_cache[name].push_back( subgraph );
913  break;
914  }
915  default:
916  wxLogTrace( ConnTrace, "Unexpected strong driver %s",
918  break;
919  }
920  }
921  }
922 
923  // Generate subgraphs for invisible power pins. These will be merged with other subgraphs
924  // on the same sheet in the next loop.
925 
926  std::unordered_map<int, CONNECTION_SUBGRAPH*> invisible_pin_subgraphs;
927 
928  for( const auto& it : m_invisible_power_pins )
929  {
930  SCH_SHEET_PATH sheet = it.first;
931  SCH_PIN* pin = it.second;
932 
933  if( !pin->ConnectedItems( sheet ).empty() && !pin->GetLibPin()->GetParent()->IsPower() )
934  {
935  // ERC will warn about this: user has wired up an invisible pin
936  continue;
937  }
938 
939  SCH_CONNECTION* connection = pin->Connection( &sheet );
940 
941  if( !connection )
942  connection = pin->InitializeConnection( sheet, this );
943 
944  // If this pin already has a subgraph, don't need to process
945  if( connection->SubgraphCode() > 0 )
946  continue;
947 
948  connection->SetName( pin->GetShownName() );
949 
950  int code = assignNewNetCode( *connection );
951 
952  connection->SetNetCode( code );
953 
954  CONNECTION_SUBGRAPH* subgraph;
955  auto jj = invisible_pin_subgraphs.find( code );
956 
957  if( jj != invisible_pin_subgraphs.end() )
958  {
959  subgraph = jj->second;
960  subgraph->AddItem( pin );
961  }
962  else
963  {
964  subgraph = new CONNECTION_SUBGRAPH( this );
965 
966  subgraph->m_code = m_last_subgraph_code++;
967  subgraph->m_sheet = sheet;
968 
969  subgraph->AddItem( pin );
970  subgraph->ResolveDrivers();
971 
972  auto key = std::make_pair( subgraph->GetNetName(), code );
973  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
974  m_subgraphs.push_back( subgraph );
975  m_driver_subgraphs.push_back( subgraph );
976 
977  invisible_pin_subgraphs[code] = subgraph;
978  }
979 
980  connection->SetSubgraphCode( subgraph->m_code );
981  }
982 
983  // Here we do all the local (sheet) processing of each subgraph, including assigning net
984  // codes, merging subgraphs together that use label connections, etc.
985 
986  // Cache remaining valid subgraphs by sheet path
987  for( auto subgraph : m_driver_subgraphs )
988  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
989 
990  std::unordered_set<CONNECTION_SUBGRAPH*> invalidated_subgraphs;
991 
992  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
993  {
994  if( subgraph->m_absorbed )
995  continue;
996 
997  SCH_CONNECTION* connection = subgraph->m_driver_connection;
998  SCH_SHEET_PATH sheet = subgraph->m_sheet;
999  wxString name = connection->Name();
1000 
1001  // Test subgraphs with weak drivers for net name conflicts and fix them
1002  unsigned suffix = 1;
1003 
1004  auto create_new_name =
1005  [&suffix]( SCH_CONNECTION* aConn ) -> wxString
1006  {
1007  wxString newName;
1008 
1009  // For group buses with a prefix, we can add the suffix to the prefix.
1010  // If they don't have a prefix, we force the creation of a prefix so that
1011  // two buses don't get inadvertently shorted together.
1012  if( aConn->Type() == CONNECTION_TYPE::BUS_GROUP )
1013  {
1014  wxString prefix = aConn->BusPrefix();
1015 
1016  if( prefix.empty() )
1017  prefix = wxT( "BUS" ); // So result will be "BUS_1{...}"
1018 
1019  wxString oldName = aConn->Name().AfterFirst( '{' );
1020 
1021  newName = wxString::Format( "%s_%u{%s", prefix, suffix, oldName );
1022 
1023  aConn->ConfigureFromLabel( newName );
1024  }
1025  else
1026  {
1027  newName = wxString::Format( "%s_%u", aConn->Name(), suffix );
1028  aConn->SetSuffix( wxString::Format( "_%u", suffix ) );
1029  }
1030 
1031  suffix++;
1032  return newName;
1033  };
1034 
1035  if( !subgraph->m_strong_driver )
1036  {
1037  std::vector<CONNECTION_SUBGRAPH*>* vec = &m_net_name_to_subgraphs_map.at( name );
1038 
1039  // If we are a unique bus vector, check if we aren't actually unique because of another
1040  // subgraph with a similar bus vector
1041  if( vec->size() <= 1 && subgraph->m_driver_connection->Type() == CONNECTION_TYPE::BUS )
1042  {
1043  wxString prefixOnly = name.BeforeFirst( '[' ) + wxT( "[]" );
1044  vec = &m_net_name_to_subgraphs_map.at( prefixOnly );
1045  }
1046 
1047  if( vec->size() > 1 )
1048  {
1049  wxString new_name = create_new_name( connection );
1050 
1051  while( m_net_name_to_subgraphs_map.count( new_name ) )
1052  new_name = create_new_name( connection );
1053 
1054  wxLogTrace( ConnTrace, "%ld (%s) is weakly driven and not unique. Changing to %s.",
1055  subgraph->m_code, name, new_name );
1056 
1057  vec->erase( std::remove( vec->begin(), vec->end(), subgraph ), vec->end() );
1058 
1059  m_net_name_to_subgraphs_map[new_name].emplace_back( subgraph );
1060 
1061  name = new_name;
1062  }
1063  else
1064  {
1065  // If there is no conflict, promote sheet pins to be strong drivers so that they
1066  // will be considered below for propagation/merging.
1067 
1068  // It is possible for this to generate a conflict if the sheet pin has the same
1069  // name as a global label on the same sheet, because global merging will then treat
1070  // this subgraph as if it had a matching local label. So, for those cases, we
1071  // don't apply this promotion
1072 
1073  if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1074  {
1075  bool conflict = false;
1076  wxString global_name = connection->Name( true );
1077  auto kk = m_net_name_to_subgraphs_map.find( global_name );
1078 
1079  if( kk != m_net_name_to_subgraphs_map.end() )
1080  {
1081  // A global will conflict if it is on the same sheet as this subgraph, since
1082  // it would be connected by implicit local label linking
1083  std::vector<CONNECTION_SUBGRAPH*>& candidates = kk->second;
1084 
1085  for( const CONNECTION_SUBGRAPH* candidate : candidates )
1086  {
1087  if( candidate->m_sheet == sheet )
1088  conflict = true;
1089  }
1090  }
1091 
1092  if( conflict )
1093  {
1094  wxLogTrace( ConnTrace,
1095  "%ld (%s) skipped for promotion due to potential conflict",
1096  subgraph->m_code, name );
1097  }
1098  else
1099  {
1100  wxLogTrace( ConnTrace,
1101  "%ld (%s) weakly driven by unique sheet pin %s, promoting",
1102  subgraph->m_code, name,
1104 
1105  subgraph->m_strong_driver = true;
1106  }
1107  }
1108  }
1109  }
1110 
1111  // Assign net codes
1112 
1113  if( connection->IsBus() )
1114  {
1115  int code = -1;
1116  auto it = m_bus_name_to_code_map.find( name );
1117 
1118  if( it != m_bus_name_to_code_map.end() )
1119  {
1120  code = it->second;
1121  }
1122  else
1123  {
1124  code = m_last_bus_code++;
1125  m_bus_name_to_code_map[ name ] = code;
1126  }
1127 
1128  connection->SetBusCode( code );
1129  assignNetCodesToBus( connection );
1130  }
1131  else
1132  {
1133  assignNewNetCode( *connection );
1134  }
1135 
1136  // Reset the flag for the next loop below
1137  subgraph->m_dirty = true;
1138 
1139  // Next, we merge together subgraphs that have label connections, and create
1140  // neighbor links for subgraphs that are part of a bus on the same sheet.
1141  // For merging, we consider each possible strong driver.
1142 
1143  // If this subgraph doesn't have a strong driver, let's skip it, since there is no
1144  // way it will be merged with anything.
1145 
1146  if( !subgraph->m_strong_driver )
1147  continue;
1148 
1149  // candidate_subgraphs will contain each valid, non-bus subgraph on the same sheet
1150  // as the subgraph we are considering that has a strong driver.
1151  // Weakly driven subgraphs are not considered since they will never be absorbed or
1152  // form neighbor links.
1153 
1154  std::vector<CONNECTION_SUBGRAPH*> candidate_subgraphs;
1155  std::copy_if( m_sheet_to_subgraphs_map[ subgraph->m_sheet ].begin(),
1156  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].end(),
1157  std::back_inserter( candidate_subgraphs ),
1158  [&] ( const CONNECTION_SUBGRAPH* candidate )
1159  {
1160  return ( !candidate->m_absorbed &&
1161  candidate->m_strong_driver &&
1162  candidate != subgraph );
1163  } );
1164 
1165  // This is a list of connections on the current subgraph to compare to the
1166  // drivers of each candidate subgraph. If the current subgraph is a bus,
1167  // we should consider each bus member.
1168  std::vector< std::shared_ptr<SCH_CONNECTION> > connections_to_check;
1169 
1170  // Also check the main driving connection
1171  connections_to_check.push_back( std::make_shared<SCH_CONNECTION>( *connection ) );
1172 
1173  auto add_connections_to_check = [&] ( CONNECTION_SUBGRAPH* aSubgraph ) {
1174  for( SCH_ITEM* possible_driver : aSubgraph->m_items )
1175  {
1176  if( possible_driver == aSubgraph->m_driver )
1177  continue;
1178 
1179  auto c = getDefaultConnection( possible_driver, aSubgraph );
1180 
1181  if( c )
1182  {
1183  if( c->Type() != aSubgraph->m_driver_connection->Type() )
1184  continue;
1185 
1186  if( c->Name( true ) == aSubgraph->m_driver_connection->Name( true ) )
1187  continue;
1188 
1189  connections_to_check.push_back( c );
1190  wxLogTrace( ConnTrace,
1191  "%lu (%s): Adding secondary driver %s", aSubgraph->m_code,
1192  aSubgraph->m_driver_connection->Name( true ), c->Name( true ) );
1193  }
1194  }
1195  };
1196 
1197  // Now add other strong drivers
1198  // The actual connection attached to these items will have been overwritten
1199  // by the chosen driver of the subgraph, so we need to create a dummy connection
1200  add_connections_to_check( subgraph );
1201 
1202  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1203  {
1204  auto member = connections_to_check[i];
1205 
1206  if( member->IsBus() )
1207  {
1208  connections_to_check.insert( connections_to_check.end(),
1209  member->Members().begin(),
1210  member->Members().end() );
1211  }
1212 
1213  wxString test_name = member->Name( true );
1214 
1215  for( auto candidate : candidate_subgraphs )
1216  {
1217  if( candidate->m_absorbed )
1218  continue;
1219 
1220  bool match = false;
1221 
1222  if( candidate->m_driver_connection->Name( true ) == test_name )
1223  {
1224  match = true;
1225  }
1226  else
1227  {
1228  if( !candidate->m_multiple_drivers )
1229  continue;
1230 
1231  for( SCH_ITEM *driver : candidate->m_drivers )
1232  {
1233  if( driver == candidate->m_driver )
1234  continue;
1235 
1236  // Sheet pins are not candidates for merging
1237  if( driver->Type() == SCH_SHEET_PIN_T )
1238  continue;
1239 
1240  if( driver->Type() == SCH_PIN_T )
1241  {
1242  auto pin = static_cast<SCH_PIN*>( driver );
1243 
1244  if( pin->IsPowerConnection() && pin->GetShownName() == test_name )
1245  {
1246  match = true;
1247  break;
1248  }
1249  }
1250  else
1251  {
1252  wxASSERT( driver->Type() == SCH_LABEL_T ||
1253  driver->Type() == SCH_GLOBAL_LABEL_T ||
1254  driver->Type() == SCH_HIER_LABEL_T );
1255 
1256  if( subgraph->GetNameForDriver( driver ) == test_name )
1257  {
1258  match = true;
1259  break;
1260  }
1261  }
1262  }
1263  }
1264 
1265  if( match )
1266  {
1267  if( connection->IsBus() && candidate->m_driver_connection->IsNet() )
1268  {
1269  wxLogTrace( ConnTrace, "%lu (%s) has bus child %lu (%s)", subgraph->m_code,
1270  connection->Name(), candidate->m_code, member->Name() );
1271 
1272  subgraph->m_bus_neighbors[member].insert( candidate );
1273  candidate->m_bus_parents[member].insert( subgraph );
1274  }
1275  else
1276  {
1277  wxLogTrace( ConnTrace, "%lu (%s) absorbs neighbor %lu (%s)",
1278  subgraph->m_code, connection->Name(),
1279  candidate->m_code, candidate->m_driver_connection->Name() );
1280 
1281  // Candidate may have other non-chosen drivers we need to follow
1282  add_connections_to_check( candidate );
1283 
1284  subgraph->Absorb( candidate );
1285  invalidated_subgraphs.insert( subgraph );
1286  }
1287  }
1288  }
1289  }
1290  }
1291 
1292  // Update any subgraph that was invalidated above
1293  for( CONNECTION_SUBGRAPH* subgraph : invalidated_subgraphs )
1294  {
1295  if( subgraph->m_absorbed )
1296  continue;
1297 
1298  subgraph->ResolveDrivers();
1299 
1300  if( subgraph->m_driver_connection->IsBus() )
1302  else
1303  assignNewNetCode( *subgraph->m_driver_connection );
1304 
1305  wxLogTrace( ConnTrace, "Re-resolving drivers for %lu (%s)", subgraph->m_code,
1306  subgraph->m_driver_connection->Name() );
1307  }
1308 
1309  // Absorbed subgraphs should no longer be considered
1310  m_driver_subgraphs.erase( std::remove_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1311  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1312  {
1313  return candidate->m_absorbed;
1314  } ),
1315  m_driver_subgraphs.end() );
1316 
1317  // Store global subgraphs for later reference
1318  std::vector<CONNECTION_SUBGRAPH*> global_subgraphs;
1319  std::copy_if( m_driver_subgraphs.begin(), m_driver_subgraphs.end(),
1320  std::back_inserter( global_subgraphs ),
1321  [&] ( const CONNECTION_SUBGRAPH* candidate ) -> bool
1322  {
1323  return !candidate->m_local_driver;
1324  } );
1325 
1326  // Recache remaining valid subgraphs by sheet path
1327  m_sheet_to_subgraphs_map.clear();
1328 
1329  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1330  m_sheet_to_subgraphs_map[ subgraph->m_sheet ].emplace_back( subgraph );
1331 
1332  // Update item connections at this point so that neighbor propagation works
1333  nextSubgraph.store( 0 );
1334 
1335  auto preliminaryUpdateTask =
1336  [&]() -> size_t
1337  {
1338  for( size_t subgraphId = nextSubgraph++;
1339  subgraphId < m_driver_subgraphs.size();
1340  subgraphId = nextSubgraph++ )
1341  {
1342  m_driver_subgraphs[subgraphId]->UpdateItemConnections();
1343  }
1344 
1345  return 1;
1346  };
1347 
1348  if( parallelThreadCount == 1 )
1349  preliminaryUpdateTask();
1350  else
1351  {
1352  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1353  returns[ii] = std::async( std::launch::async, preliminaryUpdateTask );
1354 
1355  // Finalize the threads
1356  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1357  returns[ii].wait();
1358  }
1359 
1360  // Next time through the subgraphs, we do some post-processing to handle things like
1361  // connecting bus members to their neighboring subgraphs, and then propagate connections
1362  // through the hierarchy
1363 
1364  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1365  {
1366  if( !subgraph->m_dirty )
1367  continue;
1368 
1369  wxLogTrace( ConnTrace, "Processing %lu (%s) for propagation", subgraph->m_code,
1370  subgraph->m_driver_connection->Name() );
1371 
1372  // For subgraphs that are driven by a global (power port or label) and have more
1373  // than one global driver, we need to seek out other subgraphs driven by the
1374  // same name as the non-chosen driver and update them to match the chosen one.
1375 
1376  if( !subgraph->m_local_driver && subgraph->m_multiple_drivers )
1377  {
1378  for( SCH_ITEM* driver : subgraph->m_drivers )
1379  {
1380  if( driver == subgraph->m_driver )
1381  continue;
1382 
1383  wxString secondary_name = subgraph->GetNameForDriver( driver );
1384 
1385  if( secondary_name == subgraph->m_driver_connection->Name() )
1386  continue;
1387 
1388  bool secondary_is_global = CONNECTION_SUBGRAPH::GetDriverPriority( driver )
1390 
1391  for( CONNECTION_SUBGRAPH* candidate : global_subgraphs )
1392  {
1393  if( candidate == subgraph )
1394  continue;
1395 
1396  if( !secondary_is_global && candidate->m_sheet != subgraph->m_sheet )
1397  continue;
1398 
1399  SCH_CONNECTION* conn = candidate->m_driver_connection;
1400 
1401  if( conn->Name() == secondary_name )
1402  {
1403  wxLogTrace( ConnTrace, "Global %lu (%s) promoted to %s", candidate->m_code,
1404  conn->Name(), subgraph->m_driver_connection->Name() );
1405 
1406  conn->Clone( *subgraph->m_driver_connection );
1407 
1408  candidate->m_dirty = false;
1409  }
1410  }
1411  }
1412  }
1413 
1414  // This call will handle descending the hierarchy and updating child subgraphs
1415  propagateToNeighbors( subgraph );
1416  }
1417 
1418  // Handle buses that have been linked together somewhere by member (net) connections.
1419  // This feels a bit hacky, perhaps this algorithm should be revisited in the future.
1420 
1421  // For net subgraphs that have more than one bus parent, we need to ensure that those
1422  // buses are linked together in the final netlist. The final name of each bus might not
1423  // match the local name that was used to establish the parent-child relationship, because
1424  // the bus may have been renamed by a hierarchical connection. So, for each of these cases,
1425  // we need to identify the appropriate bus members to link together (and their final names),
1426  // and then update all instances of the old name in the hierarchy.
1427 
1428  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1429  {
1430  // All SGs should have been processed by propagateToNeighbors above
1431  wxASSERT_MSG( !subgraph->m_dirty, "Subgraph not processed by propagateToNeighbors!" );
1432 
1433  if( subgraph->m_bus_parents.size() < 2 )
1434  continue;
1435 
1436  SCH_CONNECTION* conn = subgraph->m_driver_connection;
1437 
1438  wxLogTrace( ConnTrace, "%lu (%s) has multiple bus parents",
1439  subgraph->m_code, conn->Name() );
1440 
1441  wxASSERT( conn->IsNet() );
1442 
1443  for( const auto& ii : subgraph->m_bus_parents )
1444  {
1445  SCH_CONNECTION* link_member = ii.first.get();
1446 
1447  for( CONNECTION_SUBGRAPH* parent : ii.second )
1448  {
1449  while( parent->m_absorbed )
1450  parent = parent->m_absorbed_by;
1451 
1452  SCH_CONNECTION* match = matchBusMember( parent->m_driver_connection, link_member );
1453 
1454  if( !match )
1455  {
1456  wxLogTrace( ConnTrace, "Warning: could not match %s inside %lu (%s)",
1457  conn->Name(), parent->m_code, parent->m_driver_connection->Name() );
1458  continue;
1459  }
1460 
1461  if( conn->Name() != match->Name() )
1462  {
1463  wxString old_name = match->Name();
1464 
1465  wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", parent->m_code,
1466  parent->m_driver_connection->Name(), old_name, conn->Name() );
1467 
1468  match->Clone( *conn );
1469 
1470  auto jj = m_net_name_to_subgraphs_map.find( old_name );
1471 
1472  if( jj == m_net_name_to_subgraphs_map.end() )
1473  continue;
1474 
1475  for( CONNECTION_SUBGRAPH* old_sg : jj->second )
1476  {
1477  while( old_sg->m_absorbed )
1478  old_sg = old_sg->m_absorbed_by;
1479 
1480  old_sg->m_driver_connection->Clone( *conn );
1481  }
1482  }
1483  }
1484  }
1485  }
1486 
1487  nextSubgraph.store( 0 );
1488 
1489  auto updateItemConnectionsTask =
1490  [&]() -> size_t
1491  {
1492  for( size_t subgraphId = nextSubgraph++;
1493  subgraphId < m_driver_subgraphs.size();
1494  subgraphId = nextSubgraph++ )
1495  {
1496  CONNECTION_SUBGRAPH* subgraph = m_driver_subgraphs[subgraphId];
1497 
1498  // Make sure weakly-driven single-pin nets get the unconnected_ prefix
1499  if( !subgraph->m_strong_driver && subgraph->m_drivers.size() == 1 &&
1500  subgraph->m_driver->Type() == SCH_PIN_T )
1501  {
1502  SCH_PIN* pin = static_cast<SCH_PIN*>( subgraph->m_driver );
1503  wxString name = pin->GetDefaultNetName( subgraph->m_sheet, true );
1504 
1506  }
1507 
1508  subgraph->m_dirty = false;
1509  subgraph->UpdateItemConnections();
1510 
1511  // No other processing to do on buses
1512  if( subgraph->m_driver_connection->IsBus() )
1513  continue;
1514 
1515  // As a visual aid, we can check sheet pins that are driven by themselves to see
1516  // if they should be promoted to buses
1517 
1518  if( subgraph->m_driver->Type() == SCH_SHEET_PIN_T )
1519  {
1520  SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( subgraph->m_driver );
1521 
1522  if( SCH_SHEET* sheet = pin->GetParent() )
1523  {
1524  wxString pinText = pin->GetText();
1525  SCH_SCREEN* screen = sheet->GetScreen();
1526 
1527  for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
1528  {
1529  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
1530 
1531  if( label->GetText() == pinText )
1532  {
1533  SCH_SHEET_PATH path = subgraph->m_sheet;
1534  path.push_back( sheet );
1535 
1536  SCH_CONNECTION* parent_conn = label->Connection( &path );
1537 
1538  if( parent_conn && parent_conn->IsBus() )
1540 
1541  break;
1542  }
1543  }
1544 
1545  if( subgraph->m_driver_connection->IsBus() )
1546  continue;
1547  }
1548  }
1549  }
1550 
1551  return 1;
1552  };
1553 
1554  if( parallelThreadCount == 1 )
1555  updateItemConnectionsTask();
1556  else
1557  {
1558  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1559  returns[ii] = std::async( std::launch::async, updateItemConnectionsTask );
1560 
1561  // Finalize the threads
1562  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
1563  returns[ii].wait();
1564  }
1565 
1568 
1569  for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
1570  {
1571  auto key = std::make_pair( subgraph->GetNetName(),
1572  subgraph->m_driver_connection->NetCode() );
1573  m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
1574 
1575  m_net_name_to_subgraphs_map[subgraph->m_driver_connection->Name()].push_back( subgraph );
1576  }
1577 }
SCH_SHEET_PATH m_sheet
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:216
void SetBusCode(int aCode)
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache
std::unordered_map< std::shared_ptr< SCH_CONNECTION >, std::unordered_set< CONNECTION_SUBGRAPH * > > m_bus_neighbors
If a subgraph is a bus, this map contains links between the bus members and any local sheet neighbors...
SCH_ITEM * m_bus_entry
Bus entry in graph, if any.
void Absorb(CONNECTION_SUBGRAPH *aOther)
Combines another subgraph on the same sheet into this one.
This item represents a bus group.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
bool m_local_driver
True if the driver is a local (i.e. non-global) type.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
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.
void ConfigureFromLabel(const wxString &aLabel)
Configures the connection given a label.
void SetName(const wxString &aName)
NET_MAP m_net_code_to_subgraphs_map
std::vector< SCH_ITEM * > m_items
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
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:131
int NetCode() const
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
int assignNewNetCode(SCH_CONNECTION &aConnection)
Helper to assign a new net code to a connection.
void SetSubgraphCode(int aCode)
std::vector< SCH_ITEM * > m_items
bool ResolveDrivers(bool aCheckMultipleDrivers=false)
Determines which potential driver should drive the subgraph.
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
void AddItem(SCH_ITEM *aItem)
Adds a new item to the subgraph.
int SubgraphCode() const
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
void assignNetCodesToBus(SCH_CONNECTION *aConnection)
Ensures all members of the bus connection have a valid net code assigned.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
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
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:87
bool IsNet() const
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
const char * name
Definition: DXF_plotter.cpp:56
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
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.
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:109
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
std::map< wxString, int > m_bus_name_to_code_map
void SetType(CONNECTION_TYPE aType)
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
not connected (must be left open)
bool IsBus() const
CONNECTION_TYPE Type() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
void SetNetCode(int aCode)
wxString GetNetName() const
Returns the fully-qualified net name for this subgraph (if one exists)
PRIORITY GetDriverPriority()
This item represents a bus vector.
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
void UpdateItemConnections()
Updates all items to match the driver connection.

References CONNECTION_SUBGRAPH::AddItem(), assignNetCodesToBus(), assignNewNetCode(), BUS, BUS_GROUP, SCH_CONNECTION::Clone(), SCH_CONNECTION::ConfigureFromLabel(), SCH_ITEM::Connection(), ConnTrace, Format(), getDefaultConnection(), CONNECTION_SUBGRAPH::GetDriverPriority(), CONNECTION_SUBGRAPH::GetNetName(), EDA_ITEM::GetSelectMenuText(), 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, m_bus_name_to_code_map, CONNECTION_SUBGRAPH::m_code, CONNECTION_SUBGRAPH::m_dirty, CONNECTION_SUBGRAPH::m_driver, CONNECTION_SUBGRAPH::m_driver_connection, m_driver_subgraphs, CONNECTION_SUBGRAPH::m_drivers, m_global_label_cache, m_invisible_power_pins, m_item_to_subgraph_map, m_items, m_last_bus_code, m_last_subgraph_code, m_local_label_cache, m_net_code_to_subgraphs_map, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, m_sheet_to_subgraphs_map, CONNECTION_SUBGRAPH::m_strong_driver, m_subgraphs, matchBusMember(), MILLIMETRES, name, SCH_CONNECTION::Name(), EE_RTREE::OfType(), path, pin, CONNECTION_SUBGRAPH::POWER_PIN, propagateToNeighbors(), PT_NC, CONNECTION_SUBGRAPH::ResolveDrivers(), SCH_BUS_WIRE_ENTRY_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_NO_CONNECT_T, SCH_PIN_T, SCH_SHEET_PIN_T, SCH_CONNECTION::SetBusCode(), SCH_CONNECTION::SetName(), SCH_CONNECTION::SetNetCode(), SCH_CONNECTION::SetSubgraphCode(), SCH_CONNECTION::SetType(), SCH_CONNECTION::SubgraphCode(), EDA_ITEM::Type(), and CONNECTION_SUBGRAPH::UpdateItemConnections().

Referenced by Recalculate().

◆ 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 2323 of file connection_graph.cpp.

2324 {
2325  wxString msg;
2326  auto sheet = aSubgraph->m_sheet;
2327  auto screen = sheet.LastScreen();
2328 
2329  SCH_ITEM* label = nullptr;
2330  SCH_ITEM* port = nullptr;
2331 
2332  for( auto item : aSubgraph->m_items )
2333  {
2334  switch( item->Type() )
2335  {
2336  case SCH_TEXT_T:
2337  case SCH_GLOBAL_LABEL_T:
2338  {
2339  if( !label && item->Connection( &sheet )->IsBus() )
2340  label = item;
2341  break;
2342  }
2343 
2344  case SCH_SHEET_PIN_T:
2345  case SCH_HIER_LABEL_T:
2346  {
2347  if( !port && item->Connection( &sheet )->IsBus() )
2348  port = item;
2349  break;
2350  }
2351 
2352  default:
2353  break;
2354  }
2355  }
2356 
2357  if( label && port )
2358  {
2359  bool match = false;
2360 
2361  for( const auto& member : label->Connection( &sheet )->Members() )
2362  {
2363  for( const auto& test : port->Connection( &sheet )->Members() )
2364  {
2365  if( test != member && member->Name() == test->Name() )
2366  {
2367  match = true;
2368  break;
2369  }
2370  }
2371 
2372  if( match )
2373  break;
2374  }
2375 
2376  if( !match )
2377  {
2378  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
2379  ercItem->SetItems( label, port );
2380 
2381  SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
2382  screen->Append( marker );
2383 
2384  return false;
2385  }
2386  }
2387 
2388  return true;
2389 }
SCH_SHEET_PATH m_sheet
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:59
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
virtual wxPoint GetPosition() const
Definition: eda_item.h:252
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:131
std::vector< SCH_ITEM * > m_items
SCH_SCREEN * LastScreen()
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193

References 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, and SCH_TEXT_T.

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 2392 of file connection_graph.cpp.

2393 {
2394  bool conflict = false;
2395  auto sheet = aSubgraph->m_sheet;
2396  auto screen = sheet.LastScreen();
2397 
2398  SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2399  SCH_ITEM* bus_wire = nullptr;
2400  wxString bus_name;
2401 
2402  if( !aSubgraph->m_driver_connection )
2403  {
2404  // Incomplete bus entry. Let the unconnected tests handle it.
2405  return true;
2406  }
2407 
2408  for( auto item : aSubgraph->m_items )
2409  {
2410  switch( item->Type() )
2411  {
2412  case SCH_BUS_WIRE_ENTRY_T:
2413  {
2414  if( !bus_entry )
2415  bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2416  break;
2417  }
2418 
2419  default:
2420  break;
2421  }
2422  }
2423 
2424  if( bus_entry && bus_entry->m_connected_bus_item )
2425  {
2426  bus_wire = bus_entry->m_connected_bus_item;
2427 
2428  wxASSERT( bus_wire->Type() == SCH_LINE_T );
2429 
2430  // In some cases, the connection list (SCH_CONNECTION*) can be null.
2431  // Skip null connections.
2432  if( bus_entry->Connection( &sheet )
2433  && bus_wire->Type() == SCH_LINE_T
2434  && bus_wire->Connection( &sheet ) )
2435  {
2436  conflict = true; // Assume a conflict; we'll reset if we find it's OK
2437 
2438  bus_name = bus_wire->Connection( &sheet )->Name();
2439 
2440  wxString test_name = bus_entry->Connection( &sheet )->Name();
2441 
2442  for( const auto& member : bus_wire->Connection( &sheet )->Members() )
2443  {
2444  if( member->Type() == CONNECTION_TYPE::BUS )
2445  {
2446  for( const auto& sub_member : member->Members() )
2447  {
2448  if( sub_member->Name() == test_name )
2449  conflict = false;
2450  }
2451  }
2452  else if( member->Name() == test_name )
2453  {
2454  conflict = false;
2455  }
2456  }
2457  }
2458  }
2459 
2460  // Don't report warnings if this bus member has been overridden by a higher priority power pin
2461  // or global label
2462  if( conflict && CONNECTION_SUBGRAPH::GetDriverPriority( aSubgraph->m_driver )
2464  conflict = false;
2465 
2466  if( conflict )
2467  {
2468  wxString netName = aSubgraph->m_driver_connection->Name();
2469  wxString msg = wxString::Format( _( "Net %s is graphically connected to bus %s but is not a"
2470  " member of that bus" ),
2471  UnescapeString( netName ),
2472  UnescapeString( bus_name ) );
2473  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
2474  ercItem->SetItems( bus_entry, bus_wire );
2475  ercItem->SetErrorMessage( msg );
2476 
2477  SCH_MARKER* marker = new SCH_MARKER( ercItem, bus_entry->GetPosition() );
2478  screen->Append( marker );
2479 
2480  return false;
2481  }
2482 
2483  return true;
2484 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
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 ...
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
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:131
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
#define _(s)
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:57
wxString UnescapeString(const wxString &aSource)
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
SCH_SCREEN * LastScreen()
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
Class for a wire to bus entry.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
PRIORITY GetDriverPriority()
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
wxPoint GetPosition() const override

References _, 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 2266 of file connection_graph.cpp.

2267 {
2268  auto sheet = aSubgraph->m_sheet;
2269  auto screen = sheet.LastScreen();
2270 
2271  SCH_ITEM* net_item = nullptr;
2272  SCH_ITEM* bus_item = nullptr;
2273  SCH_CONNECTION conn( this );
2274 
2275  for( SCH_ITEM* item : aSubgraph->m_items )
2276  {
2277  switch( item->Type() )
2278  {
2279  case SCH_LINE_T:
2280  {
2281  if( item->GetLayer() == LAYER_BUS )
2282  bus_item = ( !bus_item ) ? item : bus_item;
2283  else
2284  net_item = ( !net_item ) ? item : net_item;
2285  break;
2286  }
2287 
2288  case SCH_LABEL_T:
2289  case SCH_GLOBAL_LABEL_T:
2290  case SCH_SHEET_PIN_T:
2291  case SCH_HIER_LABEL_T:
2292  {
2293  SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2294  conn.ConfigureFromLabel( EscapeString( text->GetShownText(), CTX_NETNAME ) );
2295 
2296  if( conn.IsBus() )
2297  bus_item = ( !bus_item ) ? item : bus_item;
2298  else
2299  net_item = ( !net_item ) ? item : net_item;
2300  break;
2301  }
2302 
2303  default:
2304  break;
2305  }
2306  }
2307 
2308  if( net_item && bus_item )
2309  {
2310  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
2311  ercItem->SetItems( net_item, bus_item );
2312 
2313  SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
2314  screen->Append( marker );
2315 
2316  return false;
2317  }
2318 
2319  return true;
2320 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:61
virtual wxPoint GetPosition() const
Definition: eda_item.h:252
std::vector< SCH_ITEM * > m_items
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:268
SCH_SCREEN * LastScreen()
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113

References 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 2661 of file connection_graph.cpp.

2662 {
2663  if( aSubgraph->m_driver )
2664  return true;
2665 
2666  std::vector<SCH_ITEM*> wires;
2667 
2668  // We've gotten this far, so we know we have no valid driver. All we need to do is check
2669  // for a wire that we can place the error on.
2670 
2671  for( SCH_ITEM* item : aSubgraph->m_items )
2672  {
2673  if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
2674  wires.emplace_back( item );
2675  else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
2676  wires.emplace_back( item );
2677  }
2678 
2679  if( !wires.empty() )
2680  {
2681  SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2682 
2683  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
2684  ercItem->SetItems( wires[0],
2685  wires.size() > 1 ? wires[1] : nullptr,
2686  wires.size() > 2 ? wires[2] : nullptr,
2687  wires.size() > 3 ? wires[3] : nullptr );
2688 
2689  SCH_MARKER* marker = new SCH_MARKER( ercItem, wires[0]->GetPosition() );
2690  screen->Append( marker );
2691 
2692  return false;
2693  }
2694 
2695  return true;
2696 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
Some wires are not connected to anything else.
Definition: erc_settings.h:65
std::vector< SCH_ITEM * > m_items
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:268
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:144
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113

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 2823 of file connection_graph.cpp.

2824 {
2825  int errors = 0;
2826 
2827  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2828 
2829  for( const SCH_SHEET_PATH& sheet : m_sheetList )
2830  {
2831  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
2832  {
2833  if( item->Type() != SCH_SHEET_T )
2834  continue;
2835 
2836  SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
2837 
2838  std::map<wxString, SCH_SHEET_PIN*> pins;
2839  std::map<wxString, SCH_HIERLABEL*> labels;
2840 
2841  for( SCH_SHEET_PIN* pin : parentSheet->GetPins() )
2842  {
2843  pins[pin->GetText()] = pin;
2844 
2845  if( pin->IsDangling() && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2846  {
2847  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2848  ercItem->SetItems( pin );
2849 
2850  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
2851  sheet.LastScreen()->Append( marker );
2852 
2853  errors++;
2854  }
2855  }
2856 
2857  std::set<wxString> matchedPins;
2858 
2859  for( SCH_ITEM* subItem : parentSheet->GetScreen()->Items() )
2860  {
2861  if( subItem->Type() == SCH_HIER_LABEL_T )
2862  {
2863  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
2864 
2865  if( !pins.count( label->GetText() ) )
2866  labels[label->GetText()] = label;
2867  else
2868  matchedPins.insert( label->GetText() );
2869  }
2870  }
2871 
2872  for( const wxString& matched : matchedPins )
2873  pins.erase( matched );
2874 
2875  for( const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
2876  {
2877  wxString msg = wxString::Format( _( "Sheet pin %s has no matching hierarchical "
2878  "label inside the sheet" ),
2879  UnescapeString( unmatched.first ) );
2880 
2881  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
2882  ercItem->SetItems( unmatched.second );
2883  ercItem->SetErrorMessage( msg );
2884  ercItem->SetIsSheetSpecific();
2885 
2886  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
2887  sheet.LastScreen()->Append( marker );
2888 
2889  errors++;
2890  }
2891 
2892  for( const std::pair<const wxString, SCH_HIERLABEL*>& unmatched : labels )
2893  {
2894  wxString msg = wxString::Format( _( "Hierarchical label %s has no matching "
2895  "sheet pin in the parent sheet" ),
2896  UnescapeString( unmatched.first ) );
2897 
2898  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
2899  ercItem->SetItems( unmatched.second );
2900  ercItem->SetErrorMessage( msg );
2901  ercItem->SetIsSheetSpecific();
2902 
2903  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
2904  parentSheet->GetScreen()->Append( marker );
2905 
2906  errors++;
2907  }
2908  }
2909  }
2910 
2911  return errors;
2912 }
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
SCHEMATIC * m_schematic
The schematic this graph represents.
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:103
#define _(s)
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Container for ERC settings.
Definition: erc_settings.h:106
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString UnescapeString(const wxString &aSource)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:184
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
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:46
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:144
SCH_SHEET_LIST m_sheetList
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133

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 2699 of file connection_graph.cpp.

2700 {
2701  // Label connection rules:
2702  // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2703  // Global labels are flagged if they appear only once, don't connect to any local labels,
2704  // and don't have a no-connect marker
2705 
2706  // So, if there is a no-connect, we will never generate a warning here
2707  if( aSubgraph->m_no_connect )
2708  return true;
2709 
2710  if( !aSubgraph->m_driver_connection )
2711  return true;
2712 
2713  // Buses are excluded from this test: many users create buses with only a single instance
2714  // and it's not really a problem as long as the nets in the bus pass ERC
2715  if( aSubgraph->m_driver_connection->IsBus() )
2716  return true;
2717 
2718  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2719  bool ok = true;
2720  SCH_TEXT* text = nullptr;
2721  bool hasOtherConnections = false;
2722  int pinCount = 0;
2723 
2724  for( auto item : aSubgraph->m_items )
2725  {
2726  switch( item->Type() )
2727  {
2728  case SCH_LABEL_T:
2729  case SCH_GLOBAL_LABEL_T:
2730  case SCH_HIER_LABEL_T:
2731  {
2732  text = static_cast<SCH_TEXT*>( item );
2733 
2734  // Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
2735  // we want to error if an individual label in the subgraph is floating, even if it's
2736  // connected to other valid things by way of another label on the same sheet.
2737 
2738  if( text->IsDangling() && settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
2739  {
2740  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LABEL_NOT_CONNECTED );
2741  ercItem->SetItems( text );
2742 
2743  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2744  aSubgraph->m_sheet.LastScreen()->Append( marker );
2745  ok = false;
2746  }
2747 
2748  break;
2749  }
2750 
2751  case SCH_PIN_T:
2752  case SCH_SHEET_PIN_T:
2753  hasOtherConnections = true;
2754  pinCount++;
2755  break;
2756 
2757  default:
2758  break;
2759  }
2760  }
2761 
2762  if( !text )
2763  return true;
2764 
2765  bool isGlobal = text->Type() == SCH_GLOBAL_LABEL_T;
2766  int errCode = isGlobal ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
2767 
2768  wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" );
2769 
2770  wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
2771 
2772  if( isGlobal )
2773  {
2774  // This will be set to true if the global is connected to a pin above, but we
2775  // want to reset this to false so that globals get flagged if they only have a
2776  // single instance connected to a single pin
2777  hasOtherConnections = ( pinCount > 1 );
2778 
2779  auto it = m_net_name_to_subgraphs_map.find( name );
2780 
2781  if( it != m_net_name_to_subgraphs_map.end() )
2782  {
2783  if( it->second.size() > 1 || aSubgraph->m_multiple_drivers )
2784  hasOtherConnections = true;
2785  }
2786  }
2787  else if( text->Type() == SCH_HIER_LABEL_T )
2788  {
2789  // For a hier label, check if the parent pin is connected
2790  if( aSubgraph->m_hier_parent &&
2791  ( aSubgraph->m_hier_parent->m_strong_driver ||
2792  aSubgraph->m_hier_parent->m_drivers.size() > 1) )
2793  {
2794  // For now, a simple check: if there is more than one driver, the parent is probably
2795  // connected elsewhere (because at least one driver will be the hier pin itself)
2796  hasOtherConnections = true;
2797  }
2798  }
2799  else
2800  {
2801  auto pair = std::make_pair( aSubgraph->m_sheet, name );
2802  auto it = m_local_label_cache.find( pair );
2803 
2804  if( it != m_local_label_cache.end() && it->second.size() > 1 )
2805  hasOtherConnections = true;
2806  }
2807 
2808  if( !hasOtherConnections && settings.IsTestEnabled( errCode ) )
2809  {
2810  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
2811  ercItem->SetItems( text );
2812 
2813  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2814  aSubgraph->m_sheet.LastScreen()->Append( marker );
2815 
2816  return false;
2817  }
2818 
2819  return ok;
2820 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
Label not connected to anything.
Definition: erc_settings.h:49
SCHEMATIC * m_schematic
The schematic this graph represents.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
std::vector< SCH_ITEM * > m_items
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Container for ERC settings.
Definition: erc_settings.h:106
A global label is unique.
Definition: erc_settings.h:63
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:56
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:144
CONNECTION_SUBGRAPH * m_hier_parent
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
bool IsBus() const

References SCH_SCREEN::Append(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, SCHEMATIC::ErcSettings(), EscapeString(), SCH_CONNECTION::IsBus(), ERC_SETTINGS::IsTestEnabled(), SCH_SHEET_PATH::LastScreen(), CONNECTION_SUBGRAPH::m_driver_connection, CONNECTION_SUBGRAPH::m_drivers, CONNECTION_SUBGRAPH::m_hier_parent, CONNECTION_SUBGRAPH::m_items, m_local_label_cache, CONNECTION_SUBGRAPH::m_multiple_drivers, m_net_name_to_subgraphs_map, CONNECTION_SUBGRAPH::m_no_connect, m_schematic, CONNECTION_SUBGRAPH::m_sheet, CONNECTION_SUBGRAPH::m_strong_driver, name, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T, SCH_LABEL_T, SCH_PIN_T, SCH_SHEET_PIN_T, and text.

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 2236 of file connection_graph.cpp.

2237 {
2238  if( !aSubgraph->m_second_driver )
2239  return true;
2240 
2241  SCH_ITEM* primary = aSubgraph->m_first_driver;
2242  SCH_ITEM* secondary = aSubgraph->m_second_driver;
2243 
2244  wxPoint pos = primary->Type() == SCH_PIN_T ?
2245  static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2246  primary->GetPosition();
2247 
2248  wxString primaryName = aSubgraph->GetNameForDriver( primary );
2249  wxString secondaryName = aSubgraph->GetNameForDriver( secondary );
2250 
2251  wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2252  "items; %s will be used in the netlist" ),
2253  primaryName, secondaryName, primaryName );
2254 
2255  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2256  ercItem->SetItems( primary, secondary );
2257  ercItem->SetErrorMessage( msg );
2258 
2259  SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2260  aSubgraph->m_sheet.LastScreen()->Append( marker );
2261 
2262  return false;
2263 }
SCH_SHEET_PATH m_sheet
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
SCH_ITEM * m_second_driver
Used for multiple drivers ERC message; stores the second possible driver (or nullptr)
virtual wxPoint GetPosition() const
Definition: eda_item.h:252
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
#define _(s)
SCH_ITEM * m_first_driver
Stores the primary driver for the multiple drivers ERC check.
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
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:144
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:56
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113

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

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 2488 of file connection_graph.cpp.

2489 {
2490  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2491  wxString msg;
2492  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2493  SCH_SCREEN* screen = sheet.LastScreen();
2494  bool ok = true;
2495 
2496  if( aSubgraph->m_no_connect != nullptr )
2497  {
2498  bool has_invalid_items = false;
2499  bool has_other_items = false;
2500  SCH_PIN* pin = nullptr;
2501  std::vector<SCH_ITEM*> invalid_items;
2502  wxPoint noConnectPos = aSubgraph->m_no_connect->GetPosition();
2503  double minDist = 0;
2504 
2505  // Any subgraph that contains both a pin and a no-connect should not
2506  // contain any other driving items.
2507 
2508  for( auto item : aSubgraph->m_items )
2509  {
2510  switch( item->Type() )
2511  {
2512  case SCH_PIN_T:
2513  {
2514  SCH_PIN* candidate = static_cast<SCH_PIN*>( item );
2515  double dist = VECTOR2I( candidate->GetTransformedPosition() - noConnectPos )
2516  .SquaredEuclideanNorm();
2517 
2518  if( !pin || dist < minDist )
2519  {
2520  pin = candidate;
2521  minDist = dist;
2522  }
2523 
2524  has_invalid_items |= has_other_items;
2525  has_other_items = true;
2526  break;
2527  }
2528 
2529  case SCH_LINE_T:
2530  case SCH_JUNCTION_T:
2531  case SCH_NO_CONNECT_T:
2532  break;
2533 
2534  default:
2535  has_invalid_items = true;
2536  has_other_items = true;
2537  invalid_items.push_back( item );
2538  }
2539  }
2540 
2541  if( pin && has_invalid_items && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
2542  {
2543  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
2544  ercItem->SetItems( pin );
2545 
2546  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2547  screen->Append( marker );
2548 
2549  ok = false;
2550  }
2551 
2552  if( !has_other_items && settings.IsTestEnabled(ERCE_NOCONNECT_NOT_CONNECTED ) )
2553  {
2554  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
2555  ercItem->SetItems( aSubgraph->m_no_connect );
2556 
2557  SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
2558  screen->Append( marker );
2559 
2560  ok = false;
2561  }
2562  }
2563  else
2564  {
2565  bool has_other_connections = false;
2566  std::vector<SCH_PIN*> pins;
2567 
2568  // Any subgraph that lacks a no-connect and contains a pin should also
2569  // contain at least one other potential driver
2570 
2571  for( SCH_ITEM* item : aSubgraph->m_items )
2572  {
2573  switch( item->Type() )
2574  {
2575  case SCH_PIN_T:
2576  {
2577  if( !pins.empty() )
2578  has_other_connections = true;
2579 
2580  pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2581 
2582  break;
2583  }
2584 
2585  default:
2586  if( aSubgraph->GetDriverPriority( item ) != CONNECTION_SUBGRAPH::PRIORITY::NONE )
2587  has_other_connections = true;
2588 
2589  break;
2590  }
2591  }
2592 
2593  // For many checks, we can just use the first pin
2594  SCH_PIN* pin = pins.empty() ? nullptr : pins[0];
2595 
2596  // Check if invisible power input pins connect to anything else via net name,
2597  // but not for power symbols as the ones in the standard library all have invisible pins
2598  // and we want to throw unconnected errors for those even if they are connected to other
2599  // net items by name, because usually failing to connect them graphically is a mistake
2600  if( pin && !has_other_connections
2601  && pin->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN
2602  && !pin->IsVisible()
2603  && !pin->GetLibPin()->GetParent()->IsPower() )
2604  {
2605  wxString name = pin->Connection( &sheet )->Name();
2606  wxString local_name = pin->Connection( &sheet )->Name( true );
2607 
2608  if( m_global_label_cache.count( name ) ||
2609  ( m_local_label_cache.count( std::make_pair( sheet, local_name ) ) ) )
2610  {
2611  has_other_connections = true;
2612  }
2613  }
2614 
2615  // Only one pin, and it's not a no-connect pin
2616  if( pin && !has_other_connections
2617  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
2618  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
2619  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2620  {
2621  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2622  ercItem->SetItems( pin );
2623 
2624  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2625  screen->Append( marker );
2626 
2627  ok = false;
2628  }
2629 
2630  // If there are multiple pins in this SG, they might be indirectly connected (by netname)
2631  // rather than directly connected (by wires). We want to flag dangling pins even if they
2632  // join nets with another pin, as it's often a mistake
2633  if( pins.size() > 1 )
2634  {
2635  for( SCH_PIN* testPin : pins )
2636  {
2637  // We only apply this test to power symbols, because other symbols have invisible
2638  // pins that are meant to be dangling, but the KiCad standard library power symbols
2639  // have invisible pins that are *not* meant to be dangling.
2640  if( testPin->GetLibPin()->GetParent()->IsPower()
2641  && testPin->ConnectedItems( sheet ).empty()
2642  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2643  {
2644  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2645  ercItem->SetItems( testPin );
2646 
2647  SCH_MARKER* marker = new SCH_MARKER( ercItem,
2648  testPin->GetTransformedPosition() );
2649  screen->Append( marker );
2650 
2651  ok = false;
2652  }
2653  }
2654  }
2655  }
2656 
2657  return ok;
2658 }
power input (GND, VCC for ICs). Must be connected to a power output.
SCH_SHEET_PATH m_sheet
Pin not connected and not no connect symbol.
Definition: erc_settings.h:41
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:194
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
SCHEMATIC * m_schematic
The schematic this graph represents.
virtual wxPoint GetPosition() const
Definition: eda_item.h:252
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
not internally connected (may be connected to anything)
std::vector< SCH_ITEM * > m_items
Container for ERC settings.
Definition: erc_settings.h:106
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
A no connect symbol is not connected to anything.
Definition: erc_settings.h:48
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
A no connect symbol is connected to more than 1 pin.
Definition: erc_settings.h:47
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:56
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:144
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
SCH_ITEM * m_no_connect
No-connect item in graph, if any.
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
not connected (must be left open)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
wxPoint GetTransformedPosition() const
Definition: sch_pin.cpp:299

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(), SCH_PIN::GetTransformedPosition(), 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 2121 of file connection_graph.cpp.

2122 {
2123  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2124 
2125  if( it == m_net_name_to_subgraphs_map.end() )
2126  return nullptr;
2127 
2128  wxASSERT( !it->second.empty() );
2129 
2130  return it->second[0];
2131 }
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map

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 2100 of file connection_graph.cpp.

2102 {
2103  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2104 
2105  if( it == m_net_name_to_subgraphs_map.end() )
2106  return nullptr;
2107 
2108  for( CONNECTION_SUBGRAPH* sg : it->second )
2109  {
2110  // Cache is supposed to be valid by now
2111  wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
2112 
2113  if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
2114  return sg;
2115  }
2116 
2117  return nullptr;
2118 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
A subgraph is a set of items that are electrically connected on a single sheet.
wxString Name(bool aIgnoreSheet=false) const

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().

◆ 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 2044 of file connection_graph.cpp.

2045 {
2046  auto it = m_bus_alias_cache.find( aName );
2047 
2048  return it != m_bus_alias_cache.end() ? it->second : nullptr;
2049 }
std::unordered_map< wxString, std::shared_ptr< BUS_ALIAS > > m_bus_alias_cache

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 2052 of file connection_graph.cpp.

2053 {
2054  std::vector<const CONNECTION_SUBGRAPH*> ret;
2055 
2056  for( auto&& subgraph : m_subgraphs )
2057  {
2058  // Graph is supposed to be up-to-date before calling this
2059  wxASSERT( !subgraph->m_dirty );
2060 
2061  if( !subgraph->m_driver )
2062  continue;
2063 
2064  auto sheet = subgraph->m_sheet;
2065  auto connection = subgraph->m_driver->Connection( &sheet );
2066 
2067  if( !connection->IsBus() )
2068  continue;
2069 
2070  auto labels = subgraph->GetBusLabels();
2071 
2072  if( labels.size() > 1 )
2073  {
2074  bool different = false;
2075  wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2076 
2077  for( unsigned i = 1; i < labels.size(); ++i )
2078  {
2079  if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2080  {
2081  different = true;
2082  break;
2083  }
2084  }
2085 
2086  if( !different )
2087  continue;
2088 
2089  wxLogTrace( ConnTrace, "SG %ld (%s) has multiple bus labels", subgraph->m_code,
2090  connection->Name() );
2091 
2092  ret.push_back( subgraph );
2093  }
2094  }
2095 
2096  return ret;
2097 }
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
static const wxChar ConnTrace[]

References ConnTrace, and m_subgraphs.

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 1935 of file connection_graph.cpp.

1937 {
1938  auto c = std::shared_ptr<SCH_CONNECTION>( nullptr );
1939 
1940  switch( aItem->Type() )
1941  {
1942  case SCH_PIN_T:
1943  {
1944  auto pin = static_cast<SCH_PIN*>( aItem );
1945 
1946  if( pin->IsPowerConnection() )
1947  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
1948 
1949  break;
1950  }
1951 
1952  case SCH_GLOBAL_LABEL_T:
1953  case SCH_HIER_LABEL_T:
1954  case SCH_LABEL_T:
1955  {
1956  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
1957  break;
1958  }
1959 
1960  default:
1961  break;
1962  }
1963 
1964  if( c )
1965  {
1966  c->SetGraph( this );
1967  c->ConfigureFromLabel( aSubgraph->GetNameForDriver( aItem ) );
1968  }
1969 
1970  return c;
1971 }
SCH_SHEET_PATH m_sheet
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113

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 buildConnectionGraph(), and propagateToNeighbors().

◆ GetNetMap()

◆ GetSubgraphForItem()

CONNECTION_SUBGRAPH * CONNECTION_GRAPH::GetSubgraphForItem ( SCH_ITEM aItem)

Definition at line 2134 of file connection_graph.cpp.

2135 {
2136  auto it = m_item_to_subgraph_map.find( aItem );
2137  CONNECTION_SUBGRAPH* ret = it != m_item_to_subgraph_map.end() ? it->second : nullptr;
2138 
2139  while( ret && ret->m_absorbed )
2140  ret = ret->m_absorbed_by;
2141 
2142  return ret;
2143 }
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
A subgraph is a set of items that are electrically connected on a single sheet.
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

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

Referenced by inheritNetclass(), and 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 1974 of file connection_graph.cpp.

1976 {
1977  wxASSERT( aBusConnection->IsBus() );
1978 
1979  SCH_CONNECTION* match = nullptr;
1980 
1981  if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
1982  {
1983  // Vector bus: compare against index, because we allow the name
1984  // to be different
1985 
1986  for( const auto& bus_member : aBusConnection->Members() )
1987  {
1988  if( bus_member->VectorIndex() == aSearch->VectorIndex() )
1989  {
1990  match = bus_member.get();
1991  break;
1992  }
1993  }
1994  }
1995  else
1996  {
1997  // Group bus
1998  for( const auto& c : aBusConnection->Members() )
1999  {
2000  // Vector inside group: compare names, because for bus groups
2001  // we expect the naming to be consistent across all usages
2002  // TODO(JE) explain this in the docs
2003  if( c->Type() == CONNECTION_TYPE::BUS )
2004  {
2005  for( const auto& bus_member : c->Members() )
2006  {
2007  if( bus_member->LocalName() == aSearch->LocalName() )
2008  {
2009  match = bus_member.get();
2010  break;
2011  }
2012  }
2013  }
2014  else if( c->LocalName() == aSearch->LocalName() )
2015  {
2016  match = c.get();
2017  break;
2018  }
2019  }
2020  }
2021 
2022  return match;
2023 }
wxString LocalName() const
long VectorIndex() const
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
bool IsBus() const
CONNECTION_TYPE Type() const
This item represents a bus vector.

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

Referenced by buildConnectionGraph(), and propagateToNeighbors().

◆ 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 1623 of file connection_graph.cpp.

1624 {
1625  SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1626  std::vector<CONNECTION_SUBGRAPH*> search_list;
1627  std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1628  std::vector<SCH_CONNECTION*> stale_bus_members;
1629 
1630  auto visit =
1631  [&]( CONNECTION_SUBGRAPH* aParent )
1632  {
1633  for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1634  {
1635  SCH_SHEET_PATH path = aParent->m_sheet;
1636  path.push_back( pin->GetParent() );
1637 
1638  auto it = m_sheet_to_subgraphs_map.find( path );
1639 
1640  if( it == m_sheet_to_subgraphs_map.end() )
1641  continue;
1642 
1643  for( CONNECTION_SUBGRAPH* candidate : it->second )
1644  {
1645  if( !candidate->m_strong_driver
1646  || candidate->m_hier_ports.empty()
1647  || visited.count( candidate ) )
1648  {
1649  continue;
1650  }
1651 
1652  for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1653  {
1654  if( candidate->GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1655  {
1656  wxLogTrace( ConnTrace, "%lu: found child %lu (%s)", aParent->m_code,
1657  candidate->m_code, candidate->m_driver_connection->Name() );
1658 
1659  candidate->m_hier_parent = aParent;
1660 
1661  search_list.push_back( candidate );
1662  break;
1663  }
1664  }
1665  }
1666  }
1667 
1668  for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1669  {
1670  SCH_SHEET_PATH path = aParent->m_sheet;
1671  path.pop_back();
1672 
1673  auto it = m_sheet_to_subgraphs_map.find( path );
1674 
1675  if( it == m_sheet_to_subgraphs_map.end() )
1676  continue;
1677 
1678  for( CONNECTION_SUBGRAPH* candidate : it->second )
1679  {
1680  if( candidate->m_hier_pins.empty()
1681  || visited.count( candidate )
1682  || candidate->m_driver_connection->Type() != aParent->m_driver_connection->Type() )
1683  {
1684  continue;
1685  }
1686 
1687  for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1688  {
1689  SCH_SHEET_PATH pin_path = path;
1690  pin_path.push_back( pin->GetParent() );
1691 
1692  if( pin_path != aParent->m_sheet )
1693  continue;
1694 
1695  if( aParent->GetNameForDriver( label ) == candidate->GetNameForDriver( pin ) )
1696  {
1697  wxLogTrace( ConnTrace, "%lu: found additional parent %lu (%s)",
1698  aParent->m_code, candidate->m_code,
1699  candidate->m_driver_connection->Name() );
1700 
1701  search_list.push_back( candidate );
1702  break;
1703  }
1704  }
1705  }
1706  }
1707  };
1708 
1709  auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1710  for( const auto& kv : aParentGraph->m_bus_neighbors )
1711  {
1712  for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1713  {
1714  // May have been absorbed but won't have been deleted
1715  while( neighbor->m_absorbed )
1716  neighbor = neighbor->m_absorbed_by;
1717 
1718  SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1719 
1720  // Now member may be out of date, since we just cloned the
1721  // connection from higher up in the hierarchy. We need to
1722  // figure out what the actual new connection is.
1723  SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1724 
1725  if( !member )
1726  {
1727  // Try harder: we might match on a secondary driver
1728  for( CONNECTION_SUBGRAPH* sg : kv.second )
1729  {
1730  if( sg->m_multiple_drivers )
1731  {
1732  SCH_SHEET_PATH sheet = sg->m_sheet;
1733 
1734  for( SCH_ITEM* driver : sg->m_drivers )
1735  {
1736  auto c = getDefaultConnection( driver, sg );
1737  member = matchBusMember( parent, c.get() );
1738 
1739  if( member )
1740  break;
1741  }
1742  }
1743 
1744  if( member )
1745  break;
1746  }
1747  }
1748 
1749  // This is bad, probably an ERC error
1750  if( !member )
1751  {
1752  wxLogTrace( ConnTrace, "Could not match bus member %s in %s",
1753  kv.first->Name(), parent->Name() );
1754  continue;
1755  }
1756 
1757  auto neighbor_conn = neighbor->m_driver_connection;
1758  auto neighbor_name = neighbor_conn->Name();
1759 
1760  // Matching name: no update needed
1761  if( neighbor_name == member->Name() )
1762  continue;
1763 
1764  // Was this neighbor already updated from a different sheet? Don't rename it again
1765  if( neighbor_conn->Sheet() != neighbor->m_sheet )
1766  continue;
1767 
1768  // Safety check against infinite recursion
1769  wxASSERT( neighbor_conn->IsNet() );
1770 
1771  wxLogTrace( ConnTrace, "%lu (%s) connected to bus member %s (local %s)",
1772  neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1773 
1774  // Take whichever name is higher priority
1777  {
1778  member->Clone( *neighbor_conn );
1779  stale_bus_members.push_back( member );
1780  }
1781  else
1782  {
1783  neighbor_conn->Clone( *member );
1784 
1785  recacheSubgraphName( neighbor, neighbor_name );
1786 
1787  // Recurse onto this neighbor in case it needs to re-propagate
1788  neighbor->m_dirty = true;
1789  propagateToNeighbors( neighbor );
1790  }
1791  }
1792  }
1793  };
1794 
1795  // If we are a bus, we must propagate to local neighbors and then the hierarchy
1796  if( conn->IsBus() )
1797  propagate_bus_neighbors( aSubgraph );
1798 
1799  // If we have both ports and pins, skip processing as we'll be visited by a parent or child.
1800  // If we only have one or the other, process (we can either go bottom-up or top-down depending
1801  // on which subgraph comes up first)
1802  if( !aSubgraph->m_hier_ports.empty() && !aSubgraph->m_hier_pins.empty() )
1803  {
1804  wxLogTrace( ConnTrace, "%lu (%s) has both hier ports and pins; deferring processing",
1805  aSubgraph->m_code, conn->Name() );
1806  return;
1807  }
1808  else if( aSubgraph->m_hier_ports.empty() && aSubgraph->m_hier_pins.empty() )
1809  {
1810  wxLogTrace( ConnTrace, "%lu (%s) has no hier pins or ports; marking clean",
1811  aSubgraph->m_code, conn->Name() );
1812  aSubgraph->m_dirty = false;
1813  return;
1814  }
1815 
1816  visited.insert( aSubgraph );
1817 
1818  wxLogTrace( ConnTrace, "Propagating %lu (%s) to subsheets",
1819  aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1820 
1821  visit( aSubgraph );
1822 
1823  for( unsigned i = 0; i < search_list.size(); i++ )
1824  {
1825  auto child = search_list[i];
1826 
1827  visited.insert( child );
1828 
1829  visit( child );
1830 
1831  child->m_dirty = false;
1832  }
1833 
1834  // Now, find the best driver for this chain of subgraphs
1835  CONNECTION_SUBGRAPH* bestDriver = aSubgraph;
1838  bool bestIsStrong = ( highest >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1839  wxString bestName = aSubgraph->m_driver_connection->Name();
1840 
1841  // Check if a subsheet has a higher-priority connection to the same net
1843  {
1844  for( CONNECTION_SUBGRAPH* subgraph : visited )
1845  {
1846  if( subgraph == aSubgraph )
1847  continue;
1848 
1850  CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
1851 
1852  bool candidateStrong = ( priority >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1853  wxString candidateName = subgraph->m_driver_connection->Name();
1854  bool shorterPath = subgraph->m_sheet.size() < bestDriver->m_sheet.size();
1855  bool asGoodPath = subgraph->m_sheet.size() <= bestDriver->m_sheet.size();
1856 
1857  // Pick a better driving subgraph if it:
1858  // a) has a power pin or global driver
1859  // b) is a strong driver and we're a weak driver
1860  // c) is a higher priority strong driver
1861  // d) matches our priority, is a strong driver, and has a shorter path
1862  // e) matches our strength and is at least as short, and is alphabetically lower
1863 
1864  if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
1865  ( !bestIsStrong && candidateStrong ) ||
1866  ( priority > highest && candidateStrong ) ||
1867  ( priority == highest && candidateStrong && shorterPath ) ||
1868  ( ( bestIsStrong == candidateStrong ) && asGoodPath && ( priority == highest ) &&
1869  ( candidateName < bestName ) ) )
1870  {
1871  bestDriver = subgraph;
1872  highest = priority;
1873  bestIsStrong = candidateStrong;
1874  bestName = candidateName;
1875  }
1876  }
1877  }
1878 
1879  if( bestDriver != aSubgraph )
1880  {
1881  wxLogTrace( ConnTrace, "%lu (%s) overridden by new driver %lu (%s)",
1882  aSubgraph->m_code, aSubgraph->m_driver_connection->Name(), bestDriver->m_code,
1883  bestDriver->m_driver_connection->Name() );
1884  }
1885 
1886  conn = bestDriver->m_driver_connection;
1887 
1888  for( CONNECTION_SUBGRAPH* subgraph : visited )
1889  {
1890  wxString old_name = subgraph->m_driver_connection->Name();
1891 
1892  subgraph->m_driver_connection->Clone( *conn );
1893 
1894  if( old_name != conn->Name() )
1895  recacheSubgraphName( subgraph, old_name );
1896 
1897  if( conn->IsBus() )
1898  propagate_bus_neighbors( subgraph );
1899  }
1900 
1901  // Somewhere along the way, a bus member may have been upgraded to a global or power label.
1902  // Because this can happen anywhere, we need a second pass to update all instances of that bus
1903  // member to have the correct connection info
1904  if( conn->IsBus() && !stale_bus_members.empty() )
1905  {
1906  for( auto stale_member : stale_bus_members )
1907  {
1908  for( CONNECTION_SUBGRAPH* subgraph : visited )
1909  {
1910  SCH_CONNECTION* member = matchBusMember( subgraph->m_driver_connection,
1911  stale_member );
1912 
1913  if( !member )
1914  {
1915  wxLogTrace( ConnTrace, "WARNING: failed to match stale member %s in %s.",
1916  stale_member->Name(), subgraph->m_driver_connection->Name() );
1917  continue;
1918  }
1919 
1920  wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", subgraph->m_code,
1921  subgraph->m_driver_connection->Name(), member->LocalName(),
1922  stale_member->Name() );
1923 
1924  member->Clone( *stale_member );
1925 
1926  propagate_bus_neighbors( subgraph );
1927  }
1928  }
1929  }
1930 
1931  aSubgraph->m_dirty = false;
1932 }
SCH_SHEET_PATH m_sheet
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
void propagateToNeighbors(CONNECTION_SUBGRAPH *aSubgraph)
Updates all neighbors of a subgraph with this one's connectivity info.
void Clone(const SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
#define kv
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
bool m_absorbed
True if this subgraph has been absorbed into another. No pointers here are safe if so!
std::unordered_map< SCH_SHEET_PATH, std::vector< CONNECTION_SUBGRAPH * > > m_sheet_to_subgraphs_map
std::vector< SCH_SHEET_PIN * > m_hier_pins
wxString LocalName() const
A subgraph is a set of items that are electrically connected on a single sheet.
static const wxChar ConnTrace[]
bool m_multiple_drivers
True if this subgraph contains more than one driver that should be shorted together in the netlist.
void recacheSubgraphName(CONNECTION_SUBGRAPH *aSubgraph, const wxString &aOldName)
wxString Name(bool aIgnoreSheet=false) const
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
size_t size() const
Forwarded method from std::vector.
bool m_strong_driver
True if the driver is "strong": a label or power object.
std::vector< SCH_ITEM * > m_drivers
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::vector< SCH_HIERLABEL * > m_hier_ports
CONNECTION_SUBGRAPH * m_absorbed_by
If this subgraph is absorbed, points to the absorbing (and valid) subgraph.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
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.
CONNECTION_SUBGRAPH * m_hier_parent
bool IsBus() const
CONNECTION_TYPE Type() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
PRIORITY GetDriverPriority()
static SCH_CONNECTION * matchBusMember(SCH_CONNECTION *aBusConnection, SCH_CONNECTION *aSearch)
Search for a matching bus member inside a bus connection.

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, SCH_SHEET_PATH::push_back(), recacheSubgraphName(), SCH_SHEET_PATH::size(), and SCH_CONNECTION::Type().

Referenced by buildConnectionGraph().

◆ recacheSubgraphName()

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

Definition at line 2026 of file connection_graph.cpp.

2028 {
2029  auto it = m_net_name_to_subgraphs_map.find( aOldName );
2030 
2031  if( it != m_net_name_to_subgraphs_map.end() )
2032  {
2033  std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2034  vec.erase( std::remove( vec.begin(), vec.end(), aSubgraph ), vec.end() );
2035  }
2036 
2037  wxLogTrace( ConnTrace, "recacheSubgraphName: %s => %s", aOldName,
2038  aSubgraph->m_driver_connection->Name() );
2039 
2040  m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
2041 }
SCH_CONNECTION * m_driver_connection
Cache for driver connection.
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
static const wxChar ConnTrace[]
wxString Name(bool aIgnoreSheet=false) const

References ConnTrace, 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 440 of file connection_graph.cpp.

442 {
443  PROF_COUNTER recalc_time( "CONNECTION_GRAPH::Recalculate" );
444 
445  if( aUnconditional )
446  Reset();
447 
448  PROF_COUNTER update_items( "updateItemConnectivity" );
449 
450  m_sheetList = aSheetList;
451 
452  for( const SCH_SHEET_PATH& sheet : aSheetList )
453  {
454  std::vector<SCH_ITEM*> items;
455 
456  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
457  {
458  if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
459  items.push_back( item );
460  }
461 
462  m_items.reserve( m_items.size() + items.size() );
463 
464  updateItemConnectivity( sheet, items );
465 
466  // UpdateDanglingState() also adds connected items for SCH_TEXT
467  sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
468  }
469 
470  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
471  update_items.Show();
472 
473  PROF_COUNTER build_graph( "buildConnectionGraph" );
474 
476 
477  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
478  build_graph.Show();
479 
480  recalc_time.Stop();
481 
482  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
483  recalc_time.Show();
484 
485 #ifndef DEBUG
486  // Pressure relief valve for release builds
487  const double max_recalc_time_msecs = 250.;
488 
489  if( m_allowRealTime && ADVANCED_CFG::GetCfg().m_RealTimeConnectivity &&
490  recalc_time.msecs() > max_recalc_time_msecs )
491  {
492  m_allowRealTime = false;
493  }
494 #endif
495 }
void buildConnectionGraph()
Generates the connection graph (after all item connectivity has been updated)
std::vector< SCH_ITEM * > m_items
A small class to help profiling.
Definition: profile.h:45
void updateItemConnectivity(const SCH_SHEET_PATH &aSheet, const std::vector< SCH_ITEM * > &aItemList)
Updates the graphical connectivity between items (i.e.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
static const wxChar ConnProfileMask[]
static bool m_allowRealTime
SCH_SHEET_LIST m_sheetList
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193

References buildConnectionGraph(), ConnProfileMask, ADVANCED_CFG::GetCfg(), m_allowRealTime, m_items, m_sheetList, PROF_COUNTER::msecs(), Reset(), PROF_COUNTER::Show(), PROF_COUNTER::Stop(), and updateItemConnectivity().

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

◆ Reset()

void CONNECTION_GRAPH::Reset ( )

Definition at line 416 of file connection_graph.cpp.

417 {
418  for( auto& subgraph : m_subgraphs )
419  delete subgraph;
420 
421  m_items.clear();
422  m_subgraphs.clear();
423  m_driver_subgraphs.clear();
424  m_sheet_to_subgraphs_map.clear();
425  m_invisible_power_pins.clear();
426  m_bus_alias_cache.clear();
427  m_net_name_to_code_map.clear();
428  m_bus_name_to_code_map.clear();
431  m_item_to_subgraph_map.clear();
432  m_local_label_cache.clear();
433  m_global_label_cache.clear();
434  m_last_net_code = 1;
435  m_last_bus_code = 1;
437 }
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
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
NET_MAP m_net_code_to_subgraphs_map
std::vector< SCH_ITEM * > m_items
std::unordered_map< wxString, std::vector< CONNECTION_SUBGRAPH * > > m_net_name_to_subgraphs_map
std::vector< CONNECTION_SUBGRAPH * > m_driver_subgraphs
std::map< wxString, std::vector< const CONNECTION_SUBGRAPH * > > m_global_label_cache
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
std::map< wxString, int > m_bus_name_to_code_map
std::map< wxString, int > m_net_name_to_code_map
std::map< std::pair< SCH_SHEET_PATH, wxString >, std::vector< const CONNECTION_SUBGRAPH * > > m_local_label_cache
std::map< SCH_ITEM *, CONNECTION_SUBGRAPH * > m_item_to_subgraph_map

References m_bus_alias_cache, m_bus_name_to_code_map, m_driver_subgraphs, m_global_label_cache, m_invisible_power_pins, m_item_to_subgraph_map, m_items, m_last_bus_code, m_last_net_code, m_last_subgraph_code, m_local_label_cache, m_net_code_to_subgraphs_map, m_net_name_to_code_map, m_net_name_to_subgraphs_map, m_sheet_to_subgraphs_map, and m_subgraphs.

Referenced by SCH_EDIT_FRAME::OpenProjectFiles(), Recalculate(), SCHEMATIC::Reset(), SCHEMATIC::SetRoot(), and ~CONNECTION_GRAPH().

◆ 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 2146 of file connection_graph.cpp.

2147 {
2148  int error_count = 0;
2149 
2150  wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::RunERC" );
2151 
2152  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2153 
2154  // We don't want to run many ERC checks more than once on a given screen even though it may
2155  // represent multiple sheets with multiple subgraphs. We can tell these apart by drivers.
2156  std::set<SCH_ITEM*> seenDriverInstances;
2157 
2158  for( auto&& subgraph : m_subgraphs )
2159  {
2160  // Graph is supposed to be up-to-date before calling RunERC()
2161  wxASSERT( !subgraph->m_dirty );
2162 
2163  if( subgraph->m_absorbed )
2164  continue;
2165 
2166  if( seenDriverInstances.count( subgraph->m_driver ) )
2167  continue;
2168 
2169  if( subgraph->m_driver )
2170  seenDriverInstances.insert( subgraph->m_driver );
2171 
2182  if( settings.IsTestEnabled( ERCE_DRIVER_CONFLICT ) )
2183  {
2184  if( !ercCheckMultipleDrivers( subgraph ) )
2185  error_count++;
2186  }
2187 
2188  subgraph->ResolveDrivers( false );
2189 
2190  if( settings.IsTestEnabled( ERCE_BUS_TO_NET_CONFLICT ) )
2191  {
2192  if( !ercCheckBusToNetConflicts( subgraph ) )
2193  error_count++;
2194  }
2195 
2196  if( settings.IsTestEnabled( ERCE_BUS_ENTRY_CONFLICT ) )
2197  {
2198  if( !ercCheckBusToBusEntryConflicts( subgraph ) )
2199  error_count++;
2200  }
2201 
2202  if( settings.IsTestEnabled( ERCE_BUS_TO_BUS_CONFLICT ) )
2203  {
2204  if( !ercCheckBusToBusConflicts( subgraph ) )
2205  error_count++;
2206  }
2207 
2208  if( settings.IsTestEnabled( ERCE_WIRE_DANGLING ) )
2209  {
2210  if( !ercCheckFloatingWires( subgraph ) )
2211  error_count++;
2212  }
2213 
2214  // The following checks are always performed since they don't currently
2215  // have an option exposed to the user
2216 
2217  if( !ercCheckNoConnects( subgraph ) )
2218  error_count++;
2219 
2220  if( settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED )
2221  || settings.IsTestEnabled( ERCE_GLOBLABEL ) )
2222  {
2223  if( !ercCheckLabels( subgraph ) )
2224  error_count++;
2225  }
2226  }
2227 
2228  // Hierarchical sheet checking is done at the schematic level
2229  if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
2230  error_count += ercCheckHierSheets();
2231 
2232  return error_count;
2233 }
bool ercCheckMultipleDrivers(const CONNECTION_SUBGRAPH *aSubgraph)
If the subgraph has multiple drivers of equal priority that are graphically connected,...
bool ercCheckBusToBusEntryConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting bus entry to bus connections.
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:59
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:123
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:61
bool ercCheckFloatingWires(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for floating wires.
std::vector< CONNECTION_SUBGRAPH * > m_subgraphs
Some wires are not connected to anything else.
Definition: erc_settings.h:65
Label not connected to anything.
Definition: erc_settings.h:49
SCHEMATIC * m_schematic
The schematic this graph represents.
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.
Container for ERC settings.
Definition: erc_settings.h:106
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:57
A global label is unique.
Definition: erc_settings.h:63
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:46
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:174
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:56
bool ercCheckLabels(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for proper connection of labels.
bool ercCheckBusToBusConflicts(const CONNECTION_SUBGRAPH *aSubgraph)
Checks one subgraph for conflicting connections between two bus items.

References ercCheckBusToBusConflicts(), ercCheckBusToBusEntryConflicts(), ercCheckBusToNetConflicts(), ercCheckFloatingWires(), ercCheckHierSheets(), ercCheckLabels(), ercCheckMultipleDrivers(), 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_WIRE_DANGLING, SCHEMATIC::ErcSettings(), ERC_SETTINGS::IsTestEnabled(), m_schematic, and m_subgraphs.

Referenced by DIALOG_ERC::testErc().

◆ SetSchematic()

void CONNECTION_GRAPH::SetSchematic ( SCHEMATIC aSchematic)
inline

Definition at line 265 of file connection_graph.h.

266  {
267  m_schematic = aSchematic;
268  }
SCHEMATIC * m_schematic
The schematic this graph represents.

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 498 of file connection_graph.cpp.

500 {
501  std::map< wxPoint, std::vector<SCH_ITEM*> > connection_map;
502 
503  for( SCH_ITEM* item : aItemList )
504  {
505  std::vector< wxPoint > points = item->GetConnectionPoints();
506  item->ConnectedItems( aSheet ).clear();
507 
508  if( item->Type() == SCH_SHEET_T )
509  {
510  for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
511  {
512  pin->InitializeConnection( aSheet, this );
513 
514  pin->ConnectedItems( aSheet ).clear();
515 
516  connection_map[ pin->GetTextPos() ].push_back( pin );
517  m_items.emplace_back( pin );
518  }
519  }
520  else if( item->Type() == SCH_SYMBOL_T )
521  {
522  SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
523 
524  for( SCH_PIN* pin : symbol->GetPins( &aSheet ) )
525  {
526  pin->InitializeConnection( aSheet, this );
527 
528  wxPoint pos = pin->GetPosition();
529 
530  // because calling the first time is not thread-safe
531  pin->GetDefaultNetName( aSheet );
532  pin->ConnectedItems( aSheet ).clear();
533 
534  // Invisible power pins need to be post-processed later
535 
536  if( pin->IsPowerConnection() && !pin->IsVisible() )
537  m_invisible_power_pins.emplace_back( std::make_pair( aSheet, pin ) );
538 
539  connection_map[ pos ].push_back( pin );
540  m_items.emplace_back( pin );
541  }
542  }
543  else
544  {
545  m_items.emplace_back( item );
546  auto conn = item->InitializeConnection( aSheet, this );
547 
548  // Set bus/net property here so that the propagation code uses it
549  switch( item->Type() )
550  {
551  case SCH_LINE_T:
552  conn->SetType( item->GetLayer() == LAYER_BUS ? CONNECTION_TYPE::BUS :
554  break;
555 
556  case SCH_BUS_BUS_ENTRY_T:
557  conn->SetType( CONNECTION_TYPE::BUS );
558  // clean previous (old) links:
559  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[0] = nullptr;
560  static_cast<SCH_BUS_BUS_ENTRY*>( item )->m_connected_bus_items[1] = nullptr;
561  break;
562 
563  case SCH_PIN_T:
564  conn->SetType( CONNECTION_TYPE::NET );
565  break;
566 
568  conn->SetType( CONNECTION_TYPE::NET );
569  // clean previous (old) link:
570  static_cast<SCH_BUS_WIRE_ENTRY*>( item )->m_connected_bus_item = nullptr;
571  break;
572 
573  default:
574  break;
575  }
576 
577  for( const wxPoint& point : points )
578  connection_map[ point ].push_back( item );
579  }
580 
581  item->SetConnectivityDirty( false );
582  }
583 
584  for( const auto& it : connection_map )
585  {
586  auto connection_vec = it.second;
587 
588  for( auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ )
589  {
590  SCH_ITEM* connected_item = *primary_it;
591 
592  // Bus entries are special: they can have connection points in the
593  // middle of a wire segment, because the junction algo doesn't split
594  // the segment in two where you place a bus entry. This means that
595  // bus entries that don't land on the end of a line segment need to
596  // have "virtual" connection points to the segments they graphically
597  // touch.
598  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
599  {
600  // If this location only has the connection point of the bus
601  // entry itself, this means that either the bus entry is not
602  // connected to anything graphically, or that it is connected to
603  // a segment at some point other than at one of the endpoints.
604  if( connection_vec.size() == 1 )
605  {
606  SCH_SCREEN* screen = aSheet.LastScreen();
607  SCH_LINE* bus = screen->GetBus( it.first );
608 
609  if( bus )
610  {
611  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
612  bus_entry->m_connected_bus_item = bus;
613  }
614  }
615  }
616 
617  // Bus-to-bus entries are treated just like bus wires
618  else if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T )
619  {
620  if( connection_vec.size() < 2 )
621  {
622  SCH_SCREEN* screen = aSheet.LastScreen();
623  SCH_LINE* bus = screen->GetBus( it.first );
624 
625  if( bus )
626  {
627  auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item );
628 
629  if( it.first == bus_entry->GetPosition() )
630  bus_entry->m_connected_bus_items[0] = bus;
631  else
632  bus_entry->m_connected_bus_items[1] = bus;
633 
634  bus_entry->ConnectedItems( aSheet ).insert( bus );
635  bus->ConnectedItems( aSheet ).insert( bus_entry );
636  }
637  }
638  }
639 
640  // Change junctions to be on bus junction layer if they are touching a bus
641  else if( connected_item->Type() == SCH_JUNCTION_T )
642  {
643  SCH_SCREEN* screen = aSheet.LastScreen();
644  SCH_LINE* bus = screen->GetBus( it.first );
645 
646  connected_item->SetLayer( bus ? LAYER_BUS_JUNCTION : LAYER_JUNCTION );
647  }
648 
649  for( auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ )
650  {
651  auto test_item = *test_it;
652 
653  if( connected_item != test_item &&
654  connected_item->ConnectionPropagatesTo( test_item ) &&
655  test_item->ConnectionPropagatesTo( connected_item ) )
656  {
657  connected_item->ConnectedItems( aSheet ).insert( test_item );
658  test_item->ConnectedItems( aSheet ).insert( connected_item );
659  }
660 
661  // Set up the link between the bus entry net and the bus
662  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
663  {
664  if( test_item->Connection( &aSheet )->IsBus() )
665  {
666  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
667  bus_entry->m_connected_bus_item = test_item;
668  }
669  }
670  }
671 
672  // If we got this far and did not find a connected bus item for a bus entry,
673  // we should do a manual scan in case there is a bus item on this connection
674  // point but we didn't pick it up earlier because there is *also* a net item here.
675  if( connected_item->Type() == SCH_BUS_WIRE_ENTRY_T )
676  {
677  auto bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( connected_item );
678 
679  if( !bus_entry->m_connected_bus_item )
680  {
681  auto screen = aSheet.LastScreen();
682  auto bus = screen->GetBus( it.first );
683 
684  if( bus )
685  bus_entry->m_connected_bus_item = bus;
686  }
687  }
688  }
689  }
690 }
virtual bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const
Return true if this item should propagate connection info to aItem.
Definition: sch_item.h:418
std::vector< SCH_ITEM * > m_items
SCH_LINE * GetBus(const wxPoint &aPosition, int aAccuracy=0, SCH_LINE_TEST_T aSearchType=ENTIRE_LENGTH_T) const
Definition: sch_screen.h:402
void SetLayer(SCH_LAYER_ID aLayer)
Set the layer this item is on.
Definition: sch_item.h:275
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:65
This item represents a net.
std::vector< std::pair< SCH_SHEET_PATH, SCH_PIN * > > m_invisible_power_pins
Schematic symbol object.
Definition: sch_symbol.h:78
SCH_SCREEN * LastScreen()
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
SCH_ITEM_SET & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieve the set of items connected to this item on the given sheet.
Definition: sch_item.cpp:164
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:193
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:866
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113

References BUS, SCH_ITEM::ConnectedItems(), SCH_ITEM::ConnectionPropagatesTo(), SCH_SCREEN::GetBus(), SCH_SYMBOL::GetPins(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, LAYER_BUS_JUNCTION, LAYER_JUNCTION, 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::SetLayer(), and EDA_ITEM::Type().

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 528 of file connection_graph.h.

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

◆ m_bus_name_to_code_map

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

Definition at line 532 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_driver_subgraphs

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

Definition at line 521 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_global_label_cache

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

Definition at line 534 of file connection_graph.h.

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

◆ m_invisible_power_pins

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

Definition at line 526 of file connection_graph.h.

Referenced by buildConnectionGraph(), Reset(), and updateItemConnectivity().

◆ m_item_to_subgraph_map

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

Definition at line 541 of file connection_graph.h.

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

◆ m_items

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

◆ m_last_bus_code

int CONNECTION_GRAPH::m_last_bus_code
private

Definition at line 547 of file connection_graph.h.

Referenced by buildConnectionGraph(), and Reset().

◆ m_last_net_code

int CONNECTION_GRAPH::m_last_net_code
private

Definition at line 545 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 549 of file connection_graph.h.

Referenced by buildConnectionGraph(), 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

◆ m_net_code_to_subgraphs_map

NET_MAP CONNECTION_GRAPH::m_net_code_to_subgraphs_map
private

Definition at line 543 of file connection_graph.h.

Referenced by buildConnectionGraph(), GetNetMap(), and Reset().

◆ m_net_name_to_code_map

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

Definition at line 530 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 551 of file connection_graph.h.

Referenced by buildConnectionGraph(), 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

Definition at line 524 of file connection_graph.h.

Referenced by buildConnectionGraph(), propagateToNeighbors(), and Reset().

◆ m_sheetList

SCH_SHEET_LIST CONNECTION_GRAPH::m_sheetList
private

Definition at line 512 of file connection_graph.h.

Referenced by ercCheckHierSheets(), and Recalculate().

◆ m_subgraphs

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

Definition at line 518 of file connection_graph.h.

Referenced by buildConnectionGraph(), GetBusesNeedingMigration(), Reset(), and RunERC().


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