Browse Source

pcbnew: weeding out bugs in the MULTICHANNEL_TOOL...

jobs
Tomasz Wlostowski 2 years ago
parent
commit
628d4d3fdb
  1. 4
      pcbnew/dialogs/dialog_multichannel_generate_rule_areas.cpp
  2. 7
      pcbnew/dialogs/dialog_multichannel_repeat_layout.cpp
  3. 310
      pcbnew/tools/multichannel_tool.cpp
  4. 11
      pcbnew/tools/multichannel_tool.h

4
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;

7
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 );

310
pcbnew/tools/multichannel_tool.cpp

@ -36,8 +36,21 @@
#include <geometry/convex_hull.h>
#include <pcb_group.h>
#include <connectivity/connectivity_data.h>
//#include <../qa/tools/pns/pns_log_viewer_frame.h>
#include <optional>
#include <algorithm>
#include <random>
#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<FOOTPRINT*> 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<FOOTPRINT*>&
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 ); //<PNS_LOG_VIEWER_FRAME>()->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<BOARD_ITEM*> &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<BOARD_ITEM*> refRouting;
std::set<BOARD_ITEM*> targetRouting;
DBG(1, "copying routing: %d fps\n", aMatches.size() );
for( auto& fpPair : aMatches )
{
std::set<BOARD_ITEM*> 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<PAD*, PAD*> pairs;
std::vector<PAD*> 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<int> 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<NETINFO_ITEM*, std::vector<PAD* > > 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<FP_WITH_CONNECTIONS*> 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<ZONE> 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;
}

11
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<PAD*, std::vector<PAD_PREFIX_ENTRY> > connsWithinRA;
typedef std::unordered_map<PAD*, std::vector<PAD_PREFIX_ENTRY> > PAD_CONNECTION_MAP;
PAD_CONNECTION_MAP connsWithinRA;
bool processed;
void sortByPadNumbers()
{
// fixme
std::unordered_map<PAD*, std::vector<PAD_PREFIX_ENTRY> > sorted;
PAD_CONNECTION_MAP sorted;
for( auto& ent : connsWithinRA )
{
auto v = ent.second;
std::vector<PAD_PREFIX_ENTRY> 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<REPORTER> m_reporter;
RULE_AREAS_DATA m_areas;
};

Loading…
Cancel
Save