139 std::map<PIN*, PIN*> pairs;
140 std::vector<PIN*> pref, ptgt;
145 for(
PIN* p : m.second->Pins() )
150 for(
PIN* p : m.first->Pins() )
166 if( pref.size() != ptgt.size() )
171 wxString::Format(
_(
"Component %s expects %lu matching pads but candidate %s provides %lu." ),
172 aReason.
m_reference,
static_cast<unsigned long>( pref.size() ),
173 aReason.
m_candidate,
static_cast<unsigned long>( ptgt.size() ) );
177 for(
unsigned int i = 0; i < pref.size(); i++ )
179 pairs[pref[i]] = ptgt[i];
182 for(
PIN* refPin : aRef->
Pins() )
187 std::optional<int> prevNet;
191 for(
PIN* ppin : refCmp->Pins() )
193 if ( ppin->GetNetCode() != refPin->GetNetCode() )
197 ppin->GetParent()->GetParent()->GetReferenceAsString(),
198 ppin->GetReference(), ppin->GetNetCode() );
200 auto tpin = pairs.find( ppin );
202 if( tpin != pairs.end() )
204 int nc = tpin->second->GetNetCode();
206 if( prevNet && ( *prevNet != nc ) )
218 if(
const NETINFO_ITEM* net = refBoard->FindNet( refPin->GetNetCode() ) )
219 refNetName = net->GetNetname();
225 tgtNetName = net->GetNetname();
228 if( refNetName.IsEmpty() )
229 refNetName = wxString::Format(
_(
"net %d" ), refPin->GetNetCode() );
231 if( tgtNetName.IsEmpty() )
232 tgtNetName = wxString::Format(
_(
"net %d" ), nc );
234 aReason.
m_reason = wxString::Format(
235 _(
"Pad %s of %s is on net %s but its match in candidate %s is on net %s." ),
255 std::vector<TOPOLOGY_MISMATCH_REASON>& aMismatchReasons )
257 aMismatchReasons.clear();
258 std::vector<COMPONENT*> matches;
262 if( partialMatches.
m_locked.find( cmpTarget ) != partialMatches.
m_locked.end() )
268 cmpTarget->m_reference );
274 localReason.
m_candidate = cmpTarget->GetParent()->GetReferenceAsString();
282 matches.push_back( cmpTarget );
286 wxLogTrace(
traceTopoMatch, wxT(
"Reject [net topo mismatch]\n") );
287 aMismatchReasons.push_back( localReason );
293 aMismatchReasons.push_back( localReason );
301 for(
size_t i = 0; i < a->
m_pins.size(); i++ )
304 PIN* pb = b->m_pins[i];
310 return (
double) n / (double) a->
m_pins.size();
313 std::sort( matches.begin(), matches.end(),
316 double simA = padSimilarity( aRef, a );
317 double simB = padSimilarity( aRef, b );
322 return a->GetParent()->GetReferenceAsString()
323 < b->GetParent()->GetReferenceAsString();
326 if( matches.empty() )
330 reason.
m_reason =
_(
"No compatible component found in the target area." );
332 if( aMismatchReasons.empty() )
333 aMismatchReasons.push_back( reason );
411 std::vector<TOPOLOGY_MISMATCH_REASON>& aMismatchReasons )
413 std::vector<BACKTRACK_STAGE> stack;
416 aMismatchReasons.clear();
418 std::vector<TOPOLOGY_MISMATCH_REASON> localReasons;
423 reason.
m_reason =
_(
"One or both of the areas has no components assigned." );
424 aMismatchReasons.push_back( reason );
431 reason.
m_reason =
_(
"Component count mismatch" );
432 aMismatchReasons.push_back( reason );
439 stack.push_back(
top );
441 bool matchFound =
false;
444 while( !stack.empty() )
447 auto& current = stack.back();
449 for(
auto it = current.m_locked.begin(); it != current.m_locked.end(); it++ )
451 if (it->second == current.m_ref)
453 wxLogTrace(
traceTopoMatch, wxT(
"stk: Remove %s from locked\n" ),
454 current.m_ref->m_reference );
455 current.m_locked.erase( it );
465 reason.
m_reason =
_(
"Iteration count exceeded (timeout)" );
467 if( aMismatchReasons.empty() )
468 aMismatchReasons.push_back( reason );
470 aMismatchReasons.insert( aMismatchReasons.begin(), reason );
475 if( current.m_currentMatch < 0 )
477 localReasons.clear();
480 if( current.m_matches.empty() && aMismatchReasons.empty() && !localReasons.empty() )
481 aMismatchReasons = localReasons;
483 current.m_currentMatch = 0;
486 wxLogTrace(
traceTopoMatch, wxT(
"stk: Current '%s' stack %d cm %d/%d locked %d/%d\n" ),
487 current.m_ref->m_reference, (
int) stack.size(), current.m_currentMatch,
488 (
int) current.m_matches.size(), (
int) current.m_locked.size(),
491 if ( current.m_matches.empty() )
493 wxLogTrace(
traceTopoMatch, wxT(
"stk: No matches at all, going up [level=%d]\n" ),
494 (
int) stack.size() );
499 if( current.m_currentMatch >= 0 && current.m_currentMatch >= current.m_matches.size() )
501 wxLogTrace(
traceTopoMatch, wxT(
"stk: No more matches, going up [level=%d]\n" ),
502 (
int) stack.size() );
507 auto& match = current.m_matches[current.m_currentMatch];
509 wxLogTrace(
traceTopoMatch, wxT(
"stk: candidate '%s', match list : ( " ),
510 current.m_matches[current.m_currentMatch]->m_reference, current.m_refIndex );
512 for(
auto m : current.m_matches )
513 wxLogTrace(
traceTopoMatch, wxT(
"%s " ), m->GetParent()->GetReferenceAsString() );
517 current.m_currentMatch++;
518 current.m_locked[match] = current.m_ref;
522 current.m_nloops = nloops;
525 aMismatchReasons.clear();
527 for(
auto iter : current.m_locked )
528 aResult[ iter.second->GetParent() ] = iter.first->GetParent();
534 int minMatches = std::numeric_limits<int>::max();
537 int bestRefIndex = 0;
544 if( cmp == current.m_ref )
549 for(
auto it = current.m_locked.begin(); it != current.m_locked.end(); it++ )
551 if( it->second == cmp )
561 localReasons.clear();
564 int nMatches = matches.size();
572 else if( nMatches == 0 )
577 if( aMismatchReasons.empty() && !localReasons.empty() )
578 aMismatchReasons = localReasons;
580 else if( nMatches < minMatches )
582 minMatches = nMatches;
589 next.m_currentMatch = -1;
593 next.m_ref = bestNextRef;
594 next.m_refIndex = bestRefIndex;
598 next.m_ref = altNextRef;
599 next.m_refIndex = altRefIndex;
602 stack.push_back(
next );