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

Constructor & Destructor Documentation

◆ CONNECTION_GRAPH()

CONNECTION_GRAPH::CONNECTION_GRAPH ( SCHEMATIC aSchematic = nullptr)
inline

Definition at line 250 of file connection_graph.h.

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

◆ ~CONNECTION_GRAPH()

CONNECTION_GRAPH::~CONNECTION_GRAPH ( )
inline

Definition at line 257 of file connection_graph.h.

258  {
259  Reset();
260  }

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

1595 {
1596  auto connections_to_check( aConnection->Members() );
1597 
1598  for( unsigned i = 0; i < connections_to_check.size(); i++ )
1599  {
1600  auto member = connections_to_check[i];
1601 
1602  if( member->IsBus() )
1603  {
1604  connections_to_check.insert( connections_to_check.end(),
1605  member->Members().begin(),
1606  member->Members().end() );
1607  continue;
1608  }
1609 
1610  assignNewNetCode( *member );
1611  }
1612 }
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 1572 of file connection_graph.cpp.

1573 {
1574  int code;
1575 
1576  auto it = m_net_name_to_code_map.find( aConnection.Name() );
1577 
1578  if( it == m_net_name_to_code_map.end() )
1579  {
1580  code = m_last_net_code++;
1581  m_net_name_to_code_map[ aConnection.Name() ] = code;
1582  }
1583  else
1584  {
1585  code = it->second;
1586  }
1587 
1588  aConnection.SetNetCode( code );
1589 
1590  return code;
1591 }
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 703 of file connection_graph.cpp.

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

2306 {
2307  wxString msg;
2308  auto sheet = aSubgraph->m_sheet;
2309  auto screen = sheet.LastScreen();
2310 
2311  SCH_ITEM* label = nullptr;
2312  SCH_ITEM* port = nullptr;
2313 
2314  for( auto item : aSubgraph->m_items )
2315  {
2316  switch( item->Type() )
2317  {
2318  case SCH_TEXT_T:
2319  case SCH_GLOBAL_LABEL_T:
2320  {
2321  if( !label && item->Connection( &sheet )->IsBus() )
2322  label = item;
2323  break;
2324  }
2325 
2326  case SCH_SHEET_PIN_T:
2327  case SCH_HIER_LABEL_T:
2328  {
2329  if( !port && item->Connection( &sheet )->IsBus() )
2330  port = item;
2331  break;
2332  }
2333 
2334  default:
2335  break;
2336  }
2337  }
2338 
2339  if( label && port )
2340  {
2341  bool match = false;
2342 
2343  for( const auto& member : label->Connection( &sheet )->Members() )
2344  {
2345  for( const auto& test : port->Connection( &sheet )->Members() )
2346  {
2347  if( test != member && member->Name() == test->Name() )
2348  {
2349  match = true;
2350  break;
2351  }
2352  }
2353 
2354  if( match )
2355  break;
2356  }
2357 
2358  if( !match )
2359  {
2360  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_BUS_CONFLICT );
2361  ercItem->SetItems( label, port );
2362 
2363  SCH_MARKER* marker = new SCH_MARKER( ercItem, label->GetPosition() );
2364  screen->Append( marker );
2365 
2366  return false;
2367  }
2368  }
2369 
2370  return true;
2371 }
SCH_SHEET_PATH m_sheet
A connection between bus objects doesn't share at least one net.
Definition: erc_settings.h:58
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:169
virtual wxPoint GetPosition() const
Definition: eda_item.h:300
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:194

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

2375 {
2376  bool conflict = false;
2377  auto sheet = aSubgraph->m_sheet;
2378  auto screen = sheet.LastScreen();
2379 
2380  SCH_BUS_WIRE_ENTRY* bus_entry = nullptr;
2381  SCH_ITEM* bus_wire = nullptr;
2382  wxString bus_name;
2383 
2384  if( !aSubgraph->m_driver_connection )
2385  {
2386  // Incomplete bus entry. Let the unconnected tests handle it.
2387  return true;
2388  }
2389 
2390  for( auto item : aSubgraph->m_items )
2391  {
2392  switch( item->Type() )
2393  {
2394  case SCH_BUS_WIRE_ENTRY_T:
2395  {
2396  if( !bus_entry )
2397  bus_entry = static_cast<SCH_BUS_WIRE_ENTRY*>( item );
2398  break;
2399  }
2400 
2401  default:
2402  break;
2403  }
2404  }
2405 
2406  if( bus_entry && bus_entry->m_connected_bus_item )
2407  {
2408  bus_wire = bus_entry->m_connected_bus_item;
2409 
2410  wxASSERT( bus_wire->Type() == SCH_LINE_T );
2411 
2412  // In some cases, the connection list (SCH_CONNECTION*) can be null.
2413  // Skip null connections.
2414  if( bus_entry->Connection( &sheet )
2415  && bus_wire->Type() == SCH_LINE_T
2416  && bus_wire->Connection( &sheet ) )
2417  {
2418  conflict = true; // Assume a conflict; we'll reset if we find it's OK
2419 
2420  bus_name = bus_wire->Connection( &sheet )->Name( true );
2421 
2422  wxString test_name = bus_entry->Connection( &sheet )->Name( true );
2423 
2424  for( const auto& member : bus_wire->Connection( &sheet )->Members() )
2425  {
2426  if( member->Type() == CONNECTION_TYPE::BUS )
2427  {
2428  for( const auto& sub_member : member->Members() )
2429  {
2430  if( sub_member->Name( true ) == test_name )
2431  conflict = false;
2432  }
2433  }
2434  else if( member->Name( true ) == test_name )
2435  {
2436  conflict = false;
2437  }
2438  }
2439  }
2440  }
2441 
2442  // Don't report warnings if this bus member has been overridden by a higher priority power pin
2443  // or global label
2444  if( conflict && CONNECTION_SUBGRAPH::GetDriverPriority( aSubgraph->m_driver )
2446  conflict = false;
2447 
2448  if( conflict )
2449  {
2450  wxString netName = aSubgraph->m_driver_connection->Name( true );
2451  wxString msg = wxString::Format( _( "Net %s is graphically connected to bus %s but is not a"
2452  " member of that bus" ),
2453  UnescapeString( netName ),
2454  UnescapeString( bus_name ) );
2455  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_ENTRY_CONFLICT );
2456  ercItem->SetItems( bus_entry, bus_wire );
2457  ercItem->SetErrorMessage( msg );
2458 
2459  SCH_MARKER* marker = new SCH_MARKER( ercItem, bus_entry->GetPosition() );
2460  screen->Append( marker );
2461 
2462  return false;
2463  }
2464 
2465  return true;
2466 }
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:169
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
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:56
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()
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:150
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:194
PRIORITY GetDriverPriority()
This item represents a bus vector.
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:161
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 2249 of file connection_graph.cpp.

