140 std::map<PIN*, PIN*> pairs;
141 std::vector<PIN*> pref, ptgt;
146 for(
PIN* p : m.second->Pins() )
151 for(
PIN* p : m.first->Pins() )
167 if( pref.size() != ptgt.size() )
172 wxString::Format(
_(
"Component %s expects %lu matching pads but candidate %s provides %lu." ),
173 aReason.
m_reference,
static_cast<unsigned long>( pref.size() ),
174 aReason.
m_candidate,
static_cast<unsigned long>( ptgt.size() ) );
178 for(
unsigned int i = 0; i < pref.size(); i++ )
180 pairs[pref[i]] = ptgt[i];
183 for(
PIN* refPin : aRef->
Pins() )
188 std::optional<int> prevNet;
192 for(
PIN* ppin : refCmp->Pins() )
194 if ( ppin->GetNetCode() != refPin->GetNetCode() )
198 ppin->GetParent()->GetParent()->GetReferenceAsString(),
199 ppin->GetReference(), ppin->GetNetCode() );
201 auto tpin = pairs.find( ppin );
203 if( tpin != pairs.end() )
205 int nc = tpin->second->GetNetCode();
207 if( prevNet && ( *prevNet != nc ) )
219 if(
const NETINFO_ITEM* net = refBoard->FindNet( refPin->GetNetCode() ) )
220 refNetName = net->GetNetname();
226 tgtNetName = net->GetNetname();
229 if( refNetName.IsEmpty() )
230 refNetName = wxString::Format(
_(
"net %d" ), refPin->GetNetCode() );
232 if( tgtNetName.IsEmpty() )
233 tgtNetName = wxString::Format(
_(
"net %d" ), nc );
235 aReason.
m_reason = wxString::Format(
236 _(
"Pad %s of %s is on net %s but its match in candidate %s is on net %s." ),
256 std::vector<TOPOLOGY_MISMATCH_REASON>& aMismatchReasons )
258 aMismatchReasons.clear();
259 std::vector<COMPONENT*> matches;
263 if( partialMatches.
m_locked.find( cmpTarget ) != partialMatches.
m_locked.end() )
269 cmpTarget->m_reference );
275 localReason.
m_candidate = cmpTarget->GetParent()->GetReferenceAsString();
283 matches.push_back( cmpTarget );
287 wxLogTrace(
traceTopoMatch, wxT(
"Reject [net topo mismatch]\n") );
288 aMismatchReasons.push_back( localReason );
294 aMismatchReasons.push_back( localReason );
302 for(
size_t i = 0; i < a->
m_pins.size(); i++ )
305 PIN* pb = b->m_pins[i];
311 return (
double) n / (double) a->
m_pins.size();
314 std::sort( matches.begin(), matches.end(),
317 double simA = padSimilarity( aRef, a );
318 double simB = padSimilarity( aRef, b );
323 return a->GetParent()->GetReferenceAsString()
324 < b->GetParent()->GetReferenceAsString();
327 if( matches.empty() )
331 reason.
m_reason =
_(
"No compatible component found in the target area." );
333 if( aMismatchReasons.empty() )
334 aMismatchReasons.push_back( reason );
412 std::vector<TOPOLOGY_MISMATCH_REASON>& aMismatchReasons )
414 std::vector<BACKTRACK_STAGE> stack;
417 aMismatchReasons.clear();
419 std::vector<TOPOLOGY_MISMATCH_REASON> localReasons;
424 reason.
m_reason =
_(
"One or both of the areas has no components assigned." );
425 aMismatchReasons.push_back( reason );
432 reason.
m_reason =
_(
"Component count mismatch" );
433 aMismatchReasons.push_back( reason );
440 stack.push_back(
top );
442 bool matchFound =
false;
445 while( !stack.empty() )
448 auto& current = stack.back();
450 for(
auto it = current.m_locked.begin(); it != current.m_locked.end(); it++ )
452 if (it->second == current.m_ref)
454 wxLogTrace(
traceTopoMatch, wxT(
"stk: Remove %s from locked\n" ),
455 current.m_ref->m_reference );
456 current.m_locked.erase( it );
466 reason.
m_reason =
_(
"Iteration count exceeded (timeout)" );
468 if( aMismatchReasons.empty() )
469 aMismatchReasons.push_back( reason );
471 aMismatchReasons.insert( aMismatchReasons.begin(), reason );
476 if( current.m_currentMatch < 0 )
478 localReasons.clear();
481 if( current.m_matches.empty() && aMismatchReasons.empty() && !localReasons.empty() )
482 aMismatchReasons = localReasons;
484 current.m_currentMatch = 0;
487 wxLogTrace(
traceTopoMatch, wxT(
"stk: Current '%s' stack %d cm %d/%d locked %d/%d\n" ),
488 current.m_ref->m_reference, (
int) stack.size(), current.m_currentMatch,
489 (
int) current.m_matches.size(), (
int) current.m_locked.size(),
492 if ( current.m_matches.empty() )
494 wxLogTrace(
traceTopoMatch, wxT(
"stk: No matches at all, going up [level=%d]\n" ),
495 (
int) stack.size() );
500 if( current.m_currentMatch >= 0 && current.m_currentMatch >= current.m_matches.size() )
502 wxLogTrace(
traceTopoMatch, wxT(
"stk: No more matches, going up [level=%d]\n" ),
503 (
int) stack.size() );
508 auto& match = current.m_matches[current.m_currentMatch];
510 wxLogTrace(
traceTopoMatch, wxT(
"stk: candidate '%s', match list : ( " ),
511 current.m_matches[current.m_currentMatch]->m_reference, current.m_refIndex );
513 for(
auto m : current.m_matches )
514 wxLogTrace(
traceTopoMatch, wxT(
"%s " ), m->GetParent()->GetReferenceAsString() );
518 current.m_currentMatch++;
519 current.m_locked[match] = current.m_ref;
523 current.m_nloops = nloops;
526 aMismatchReasons.clear();
528 for(
auto iter : current.m_locked )
529 aResult[ iter.second->GetParent() ] = iter.first->GetParent();
535 int minMatches = std::numeric_limits<int>::max();
538 int bestRefIndex = 0;
545 if( cmp == current.m_ref )
550 for(
auto it = current.m_locked.begin(); it != current.m_locked.end(); it++ )
552 if( it->second == cmp )
562 localReasons.clear();
565 int nMatches = matches.size();
573 else if( nMatches == 0 )
578 if( aMismatchReasons.empty() && !localReasons.empty() )
579 aMismatchReasons = localReasons;
581 else if( nMatches < minMatches )
583 minMatches = nMatches;
590 next.m_currentMatch = -1;
594 next.m_ref = bestNextRef;
595 next.m_refIndex = bestRefIndex;
599 next.m_ref = altNextRef;
600 next.m_refIndex = altRefIndex;
603 stack.push_back(
next );