KiCad PCB EDA Suite
Loading...
Searching...
No Matches
topo_match.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <cstdio>
25#include <cstdlib>
26#include <cmath>
27#include <string>
28#include <vector>
29#include <algorithm>
30#include <cassert>
31#include <map>
32#include <set>
33#include <cctype>
34
35#include <pad.h>
36#include <footprint.h>
37#include <refdes_utils.h>
38#include <board.h>
39#include <wx/string.h>
40#include <wx/log.h>
41
42#include "topo_match.h"
43
44
45static const wxString traceTopoMatch = wxT( "TOPO_MATCH" );
46
47
48namespace TMATCH
49{
50
51bool PIN::IsIsomorphic( const PIN& b, TOPOLOGY_MISMATCH_REASON& aReason ) const
52{
53 if( m_conns.size() != b.m_conns.size() )
54 {
55 wxLogTrace( traceTopoMatch,
56 wxT( "[conns mismatch n1 %d n2 %d c-ref %d c-other %d thispin %s-%s "
57 "otherpin %s-%s" ),
59 b.m_netcode,
60 (int) m_conns.size(),
61 (int) b.m_conns.size(),
62 m_parent->m_reference,
63 m_ref,
65 b.m_ref );
66
67 aReason.m_reference = m_parent->GetParent()->GetReferenceAsString();
69 aReason.m_reason = wxString::Format(
70 _( "Pad %s of %s connects to %lu pads, but candidate pad %s of %s connects to %lu." ), m_ref,
71 aReason.m_reference, static_cast<unsigned long>( m_conns.size() ), b.m_ref, aReason.m_candidate,
72 static_cast<unsigned long>( b.m_conns.size() ) );
73
74 for( auto c : m_conns )
75 {
76 wxLogTrace( traceTopoMatch, wxT( "%s-%s " ), c->m_parent->m_reference, c->m_ref );
77 }
78
79 wxLogTrace( traceTopoMatch, wxT( "||" ) );
80
81 for( auto c : b.m_conns )
82 {
83 wxLogTrace( traceTopoMatch, wxT( "%s-%s " ), c->m_parent->m_reference, c->m_ref );
84 }
85
86
87 wxLogTrace( traceTopoMatch, wxT( "] " ) );
88 return false;
89 }
90
91 if( m_conns.empty() )
92 {
93 wxLogTrace( traceTopoMatch, wxT( "[conns empty]" ) );
94 return true;
95 }
96
97 std::vector<bool> matches( m_conns.size() );
98
99 for( int i = 0; i < m_conns.size(); i++ )
100 matches[i] = false;
101
102 int nref = 0;
103
104 for( auto& cref : m_conns )
105 {
106 for( int i = 0; i < m_conns.size(); i++ )
107 {
108 if( b.m_conns[i]->IsTopologicallySimilar( *cref ) )
109 {
110 matches[nref] = true;
111 break;
112 }
113 }
114
115 nref++;
116 }
117
118 for( int i = 0; i < m_conns.size(); i++ )
119 {
120 if( !matches[i] )
121 {
122 aReason.m_reference = m_parent->GetParent()->GetReferenceAsString();
124 aReason.m_reason = wxString::Format(
125 _( "Pad %s of %s cannot match candidate pad %s of %s due to differing connectivity." ), m_ref,
126 aReason.m_reference, b.m_ref, aReason.m_candidate );
127
128 return false;
129 }
130 }
131
132 return true;
133}
134
135
136// fixme: terrible performance, but computers are fast these days, ain't they? :D
137bool checkIfPadNetsMatch( const BACKTRACK_STAGE& aMatches, CONNECTION_GRAPH* aRefGraph, COMPONENT* aRef,
138 COMPONENT* aTgt, TOPOLOGY_MISMATCH_REASON& aReason )
139{
140 std::map<PIN*, PIN*> pairs;
141 std::vector<PIN*> pref, ptgt;
142
143 // GetMatchingComponentPairs() returns target->reference map
144 for( auto& m : aMatches.GetMatchingComponentPairs() )
145 {
146 for( PIN* p : m.second->Pins() )
147 {
148 pref.push_back( p );
149 }
150
151 for( PIN* p : m.first->Pins() )
152 {
153 ptgt.push_back( p );
154 }
155 }
156
157 for( PIN* p : aRef->Pins() )
158 {
159 pref.push_back( p );
160 }
161
162 for( PIN* p : aTgt->Pins() )
163 {
164 ptgt.push_back( p );
165 }
166
167 if( pref.size() != ptgt.size() )
168 {
169 aReason.m_reference = aRef->GetParent()->GetReferenceAsString();
170 aReason.m_candidate = aTgt->GetParent()->GetReferenceAsString();
171 aReason.m_reason =
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() ) );
175 return false;
176 }
177
178 for( unsigned int i = 0; i < pref.size(); i++ )
179 {
180 pairs[pref[i]] = ptgt[i];
181 }
182
183 for( PIN* refPin : aRef->Pins() )
184 {
185 wxLogTrace( traceTopoMatch, wxT( "pad %s-%s: " ),
186 aRef->GetParent()->GetReferenceAsString(), refPin->GetReference() );
187
188 std::optional<int> prevNet;
189
190 for( COMPONENT* refCmp : aRefGraph->Components() )
191 {
192 for( PIN* ppin : refCmp->Pins() )
193 {
194 if ( ppin->GetNetCode() != refPin->GetNetCode() )
195 continue;
196
197 wxLogTrace( traceTopoMatch, wxT( "{ref %s-%s:%d} " ),
198 ppin->GetParent()->GetParent()->GetReferenceAsString(),
199 ppin->GetReference(), ppin->GetNetCode() );
200
201 auto tpin = pairs.find( ppin );
202
203 if( tpin != pairs.end() )
204 {
205 int nc = tpin->second->GetNetCode();
206
207 if( prevNet && ( *prevNet != nc ) )
208 {
209 wxLogTrace( traceTopoMatch, wxT( "nets inconsistent\n" ) );
210
211 aReason.m_reference = aRef->GetParent()->GetReferenceAsString();
212 aReason.m_candidate = aTgt->GetParent()->GetReferenceAsString();
213
214 wxString refNetName;
215 wxString tgtNetName;
216
217 if( const BOARD* refBoard = aRef->GetParent()->GetBoard() )
218 {
219 if( const NETINFO_ITEM* net = refBoard->FindNet( refPin->GetNetCode() ) )
220 refNetName = net->GetNetname();
221 }
222
223 if( const BOARD* tgtBoard = aTgt->GetParent()->GetBoard() )
224 {
225 if( const NETINFO_ITEM* net = tgtBoard->FindNet( nc ) )
226 tgtNetName = net->GetNetname();
227 }
228
229 if( refNetName.IsEmpty() )
230 refNetName = wxString::Format( _( "net %d" ), refPin->GetNetCode() );
231
232 if( tgtNetName.IsEmpty() )
233 tgtNetName = wxString::Format( _( "net %d" ), nc );
234
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." ),
237 refPin->GetReference(), aReason.m_reference, refNetName, aReason.m_candidate,
238 tgtNetName );
239
240 return false;
241 }
242
243 prevNet = nc;
244 }
245 }
246 }
247 }
248
249 return true;
250}
251
252
253std::vector<COMPONENT*>
255 const BACKTRACK_STAGE& partialMatches,
256 std::vector<TOPOLOGY_MISMATCH_REASON>& aMismatchReasons )
257{
258 aMismatchReasons.clear();
259 std::vector<COMPONENT*> matches;
260 for( auto cmpTarget : m_components )
261 {
262 // already matched to sth? move on.
263 if( partialMatches.m_locked.find( cmpTarget ) != partialMatches.m_locked.end() )
264 {
265 continue;
266 }
267
268 wxLogTrace( traceTopoMatch, wxT( "Check '%s'/'%s' " ), aRef->m_reference,
269 cmpTarget->m_reference );
270
271 // first, a basic heuristic (reference prefix, pin count & footprint) followed by a pin
272 // connection topology check
273 TOPOLOGY_MISMATCH_REASON localReason;
274 localReason.m_reference = aRef->GetParent()->GetReferenceAsString();
275 localReason.m_candidate = cmpTarget->GetParent()->GetReferenceAsString();
276
277 if( aRef->MatchesWith( cmpTarget, localReason ) )
278 {
279 // then a net integrity check (expensive because of poor optimization)
280 if( checkIfPadNetsMatch( partialMatches, aRefGraph, aRef, cmpTarget, localReason ) )
281 {
282 wxLogTrace( traceTopoMatch, wxT("match!\n") );
283 matches.push_back( cmpTarget );
284 }
285 else
286 {
287 wxLogTrace( traceTopoMatch, wxT("Reject [net topo mismatch]\n") );
288 aMismatchReasons.push_back( localReason );
289 }
290 }
291 else
292 {
293 wxLogTrace( traceTopoMatch, wxT("reject\n") );
294 aMismatchReasons.push_back( localReason );
295 }
296 }
297
298 auto padSimilarity = []( COMPONENT* a, COMPONENT* b ) -> double
299 {
300 int n = 0;
301
302 for( size_t i = 0; i < a->m_pins.size(); i++ )
303 {
304 PIN* pa = a->m_pins[i];
305 PIN* pb = b->m_pins[i];
306
307 if( pa->GetNetCode() == pb->GetNetCode() )
308 n++;
309 }
310
311 return (double) n / (double) a->m_pins.size();
312 };
313
314 std::sort( matches.begin(), matches.end(),
315 [&]( COMPONENT* a, COMPONENT* b ) -> bool
316 {
317 double simA = padSimilarity( aRef, a );
318 double simB = padSimilarity( aRef, b );
319
320 if( simA != simB )
321 return simA > simB;
322
323 return a->GetParent()->GetReferenceAsString()
324 < b->GetParent()->GetReferenceAsString();
325 } );
326
327 if( matches.empty() )
328 {
330 reason.m_reference = aRef->GetParent()->GetReferenceAsString();
331 reason.m_reason = _( "No compatible component found in the target area." );
332
333 if( aMismatchReasons.empty() )
334 aMismatchReasons.push_back( reason );
335 }
336
337 return matches;
338}
339
340
342{
343 std::sort( m_pins.begin(), m_pins.end(),
344 []( PIN* a, PIN* b )
345 {
346 return a->GetReference() < b->GetReference();
347 } );
348}
349
350
352{
353 std::sort( m_components.begin(), m_components.end(),
354 []( COMPONENT* a, COMPONENT* b )
355 {
356 if( a->GetPinCount() != b->GetPinCount() )
357 return a->GetPinCount() > b->GetPinCount();
358
359 return a->GetParent()->GetReferenceAsString() < b->GetParent()->GetReferenceAsString();
360 } );
361}
362
363
365{
366 std::map<int, std::vector<PIN*>> nets;
367
369
370 for( auto c : m_components )
371 {
372 c->sortPinsByName();
373
374 for( auto p : c->Pins() )
375 {
376 if( p->GetNetCode() > 0 )
377 nets[p->GetNetCode()].push_back( p );
378 }
379 }
380
381 for( auto iter : nets )
382 {
383 wxLogTrace( traceTopoMatch, wxT( "net %d: %d connections\n" ), iter.first,
384 (int) iter.second.size() );
385
386 for( auto p : iter.second )
387 {
388 for( auto p2 : iter.second )
389 {
390 if( p != p2 && !alg::contains( p->m_conns, p2 ) )
391 {
392 p->m_conns.push_back( p2 );
393 }
394 }
395 }
396 }
397
398/* for( auto c : m_components )
399 for( auto p : c->Pins() )
400 {
401 printf("pin %s: \n", p->m_ref.c_str().AsChar() );
402
403 for( auto c : p->m_conns )
404 printf( "%s ", c->m_ref.c_str().AsChar() );
405 printf("\n");
406 }
407 */
408}
409
410
412 std::vector<TOPOLOGY_MISMATCH_REASON>& aMismatchReasons )
413{
414 std::vector<BACKTRACK_STAGE> stack;
416
417 aMismatchReasons.clear();
418
419 std::vector<TOPOLOGY_MISMATCH_REASON> localReasons;
420
421 if( m_components.empty()|| aTarget->m_components.empty() )
422 {
424 reason.m_reason = _( "One or both of the areas has no components assigned." );
425 aMismatchReasons.push_back( reason );
426 return false;
427 }
428
429 if( m_components.size() != aTarget->m_components.size() )
430 {
432 reason.m_reason = _( "Component count mismatch" );
433 aMismatchReasons.push_back( reason );
434 return false;
435 }
436
437 top.m_ref = m_components.front();
438 top.m_refIndex = 0;
439
440 stack.push_back( top );
441
442 bool matchFound = false;
443 int nloops = 0;
444
445 while( !stack.empty() )
446 {
447 nloops++;
448 auto& current = stack.back();
449
450 for( auto it = current.m_locked.begin(); it != current.m_locked.end(); it++ )
451 {
452 if (it->second == current.m_ref)
453 {
454 wxLogTrace( traceTopoMatch, wxT( "stk: Remove %s from locked\n" ),
455 current.m_ref->m_reference );
456 current.m_locked.erase( it );
457 break;
458 }
459 }
460
461 if( nloops >= c_ITER_LIMIT )
462 {
463 wxLogTrace( traceTopoMatch, wxT( "stk: Iter cnt exceeded\n" ) );
464
466 reason.m_reason = _( "Iteration count exceeded (timeout)" );
467
468 if( aMismatchReasons.empty() )
469 aMismatchReasons.push_back( reason );
470 else
471 aMismatchReasons.insert( aMismatchReasons.begin(), reason );
472
473 return false;
474 }
475
476 if( current.m_currentMatch < 0 )
477 {
478 localReasons.clear();
479 current.m_matches = aTarget->findMatchingComponents( this, current.m_ref, current, localReasons );
480
481 if( current.m_matches.empty() && aMismatchReasons.empty() && !localReasons.empty() )
482 aMismatchReasons = localReasons;
483
484 current.m_currentMatch = 0;
485 }
486
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(),
490 (int) m_components.size() );
491
492 if ( current.m_matches.empty() )
493 {
494 wxLogTrace( traceTopoMatch, wxT( "stk: No matches at all, going up [level=%d]\n" ),
495 (int) stack.size() );
496 stack.pop_back();
497 continue;
498 }
499
500 if( current.m_currentMatch >= 0 && current.m_currentMatch >= current.m_matches.size() )
501 {
502 wxLogTrace( traceTopoMatch, wxT( "stk: No more matches, going up [level=%d]\n" ),
503 (int) stack.size() );
504 stack.pop_back();
505 continue;
506 }
507
508 auto& match = current.m_matches[current.m_currentMatch];
509
510 wxLogTrace( traceTopoMatch, wxT( "stk: candidate '%s', match list : ( " ),
511 current.m_matches[current.m_currentMatch]->m_reference, current.m_refIndex );
512
513 for( auto m : current.m_matches )
514 wxLogTrace( traceTopoMatch, wxT( "%s " ), m->GetParent()->GetReferenceAsString() );
515
516 wxLogTrace( traceTopoMatch, wxT( "\n" ) );
517
518 current.m_currentMatch++;
519 current.m_locked[match] = current.m_ref;
520
521 if( current.m_locked.size() == m_components.size() )
522 {
523 current.m_nloops = nloops;
524
525 aResult.clear();
526 aMismatchReasons.clear();
527
528 for( auto iter : current.m_locked )
529 aResult[ iter.second->GetParent() ] = iter.first->GetParent();
530
531 return true;
532 }
533
534
535 int minMatches = std::numeric_limits<int>::max();
536 COMPONENT* altNextRef = nullptr;
537 COMPONENT* bestNextRef = nullptr;
538 int bestRefIndex = 0;
539 int altRefIndex = 0;
540
541 for( size_t i = 0; i < m_components.size(); i++ )
542 {
543 COMPONENT* cmp = m_components[i];
544
545 if( cmp == current.m_ref )
546 continue;
547
548 bool found = false;
549
550 for( auto it = current.m_locked.begin(); it != current.m_locked.end(); it++ )
551 {
552 if( it->second == cmp )
553 {
554 found = true;
555 break;
556 }
557 }
558
559 if( found )
560 continue;
561
562 localReasons.clear();
563 auto matches = aTarget->findMatchingComponents( this, cmp, current, localReasons );
564
565 int nMatches = matches.size();
566
567 if( nMatches == 1 )
568 {
569 bestNextRef = cmp;
570 bestRefIndex = i;
571 break;
572 }
573 else if( nMatches == 0 )
574 {
575 altNextRef = cmp;
576 altRefIndex = i;
577
578 if( aMismatchReasons.empty() && !localReasons.empty() )
579 aMismatchReasons = localReasons;
580 }
581 else if( nMatches < minMatches )
582 {
583 minMatches = nMatches;
584 bestNextRef = cmp;
585 bestRefIndex = i;
586 }
587 }
588
589 BACKTRACK_STAGE next( current );
590 next.m_currentMatch = -1;
591
592 if( bestNextRef )
593 {
594 next.m_ref = bestNextRef;
595 next.m_refIndex = bestRefIndex;
596 }
597 else
598 {
599 next.m_ref = altNextRef;
600 next.m_refIndex = altRefIndex;
601 }
602
603 stack.push_back( next );
604 };
605
606 return false;
607}
608
609
610#if 0
611int main()
612{
613 FILE * f = fopen("connectivity.dump","rb" );
614 auto cgRef = loadCGraph(f);
615 auto cgTarget = loadCGraph(f);
616
617 cgRef->buildConnectivity();
618 cgTarget->buildConnectivity();
619
620 int attempts = 0;
621 int max_loops = 0;
622
623 for( ;; )
624 {
625 cgRef->shuffle();
626 cgTarget->shuffle();
627
628 const BacktrackStage latest = cgRef->matchCGraphs( cgTarget );
629
630 if( !latest.locked.size() )
631 {
632 printf("MATCH FAIL\n");
633 break;
634 }
635
636 //printf("loops: %d\n", latest.nloops );
637 //printf("Locked: %d\n", latest.locked.size() );
638
639 //if (matchFound)
640 //{
641 // for( auto& iter : latest.locked )
642 //{
643 // printf("%-10s : %-10s\n", iter.first->reference.c_str(), iter.second->reference.c_str() );
644 //}
645
646 //}
647
648 if( latest.nloops > max_loops )
649 {
650 max_loops = latest.nloops;
651 }
652
653 if (attempts % 10000 == 0)
654 {
655 printf("attempts: %d maxloops: %d\n", attempts, max_loops );
656 }
657
658 attempts++;
659
660 }
661
662 fclose(f);
663
664 return 0;
665}
666
667#endif
668
669
670COMPONENT::COMPONENT( const wxString& aRef, FOOTPRINT* aParentFp,
671 std::optional<VECTOR2I> aRaOffset ) :
672 m_reference( aRef ),
673 m_parentFootprint( aParentFp ), m_raOffset( aRaOffset )
674{
676}
677
678
679bool COMPONENT::isChannelSuffix( const wxString& aSuffix )
680{
681 if( aSuffix.IsEmpty() )
682 return true;
683
684 for( wxUniChar ch : aSuffix )
685 {
686 if( std::isalpha( static_cast<int>( ch ) ) )
687 return false;
688 }
689
690 return true;
691}
692
693
694bool COMPONENT::prefixesShareCommonBase( const wxString& aPrefixA, const wxString& aPrefixB )
695{
696 if( aPrefixA == aPrefixB )
697 return true;
698
699 size_t commonLen = 0;
700 size_t minLen = std::min( aPrefixA.length(), aPrefixB.length() );
701
702 while( commonLen < minLen && aPrefixA[commonLen] == aPrefixB[commonLen] )
703 commonLen++;
704
705 if( commonLen == 0 )
706 return false;
707
708 wxString suffixA = aPrefixA.Mid( commonLen );
709 wxString suffixB = aPrefixB.Mid( commonLen );
710
711 return isChannelSuffix( suffixA ) && isChannelSuffix( suffixB );
712}
713
714
715bool COMPONENT::IsSameKind( const COMPONENT& b ) const
716{
718 return false;
719
720 return ( m_parentFootprint->GetFPID() == b.m_parentFootprint->GetFPID() )
721 || ( m_parentFootprint->GetFPID().empty() && b.m_parentFootprint->GetFPID().empty() );
722}
723
724
726{
727 m_pins.push_back( aPin );
728 aPin->SetParent( this );
729}
730
731
733{
734 if( GetPinCount() != b->GetPinCount() )
735 {
738 aReason.m_reason =
739 wxString::Format( _( "Component %s has %d pads but candidate %s has %d." ), aReason.m_reference,
740 GetPinCount(), aReason.m_candidate, b->GetPinCount() );
741 return false;
742 }
743
744 if( !IsSameKind( *b ) )
745 {
748
750 {
751 aReason.m_reason = wxString::Format(
752 _( "Reference prefix mismatch: %s uses prefix '%s' but candidate %s uses '%s'." ),
753 aReason.m_reference, m_prefix, aReason.m_candidate, b->m_prefix );
754 }
755 else
756 {
757 wxString refFootprint = GetParent()->GetFPIDAsString();
758 wxString candFootprint = b->GetParent()->GetFPIDAsString();
759
760 if( refFootprint.IsEmpty() )
761 refFootprint = _( "(no library ID)" );
762
763 if( candFootprint.IsEmpty() )
764 candFootprint = _( "(no library ID)" );
765
766 aReason.m_reason =
767 wxString::Format( _( "Library link mismatch: %s expects '%s' but candidate %s is '%s'." ),
768 aReason.m_reference, refFootprint, aReason.m_candidate, candFootprint );
769 }
770
771 return false;
772 }
773
774 for( int pin = 0; pin < b->GetPinCount(); pin++ )
775 {
776 if( !b->m_pins[pin]->IsIsomorphic( *m_pins[pin], aReason ) )
777 {
778 if( aReason.m_reason.IsEmpty() )
779 {
782 aReason.m_reason = wxString::Format( _( "Component pads differ between %s and %s." ),
783 aReason.m_reference, aReason.m_candidate );
784 }
785
786 return false;
787 }
788
789 }
790
791 return true;
792}
793
794
796{
797 auto cmp = new COMPONENT( aFp->GetReference(), aFp );
798
799 for( auto pad : aFp->Pads() )
800 {
801 auto pin = new PIN( );
802 pin->m_netcode = pad->GetNetCode();
803 pin->m_ref = pad->GetNumber();
804 cmp->AddPin( pin );
805 }
806
807 m_components.push_back( cmp );
808}
809
810
811std::unique_ptr<CONNECTION_GRAPH>
812CONNECTION_GRAPH::BuildFromFootprintSet( const std::set<FOOTPRINT*>& aFps )
813{
814 auto cgraph = std::make_unique<CONNECTION_GRAPH>();
815 VECTOR2I ref(0, 0);
816
817 if( aFps.size() > 0 )
818 ref = (*aFps.begin())->GetPosition();
819
820 for( auto fp : aFps )
821 {
822 cgraph->AddFootprint( fp, fp->GetPosition() - ref );
823 }
824
825 cgraph->BuildConnectivity();
826
827 return std::move(cgraph);
828}
829
830
835
836
838{
839 for( COMPONENT* fp : m_components )
840 {
841 delete fp;
842 }
843}
844
845
847{
848 for( PIN* p : m_pins )
849 {
850 delete p;
851 }
852}
853
854
855}; // namespace TMATCH
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
std::deque< PAD * > & Pads()
Definition footprint.h:306
wxString GetFPIDAsString() const
Definition footprint.h:357
const LIB_ID & GetFPID() const
Definition footprint.h:351
wxString GetReferenceAsString() const
Definition footprint.h:760
const wxString & GetReference() const
Definition footprint.h:751
bool empty() const
Definition lib_id.h:193
Handle the data for a net.
Definition netinfo.h:54
const std::map< COMPONENT *, COMPONENT * > & GetMatchingComponentPairs() const
Definition topo_match.h:161
std::map< COMPONENT *, COMPONENT * > m_locked
Definition topo_match.h:168
static bool prefixesShareCommonBase(const wxString &aPrefixA, const wxString &aPrefixB)
Check if two prefixes share a common starting sequence.
bool IsSameKind(const COMPONENT &b) const
int GetPinCount() const
Definition topo_match.h:63
COMPONENT(const wxString &aRef, FOOTPRINT *aParentFp, std::optional< VECTOR2I > aRaOffset=std::optional< VECTOR2I >())
FOOTPRINT * m_parentFootprint
Definition topo_match.h:94
std::optional< VECTOR2I > m_raOffset
Definition topo_match.h:91
bool MatchesWith(COMPONENT *b, TOPOLOGY_MISMATCH_REASON &aDetail)
wxString m_prefix
Definition topo_match.h:93
void AddPin(PIN *p)
std::vector< PIN * > & Pins()
Definition topo_match.h:65
friend class PIN
Definition topo_match.h:54
wxString m_reference
Definition topo_match.h:92
static bool isChannelSuffix(const wxString &aSuffix)
Check if a suffix looks like a channel identifier.
std::vector< PIN * > m_pins
Definition topo_match.h:95
FOOTPRINT * GetParent() const
Definition topo_match.h:66
std::vector< COMPONENT * > & Components()
Definition topo_match.h:187
std::vector< COMPONENT * > m_components
Definition topo_match.h:198
void AddFootprint(FOOTPRINT *aFp, const VECTOR2I &aOffset)
static std::unique_ptr< CONNECTION_GRAPH > BuildFromFootprintSet(const std::set< FOOTPRINT * > &aFps)
bool FindIsomorphism(CONNECTION_GRAPH *target, COMPONENT_MATCHES &result, std::vector< TOPOLOGY_MISMATCH_REASON > &aFailureDetails)
std::vector< COMPONENT * > findMatchingComponents(CONNECTION_GRAPH *aRefGraph, COMPONENT *ref, const BACKTRACK_STAGE &partialMatches, std::vector< TOPOLOGY_MISMATCH_REASON > &aFailureDetails)
std::vector< PIN * > m_conns
Definition topo_match.h:135
void SetParent(COMPONENT *parent)
Definition topo_match.h:106
COMPONENT * m_parent
Definition topo_match.h:134
bool IsIsomorphic(const PIN &b, TOPOLOGY_MISMATCH_REASON &aDetail) const
int GetNetCode() const
Definition topo_match.h:124
wxString m_ref
Definition topo_match.h:132
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
std::map< FOOTPRINT *, FOOTPRINT * > COMPONENT_MATCHES
Definition topo_match.h:172
bool checkIfPadNetsMatch(const BACKTRACK_STAGE &aMatches, CONNECTION_GRAPH *aRefGraph, COMPONENT *aRef, COMPONENT *aTgt, TOPOLOGY_MISMATCH_REASON &aReason)
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
CITER next(CITER it)
Definition ptree.cpp:124
Collection of utility functions for component reference designators (refdes)
KIBIS top(path, &reporter)
KIBIS_PIN * pin
static const wxString traceTopoMatch
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695