2250 {
2251  auto sheet = aSubgraph->m_sheet;
2252  auto screen = sheet.LastScreen();
2253 
2254  SCH_ITEM* net_item = nullptr;
2255  SCH_ITEM* bus_item = nullptr;
2256  SCH_CONNECTION conn( this );
2257 
2258  for( auto item : aSubgraph->m_items )
2259  {
2260  switch( item->Type() )
2261  {
2262  case SCH_LINE_T:
2263  {
2264  if( item->GetLayer() == LAYER_BUS )
2265  bus_item = ( !bus_item ) ? item : bus_item;
2266  else
2267  net_item = ( !net_item ) ? item : net_item;
2268  break;
2269  }
2270 
2271  case SCH_GLOBAL_LABEL_T:
2272  case SCH_SHEET_PIN_T:
2273  case SCH_HIER_LABEL_T:
2274  {
2275  SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2276  conn.ConfigureFromLabel( EscapeString( text->GetShownText(), CTX_NETNAME ) );
2277 
2278  if( conn.IsBus() )
2279  bus_item = ( !bus_item ) ? item : bus_item;
2280  else
2281  net_item = ( !net_item ) ? item : net_item;
2282  break;
2283  }
2284 
2285  default:
2286  break;
2287  }
2288  }
2289 
2290  if( net_item && bus_item )
2291  {
2292  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_BUS_TO_NET_CONFLICT );
2293  ercItem->SetItems( net_item, bus_item );
2294 
2295  SCH_MARKER* marker = new SCH_MARKER( ercItem, net_item->GetPosition() );
2296  screen->Append( marker );
2297 
2298  return false;
2299  }
2300 
2301  return true;
2302 }
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:169
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:60
virtual wxPoint GetPosition() const
Definition: eda_item.h:300
std::vector< SCH_ITEM * > m_items
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: sch_text.cpp:508
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)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
Definition: string.cpp:77
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194

References SCH_CONNECTION::ConfigureFromLabel(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_BUS_TO_NET_CONFLICT, EscapeString(), EDA_ITEM::GetPosition(), SCH_TEXT::GetShownText(), 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_LINE_T, and SCH_SHEET_PIN_T.

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

2644 {
2645  if( aSubgraph->m_driver )
2646  return true;
2647 
2648  std::vector<SCH_ITEM*> wires;
2649 
2650  // We've gotten this far, so we know we have no valid driver. All we need to do is check
2651  // for a wire that we can place the error on.
2652 
2653  for( SCH_ITEM* item : aSubgraph->m_items )
2654  {
2655  if( item->Type() == SCH_LINE_T && item->GetLayer() == LAYER_WIRE )
2656  wires.emplace_back( item );
2657  else if( item->Type() == SCH_BUS_WIRE_ENTRY_T )
2658  wires.emplace_back( item );
2659  }
2660 
2661  if( !wires.empty() )
2662  {
2663  SCH_SCREEN* screen = aSubgraph->m_sheet.LastScreen();
2664 
2665  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_WIRE_DANGLING );
2666  ercItem->SetItems( wires[0],
2667  wires.size() > 1 ? wires[1] : nullptr,
2668  wires.size() > 2 ? wires[2] : nullptr,
2669  wires.size() > 3 ? wires[3] : nullptr );
2670 
2671  SCH_MARKER* marker = new SCH_MARKER( ercItem, wires[0]->GetPosition() );
2672  screen->Append( marker );
2673 
2674  return false;
2675  }
2676 
2677  return true;
2678 }
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:169
Some wires are not connected to anything else.
Definition: erc_settings.h:64
std::vector< SCH_ITEM * > m_items
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:285
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:129
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:161

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

2806 {
2807  int errors = 0;
2808 
2809  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2810 
2811  for( const SCH_SHEET_PATH& sheet : m_sheetList )
2812  {
2813  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
2814  {
2815  if( item->Type() != SCH_SHEET_T )
2816  continue;
2817 
2818  SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( item );
2819 
2820  std::map<wxString, SCH_SHEET_PIN*> pins;
2821 
2822  for( SCH_SHEET_PIN* pin : parentSheet->GetPins() )
2823  {
2824  pins[pin->GetText()] = pin;
2825 
2826  if( pin->IsDangling() && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2827  {
2828  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2829  ercItem->SetItems( pin );
2830 
2831  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetPosition() );
2832  sheet.LastScreen()->Append( marker );
2833 
2834  errors++;
2835  }
2836  }
2837 
2838  for( SCH_ITEM* subItem : parentSheet->GetScreen()->Items() )
2839  {
2840  if( subItem->Type() == SCH_HIER_LABEL_T )
2841  {
2842  SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( subItem );
2843  pins.erase( label->GetText() );
2844  }
2845  }
2846 
2847  for( const std::pair<const wxString, SCH_SHEET_PIN*>& unmatched : pins )
2848  {
2849  wxString msg = wxString::Format( _( "Sheet pin %s has no matching hierarchical "
2850  "label inside the sheet" ),
2851  UnescapeString( unmatched.first ) );
2852 
2853  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_HIERACHICAL_LABEL );
2854  ercItem->SetItems( unmatched.second );
2855  ercItem->SetErrorMessage( msg );
2856  ercItem->SetIsSheetSpecific();
2857 
2858  SCH_MARKER* marker = new SCH_MARKER( ercItem, unmatched.second->GetPosition() );
2859  sheet.LastScreen()->Append( marker );
2860 
2861  errors++;
2862  }
2863  }
2864  }
2865 
2866  return errors;
2867 }
Pin not connected and not no connect symbol.
Definition: erc_settings.h:40
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:169
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:114
SCHEMATIC * m_schematic
The schematic this graph represents.
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:285
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:85
Container for ERC settings.
Definition: erc_settings.h:97
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:219
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:365
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:45
#define _(s)
Definition: 3d_actions.cpp:33
SCH_SHEET_LIST m_sheetList
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:150
EE_RTREE & Items()
Definition: sch_screen.h:159
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:132
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133

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

