From 628d4d3fdb94c890bf8ab48155266150d274af4b Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Mon, 8 Jan 2024 22:37:56 +0100 Subject: [PATCH] pcbnew: weeding out bugs in the MULTICHANNEL_TOOL... --- ...ialog_multichannel_generate_rule_areas.cpp | 4 +- .../dialog_multichannel_repeat_layout.cpp | 7 +- pcbnew/tools/multichannel_tool.cpp | 310 ++++++++++++------ pcbnew/tools/multichannel_tool.h | 11 +- 4 files changed, 221 insertions(+), 111 deletions(-) diff --git a/pcbnew/dialogs/dialog_multichannel_generate_rule_areas.cpp b/pcbnew/dialogs/dialog_multichannel_generate_rule_areas.cpp index 98aadf33a5..bd60e0885f 100644 --- a/pcbnew/dialogs/dialog_multichannel_generate_rule_areas.cpp +++ b/pcbnew/dialogs/dialog_multichannel_generate_rule_areas.cpp @@ -39,7 +39,7 @@ DIALOG_MULTICHANNEL_GENERATE_RULE_AREAS::DIALOG_MULTICHANNEL_GENERATE_RULE_AREAS auto raData = m_parentTool->GetData(); - m_sheetsGrid->CreateGrid( 10, 3 ); + m_sheetsGrid->AppendCols( 3 ); m_sheetsGrid->EnableEditing( true ); m_sheetsGrid->HideRowLabels(); m_sheetsGrid->SetColLabelValue( 0, wxT("Generate") ); @@ -74,7 +74,7 @@ bool DIALOG_MULTICHANNEL_GENERATE_RULE_AREAS::TransferDataFromWindow() { auto raData = m_parentTool->GetData(); - for( int i = 0; i < raData->m_areas.size(); i++) + for( size_t i = 0; i < raData->m_areas.size(); i++) { wxString enabled = m_sheetsGrid->GetCellValue( i, 0 ); raData->m_areas[i].m_generateEnabled = ( !enabled.CompareTo( wxT("1") ) ) ? true : false; diff --git a/pcbnew/dialogs/dialog_multichannel_repeat_layout.cpp b/pcbnew/dialogs/dialog_multichannel_repeat_layout.cpp index 62734e2ed0..90bed798f4 100644 --- a/pcbnew/dialogs/dialog_multichannel_repeat_layout.cpp +++ b/pcbnew/dialogs/dialog_multichannel_repeat_layout.cpp @@ -37,6 +37,8 @@ DIALOG_MULTICHANNEL_REPEAT_LAYOUT::DIALOG_MULTICHANNEL_REPEAT_LAYOUT ( auto data = m_parentTool->GetData(); m_refRAName->SetLabelText( data->m_refRA->m_area->GetZoneName() ); + printf("CMAP: %d entries\n", (int) data->m_compatMap.size() ); + for( auto& ra : data->m_compatMap ) { TABLE_ENTRY ent; @@ -63,7 +65,8 @@ DIALOG_MULTICHANNEL_REPEAT_LAYOUT::DIALOG_MULTICHANNEL_REPEAT_LAYOUT ( int i = 0; - m_raGrid->CreateGrid( 10, 3 ); + m_raGrid->ClearGrid(); + m_raGrid->AppendCols( 3 ); m_raGrid->EnableEditing( true ); m_raGrid->HideRowLabels(); m_raGrid->SetColLabelValue( 0, wxT("Copy") ); @@ -101,7 +104,7 @@ bool DIALOG_MULTICHANNEL_REPEAT_LAYOUT::TransferDataFromWindow() { auto data = m_parentTool->GetData(); - for( int i = 0; i < m_targetRAs.size(); i++) + for( size_t i = 0; i < m_targetRAs.size(); i++) { wxString doCopy = m_raGrid->GetCellValue( i, 0 ); diff --git a/pcbnew/tools/multichannel_tool.cpp b/pcbnew/tools/multichannel_tool.cpp index 2af921c2c5..82108c40ed 100644 --- a/pcbnew/tools/multichannel_tool.cpp +++ b/pcbnew/tools/multichannel_tool.cpp @@ -36,8 +36,21 @@ #include #include #include -//#include <../qa/tools/pns/pns_log_viewer_frame.h> - +#include +#include +#include + +#define MULTICHANNEL_EXTRA_DEBUG + +#ifdef MULTICHANNEL_EXTRA_DEBUG + #define DBG( level, fmt, ...) \ + fprintf( stderr, "%s", wxString::Format( fmt, __VA_ARGS__ ).c_str().AsChar() ) + #define DBGn( level, fmt ) \ + fprintf( stderr, "%s", wxString(fmt).c_str().AsChar() ) +#else + #define DBG( level, fmt, ...) + #define DBGn( level, fmt ) +#endif MULTICHANNEL_TOOL::MULTICHANNEL_TOOL() : PCB_TOOL_BASE( "pcbnew.Multichannel" ) { @@ -84,7 +97,6 @@ bool MULTICHANNEL_TOOL::identifyComponentsInRuleArea( ZONE* aRuleArea, std::set< for( auto& fp : board()->Footprints() ) { ctx.SetItems( fp, fp ); - //printf("Test fp %x\n", fp); auto val = ucode.Run( &ctx ); if( val->AsDouble() != 0.0 ) { @@ -116,8 +128,6 @@ std::set MULTICHANNEL_TOOL::queryComponentsInSheet( wxString aSheetN } } -// printf("sheet %s : %d components\n", aSheetName.c_str().AsChar(), rv.size() ); - return rv; } @@ -135,8 +145,6 @@ const SHAPE_LINE_CHAIN MULTICHANNEL_TOOL::buildRAOutline( std::set& bbCorners.push_back( { bb.GetX() + bb.GetWidth(), bb.GetY() } ); bbCorners.push_back( { bb.GetX() + bb.GetWidth(), bb.GetY() + bb.GetHeight() } ); bbCorners.push_back( { bb.GetX(), bb.GetY() + bb.GetHeight() } ); - - //printf("- bb %s %d %d %d %d\n", fp->GetReference().c_str().AsChar(), bb.GetX(), bb.GetY(), bb.GetWidth(), bb.GetHeight() ); } BuildConvexHull( hullVertices, bbCorners ); @@ -225,6 +233,9 @@ void MULTICHANNEL_TOOL::findExistingRuleAreas() m_areas.m_areas.push_back( area ); } + + DBG(1, "Total RAs found: %d\n", (int)m_areas.m_areas.size() ); + } @@ -270,6 +281,7 @@ int MULTICHANNEL_TOOL::repeatLayout( const TOOL_EVENT& aEvent ) findExistingRuleAreas(); + m_areas.m_refRA = nullptr; for( auto& ra : m_areas.m_areas ) @@ -284,6 +296,7 @@ int MULTICHANNEL_TOOL::repeatLayout( const TOOL_EVENT& aEvent ) if( !m_areas.m_refRA ) return -1; + m_areas.m_compatMap.clear(); for( auto& ra : m_areas.m_areas ) { if( ra.m_area == m_areas.m_refRA->m_area ) @@ -302,8 +315,16 @@ int MULTICHANNEL_TOOL::repeatLayout( const TOOL_EVENT& aEvent ) BOARD_COMMIT commit( frame()->GetToolManager(), true ); //()->GetToolManager(), true ); + int totalCopied = 0; + for( auto& targetArea : m_areas.m_compatMap ) { + if( !targetArea.second.m_doCopy ) + { + DBG(1, "skipping copy to RA '%s' (disabled in dialog)\n", targetArea.first->m_ruleName ); + continue; + } + if( !targetArea.second.m_isOk ) continue; @@ -318,9 +339,14 @@ int MULTICHANNEL_TOOL::repeatLayout( const TOOL_EVENT& aEvent ) return 0; } + + totalCopied++; } commit.Push( _("Repeat layout")); + + frame()->ShowInfoBarMsg( + wxString::Format( _("Copied to %d Rule Areas."), totalCopied ), true ); return 0; } @@ -356,7 +382,7 @@ int MULTICHANNEL_TOOL::findRoutedConnections( std::set &aOutput, for( auto pad : aFp->Pads() ) { auto connItems = aConnectivity->GetConnectedItems( - pad, { PCB_PAD_T, PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T }, false ); + pad, { PCB_PAD_T, PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T }, true ); for( auto item : connItems ) conns.insert( item ); @@ -405,19 +431,24 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( FP_PAIRS& aMatches, BOARD_COMMIT* auto connectivity = board()->GetConnectivity(); - printf("Copy-routing %d\n", aOpts.m_copyRouting?1:0); - printf("Copy-placement %d\n", aOpts.m_copyPlacement?1:0); + aCommit->Modify( aTargetArea->m_area ); if( aOpts.m_copyRouting ) { std::set refRouting; + std::set targetRouting; + + DBG(1, "copying routing: %d fps\n", aMatches.size() ); for( auto& fpPair : aMatches ) { - std::set targetRouting; findRoutedConnections( targetRouting, connectivity, targetPoly, aTargetArea, fpPair.second, aOpts ); findRoutedConnections( refRouting, connectivity, refPoly, aRefArea, fpPair.first, aOpts ); + DBG(2, "target-routes %d\n", (int)targetRouting.size() ); + + } + for( auto item : targetRouting ) { if( item->IsLocked() && !aOpts.m_includeLockedItems ) @@ -425,7 +456,6 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( FP_PAIRS& aMatches, BOARD_COMMIT* aCommit->Remove( item ); } - } for( auto item : refRouting ) { @@ -435,10 +465,11 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( FP_PAIRS& aMatches, BOARD_COMMIT* } } - aCommit->Modify( aTargetArea->m_area ); aTargetArea->m_area->RemoveAllContours(); aTargetArea->m_area->AddPolygon( newTargetOutline ); + aTargetArea->m_area->UnHatchBorder(); + aTargetArea->m_area->HatchBorder(); if( aOpts.m_copyPlacement ) { @@ -447,21 +478,22 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( FP_PAIRS& aMatches, BOARD_COMMIT* auto refFP = fpPair.first; auto targetFP = fpPair.second; +#if 0 //printf("ref-ls: %s\n", aRefArea->m_area->GetLayerSet().FmtHex().c_str() ); //printf("target-ls: %s\n", aRefArea->m_area->GetLayerSet().FmtHex().c_str() ); -#if 0 if( ! aRefArea->m_area->GetLayerSet().Contains( refFP->GetLayer() ) ); { - printf("discard ref:%s (ref layer)\n", refFP->GetReference().c_str().AsChar() ); + DBG(2, wxT("discard ref:%s (ref layer)\n"), refFP->GetReference() ); continue; } if( ! aTargetArea->m_area->GetLayerSet().Contains( refFP->GetLayer() ) ); { - printf("discard ref:%s (target layer)\n", refFP->GetReference().c_str().AsChar() ); + DBG(2, wxT("discard ref:%s (target layer)\n"), refFP->GetReference() ); continue; } #endif + if( targetFP->IsLocked() && !aOpts.m_includeLockedItems ) continue; @@ -482,16 +514,83 @@ bool MULTICHANNEL_TOOL::copyRuleAreaContents( FP_PAIRS& aMatches, BOARD_COMMIT* } +bool MULTICHANNEL_TOOL::checkIfPadNetsMatch( FP_WITH_CONNECTIONS& aRef, FP_WITH_CONNECTIONS& aTgt, FP_PAIRS& aMatches ) const +{ +#ifdef MULTICHANNEL_EXTRA_DEBUG + DBG(2, "ref: %d pads\n", (int)aRef.connsWithinRA.size() ); + DBG(2, "matches so far: %d\n", (int)aMatches.size() ); +#endif + + std::map pairs; + std::vector pref, ptgt; + + for( auto &m : aMatches ) + { + for( auto p : m.first->Pads() ) + pref.push_back( p ); + + for( auto p : m.second->Pads() ) + ptgt.push_back( p ); + + } + + for( auto p : aRef.fp->Pads() ) + pref.push_back( p ); + + for( auto p : aTgt.fp->Pads() ) + ptgt.push_back( p ); + + if( pref.size() != ptgt.size() ) + return false; + + for( unsigned int i = 0; i < pref.size(); i++ ) + pairs[pref[i]] = ptgt[i]; + + for( auto& ref : aRef.connsWithinRA ) + { + DBG(2, wxT("pad %s: %s -> "), ref.first->GetNumber(), ref.first->GetNetname() ); + + std::optional prevNet; + int i = 0; + + for( auto& pc : ref.second ) + { + auto tpad = pairs.find( pc.pad ); + + + i++; + if( tpad != pairs.end() ) + { + int nc = tpad->second->GetNetCode(); + + DBG(3, wxT(" %s[%d]"), tpad->second->GetNetname(), tpad->second->GetNetCode() ); + + if( prevNet && (*prevNet != nc ) ) + { + return false; + } + + prevNet = nc; + } + else + { + DBGn(3, wxT(" ?") ); + } + } + DBGn(3, wxT("\n") ); + } + + return true; +} + bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_AREA* aTargetArea, RULE_AREA_COMPAT_DATA& aMatches ) { std::map > allPads; PROF_TIMER totalMatch("total-match"); - { - //PROF_TIMER tmr1("buldPads"); - for( auto fp : board()->Footprints() ) + { for( auto pad : fp->Pads() ) { auto iter = allPads.find( pad->GetNet() ); @@ -501,7 +600,6 @@ bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_ARE else allPads[ pad->GetNet() ].push_back( pad ); } - //tmr1.Show(); } auto belongsToRAFootprint = [] ( RULE_AREA* ra, PAD *aPad ) -> FOOTPRINT* @@ -536,16 +634,14 @@ bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_ARE { fp.connsWithinRA[ pad ] = findPadConnectionsWithinRA ( ra, pad ); - #if 0 - printf("p %s-%s ->", pad->GetParentAsString().c_str().AsChar(), pad->GetNumber().c_str().AsChar() ); + DBG(3, wxT("p %s-%s ->"), pad->GetParentAsString(), pad->GetNumber() ); for( auto p : fp.connsWithinRA[ pad ] ) { - printf(" %s-%s", p.pad->GetParentAsString().c_str().AsChar(), p.pad->GetNumber().c_str().AsChar() ); + DBG(3, wxT(" %s-%s"), p.pad->GetParentAsString(), p.pad->GetNumber() ); } - printf("\n"); - #endif + DBGn(3, wxT("\n") ); } } @@ -554,54 +650,61 @@ bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_ARE auto matchConnections = [&] ( FP_WITH_CONNECTIONS*aRef, FP_WITH_CONNECTIONS* aTarget ) -> bool { - #if 0 for( auto ref : aRef->connsWithinRA ) + { + DBG(2, wxT("ref [%s]: "), ref.first->GetNumber() ); for( auto conn : ref.second ) - printf("ref: %s-%s\n", ref.first->GetNumber().c_str().AsChar(), - conn.format().c_str().AsChar() ); + DBG(2, wxT("%s[%s] "), conn.format(), conn.pad->GetNetname() ); + DBGn(2,wxT("\n")); + } for( auto tgt : aTarget->connsWithinRA ) - for( auto conn : tgt.second ) - printf("tgt: %s-%s\n", tgt.first->GetNumber().c_str().AsChar(), - conn.format().c_str().AsChar() ); - #endif + { + DBG(2, wxT("tgt [%s]: "), tgt.first->GetNumber() ); + for( auto conn : tgt.second ) + DBG(2, wxT("%s[%s]"), conn.format(), conn.pad->GetNetname() ); + DBGn(2,wxT("\n")); + } + + bool matchFound = false; for( auto ref : aRef->connsWithinRA ) { - bool matchFound = false; - for( auto tgt : aTarget->connsWithinRA) { bool padsMatch = true; + if( ref.second.size() != tgt.second.size() ) + { + padsMatch = false; continue; + } - for( int i = 0; i < ref.second.size(); i++ ) + for( unsigned int i = 0; i < ref.second.size(); i++ ) { PAD_PREFIX_ENTRY&eref = ref.second[i]; PAD_PREFIX_ENTRY&etgt = tgt.second[i]; - //printf("test %s vs %s\n", eref.format().c_str().AsChar(), - //etgt.format().c_str().AsChar() ); - if( ! eref.matchesPadNumberAndPrefix( etgt )) { padsMatch = false; break; - //printf("i %d match found\n", i ); - - //printf("match ref %s tgt %s", eref.Format().c_str(), etgt.Format().c_str() ); } } + if( padsMatch ) + { matchFound = true; + } } if( !matchFound ) + { return false; + } } - return true; + return matchFound; }; if( aRefArea->m_raFootprints.size() != aTargetArea->m_raFootprints.size() ) @@ -615,13 +718,8 @@ bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_ARE return false; } - { - //PROF_TIMER tmr1("buldPadCons"); - buildPadConnectionsWithinRA( aRefArea ); buildPadConnectionsWithinRA( aTargetArea ); - //tmr1.Show(); - } for( auto& refFP : aRefArea->m_raFootprints ) { @@ -635,14 +733,29 @@ bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_ARE targetFP.processed = false; } - int targetsRemaining = aTargetArea->m_raFootprints.size(); + //int targetsRemaining = aTargetArea->m_raFootprints.size(); + + std::sort( aRefArea->m_raFootprints.begin(), aRefArea->m_raFootprints.end(), + [] ( const FP_WITH_CONNECTIONS& a, const FP_WITH_CONNECTIONS& b ) -> int + { + return a.fp->GetPadCount() > b.fp->GetPadCount(); + } ); + + const int MATCH_MAX_ATTEMPTS = 10; + FOOTPRINT* failingRefFP = nullptr; + for( int attempt = 0; attempt < MATCH_MAX_ATTEMPTS; attempt++) { - //PROF_TIMER tmr1("matchTopo"); + aMatches.m_matchingFootprints.clear(); + + for( auto &targetFP : aTargetArea->m_raFootprints ) + { + targetFP.processed = false; + } + for( auto& refFP : aRefArea->m_raFootprints ) { - //int tid = random() % targetsRemaining; - //FP_WITH_CONNECTIONS* targetFP = nullptr; + std::vector candidates; bool anyMatchesFound = false; @@ -655,65 +768,65 @@ bool MULTICHANNEL_TOOL::resolveConnectionTopology( RULE_AREA* aRefArea, RULE_ARE { bool matches = matchConnections( &refFP, &targetFP ); - //printf("testFP %s vs %s\n", refFP.fp->GetReference().c_str().AsChar(), - // targetFP.fp->GetReference().c_str().AsChar() ); + DBG(2, wxT("testFP %s vs %s\n"), refFP.fp->GetReference().c_str().AsChar(), + targetFP.fp->GetReference().c_str().AsChar() ); if( matches ) { - // printf("%s: matches %s\n", refFP.fp->GetReference().c_str().AsChar(), targetFP.fp->GetReference().c_str().AsChar() ); - //refFP.processed = true; - //targetFP.processed = true; - anyMatchesFound = true; - targetFP.processed = true; - aMatches.m_matchingFootprints.push_back( { refFP.fp, targetFP.fp } ); - break; - } - //else - - /*if( tid == 0 ) - { - targetFP = &fp; - break; + DBG(2, wxT("%s: matches %s\n"), refFP.fp->GetReference().c_str().AsChar(), targetFP.fp->GetReference().c_str().AsChar() ); + candidates.push_back( &targetFP ); } - else - tid--;*/ } } - if( !anyMatchesFound ) - { - aMatches.m_errorMsg = wxString::Format( wxT("Topology mismatch (no counterpart found for component %s)"), - refFP.fp->GetReference() ); - - aMatches.m_isOk = false; - printf("%s: no match\n", refFP.fp->GetReference().c_str().AsChar() ); - return false; - - } + + DBG(2, wxT("Candidates for %s: %d\n"), refFP.fp->GetReference(), (int) candidates.size() ); + FP_WITH_CONNECTIONS* best = nullptr; + for( auto &c: candidates ) + { + bool chk = checkIfPadNetsMatch( refFP, *c, aMatches.m_matchingFootprints ); + DBG(2, wxT("\n %s om %d\n"), c->fp->GetReference(), chk ? 1 : 0); - } - //tmr1.Show(); - } + if( chk ) + { + anyMatchesFound = true; + best = c; + } + } - printf("match done\n"); - /*for( auto refPad : refFP->Pads() ) + if( !anyMatchesFound ) { - auto refNet = refPad->GetNet(); - auto refPads = allPads[ refNet ]; + failingRefFP = refFP.fp; + break; + } + else + { + best->processed = true; + aMatches.m_matchingFootprints.push_back( { refFP.fp, best->fp } ); + } + } - - }*/ - //} + if( aMatches.m_matchingFootprints.size() == aTargetArea->m_raFootprints.size() ) + { + aMatches.m_isOk = true; + totalMatch.Show(); + return true; + } - aMatches.m_isOk = true; + auto rng = std::default_random_engine {}; + std::shuffle( aTargetArea->m_raFootprints.begin(), aTargetArea->m_raFootprints.end(), rng); + } - totalMatch.Show(); + aMatches.m_errorMsg = wxString::Format( wxT("Topology mismatch (no counterpart found for component %s)"), + failingRefFP->GetReference() ); - return true; + aMatches.m_isOk = false; + DBG(2, wxT("%s: no match\n"), failingRefFP->GetReference() ); + return false; } @@ -754,7 +867,6 @@ int MULTICHANNEL_TOOL::autogenerateRuleAreas( const TOOL_EVENT& aEvent ) for( auto& ra : m_areas.m_areas ) { - //printf("cmps: %d raf: %d\n", components.size(), ra.m_sheetComponents.size() ); if( components == ra.m_sheetComponents ) { m_reporter->Report( wxString::Format( wxT("Placement rule area for sheet '%s' already exists as '%s'\n"), @@ -781,8 +893,6 @@ int MULTICHANNEL_TOOL::autogenerateRuleAreas( const TOOL_EVENT& aEvent ) auto raOutline = buildRAOutline( ra.m_sheetComponents, 100000 ); - //printf("RA %s : %d vts\n", ra.m_sheetName.c_str().AsChar(), raOutline.PointCount() ); - std::unique_ptr newZone ( new ZONE( board() ) ); newZone->SetZoneName( wxString::Format( wxT("auto-placement-area-%s"), ra.m_sheetPath ) ); @@ -798,9 +908,7 @@ int MULTICHANNEL_TOOL::autogenerateRuleAreas( const TOOL_EVENT& aEvent ) newZone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH ); //aBoard->Add( newZone.release() ); commit.Add( newZone.get() ); - commit.Push( wxT("Auto-generate placement rule areas") ); - - + commit.Push( _("Auto-generate placement rule areas") ); if( m_areas.m_groupItems ) { @@ -809,8 +917,6 @@ int MULTICHANNEL_TOOL::autogenerateRuleAreas( const TOOL_EVENT& aEvent ) PCB_GROUP *grp = new PCB_GROUP( board() ); - printf("groupItems: %p\n", newZone.get() ); - grpCommit.Add( grp ); grpCommit.Stage( newZone.get(), CHT_GROUP ); @@ -820,14 +926,12 @@ int MULTICHANNEL_TOOL::autogenerateRuleAreas( const TOOL_EVENT& aEvent ) { grpCommit.Stage( fp, CHT_GROUP ); grp->AddItem( fp ); - printf("groupItems: %p\n", fp ); } - grpCommit.Push( wxT("Group components with their placement rule areas") ); + grpCommit.Push( _("Group components with their placement rule areas") ); } newZone.release(); } - return true; } diff --git a/pcbnew/tools/multichannel_tool.h b/pcbnew/tools/multichannel_tool.h index 0035c9ef01..cb2fd9130c 100644 --- a/pcbnew/tools/multichannel_tool.h +++ b/pcbnew/tools/multichannel_tool.h @@ -65,7 +65,7 @@ struct PAD_PREFIX_ENTRY bool processed; wxString format() const { - return wxString::Format( wxT("%s-%s"), componentPrefix, pad->GetNumber() ); + return wxString::Format( wxT("%s-%s[%s]"), componentPrefix, pad->GetNumber(), pad->GetNetname().c_str().AsChar() ); } bool matchesPadNumberAndPrefix( const PAD_PREFIX_ENTRY& aOther ) const @@ -83,16 +83,17 @@ struct PAD_PREFIX_ENTRY struct FP_WITH_CONNECTIONS { FOOTPRINT* fp; - std::unordered_map > connsWithinRA; + typedef std::unordered_map > PAD_CONNECTION_MAP; + PAD_CONNECTION_MAP connsWithinRA; bool processed; void sortByPadNumbers() { // fixme - std::unordered_map > sorted; + PAD_CONNECTION_MAP sorted; for( auto& ent : connsWithinRA ) { - auto v = ent.second; + std::vector v( ent.second ); auto compare = [] ( const PAD_PREFIX_ENTRY& a, const PAD_PREFIX_ENTRY& b ) -> int { if( a.pad->GetNumber() > b.pad->GetNumber() ) @@ -187,6 +188,8 @@ class MULTICHANNEL_TOOL : public PCB_TOOL_BASE FOOTPRINT* aFp, const REPEAT_LAYOUT_OPTIONS& aOpts ) const; + bool checkIfPadNetsMatch( FP_WITH_CONNECTIONS& aRef, FP_WITH_CONNECTIONS& aTgt, FP_PAIRS& aMatches ) const; + std::unique_ptr m_reporter; RULE_AREAS_DATA m_areas; };