114 const std::vector<SHEET_SYMBOLS>& aSheets )
121 result.edges.reserve( 256 );
125 const auto& sheet = *view.input;
132 auto consider = [&](
SCH_ITEM* cand ) ->
bool
145 if( s.
y == e.
y && p.
y == s.
y )
147 int minx = std::min( s.
x, e.
x );
148 int maxx = std::max( s.
x, e.
x );
150 if( p.
x >= minx && p.
x <= maxx )
156 else if( s.
x == e.
x && p.
x == s.
x )
158 int miny = std::min( s.
y, e.
y );
159 int maxy = std::max( s.
y, e.
y );
161 if( p.
y >= miny && p.
y <= maxy )
182 for(
const auto& [symbol, pins] : view.symbols )
184 if( pins.size() != 2 )
193 if( !findWireOnScreen( pins[0], wireA ) || !findWireOnScreen( pins[1], wireB ) )
204 if( pins[0]->IsPower() || pins[1]->IsPower() )
212 if( aS.
x == aE.
x && bS.
x == bE.
x && aS.
x == bS.
x )
214 else if( aS.
y == aE.
y && bS.
y == bE.
y && aS.
y == bS.
y )
221 const wxString& netA = sheet.Key( pins[0] );
222 const wxString& netB = sheet.Key( pins[1] );
224 if( netA.IsEmpty() || netB.IsEmpty() || netA == netB )
227 result.edges.push_back( { netA, netB, symbol, sc } );
235 std::set<wxString> powerNets;
239 const auto& sheet = *view.input;
241 for(
const auto& entry : view.symbols )
247 if(
const auto* net = sheet.Find( p ) )
248 powerNets.insert( net->key );
258 std::set<wxString> powerAdjacentNets;
262 if( powerNets.contains( be.
a ) || powerNets.contains( be.
b ) )
264 if( !powerNets.contains( be.
a ) )
265 powerAdjacentNets.insert( be.
a );
267 if( !powerNets.contains( be.
b ) )
268 powerAdjacentNets.insert( be.
b );
273 result.adjacency[be.
a].push_back( { be.
b, be.
sym } );
274 result.adjacency[be.
b].push_back( { be.
a, be.
sym } );
280 std::map<wxString, int> degree;
282 for(
const auto&
kv :
result.adjacency )
283 degree[
kv.first] =
static_cast<int>(
kv.second.size() );
285 if(
result.adjacency.size() <= 2 )
286 powerAdjacentNets.clear();
288 if( powerAdjacentNets.size() <= 2 )
289 powerAdjacentNets.clear();
291 std::queue<wxString> q;
292 std::set<wxString> removed;
294 for(
const auto&
kv : degree )
296 if(
kv.second <= 1 && powerAdjacentNets.contains(
kv.first ) )
302 wxString n = q.front();
305 if( removed.contains( n ) )
312 if( removed.contains( e.other ) )
315 if( degree.count( e.other ) )
319 if( degree[e.other] <= 1 && powerAdjacentNets.contains( e.other ) )
325 if( !removed.empty() )
327 std::map<wxString, std::vector<BRIDGE_NEIGHBOR>> newAdj;
329 for(
const auto&
kv :
result.adjacency )
331 if( removed.contains(
kv.first ) )
336 if( removed.contains( e.
other ) )
339 newAdj[
kv.first].push_back( e );
343 result.adjacency.swap( newAdj );
566 std::set<wxString> unresolvedTerminals;
575 chain->ReplaceNets( {} );
576 unresolvedTerminals.insert(
chain->GetName() );
580 std::unordered_map<wxString, SCH_NETCHAIN*> netToNetChain;
583 std::vector<SHEET_SYMBOLS> sheetSymbols;
584 sheetSymbols.reserve( aConnectivity.
sheets.size() );
586 for(
const auto& sheet : aConnectivity.
sheets )
598 view.
symbols.push_back( { symbol, symbol->
GetPins( &sheet.path ) } );
603 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: screens=%zu (global build)", sheetSymbols.size() );
604 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: debug start passes (pre-pass chains=%zu)",
610 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 1 (per-sheet 2-pin symbols)" );
613 auto& bridgeEdges = bridgeGraph.
edges;
616 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: bridgeEdges=%zu adjacency=%zu",
617 bridgeEdges.size(), adjacency.size() );
623 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: targeted stub pruning start (adj=%zu)", adjacency.size() );
624 std::set<wxString> seen;
625 std::set<wxString> globalPrune;
626 for(
const auto&
kv : adjacency )
628 const wxString& start =
kv.first;
629 if( seen.contains( start ) )
continue;
633 std::vector<wxString>
comp; std::queue<wxString> q; q.push( start ); seen.insert( start );
636 wxString cur = q.front(); q.pop();
comp.push_back( cur );
640 if( !seen.contains( e.other ) )
642 seen.insert( e.other );
650 if(
comp.size() <= 4 )
continue;
651 std::map<wxString,int> degree;
652 for(
const wxString& n :
comp ) degree[n] = (int) adjacency.at( n ).size();
654 for(
const wxString& n :
comp )
656 const auto& nbrs = adjacency.at( n );
657 if( nbrs.size() == 1 )
659 const wxString neigh = nbrs[0].other;
660 if( degree.count( neigh ) && degree[neigh] > 2 )
candidates.push_back( n );
668 [](
const wxString& a,
const wxString& b )
670 return a.CmpNoCase( b ) < 0;
676 for(
size_t i = 0; i < needPrune; ++i ) globalPrune.insert(
candidates[i] );
678 if( !globalPrune.empty() )
680 std::map<wxString,std::vector<BRIDGE_NEIGHBOR>> newAdj;
681 for(
const auto& kv2 : adjacency )
683 if( globalPrune.contains( kv2.first ) )
continue;
686 if( globalPrune.contains( e.
other ) )
continue;
687 newAdj[kv2.first].push_back( e );
690 adjacency.swap( newAdj );
691 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pruned %zu targeted stub nets", globalPrune.size() );
696 auto neighbors_of = [&](
const wxString& n ) ->
const std::vector<BRIDGE_NEIGHBOR>*
698 if(
auto it = adjacency.find(n); it != adjacency.end() )
return &it->second;
706 std::set<wxString> netsAll;
707 for(
const auto&
kv : adjacency ) netsAll.insert(
kv.first );
710 std::set<wxString> visited;
711 for(
const wxString& start : netsAll )
713 if( visited.contains( start ) )
continue;
714 std::queue<wxString> q; q.push( start );
715 std::set<wxString>
comp;
comp.insert( start ); visited.insert( start );
718 wxString cur = q.front(); q.pop();
719 if(
auto nbrs = neighbors_of( cur ) )
723 if( visited.contains( e.other ) )
continue;
724 visited.insert( e.other );
725 comp.insert( e.other );
730 if(
comp.size() >= 2 )
732 auto sig = std::make_unique<SCH_NETCHAIN>();
733 for(
const wxString& n :
comp ) sig->AddNet( n );
738 netToNetChain.reserve( adjacency.size() );
740 if( sigUP )
for(
const wxString& n : sigUP->GetNets() ) netToNetChain[n] = sigUP.get();
744 const auto first = netToNetChain.find( edge.a );
745 const auto second = netToNetChain.find( edge.b );
747 if( first != netToNetChain.end() && second != netToNetChain.end()
748 && first->second == second->second && edge.sym )
750 first->second->AddSymbol( edge.sym );
758 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pre-label potentialNetChains=%zu",
769 for(
const wxString& n : sigUP->GetNets() )
774 netsStr += wxS(
" " );
778 netsStr += wxS(
"..." );
785 wxLogTrace(
traceSchNetChain,
" chain %p name='%s' nets=%zu [%s]", (
void*) sigUP.get(),
786 sigUP->GetName(), sigUP->GetNets().size(), netsStr );
795 std::set<wxString> committedNames;
800 committedNames.insert(
chain->GetName() );
803 for(
const auto& sheet : aConnectivity.
sheets )
812 const auto* connection = sheet.Find( item );
818 const wxString& net = connection->name;
821 if( !net.IsEmpty() && net.Length() < 2048 && netToNetChain.count( net ) )
825 if(
name.Length() > 512 )
826 name.Truncate( 512 );
828 if(
name.StartsWith( wxS(
"/" ) ) )
835 if( !committedNames.contains(
name )
846 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 3 (default naming)" );
849 if( sig->GetName().IsEmpty() )
851 sig->SetName( wxString::Format( wxT(
"NetChain%d" ), idx ) );
864 std::map<SCH_NETCHAIN*, std::vector<PIN_INFO>> chainPins;
870 const auto& sheet = *view.input;
873 for(
const auto& [sym, pins] : view.symbols )
877 const auto chain = netToNetChain.find( sheet.Key( p ) );
879 if(
chain != netToNetChain.end() )
880 chainPins[
chain->second].push_back( { p, sym, &sheetPath, p->GetPosition() } );
889 const auto& pins = chainPins[sig.get()];
893 size_t bestI = 0, bestJ = 0;
895 for(
size_t i = 0; i < pins.size(); ++i )
897 for(
size_t j = i + 1; j < pins.size(); ++j )
901 int64_t dx = pa.
x - pb.
x;
902 int64_t dy = pa.
y - pb.
y;
903 int64_t d = dx * dx + dy * dy;
908 a = pins[i].pin->m_Uuid;
909 b = pins[j].pin->m_Uuid;
916 sig->SetTerminalPins( a, b );
918 if( best >= 0 && bestI < pins.size() && bestJ < pins.size() )
920 sig->SetTerminalPaths( pins[bestI].sheet->Path(), pins[bestJ].sheet->Path() );
921 sig->SetTerminalRefs( pins[bestI].sym->GetRef( pins[bestI].sheet ), pins[bestI].pin->GetNumber(),
922 pins[bestJ].sym->GetRef( pins[bestJ].sheet ), pins[bestJ].pin->GetNumber() );
926 wxLogTrace(
traceSchNetChain,
"RebuildNetChains: pass 5 (apply symbol names)" );
940 for(
const wxString& n : sig->
GetNets() )
941 netsStr += n + wxS(
" " );
944 sig->
GetNets().size(), netsStr );
954 std::set<wxString> alreadyCommitted;
959 alreadyCommitted.insert(
chain->GetName() );
963 std::map<std::pair<wxString, wxString>, wxString> refPinToNet;
969 const auto& sheet = *view.input;
971 for(
const auto& [sym, pins] : view.symbols )
973 const wxString ref = sym->GetRef( &sheet.path );
977 if(
const auto* net = sheet.Find(
pin ) )
978 refPinToNet[{ ref,
pin->GetNumber() }] = net->key;
986 std::unordered_map<wxString, SCH_NETCHAIN*> committedByName;
991 committedByName[
chain->GetName()] =
chain.get();
996 std::set<wxString> refreshedThisPass;
1000 if( unresolvedTerminals.contains( chainName ) )
1004 const auto committed = committedByName.find( chainName );
1006 if( committed != committedByName.end() )
1011 for(
int endpoint = 0; endpoint < 2; ++endpoint )
1013 const KIID&
id = endpoint == 0 ?
chain.GetTerminalPinA() :
chain.GetTerminalPinB();
1015 for(
const auto& sheet : aConnectivity.
sheets )
1017 SCH_SCREEN* screen = sheet.path.LastScreen();
1019 if( screen && sheet.path.PathRef() ==
chain.GetTerminalPath( endpoint ) )
1038 if( alreadyCommitted.count( chainName ) )
1040 auto it = committedByName.find( chainName );
1042 if( it != committedByName.end() && it->second )
1045 refreshedThisPass.insert( chainName );
1053 alreadyCommitted.insert( chainName );
1054 refreshedThisPass.insert( chainName );
1062 if( memberNets.empty() || unresolvedTerminals.contains( chainName ) )
1067 if( alreadyCommitted.count( chainName ) && refreshedThisPass.count( chainName ) )
1077 SCH_PIN* terminalPinA =
nullptr;
1078 SCH_PIN* terminalPinB =
nullptr;
1079 std::set<SCH_SYMBOL*> symbols;
1083 const auto& sheet = *view.input;
1085 for(
const auto& [sym, pins] : view.symbols )
1087 const wxString ref = sym->GetRef( &sheet.path );
1088 bool symContributes =
false;
1092 const auto* net = sheet.Find(
pin );
1097 if( memberNets.count( net->name ) )
1098 symContributes =
true;
1100 if( ref == termRefs.first.ref &&
pin->GetNumber() == termRefs.first.pin )
1103 if( ref == termRefs.second.ref &&
pin->GetNumber() == termRefs.second.pin )
1107 if( symContributes )
1108 symbols.insert( sym );
1112 if( !terminalPinA || !terminalPinB || symbols.empty() )
1115 "RebuildNetChains: cannot restore manual chain '%s' "
1116 "(terminals or member nets unresolved)",
1121 if( alreadyCommitted.count( chainName ) )
1123 auto it = committedByName.find( chainName );
1125 if( it != committedByName.end() && it->second )
1134 terminalPinB->
m_Uuid, termRefs.first.ref, termRefs.first.pin,
1135 termRefs.second.ref, termRefs.second.pin );
1136 alreadyCommitted.insert( chainName );