2682 {
2683  // Label connection rules:
2684  // Local labels are flagged if they don't connect to any pins and don't have a no-connect
2685  // Global labels are flagged if they appear only once, don't connect to any local labels,
2686  // and don't have a no-connect marker
2687 
2688  // So, if there is a no-connect, we will never generate a warning here
2689  if( aSubgraph->m_no_connect )
2690  return true;
2691 
2692  if( !aSubgraph->m_driver_connection )
2693  return true;
2694 
2695  // Buses are excluded from this test: many users create buses with only a single instance
2696  // and it's not really a problem as long as the nets in the bus pass ERC
2697  if( aSubgraph->m_driver_connection->IsBus() )
2698  return true;
2699 
2700  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2701  bool ok = true;
2702  SCH_TEXT* text = nullptr;
2703  bool hasOtherConnections = false;
2704  int pinCount = 0;
2705 
2706  for( auto item : aSubgraph->m_items )
2707  {
2708  switch( item->Type() )
2709  {
2710  case SCH_LABEL_T:
2711  case SCH_GLOBAL_LABEL_T:
2712  case SCH_HIER_LABEL_T:
2713  {
2714  text = static_cast<SCH_TEXT*>( item );
2715 
2716  // Below, we'll create an ERC if the whole subgraph is unconnected. But, additionally,
2717  // we want to error if an individual label in the subgraph is floating, even if it's
2718  // connected to other valid things by way of another label on the same sheet.
2719 
2720  if( text->IsDangling() && settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED ) )
2721  {
2722  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LABEL_NOT_CONNECTED );
2723  ercItem->SetItems( text );
2724 
2725  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2726  aSubgraph->m_sheet.LastScreen()->Append( marker );
2727  ok = false;
2728  }
2729 
2730  break;
2731  }
2732 
2733  case SCH_PIN_T:
2734  case SCH_SHEET_PIN_T:
2735  hasOtherConnections = true;
2736  pinCount++;
2737  break;
2738 
2739  default:
2740  break;
2741  }
2742  }
2743 
2744  if( !text )
2745  return true;
2746 
2747  bool isGlobal = text->Type() == SCH_GLOBAL_LABEL_T;
2748  int errCode = isGlobal ? ERCE_GLOBLABEL : ERCE_LABEL_NOT_CONNECTED;
2749 
2750  wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::ercCheckLabels" );
2751 
2752  wxString name = EscapeString( text->GetShownText(), CTX_NETNAME );
2753 
2754  if( isGlobal )
2755  {
2756  // This will be set to true if the global is connected to a pin above, but we
2757  // want to reset this to false so that globals get flagged if they only have a
2758  // single instance connected to a single pin
2759  hasOtherConnections = ( pinCount < 2 );
2760 
2761  auto it = m_net_name_to_subgraphs_map.find( name );
2762 
2763  if( it != m_net_name_to_subgraphs_map.end() )
2764  {
2765  if( it->second.size() > 1 || aSubgraph->m_multiple_drivers )
2766  hasOtherConnections = true;
2767  }
2768  }
2769  else if( text->Type() == SCH_HIER_LABEL_T )
2770  {
2771  // For a hier label, check if the parent pin is connected
2772  if( aSubgraph->m_hier_parent &&
2773  ( aSubgraph->m_hier_parent->m_strong_driver ||
2774  aSubgraph->m_hier_parent->m_drivers.size() > 1) )
2775  {
2776  // For now, a simple check: if there is more than one driver, the parent is probably
2777  // connected elsewhere (because at least one driver will be the hier pin itself)
2778  hasOtherConnections = true;
2779  }
2780  }
2781  else
2782  {
2783  auto pair = std::make_pair( aSubgraph->m_sheet, name );
2784  auto it = m_local_label_cache.find( pair );
2785 
2786  if( it != m_local_label_cache.end() && it->second.size() > 1 )
2787  hasOtherConnections = true;
2788  }
2789 
2790  if( !hasOtherConnections && settings.IsTestEnabled( errCode ) )
2791  {
2792  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( errCode );
2793  ercItem->SetItems( text );
2794 
2795  SCH_MARKER* marker = new SCH_MARKER( ercItem, text->GetPosition() );
2796  aSubgraph->m_sheet.LastScreen()->Append( marker );
2797 
2798  return false;
2799  }
2800 
2801  return ok;
2802 }
bool IsDangling() const override
Definition: sch_text.h:303
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:169
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:114
Label not connected to anything.
Definition: erc_settings.h:48
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:97
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: sch_text.cpp:508
wxPoint GetPosition() const override
Definition: sch_text.h:312
A global label is unique.
Definition: erc_settings.h:62
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:59
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:129
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
These Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which ar...
Definition: string.cpp:77
CONNECTION_SUBGRAPH * m_hier_parent
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:132
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
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:161

References SCH_SCREEN::Append(), ERC_ITEM::Create(), CTX_NETNAME, ERCE_GLOBLABEL, ERCE_LABEL_NOT_CONNECTED, SCHEMATIC::ErcSettings(), EscapeString(), SCH_TEXT::GetPosition(), SCH_TEXT::GetShownText(), SCH_CONNECTION::IsBus(), SCH_TEXT::IsDangling(), 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 EDA_ITEM::Type().

Referenced by RunERC().

◆ ercCheckMultipleDrivers()

bool CONNECTION_GRAPH::ercCheckMultipleDrivers ( const CONNECTION_SUBGRAPH aSubgraph)
private

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

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

Definition at line 2219 of file connection_graph.cpp.

2220 {
2221  if( !aSubgraph->m_second_driver )
2222  return true;
2223 
2224  SCH_ITEM* primary = aSubgraph->m_first_driver;
2225  SCH_ITEM* secondary = aSubgraph->m_second_driver;
2226 
2227  wxPoint pos = primary->Type() == SCH_PIN_T ?
2228  static_cast<SCH_PIN*>( primary )->GetTransformedPosition() :
2229  primary->GetPosition();
2230 
2231  wxString primaryName = aSubgraph->GetNameForDriver( primary );
2232  wxString secondaryName = aSubgraph->GetNameForDriver( secondary );
2233 
2234  wxString msg = wxString::Format( _( "Both %s and %s are attached to the same "
2235  "items; %s will be used in the netlist" ),
2236  primaryName, secondaryName, primaryName );
2237 
2238  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_DRIVER_CONFLICT );
2239  ercItem->SetItems( primary, secondary );
2240  ercItem->SetErrorMessage( msg );
2241 
2242  SCH_MARKER* marker = new SCH_MARKER( ercItem, pos );
2243  aSubgraph->m_sheet.LastScreen()->Append( marker );
2244 
2245  return false;
2246 }
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:169
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:300
const wxString & GetNameForDriver(SCH_ITEM *aItem)
Returns the candidate net name for a driver.
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:129
#define _(s)
Definition: 3d_actions.cpp:33
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:55
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:161

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

