56#include <wx/richmsgdlg.h>
60#define MULTICHANNEL_EXTRA_DEBUG
67 std::vector<wxString> refs;
74 refs.push_back( fp->GetReferenceAsString() );
77 std::sort( refs.begin(), refs.end(),
78 [](
const wxString& aLhs,
const wxString& aRhs )
80 return aLhs.CmpNoCase( aRhs ) < 0;
88 size_t componentsOnLine = 0;
90 for(
const wxString& ref : refs )
92 if( componentsOnLine == 10 )
106 if( !line.IsEmpty() )
122 for(
const wxString& reason : aReasons )
124 if( !
text.IsEmpty() )
135 const std::vector<wxString>& aReasons )
137 if( !aParent || aReasons.empty() )
140 wxRichMessageDialog dlg( aParent, aSummary,
_(
"Topology mismatch" ), wxICON_ERROR | wxOK );
157 const std::vector<wxString>& aReasons )
const
159 wxWindow* parent = aParent ? aParent :
frame();
172 std::set<FOOTPRINT*>& aComponents )
174 if( !aRuleArea || !aRuleArea->
m_zone )
185 aComponents.insert(
static_cast<FOOTPRINT*
>( item ) );
188 return (
int) aComponents.size();
197 [&](
const wxString& aMessage,
int aOffset )
210 sourceName.Replace( wxT(
"'" ), wxT(
"\\'" ) );
217 ruleText = wxT(
"A.memberOfSheetOrChildren('" ) + sourceName + wxT(
"')" );
220 ruleText = wxT(
"A.hasComponentClass('" ) + sourceName + wxT(
"')" );
223 ruleText = wxT(
"A.memberOfGroup('" ) + sourceName + wxT(
"')" );
230 auto ok = compiler.
Compile( ruleText, &ucode, &preflightCtx );
244 fp->GetSheetname() );
246 aComponents.insert( fp );
256 if( !aRuleArea || !aRuleArea->
m_zone )
281 if( !boardItem->IsConnected() || boardItem->Type() ==
PCB_ZONE_T )
282 aItems.insert( boardItem );
286 return aItems.size() > 0;
294 bool zoneOnBoard =
false;
298 if( zone == aRuleArea->
m_zone )
322 if( !boardItem->IsConnected() || boardItem->Type() ==
PCB_ZONE_T )
323 aItems.insert( boardItem );
328 return aItems.size() > 0;
337 [&](
const wxString& aMessage,
int aOffset )
348 wxString ruleText = wxString::Format( wxT(
"A.enclosedByArea('%s')" ),
351 if( !compiler.
Compile( ruleText, &ucode, &preflightCtx ) )
358 auto val = ucode.
Run( &ctx );
360 if( val->AsDouble() != 0.0 )
361 aItems.insert( aItem );
366 if( zone == aRuleArea->
m_zone )
374 if( !drawing->IsConnected() )
375 testAndAdd( drawing );
384 std::set<FOOTPRINT*> rv;
386 if( aSheetName.EndsWith( wxT(
"/" ) ) )
387 aSheetName.RemoveLast();
389 wxString childPrefix = aSheetName + wxT(
"/" );
393 auto sn = fp->GetSheetname();
395 if( sn.EndsWith( wxT(
"/" ) ) )
398 if( sn == aSheetName || sn.StartsWith( childPrefix ) )
409 std::set<FOOTPRINT*> rv;
413 if( fp->GetComponentClass()->ContainsClassName( aComponentClassName ) )
426 aOut.insert(
static_cast<FOOTPRINT*
>( item ) );
440 else if( item->IsBOARD_ITEM() )
441 aOut.insert(
static_cast<BOARD_ITEM*
>( item ) );
448 std::set<FOOTPRINT*> rv;
452 if(
group->GetName().Matches( aGroupName ) )
466 if( !
group->GetName().Matches( aGroupName ) )
481 std::set<BOARD_ITEM*> rv;
485 if( !
group->GetName().Matches( aGroupName ) )
490 if( item->IsBOARD_ITEM() )
491 rv.insert(
static_cast<BOARD_ITEM*
>( item ) );
501 std::vector<VECTOR2I> bbCorners;
502 bbCorners.reserve( aFootprints.size() * 4 );
506 const BOX2I bb = fp->GetBoundingBox(
false ).GetInflated( aMargin );
510 std::vector<VECTOR2I> hullVertices;
521 std::vector<VECTOR2I> bbCorners;
522 bbCorners.reserve( aItems.size() * 4 );
526 BOX2I bb = item->GetBoundingBox();
529 bb =
static_cast<FOOTPRINT*
>( item )->GetBoundingBox(
false );
534 std::vector<VECTOR2I> hullVertices;
548 std::vector<wxString> segments;
551 for( wxUniChar ch : aSheetName )
556 segments.push_back( cur );
567 segments.push_back( cur );
569 std::vector<wxString> rv;
570 wxString prefix = wxT(
"/" );
572 for(
size_t i = 0; i + 1 < segments.size(); ++i )
574 prefix += segments[i] + wxT(
"/" );
575 rv.push_back( prefix );
586 std::map<wxString, wxString> uniqueSheets;
587 std::set<wxString> uniqueComponentClasses;
588 std::set<wxString> uniqueGroups;
594 uniqueSheets[fp->GetSheetname()] = fp->GetSheetfile();
598 uniqueSheets.emplace( parent, wxString() );
603 uniqueComponentClasses.insert( singleClass->GetName() );
609 if( !grp->GetName().IsEmpty() )
610 uniqueGroups.insert( grp->GetName() );
614 for(
const auto& [sheetPath, sheetFile] : uniqueSheets )
623 m_areas.m_areas.push_back( ent );
628 (
int)
m_areas.m_areas.size() );
631 for(
const wxString& compClass : uniqueComponentClasses )
639 m_areas.m_areas.push_back( ent );
643 static_cast<int>(
m_areas.m_areas.size() ) );
646 for(
const wxString& groupName : uniqueGroups )
654 m_areas.m_areas.push_back( ent );
658 static_cast<int>(
m_areas.m_areas.size() ) );
669 if( !zone->GetIsRuleArea() )
672 if( !zone->GetPlacementAreaEnabled() )
680 area.
m_center = zone->Outline()->COutline( 0 ).Centre();
698 m_areas.m_areas.push_back( area );
729 std::vector<ZONE*> refRAs;
731 auto isSelectedItemAnRA =
737 ZONE* zone =
static_cast<ZONE*
>( aItem );
750 if(
ZONE* zone = isSelectedItemAnRA( item ) )
752 refRAs.push_back( zone );
760 if(
ZONE* grpZone = isSelectedItemAnRA( grpItem ) )
761 refRAs.push_back( grpZone );
766 if( refRAs.size() != 1 )
771 _(
"Select a reference Rule Area to copy from..." ),
774 return isSelectedItemAnRA( aItem ) !=
nullptr;
788 if(
m_areas.m_areas.size() <= 1 )
790 frame()->ShowInfoBarError(
_(
"No Rule Areas to repeat layout to have been found." ),
true );
810 if( ra.
m_zone == aRefZone )
822 std::vector<RULE_AREA*> targets;
829 targets.push_back( &ra );
833 if( targets.empty() )
836 int total =
static_cast<int>( targets.size() );
837 std::atomic<int> completed( 0 );
838 std::atomic<bool> cancelled(
false );
839 std::atomic<int> matchedComponents( 0 );
840 std::atomic<int> totalComponents( 0 );
855 auto future =
tp.submit_task(
856 [
this, refRA, &targets, &completed, &cancelled, &matchedComponents, &isoParams]()
860 if( cancelled.load( std::memory_order_relaxed ) )
863 matchedComponents.store( 0, std::memory_order_relaxed );
867 completed.fetch_add( 1, std::memory_order_relaxed );
873 std::unique_ptr<WX_PROGRESS_REPORTER>
reporter;
874 auto startTime = std::chrono::steady_clock::now();
875 double highWaterMark = 0.0;
877 while( future.wait_for( std::chrono::milliseconds( 100 ) ) != std::future_status::ready )
881 auto elapsed = std::chrono::steady_clock::now() - startTime;
883 if( elapsed > std::chrono::seconds( 1 ) )
885 reporter = std::make_unique<WX_PROGRESS_REPORTER>(
891 wxLog::FlushActive();
897 int done = completed.load( std::memory_order_relaxed );
898 int matched = matchedComponents.load( std::memory_order_relaxed );
899 int compTotal = totalComponents.load( std::memory_order_relaxed );
901 double fraction = ( compTotal > 0 )
902 ?
static_cast<double>( matched ) / compTotal
904 double progress =
static_cast<double>( done + fraction ) / total;
906 if( progress > highWaterMark )
907 highWaterMark = progress;
909 reporter->SetCurrentProgress( highWaterMark );
911 _(
"Resolving topology %d of %d (%d/%d components)" ),
912 done + 1, total, matched, compTotal ) );
915 cancelled.store(
true, std::memory_order_relaxed );
924 if( cancelled.load( std::memory_order_relaxed ) )
936 wxString* aErrorOut )
938 wxCHECK_MSG( aRefArea.
m_zone, -1, wxT(
"Reference Rule Area has no zone." ) );
939 wxCHECK_MSG( aTargetArea.
m_zone, -1, wxT(
"Target Rule Area has no zone." ) );
941 const bool silent = aErrorOut !=
nullptr;
943 auto reportError = [&](
const wxString& aMsg )
947 else if(
Pgm().IsGUI() )
948 frame()->ShowInfoBarError( aMsg,
true );
960 else if(
Pgm().IsGUI() )
962 wxString summary = wxString::Format(
_(
"Rule Area topologies do not match: %s" ), compat.
m_errorMsg );
969 std::optional<BOARD_COMMIT> localCommit;
971 if( !aExternalCommit )
972 localCommit.emplace(
GetManager(),
true,
false );
974 BOARD_COMMIT& commit = aExternalCommit ? *aExternalCommit : *localCommit;
988 auto errMsg = wxString::Format(
_(
"Could not copy the layout from '%s' to '%s'." ),
991 if( !aExternalCommit )
994 reportError( errMsg );
1008 if( !aExternalCommit )
1011 reportError(
_(
"Target group does not have a group." ) );
1021 group->AddItem( item );
1025 if( !aExternalCommit )
1026 commit.
Push(
_(
"Repeat Layout" ) );
1034 int totalCopied = 0;
1038 for(
auto& [targetArea, compatData] :
m_areas.m_compatMap )
1040 if( !compatData.m_doCopy )
1043 targetArea->m_ruleName );
1047 if( !compatData.m_isOk )
1052 auto errMsg = wxString::Format(
_(
"Could not copy the layout from '%s' to '%s'." ),
1053 m_areas.m_refRA->m_zone->GetZoneName(), targetArea->m_zone->GetZoneName() );
1058 frame()->ShowInfoBarError( errMsg,
true );
1067 if(
m_areas.m_options.m_groupItems )
1069 for(
const auto& [targetArea, compatData] :
m_areas.m_compatMap )
1071 if( compatData.m_groupableItems.size() < 2 )
1090 for(
BOARD_ITEM* item : compatData.m_groupableItems )
1093 group->AddItem( item );
1098 commit.
Push(
_(
"Repeat Layout" ) );
1101 frame()->ShowInfoBarMsg( wxString::Format(
_(
"Copied to %d Rule Areas." ), totalCopied ),
true );
1113 for(
auto k : aRef )
1121 if( ( c >=
'a' && c <=
'z' ) || ( c >=
'A' && c <=
'Z' ) || ( c ==
'_' ) )
1132 std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
1135 if( !aRuleArea || !aRuleArea->
m_zone )
1164 if(
EDA_GROUP* parent = bci->GetParentGroup() )
1170 if( bci->IsConnected() )
1171 aOutput.insert( bci );
1175 return (
int) aOutput.size();
1182 bool zoneOnBoard =
false;
1186 if( zone == aRuleArea->
m_zone )
1200 if( aOutput.contains( aItem ) )
1204 if(
EDA_GROUP* parent = aItem->GetParentGroup() )
1214 aItem->TransformShapeToPolygon( itemShape, aItem->GetLayer(), 0, maxError,
ERROR_OUTSIDE );
1223 aOutput.insert( aItem );
1229 enclosedByZone( track );
1233 if( drawing->IsConnected() )
1246 [&](
const wxString& aMessage,
int aOffset )
1257 wxString ruleText = wxString::Format( wxT(
"A.enclosedByArea('%s')" ),
1263 if( aOutput.contains( aItem ) )
1267 if(
EDA_GROUP* parent = aItem->GetParentGroup() )
1278 aOutput.insert( aItem );
1283 if( compiler.
Compile( ruleText, &ucode, &preflightCtx ) )
1286 testAndAdd( track );
1290 if( drawing->IsConnected() )
1316 targetAnchorFp = targetFP;
1324 if( targetAnchorFp )
1331 disp = newpos - oldpos;
1344 newTargetOutline.
Move( disp );
1359 std::vector<std::pair<BOARD_ITEM*, BOARD_ITEM*>> groupFixupPairs;
1360 std::set<BOARD_ITEM*> reproducedSourceItems;
1362 auto fixupParentGroup =
1367 destItem->SetParentGroup(
nullptr );
1369 if( !preserveGroups )
1373 groupFixupPairs.emplace_back( sourceItem, destItem );
1375 reproducedSourceItems.insert( sourceItem );
1381 bool targetZoneOnBoard =
false;
1383 if( aTargetArea->
m_zone )
1387 if( z == aTargetArea->
m_zone )
1389 targetZoneOnBoard =
true;
1395 if( targetZoneOnBoard )
1403 if( preserveGroups )
1406 groupFixupPairs.emplace_back( aRefArea->
m_zone, aTargetArea->
m_zone );
1408 reproducedSourceItems.insert( aRefArea->
m_zone );
1414 std::set<BOARD_CONNECTED_ITEM*> refRouting;
1415 std::set<BOARD_CONNECTED_ITEM*> targetRouting;
1421 std::set<int> targc;
1425 for(
PAD*
pad : refFP->Pads() )
1426 refc.insert(
pad->GetNetCode() );
1428 for(
PAD*
pad : targetFP->Pads() )
1429 targc.insert(
pad->GetNetCode() );
1436 std::set<int> targetGroupNets;
1445 targetGroupNets.insert(
pad->GetNetCode() );
1449 targetGroupNets.insert( bci->GetNetCode() );
1468 if( item->GetParentGroup() )
1471 if( item->IsLocked() )
1474 if( item->GetNetCode() <= 0 || !targetGroupNets.contains( item->GetNetCode() ) )
1518 fixupParentGroup( item,
copied );
1528 std::vector<PCB_GENERATOR*> refGenerators;
1529 std::vector<PCB_GENERATOR*> targetGenerators;
1536 refGenerators.push_back(
static_cast<PCB_GENERATOR*
>( item ) );
1541 if( !targetGroup && !aTargetArea->
m_components.empty() )
1542 targetGroup = ( *aTargetArea->
m_components.begin() )->GetParentGroup();
1549 targetGenerators.push_back(
static_cast<PCB_GENERATOR*
>( member ) );
1560 if( gen->GetGeneratorType() != wxT(
"tuning_pattern" ) )
1563 if( gen->HitTest( refOut,
false ) )
1564 refGenerators.push_back( gen );
1565 else if( gen->HitTest( targetOut,
false ) )
1566 targetGenerators.push_back( gen );
1579 aCommit->
Remove( child );
1602 clone->
Move( disp );
1603 aCommit->
Add( clone );
1613 aCommit->
Add( child );
1623 std::set<BOARD_ITEM*> sourceItems;
1624 std::set<BOARD_ITEM*> targetItems;
1642 if( item->GetParent() && item->GetParent()->Type() ==
PCB_FOOTPRINT_T )
1659 ZONE* zone =
static_cast<ZONE*
>( item );
1682 if( item->GetParent() && item->GetParent()->Type() ==
PCB_FOOTPRINT_T )
1692 ZONE* zone =
static_cast<ZONE*
>( item );
1694 if( !skipLayerFilter )
1696 LSET allowedLayers =
1704 ZONE* targetZone =
static_cast<ZONE*
>( item->Duplicate(
false ) );
1711 if( !skipLayerFilter )
1725 fixupParentGroup( item,
copied );
1743 refFP->GetReference() );
1749 refFP->GetReference() );
1756 && !refFP->GetEffectiveShape( refFP->GetLayer() )->Collide( &refPoly, 0 ) )
1764 aCommit->
Modify( targetFP );
1766 targetFP->SetLayerAndFlip( refFP->GetLayer() );
1767 targetFP->SetOrientation( refFP->GetOrientation() );
1768 targetFP->SetPosition( refFP->GetPosition() );
1769 targetFP->Rotate(
VECTOR2( 0, 0 ), rot );
1770 targetFP->Move( disp );
1772 for(
PCB_FIELD* refField : refFP->GetFields() )
1774 wxCHECK2( refField,
continue );
1776 PCB_FIELD* targetField = targetFP->GetField( refField->GetName() );
1781 targetField->
SetLayerSet( refField->GetLayerSet() );
1782 targetField->
SetVisible( refField->IsVisible() );
1784 targetField->
SetPosition( refField->GetPosition() );
1787 targetField->
Move( disp );
1794 std::set<PCB_TEXT*> consumedTargets;
1796 for(
BOARD_ITEM* refItem : refFP->GraphicalItems() )
1804 for(
BOARD_ITEM* targetItem : targetFP->GraphicalItems() )
1811 if( consumedTargets.contains( candidate ) || candidate->
GetText() != refText->
GetText() )
1816 targetText = candidate;
1825 consumedTargets.insert( targetText );
1833 targetText->
Move( disp );
1838 targetFP->Models() = refFP->Models();
1840 std::set<PAD*> consumedPads;
1842 for(
PAD* refPad : refFP->Pads() )
1844 for(
PAD* targetPad : targetFP->Pads() )
1846 if( consumedPads.contains( targetPad ) || targetPad->GetNumber() != refPad->GetNumber() )
1851 consumedPads.insert( targetPad );
1852 targetPad->ImportSettingsFrom( *refPad );
1862 if( preserveGroups && refFP->GetParentGroup() )
1863 groupFixupPairs.emplace_back( refFP, targetFP );
1865 if( preserveGroups )
1866 reproducedSourceItems.insert( refFP );
1873 if( preserveGroups && !groupFixupPairs.empty() )
1875 std::map<EDA_GROUP*, EDA_GROUP*> groupMap;
1876 std::map<EDA_GROUP*, bool> fullyReproducedCache;
1878 auto groupFullyReproduced =
1881 if(
auto it = fullyReproducedCache.find( aGroup ); it != fullyReproducedCache.end() )
1884 bool reproduced =
true;
1886 for(
EDA_ITEM* member : aGroup->GetItems() )
1890 if( !member->IsBOARD_ITEM()
1891 || !reproducedSourceItems.contains(
static_cast<BOARD_ITEM*
>( member ) ) )
1898 fullyReproducedCache[aGroup] = reproduced;
1902 for(
const auto& [sourceItem, destItem] : groupFixupPairs )
1906 if( !parentGroup || !groupFullyReproduced( parentGroup ) )
1909 if( !groupMap.contains( parentGroup ) )
1919 newGroup->
Move( disp );
1922 groupMap[parentGroup] = newGroup;
1923 aCommit->
Add( newGroup );
1928 if(
EDA_GROUP* oldGroup = destItem->GetParentGroup() )
1930 if( oldGroup != groupMap[parentGroup] )
1931 aCommit->
Modify( oldGroup->AsEdaItem() );
1934 groupMap[parentGroup]->AddItem( destItem );
1954 if( aComponentMatches.empty() )
1961 const std::vector<BOARD_CONNECTED_ITEM*> refConnectedPads = connectivity->
GetNetItems( aRef->
GetNetCode(),
1969 const PAD* refPad =
static_cast<const PAD*
>( refConItem );
1972 if( aComponentMatches.contains( sourceFootprint ) )
1974 const FOOTPRINT* targetFootprint = aComponentMatches[sourceFootprint];
1975 std::vector<const PAD*> targetFpPads = targetFootprint->
GetPads( refPad->
GetNumber() );
1977 if( !targetFpPads.empty() )
1979 int targetNetCode = targetFpPads[0]->GetNet()->GetNetCode();
1990 const std::set<FOOTPRINT*>& aFootprints,
1991 const std::unordered_set<EDA_ITEM*>& aItems )
1993 std::vector<NETINFO_ITEM*> created;
1994 std::map<int, NETINFO_ITEM*> remap;
2000 auto isAutoName = [](
const wxString& aName )
2002 return aName.StartsWith( wxT(
"Net-(" ) ) || aName.StartsWith( wxT(
"unconnected-" ) );
2007 int code = aItem->GetNetCode();
2014 if( !oldNet || !isAutoName( oldNet->
GetNetname() ) )
2017 auto it = remap.find( code );
2019 if( it == remap.end() )
2025 name = wxString::Format( wxT(
"__dbapply_%d_%d" ), code, counter++ );
2029 aBoard->
Add( newNet );
2030 created.push_back( newNet );
2031 it = remap.emplace( code, newNet ).first;
2034 aItem->SetNet( it->second );
2039 for(
PAD*
pad : fp->Pads() )
2060 if( aRef.empty() || aRef.size() != aTarget.size() )
2069 std::map<KIID, FOOTPRINT*> targetByUuid;
2073 KIID uuid = symbolUuid( fp );
2076 if( uuid ==
niluuid || !targetByUuid.emplace( uuid, fp ).second )
2081 std::set<FOOTPRINT*> used;
2085 KIID uuid = symbolUuid( refFp );
2090 auto it = targetByUuid.find( uuid );
2092 if( it == targetByUuid.end() )
2098 if( refFp->GetFPID() != targetFp->
GetFPID() || refFp->Pads().size() != targetFp->
Pads().size() )
2101 if( !used.insert( targetFp ).second )
2104 result[refFp] = targetFp;
2107 aResult = std::move(
result );
2134 std::set<FOOTPRINT*> shared;
2137 std::inserter( shared, shared.begin() ) );
2139 if( !shared.empty() )
2143 aMatches.
m_errorMsg =
_(
"Target Rule Area shares components with the reference area" );
2146 _(
"This target Rule Area selects the same components as the reference area. "
2147 "Repeat layout cannot copy a Rule Area onto itself. Give each placement Rule "
2148 "Area a distinct sheet, component class or group." ) );
2149 aMatches.
m_mismatchReasons.push_back( wxString::Format(
_(
"Shared components:\n%s" ),
2157 std::unordered_map<int, std::vector<const RULE_AREA*>> netInternalAreas;
2161 std::unordered_map<int, int> areaNetPadCounts;
2167 if(
pad->GetNetCode() > 0 )
2168 areaNetPadCounts[
pad->GetNetCode()]++;
2172 for(
const auto& [netCode, padCount] : areaNetPadCounts )
2175 netInternalAreas[netCode].push_back( &area );
2186 if( aB->m_components.count( fp ) )
2193 std::unordered_set<int> globalNets;
2195 for(
const auto& [netCode, areas] : netInternalAreas )
2197 for(
size_t i = 0; i < areas.size() && !globalNets.count( netCode ); i++ )
2199 for(
size_t j = i + 1; j < areas.size(); j++ )
2201 if( disjoint( areas[i], areas[j] ) )
2203 globalNets.insert( netCode );
2224 std::vector<TMATCH::TOPOLOGY_MISMATCH_REASON> mismatchReasons;
2228 mismatchReasons, aParams );
2240 if( !status && !cancelled
2247 aMatches.
m_isOk = status;
2258 for(
const auto& reason : mismatchReasons )
2260 if( reason.m_reason.IsEmpty() )
2263 if( !reason.m_reference.IsEmpty() && !reason.m_candidate.IsEmpty() )
2265 else if( !reason.m_reference.IsEmpty() )
2269 reason.m_reason ) );
2276 aMatches.
m_mismatchReasons.push_back(
_(
"The components in the two areas could not be paired up." ) );
2283 aMatches.
m_mismatchReasons.push_back( wxString::Format(
_(
"Reference area components:\n%s" ),
2285 aMatches.
m_mismatchReasons.push_back( wxString::Format(
_(
"Target area components:\n%s" ),
2296 const std::unordered_set<BOARD_ITEM*>& aItemsToRemove )
2302 std::vector<EDA_ITEM*> pruneList;
2308 if( refItem->m_Uuid == testItem->m_Uuid )
2309 pruneList.push_back( refItem );
2313 if( !pruneList.empty() )
2318 group->RemoveItem( item );
2320 if(
group->GetItems().size() < 2 )
2335 if(
m_areas.m_areas.size() <= 1 )
2337 frame()->ShowInfoBarError(
_(
"Cannot auto-generate any placement areas because the "
2338 "schematic has only one or no hierarchical sheets, "
2339 "groups, or component classes." ),
2347 if( ret != wxID_OK )
2367 wxString existingAreaTraceFormat;
2372 existingAreaTraceFormat = wxT(
"Placement rule area for sheet '%s' already exists as '%s'\n" );
2377 existingAreaTraceFormat = wxT(
"Placement rule area for component class '%s' already exists as '%s'\n" );
2382 existingAreaTraceFormat = wxT(
"Placement rule area for group '%s' already exists as '%s'\n" );
2385 std::unique_ptr<ZONE> newZone(
new ZONE(
board() ) );
2386 newZone->SetZoneName( wxString::Format( wxT(
"auto-placement-area-%s" ),
source ) );
2387 newZone->SetPlacementAreaSourceType( ra.
m_sourceType );
2388 newZone->SetPlacementAreaSource(
source );
2390 std::vector<ZONE*> oldZones;
2394 if( !zone->GetIsRuleArea() || !zone->GetPlacementAreaEnabled() )
2397 if( zone->GetPlacementAreaSourceType() != newZone->GetPlacementAreaSourceType()
2398 || zone->GetPlacementAreaSource() != newZone->GetPlacementAreaSource() )
2405 oldZones.push_back( zone );
2408 if( !oldZones.empty() && !
m_areas.m_replaceExisting )
2420 if( groupItems.empty() )
2423 wxT(
"Skipping placement rule area generation for source group '%s': group has no board items." ),
2435 std::set<BOARD_ITEM*> outlineItems;
2436 std::set<EDA_GROUP*> groups;
2437 std::set<int> channelNets;
2441 outlineItems.insert( fp );
2444 channelNets.insert(
pad->GetNetCode() );
2455 std::set<int> foreignNets;
2463 foreignNets.insert(
pad->GetNetCode() );
2468 int net = track->GetNetCode();
2470 if( net > 0 && channelNets.count( net ) && !foreignNets.count( net ) )
2471 outlineItems.insert( track );
2478 newZone->GetZoneName(),
2481 newZone->SetIsRuleArea(
true );
2483 newZone->SetPlacementAreaEnabled(
true );
2484 newZone->SetDoNotAllowZoneFills(
false );
2485 newZone->SetDoNotAllowVias(
false );
2486 newZone->SetDoNotAllowTracks(
false );
2487 newZone->SetDoNotAllowPads(
false );
2488 newZone->SetDoNotAllowFootprints(
false );
2490 newZone->AddPolygon( raOutline );
2493 for(
ZONE* oldZone : oldZones )
2494 commit.
Remove( oldZone );
2496 ra.
m_zone = newZone.release();
2503 if(
m_areas.m_options.m_groupItems )
2510 std::unordered_set<BOARD_ITEM*> toPrune;
2526 group->AddItem( fp );
2531 commit.
Push(
_(
"Auto-generate Placement Rule Areas" ) );
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual void SetLayerSet(const LSET &aLayers)
virtual bool IsKnockout() const
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetIsKnockout(bool aKnockout)
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
FOOTPRINT * GetParentFootprint() const
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
constexpr BOX2< Vec > GetInflated(coord_type aDx, coord_type aDy) const
Get a new rectangle that is this one, inflated by aDx and aDy.
Represent a set of changes (additions, deletions or modifications) of a data model (e....
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
int GetStatus(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Returns status of an item.
A lightweight representation of a component class.
const std::vector< COMPONENT_CLASS * > & GetConstituentClasses() const
Fetches a vector of the constituent classes for this (effective) class.
const std::vector< BOARD_CONNECTED_ITEM * > GetNetItems(int aNetCode, const std::vector< KICAD_T > &aTypes) const
Return the list of items that belong to a certain net.
A set of EDA_ITEMs (i.e., without duplicates).
std::unordered_set< EDA_ITEM * > & GetItems()
virtual EDA_ITEM * AsEdaItem()=0
A base class for most all the KiCad significant classes used in schematics and boards.
virtual EDA_GROUP * GetParentGroup() const
KICAD_T Type() const
Returns the type of object.
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
virtual void SetParentGroup(EDA_GROUP *aGroup)
virtual const wxString & GetText() const
Return the string associated with the text object.
virtual bool IsVisible() const
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
virtual void SetVisible(bool aVisible)
const TEXT_ATTRIBUTES & GetAttributes() const
wxString AsString() const
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
VALUE * Run(CONTEXT *ctx)
virtual double AsDouble() const
LSET is a set of PCB_LAYER_IDs.
bool ContainsAll(const LSET &aLayers) const
See if this layer set contains all layers in another set.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Handle the data for a net.
const wxString & GetNetname() const
const wxString & GetNumber() const
void SetItems(BOARD_ITEM *a, BOARD_ITEM *b=nullptr)
static TOOL_ACTION repeatLayout
static TOOL_ACTION generatePlacementRuleAreas
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
PCB_GENERATOR * DeepClone() const
void Move(const VECTOR2I &aMoveVector) override
Move this object.
A set of BOARD_ITEMs (i.e., without duplicates).
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
EDA_ANGLE GetTextAngle() const override
VECTOR2I GetPosition() const override
void SetPosition(const VECTOR2I &aPos) override
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void SetTextAngle(const EDA_ANGLE &aAngle) override
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
A small class to help profiling.
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
virtual void CacheTriangulation(bool aSimplify=false, const TASK_SUBMITTER &aSubmitter={})
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
static std::unique_ptr< CONNECTION_GRAPH > BuildFromFootprintSet(const std::set< FOOTPRINT * > &aFps, const std::set< FOOTPRINT * > &aOtherChannelFps={}, const std::unordered_set< int > &aGlobalNets={})
Define a general 2D-vector/point.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
wxString GetPlacementAreaSource() const
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
SHAPE_POLY_SET * Outline()
const wxString & GetZoneName() const
bool GetPlacementAreaEnabled() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
void UnHatchBorder()
Clear the zone's hatch.
void RemoveAllContours(void)
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
SHAPE_LINE_CHAIN RectifyPolygon(const SHAPE_LINE_CHAIN &aPoly)
Take a polygon and 'rectify' it, so that all sides are H/V.
void CollectBoxCorners(const BOX2I &aBox, std::vector< VECTOR2I > &aCorners)
Add the 4 corners of a BOX2I to a vector.
std::map< FOOTPRINT *, FOOTPRINT * > COMPONENT_MATCHES
Class to handle a set of BOARD_ITEMs.
PGM_BASE & Pgm()
The global program "get" accessor.
Utility functions for working with shapes.
void AccumulateDescription(wxString &aDesc, const wxString &aItem)
Utility to build comma separated lists in messages.
bool m_connectedRoutingOnly
bool m_includeLockedItems
std::vector< wxString > m_mismatchReasons
std::unordered_set< BOARD_ITEM * > m_affectedItems
Filled in by copyRuleAreaContents with items that were affected by the copy operation.
TMATCH::COMPONENT_MATCHES m_matchingComponents
std::unordered_set< BOARD_ITEM * > m_groupableItems
Filled in by copyRuleAreaContents with affected items that can be grouped together.
std::unordered_set< EDA_ITEM * > m_designBlockItems
PLACEMENT_SOURCE_T m_sourceType
wxString m_componentClass
std::set< FOOTPRINT * > m_components
std::atomic< bool > * m_cancelled
std::atomic< int > * m_matchedComponents
std::atomic< int > * m_totalComponents
IbisParser parser & reporter
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I