2471 {
2472  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2473  wxString msg;
2474  const SCH_SHEET_PATH& sheet = aSubgraph->m_sheet;
2475  SCH_SCREEN* screen = sheet.LastScreen();
2476  bool ok = true;
2477 
2478  if( aSubgraph->m_no_connect != nullptr )
2479  {
2480  bool has_invalid_items = false;
2481  bool has_other_items = false;
2482  SCH_PIN* pin = nullptr;
2483  std::vector<SCH_ITEM*> invalid_items;
2484  wxPoint noConnectPos = aSubgraph->m_no_connect->GetPosition();
2485  double minDist = 0;
2486 
2487  // Any subgraph that contains both a pin and a no-connect should not
2488  // contain any other driving items.
2489 
2490  for( auto item : aSubgraph->m_items )
2491  {
2492  switch( item->Type() )
2493  {
2494  case SCH_PIN_T:
2495  {
2496  SCH_PIN* candidate = static_cast<SCH_PIN*>( item );
2497  double dist = VECTOR2I( candidate->GetTransformedPosition() - noConnectPos )
2498  .SquaredEuclideanNorm();
2499 
2500  if( !pin || dist < minDist )
2501  {
2502  pin = candidate;
2503  minDist = dist;
2504  }
2505 
2506  has_invalid_items |= has_other_items;
2507  has_other_items = true;
2508  break;
2509  }
2510 
2511  case SCH_LINE_T:
2512  case SCH_JUNCTION_T:
2513  case SCH_NO_CONNECT_T:
2514  break;
2515 
2516  default:
2517  has_invalid_items = true;
2518  has_other_items = true;
2519  invalid_items.push_back( item );
2520  }
2521  }
2522 
2523  if( pin && has_invalid_items && settings.IsTestEnabled( ERCE_NOCONNECT_CONNECTED ) )
2524  {
2525  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_CONNECTED );
2526  ercItem->SetItems( pin );
2527 
2528  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2529  screen->Append( marker );
2530 
2531  ok = false;
2532  }
2533 
2534  if( !has_other_items && settings.IsTestEnabled(ERCE_NOCONNECT_NOT_CONNECTED ) )
2535  {
2536  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_NOCONNECT_NOT_CONNECTED );
2537  ercItem->SetItems( aSubgraph->m_no_connect );
2538 
2539  SCH_MARKER* marker = new SCH_MARKER( ercItem, aSubgraph->m_no_connect->GetPosition() );
2540  screen->Append( marker );
2541 
2542  ok = false;
2543  }
2544  }
2545  else
2546  {
2547  bool has_other_connections = false;
2548  std::vector<SCH_PIN*> pins;
2549 
2550  // Any subgraph that lacks a no-connect and contains a pin should also
2551  // contain at least one other potential driver
2552 
2553  for( SCH_ITEM* item : aSubgraph->m_items )
2554  {
2555  switch( item->Type() )
2556  {
2557  case SCH_PIN_T:
2558  {
2559  if( !pins.empty() )
2560  has_other_connections = true;
2561 
2562  pins.emplace_back( static_cast<SCH_PIN*>( item ) );
2563 
2564  break;
2565  }
2566 
2567  default:
2568  if( aSubgraph->GetDriverPriority( item ) != CONNECTION_SUBGRAPH::PRIORITY::NONE )
2569  has_other_connections = true;
2570 
2571  break;
2572  }
2573  }
2574 
2575  // For many checks, we can just use the first pin
2576  SCH_PIN* pin = pins.empty() ? nullptr : pins[0];
2577 
2578  // Check if invisible power input pins connect to anything else via net name,
2579  // but not for power symbols as the ones in the standard library all have invisible pins
2580  // and we want to throw unconnected errors for those even if they are connected to other
2581  // net items by name, because usually failing to connect them graphically is a mistake
2582  if( pin && !has_other_connections
2584  && !pin->IsVisible()
2585  && !pin->GetLibPin()->GetParent()->IsPower() )
2586  {
2587  wxString name = pin->Connection( &sheet )->Name();
2588  wxString local_name = pin->Connection( &sheet )->Name( true );
2589 
2590  if( m_global_label_cache.count( name ) ||
2591  ( m_local_label_cache.count( std::make_pair( sheet, local_name ) ) ) )
2592  {
2593  has_other_connections = true;
2594  }
2595  }
2596 
2597  // Only one pin, and it's not a no-connect pin
2598  if( pin && !has_other_connections
2599  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NC
2600  && pin->GetType() != ELECTRICAL_PINTYPE::PT_NIC
2601  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2602  {
2603  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2604  ercItem->SetItems( pin );
2605 
2606  SCH_MARKER* marker = new SCH_MARKER( ercItem, pin->GetTransformedPosition() );
2607  screen->Append( marker );
2608 
2609  ok = false;
2610  }
2611 
2612  // If there are multiple pins in this SG, they might be indirectly connected (by netname)
2613  // rather than directly connected (by wires). We want to flag dangling pins even if they
2614  // join nets with another pin, as it's often a mistake
2615  if( pins.size() > 1 )
2616  {
2617  for( SCH_PIN* testPin : pins )
2618  {
2619  // We only apply this test to power symbols, because other symbols have invisible
2620  // pins that are meant to be dangling, but the KiCad standard library power symbols
2621  // have invisible pins that are *not* meant to be dangling.
2622  if( testPin->GetLibPin()->GetParent()->IsPower()
2623  && testPin->ConnectedItems( sheet ).empty()
2624  && settings.IsTestEnabled( ERCE_PIN_NOT_CONNECTED ) )
2625  {
2626  std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_PIN_NOT_CONNECTED );
2627  ercItem->SetItems( testPin );
2628 
2629  SCH_MARKER* marker = new SCH_MARKER( ercItem,
2630  testPin->GetTransformedPosition() );
2631  screen->Append( marker );
2632 
2633  ok = false;
2634  }
2635  }
2636  }
2637  }
2638 
2639  return ok;
2640 }
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:40
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:69
bool IsVisible() const
Definition: sch_pin.h:112
LIB_PART * GetParent() const
Definition: lib_item.h:183
static std::shared_ptr< ERC_ITEM > Create(int aErrorCode)
Constructs an ERC_ITEM for the given error code.
Definition: erc_item.cpp:169
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:114
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Returns 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:300
VECTOR2< int > VECTOR2I
Definition: vector2d.h:630
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
not internally connected (may be connected to anything)
wxString Name(bool aIgnoreSheet=false) const
std::vector< SCH_ITEM * > m_items
Container for ERC settings.
Definition: erc_settings.h:97
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:47
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:46
bool IsPower() const
SCH_SCREEN * LastScreen()
const char * name
Definition: DXF_plotter.cpp:59
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:129
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:88
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:132
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:194
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:161
wxPoint GetTransformedPosition() const
Returns the pin's position in global coordinates.
Definition: sch_pin.cpp:274

References SCH_SCREEN::Append(), SCH_ITEM::Connection(), ERC_ITEM::Create(), ERCE_NOCONNECT_CONNECTED, ERCE_NOCONNECT_NOT_CONNECTED, ERCE_PIN_NOT_CONNECTED, SCHEMATIC::ErcSettings(), CONNECTION_SUBGRAPH::GetDriverPriority(), SCH_PIN::GetLibPin(), LIB_ITEM::GetParent(), EDA_ITEM::GetPosition(), SCH_PIN::GetTransformedPosition(), SCH_PIN::GetType(), LIB_PART::IsPower(), ERC_SETTINGS::IsTestEnabled(), SCH_PIN::IsVisible(), 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, SCH_CONNECTION::Name(), CONNECTION_SUBGRAPH::NONE, 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 2104 of file connection_graph.cpp.

2105 {
2106  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2107 
2108  if( it == m_net_name_to_subgraphs_map.end() )
2109  return nullptr;
2110 
2111  wxASSERT( !it->second.empty() );
2112 
2113  return it->second[0];
2114 }
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 2083 of file connection_graph.cpp.

2085 {
2086  auto it = m_net_name_to_subgraphs_map.find( aNetName );
2087 
2088  if( it == m_net_name_to_subgraphs_map.end() )
2089  return nullptr;
2090 
2091  for( CONNECTION_SUBGRAPH* sg : it->second )
2092  {
2093  // Cache is supposed to be valid by now
2094  wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
2095 
2096  if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
2097  return sg;
2098  }
2099 
2100  return nullptr;
2101 }
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 2027 of file connection_graph.cpp.

2028 {
2029  auto it = m_bus_alias_cache.find( aName );
2030 
2031  return it != m_bus_alias_cache.end() ? it->second : nullptr;
2032 }
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 2035 of file connection_graph.cpp.

2036 {
2037  std::vector<const CONNECTION_SUBGRAPH*> ret;
2038 
2039  for( auto&& subgraph : m_subgraphs )
2040  {
2041  // Graph is supposed to be up-to-date before calling this
2042  wxASSERT( !subgraph->m_dirty );
2043 
2044  if( !subgraph->m_driver )
2045  continue;
2046 
2047  auto sheet = subgraph->m_sheet;
2048  auto connection = subgraph->m_driver->Connection( &sheet );
2049 
2050  if( !connection->IsBus() )
2051  continue;
2052 
2053  auto labels = subgraph->GetBusLabels();
2054 
2055  if( labels.size() > 1 )
2056  {
2057  bool different = false;
2058  wxString first = static_cast<SCH_TEXT*>( labels.at( 0 ) )->GetShownText();
2059 
2060  for( unsigned i = 1; i < labels.size(); ++i )
2061  {
2062  if( static_cast<SCH_TEXT*>( labels.at( i ) )->GetShownText() != first )
2063  {
2064  different = true;
2065  break;
2066  }
2067  }
2068 
2069  if( !different )
2070  continue;
2071 
2072  wxLogTrace( ConnTrace, "SG %ld (%s) has multiple bus labels", subgraph->m_code,
2073  connection->Name() );
2074 
2075  ret.push_back( subgraph );
2076  }
2077  }
2078 
2079  return ret;
2080 }
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 1918 of file connection_graph.cpp.

1920 {
1921  auto c = std::shared_ptr<SCH_CONNECTION>( nullptr );
1922 
1923  switch( aItem->Type() )
1924  {
1925  case SCH_PIN_T:
1926  {
1927  auto pin = static_cast<SCH_PIN*>( aItem );
1928 
1929  if( pin->IsPowerConnection() )
1930  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
1931 
1932  break;
1933  }
1934 
1935  case SCH_GLOBAL_LABEL_T:
1936  case SCH_HIER_LABEL_T:
1937  case SCH_LABEL_T:
1938  {
1939  c = std::make_shared<SCH_CONNECTION>( aItem, aSubgraph->m_sheet );
1940  break;
1941  }
1942 
1943  default:
1944  break;
1945  }
1946 
1947  if( c )
1948  {
1949  c->SetGraph( this );
1950  c->ConfigureFromLabel( aSubgraph->GetNameForDriver( aItem ) );
1951  }
1952 
1953  return c;
1954 }
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:161

References CONNECTION_SUBGRAPH::GetNameForDriver(), CONNECTION_SUBGRAPH::m_sheet, 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 2117 of file connection_graph.cpp.

2118 {
2119  auto it = m_item_to_subgraph_map.find( aItem );
2120  CONNECTION_SUBGRAPH* ret = it != m_item_to_subgraph_map.end() ? it->second : nullptr;
2121 
2122  while( ret && ret->m_absorbed )
2123  ret = ret->m_absorbed_by;
2124 
2125  return ret;
2126 }
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 1957 of file connection_graph.cpp.

1959 {
1960  wxASSERT( aBusConnection->IsBus() );
1961 
1962  SCH_CONNECTION* match = nullptr;
1963 
1964  if( aBusConnection->Type() == CONNECTION_TYPE::BUS )
1965  {
1966  // Vector bus: compare against index, because we allow the name
1967  // to be different
1968 
1969  for( const auto& bus_member : aBusConnection->Members() )
1970  {
1971  if( bus_member->VectorIndex() == aSearch->VectorIndex() )
1972  {
1973  match = bus_member.get();
1974  break;
1975  }
1976  }
1977  }
1978  else
1979  {
1980  // Group bus
1981  for( const auto& c : aBusConnection->Members() )
1982  {
1983  // Vector inside group: compare names, because for bus groups
1984  // we expect the naming to be consistent across all usages
1985  // TODO(JE) explain this in the docs
1986  if( c->Type() == CONNECTION_TYPE::BUS )
1987  {
1988  for( const auto& bus_member : c->Members() )
1989  {
1990  if( bus_member->LocalName() == aSearch->LocalName() )
1991  {
1992  match = bus_member.get();
1993  break;
1994  }
1995  }
1996  }
1997  else if( c->LocalName() == aSearch->LocalName() )
1998  {
1999  match = c.get();
2000  break;
2001  }
2002  }
2003  }
2004 
2005  return match;
2006 }
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 1615 of file connection_graph.cpp.

1616 {
1617  SCH_CONNECTION* conn = aSubgraph->m_driver_connection;
1618  std::vector<CONNECTION_SUBGRAPH*> search_list;
1619  std::unordered_set<CONNECTION_SUBGRAPH*> visited;
1620  std::vector<SCH_CONNECTION*> stale_bus_members;
1621 
1622  auto visit =
1623  [&]( CONNECTION_SUBGRAPH* aParent )
1624  {
1625  for( SCH_SHEET_PIN* pin : aParent->m_hier_pins )
1626  {
1627  SCH_SHEET_PATH path = aParent->m_sheet;
1628  path.push_back( pin->GetParent() );
1629 
1630  auto it = m_sheet_to_subgraphs_map.find( path );
1631 
1632  if( it == m_sheet_to_subgraphs_map.end() )
1633  continue;
1634 
1635  for( CONNECTION_SUBGRAPH* candidate : it->second )
1636  {
1637  if( !candidate->m_strong_driver
1638  || candidate->m_hier_ports.empty()
1639  || visited.count( candidate ) )
1640  {
1641  continue;
1642  }
1643 
1644  for( SCH_HIERLABEL* label : candidate->m_hier_ports )
1645  {
1646  if( candidate->GetNameForDriver( label ) == aParent->GetNameForDriver( pin ) )
1647  {
1648  wxLogTrace( ConnTrace, "%lu: found child %lu (%s)", aParent->m_code,
1649  candidate->m_code, candidate->m_driver_connection->Name() );
1650 
1651  candidate->m_hier_parent = aParent;
1652 
1653  search_list.push_back( candidate );
1654  break;
1655  }
1656  }
1657  }
1658  }
1659 
1660  for( SCH_HIERLABEL* label : aParent->m_hier_ports )
1661  {
1662  SCH_SHEET_PATH path = aParent->m_sheet;
1663  path.pop_back();
1664 
1665  auto it = m_sheet_to_subgraphs_map.find( path );
1666 
1667  if( it == m_sheet_to_subgraphs_map.end() )
1668  continue;
1669 
1670  for( CONNECTION_SUBGRAPH* candidate : it->second )
1671  {
1672  if( candidate->m_hier_pins.empty()
1673  || visited.count( candidate )
1674  || candidate->m_driver_connection->Type() != aParent->m_driver_connection->Type() )
1675  {
1676  continue;
1677  }
1678 
1679  for( SCH_SHEET_PIN* pin : candidate->m_hier_pins )
1680  {
1681  SCH_SHEET_PATH pin_path = path;
1682  pin_path.push_back( pin->GetParent() );
1683 
1684  if( pin_path != aParent->m_sheet )
1685  continue;
1686 
1687  if( aParent->GetNameForDriver( label ) == candidate->GetNameForDriver( pin ) )
1688  {
1689  wxLogTrace( ConnTrace, "%lu: found additional parent %lu (%s)",
1690  aParent->m_code, candidate->m_code,
1691  candidate->m_driver_connection->Name() );
1692 
1693  search_list.push_back( candidate );
1694  break;
1695  }
1696  }
1697  }
1698  }
1699  };
1700 
1701  auto propagate_bus_neighbors = [&]( CONNECTION_SUBGRAPH* aParentGraph ) {
1702  for( const auto& kv : aParentGraph->m_bus_neighbors )
1703  {
1704  for( CONNECTION_SUBGRAPH* neighbor : kv.second )
1705  {
1706  // May have been absorbed but won't have been deleted
1707  while( neighbor->m_absorbed )
1708  neighbor = neighbor->m_absorbed_by;
1709 
1710  SCH_CONNECTION* parent = aParentGraph->m_driver_connection;
1711 
1712  // Now member may be out of date, since we just cloned the
1713  // connection from higher up in the hierarchy. We need to
1714  // figure out what the actual new connection is.
1715  SCH_CONNECTION* member = matchBusMember( parent, kv.first.get() );
1716 
1717  if( !member )
1718  {
1719  // Try harder: we might match on a secondary driver
1720  for( CONNECTION_SUBGRAPH* sg : kv.second )
1721  {
1722  if( sg->m_multiple_drivers )
1723  {
1724  SCH_SHEET_PATH sheet = sg->m_sheet;
1725 
1726  for( SCH_ITEM* driver : sg->m_drivers )
1727  {
1728  auto c = getDefaultConnection( driver, sg );
1729  member = matchBusMember( parent, c.get() );
1730 
1731  if( member )
1732  break;
1733  }
1734  }
1735 
1736  if( member )
1737  break;
1738  }
1739  }
1740 
1741  // This is bad, probably an ERC error
1742  if( !member )
1743  {
1744  wxLogTrace( ConnTrace, "Could not match bus member %s in %s",
1745  kv.first->Name(), parent->Name() );
1746  continue;
1747  }
1748 
1749  auto neighbor_conn = neighbor->m_driver_connection;
1750  auto neighbor_name = neighbor_conn->Name();
1751 
1752  // Matching name: no update needed
1753  if( neighbor_name == member->Name() )
1754  continue;
1755 
1756  // Was this neighbor already updated from a different sheet? Don't rename it again
1757  if( neighbor_conn->Sheet() != neighbor->m_sheet )
1758  continue;
1759 
1760  // Safety check against infinite recursion
1761  wxASSERT( neighbor_conn->IsNet() );
1762 
1763  wxLogTrace( ConnTrace, "%lu (%s) connected to bus member %s (local %s)",
1764  neighbor->m_code, neighbor_name, member->Name(), member->LocalName() );
1765 
1766  // Take whichever name is higher priority
1769  {
1770  member->Clone( *neighbor_conn );
1771  stale_bus_members.push_back( member );
1772  }
1773  else
1774  {
1775  neighbor_conn->Clone( *member );
1776 
1777  recacheSubgraphName( neighbor, neighbor_name );
1778 
1779  // Recurse onto this neighbor in case it needs to re-propagate
1780  neighbor->m_dirty = true;
1781  propagateToNeighbors( neighbor );
1782  }
1783  }
1784  }
1785  };
1786 
1787  // If we are a bus, we must propagate to local neighbors and then the hierarchy
1788  if( conn->IsBus() )
1789  propagate_bus_neighbors( aSubgraph );
1790 
1791  // If we don't have any hier pins (i.e. no children), nothing to do
1792  if( aSubgraph->m_hier_pins.empty() )
1793  {
1794  // If we also don't have any parents, we'll never be visited again
1795  if( aSubgraph->m_hier_ports.empty() )
1796  aSubgraph->m_dirty = false;
1797 
1798  return;
1799  }
1800 
1801  // If we do have hier ports, skip this subgraph as it will be visited by a parent
1802  // TODO(JE) this will leave the subgraph dirty if there is no matching parent subgraph,
1803  // which should be flagged as an ERC error
1804  if( !aSubgraph->m_hier_ports.empty() )
1805  return;
1806 
1807  visited.insert( aSubgraph );
1808 
1809  wxLogTrace( ConnTrace, "Propagating %lu (%s) to subsheets",
1810  aSubgraph->m_code, aSubgraph->m_driver_connection->Name() );
1811 
1812  visit( aSubgraph );
1813 
1814  for( unsigned i = 0; i < search_list.size(); i++ )
1815  {
1816  auto child = search_list[i];
1817 
1818  visited.insert( child );
1819 
1820  visit( child );
1821 
1822  child->m_dirty = false;
1823  }
1824 
1825  // Now, find the best driver for this chain of subgraphs
1826  CONNECTION_SUBGRAPH* original = aSubgraph;
1829  bool originalStrong = ( highest >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1830  wxString originalName = original->m_driver_connection->Name();
1831 
1832  // Check if a subsheet has a higher-priority connection to the same net
1834  {
1835  for( CONNECTION_SUBGRAPH* subgraph : visited )
1836  {
1837  if( subgraph == original )
1838  continue;
1839 
1841  CONNECTION_SUBGRAPH::GetDriverPriority( subgraph->m_driver );
1842 
1843  bool candidateStrong = ( priority >= CONNECTION_SUBGRAPH::PRIORITY::HIER_LABEL );
1844  wxString candidateName = subgraph->m_driver_connection->Name();
1845  bool shorterPath = subgraph->m_sheet.size() < original->m_sheet.size();
1846  bool asGoodPath = subgraph->m_sheet.size() <= original->m_sheet.size();
1847 
1848  // Pick a better driving subgraph if it:
1849  // a) has a power pin or global driver
1850  // b) is a strong driver and we're a weak driver
1851  // c) meets or exceeds our priority, is a strong driver, and has a shorter path
1852  // d) matches our strength and is at least as short, and is alphabetically lower
1853 
1854  if( ( priority >= CONNECTION_SUBGRAPH::PRIORITY::POWER_PIN ) ||
1855  ( !originalStrong && candidateStrong ) ||
1856  ( priority >= highest && candidateStrong && shorterPath ) ||
1857  ( ( originalStrong == candidateStrong ) && asGoodPath &&
1858  ( candidateName < originalName ) ) )
1859  {
1860  original = subgraph;
1861  highest = priority;
1862  originalStrong = candidateStrong;
1863  originalName = subgraph->m_driver_connection->Name();
1864  }
1865  }
1866  }
1867 
1868  if( original != aSubgraph )
1869  {
1870  wxLogTrace( ConnTrace, "%lu (%s) overridden by new driver %lu (%s)",
1871  aSubgraph->m_code, aSubgraph->m_driver_connection->Name(), original->m_code,
1872  original->m_driver_connection->Name() );
1873  }
1874 
1875  conn = original->m_driver_connection;
1876 
1877  for( CONNECTION_SUBGRAPH* subgraph : visited )
1878  {
1879  wxString old_name = subgraph->m_driver_connection->Name();
1880 
1881  subgraph->m_driver_connection->Clone( *conn );
1882 
1883  if( old_name != conn->Name() )
1884  recacheSubgraphName( subgraph, old_name );
1885 
1886  if( conn->IsBus() )
1887  propagate_bus_neighbors( subgraph );
1888  }
1889 
1890  // Somewhere along the way, a bus member may have been upgraded to a global or power label.
1891  // Because this can happen anywhere, we need a second pass to update all instances of that bus
1892  // member to have the correct connection info
1893  if( conn->IsBus() && !stale_bus_members.empty() )
1894  {
1895  for( auto stale_member : stale_bus_members )
1896  {
1897  for( CONNECTION_SUBGRAPH* subgraph : visited )
1898  {
1899  SCH_CONNECTION* member = matchBusMember( subgraph->m_driver_connection,
1900  stale_member );
1901  wxASSERT( member );
1902 
1903  wxLogTrace( ConnTrace, "Updating %lu (%s) member %s to %s", subgraph->m_code,
1904  subgraph->m_driver_connection->Name(), member->LocalName(),
1905  stale_member->Name() );
1906 
1907  member->Clone( *stale_member );
1908 
1909  propagate_bus_neighbors( subgraph );
1910  }
1911  }
1912  }
1913 
1914  aSubgraph->m_dirty = false;
1915 }
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.
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
Definition: sch_sheet.h:169
#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[]
void pop_back()
Forwarded method from std::vector.
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.h:85
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void Clone(SCH_CONNECTION &aOther)
Copies connectivity information (but not parent) from another connection.
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:194
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(), SCH_SHEET_PIN::GetParent(), 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(), SCH_SHEET_PATH::pop_back(), 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 2009 of file connection_graph.cpp.

2011 {
2012  auto it = m_net_name_to_subgraphs_map.find( aOldName );
2013 
2014  if( it != m_net_name_to_subgraphs_map.end() )
2015  {
2016  std::vector<CONNECTION_SUBGRAPH*>& vec = it->second;
2017  vec.erase( std::remove( vec.begin(), vec.end(), aSubgraph ), vec.end() );
2018  }
2019 
2020  wxLogTrace( ConnTrace, "recacheSubgraphName: %s => %s", aOldName,
2021  aSubgraph->m_driver_connection->Name() );
2022 
2023  m_net_name_to_subgraphs_map[aSubgraph->m_driver_connection->Name()].push_back( aSubgraph );
2024 }
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 436 of file connection_graph.cpp.

438 {
439  PROF_COUNTER recalc_time( "CONNECTION_GRAPH::Recalculate" );
440 
441  if( aUnconditional )
442  Reset();
443 
444  PROF_COUNTER update_items( "updateItemConnectivity" );
445 
446  m_sheetList = aSheetList;
447 
448  for( const SCH_SHEET_PATH& sheet : aSheetList )
449  {
450  std::vector<SCH_ITEM*> items;
451 
452  for( SCH_ITEM* item : sheet.LastScreen()->Items() )
453  {
454  if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) )
455  items.push_back( item );
456  }
457 
458  m_items.reserve( m_items.size() + items.size() );
459 
460  updateItemConnectivity( sheet, items );
461 
462  // UpdateDanglingState() also adds connected items for SCH_TEXT
463  sheet.LastScreen()->TestDanglingEnds( &sheet, aChangedItemHandler );
464  }
465 
466  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
467  update_items.Show();
468 
469  PROF_COUNTER build_graph( "buildConnectionGraph" );
470 
472 
473  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
474  build_graph.Show();
475 
476  recalc_time.Stop();
477 
478  if( wxLog::IsAllowedTraceMask( ConnProfileMask ) )
479  recalc_time.Show();
480 
481 #ifndef DEBUG
482  // Pressure relief valve for release builds
483  const double max_recalc_time_msecs = 250.;
484 
485  if( m_allowRealTime && ADVANCED_CFG::GetCfg().m_RealTimeConnectivity &&
486  recalc_time.msecs() > max_recalc_time_msecs )
487  {
488  m_allowRealTime = false;
489  }
490 #endif
491 }
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:194

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

413 {
414  for( auto& subgraph : m_subgraphs )
415  delete subgraph;
416 
417  m_items.clear();
418  m_subgraphs.clear();
419  m_driver_subgraphs.clear();
420  m_sheet_to_subgraphs_map.clear();
421  m_invisible_power_pins.clear();
422  m_bus_alias_cache.clear();
423  m_net_name_to_code_map.clear();
424  m_bus_name_to_code_map.clear();
427  m_item_to_subgraph_map.clear();
428  m_local_label_cache.clear();
429  m_global_label_cache.clear();
430  m_last_net_code = 1;
431  m_last_bus_code = 1;
433 }
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 2129 of file connection_graph.cpp.

2130 {
2131  int error_count = 0;
2132 
2133  wxCHECK_MSG( m_schematic, true, "Null m_schematic in CONNECTION_GRAPH::RunERC" );
2134 
2135  ERC_SETTINGS& settings = m_schematic->ErcSettings();
2136 
2137  // We don't want to run many ERC checks more than once on a given screen even though it may
2138  // represent multiple sheets with multiple subgraphs. We can tell these apart by drivers.
2139  std::set<SCH_ITEM*> seenDriverInstances;
2140 
2141  for( auto&& subgraph : m_subgraphs )
2142  {
2143  // Graph is supposed to be up-to-date before calling RunERC()
2144  wxASSERT( !subgraph->m_dirty );
2145 
2146  if( subgraph->m_absorbed )
2147  continue;
2148 
2149  if( seenDriverInstances.count( subgraph->m_driver ) )
2150  continue;
2151 
2152  if( subgraph->m_driver )
2153  seenDriverInstances.insert( subgraph->m_driver );
2154 
2165  if( settings.IsTestEnabled( ERCE_DRIVER_CONFLICT ) )
2166  {
2167  if( !ercCheckMultipleDrivers( subgraph ) )
2168  error_count++;
2169  }
2170 
2171  subgraph->ResolveDrivers( false );
2172 
2173  if( settings.IsTestEnabled( ERCE_BUS_TO_NET_CONFLICT ) )
2174  {
2175  if( !ercCheckBusToNetConflicts( subgraph ) )
2176  error_count++;
2177  }
2178 
2179  if( settings.IsTestEnabled( ERCE_BUS_ENTRY_CONFLICT ) )
2180  {
2181  if( !ercCheckBusToBusEntryConflicts( subgraph ) )
2182  error_count++;
2183  }
2184 
2185  if( settings.IsTestEnabled( ERCE_BUS_TO_BUS_CONFLICT ) )
2186  {
2187  if( !ercCheckBusToBusConflicts( subgraph ) )
2188  error_count++;
2189  }
2190 
2191  if( settings.IsTestEnabled( ERCE_WIRE_DANGLING ) )
2192  {
2193  if( !ercCheckFloatingWires( subgraph ) )
2194  error_count++;
2195  }
2196 
2197  // The following checks are always performed since they don't currently
2198  // have an option exposed to the user
2199 
2200  if( !ercCheckNoConnects( subgraph ) )
2201  error_count++;
2202 
2203  if( settings.IsTestEnabled( ERCE_LABEL_NOT_CONNECTED )
2204  || settings.IsTestEnabled( ERCE_GLOBLABEL ) )
2205  {
2206  if( !ercCheckLabels( subgraph ) )
2207  error_count++;
2208  }
2209  }
2210 
2211  // Hierarchical sheet checking is done at the schematic level
2212  if( settings.IsTestEnabled( ERCE_HIERACHICAL_LABEL ) )
2213  error_count += ercCheckHierSheets();
2214 
2215  return error_count;
2216 }
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:58
bool IsTestEnabled(int aErrorCode) const
Definition: erc_settings.h:114
A bus wire is graphically connected to a net port/pin (or vice versa).
Definition: erc_settings.h:60
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:64
Label not connected to anything.
Definition: erc_settings.h:48
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:97
A wire connected to a bus doesn't match the bus.
Definition: erc_settings.h:56
A global label is unique.
Definition: erc_settings.h:62
Mismatch between hierarchical labels and pins sheets.
Definition: erc_settings.h:45
ERC_SETTINGS & ErcSettings() const
Definition: schematic.cpp:132
Conflicting drivers (labels, etc) on a subgraph.
Definition: erc_settings.h:55
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 264 of file connection_graph.h.

265  {
266  m_schematic = aSchematic;
267  }
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_COMPONENTs in this map – we must store a structure that links a specific pin on a component back to that component: a SCH_PIN_CONNECTION. This wrapper class is a convenience for linking a pin and component 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 494 of file connection_graph.cpp.

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

References BUS, SCH_ITEM::ConnectedItems(), SCH_ITEM::ConnectionPropagatesTo(), SCH_SCREEN::GetBus(), SCH_COMPONENT::GetPins(), SCH_SHEET_PATH::LastScreen(), LAYER_BUS, LAYER_BUS_JUNCTION, LAYER_JUNCTION, m_invisible_power_pins, m_items, NET, SCH_BUS_BUS_ENTRY_T, SCH_BUS_WIRE_ENTRY_T, SCH_COMPONENT_T, SCH_JUNCTION_T, SCH_LINE_T, SCH_PIN_T, SCH_SHEET_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 347 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 351 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 340 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 353 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 345 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 360 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 366 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 364 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 368 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 362 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 349 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 370 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 343 of file connection_graph.h.

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

◆ m_sheetList

SCH_SHEET_LIST CONNECTION_GRAPH::m_sheetList
private

Definition at line 331 of file connection_graph.h.

Referenced by ercCheckHierSheets(), and Recalculate().

◆ m_subgraphs

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

Definition at line 337 of file connection_graph.h.

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


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