54#define MULTICHANNEL_EXTRA_DEBUG
78 std::set<FOOTPRINT*>& aComponents )
84 auto reportError = [&](
const wxString& aMessage,
int aOffset )
100 case RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME:
106 case RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS:
110 case RULE_AREA_PLACEMENT_SOURCE_TYPE::GROUP_PLACEMENT:
115 auto ok = compiler.
Compile( ruleText, &ucode, &preflightCtx );
125 auto val = ucode.
Run( &ctx );
126 if( val->AsDouble() != 0.0 )
129 fp->GetSheetname() );
131 aComponents.insert( fp );
141 std::vector<BOARD_ITEM*> result;
147 auto reportError = [&](
const wxString& aMessage,
int aOffset )
156 bool restoreBlankName =
false;
160 restoreBlankName =
true;
164 wxString ruleText = wxString::Format( wxT(
"A.enclosedByArea('%s')" ), aRuleArea->
GetZoneName() );
166 if( !compiler.
Compile( ruleText, &ucode, &preflightCtx ) )
168 if( restoreBlankName )
178 auto val = ucode.
Run( &ctx );
180 if( val->AsDouble() != 0.0 )
181 aItems.insert( aItem );
186 if( zone == aRuleArea )
193 testAndAdd( drawing );
198 bool addGroup =
true;
200 group->RunOnChildren(
203 if( aItem->
IsType( { PCB_ZONE_T, PCB_SHAPE_T, PCB_DIMENSION_T } ) )
205 ctx.SetItems( aItem, aItem );
206 auto val = ucode.Run( &ctx );
208 if( val->AsDouble() == 0.0 )
212 RECURSE_MODE::RECURSE );
215 aItems.insert(
group );
218 if( restoreBlankName )
227 std::set<FOOTPRINT*> rv;
228 if( aSheetName.EndsWith( wxT(
"/" ) ) )
229 aSheetName.RemoveLast();
231 for(
auto& fp :
board()->Footprints() )
233 auto sn = fp->GetSheetname();
234 if( sn.EndsWith( wxT(
"/" ) ) )
237 if( sn == aSheetName )
250 std::set<FOOTPRINT*> rv;
252 for(
auto& fp :
board()->Footprints() )
254 if( fp->GetComponentClass()->ContainsClassName( aComponentClassName ) )
265 std::set<FOOTPRINT*> rv;
269 if(
group->GetName() == aGroupName )
274 rv.insert(
static_cast<FOOTPRINT*
>( item ) );
286 std::vector<VECTOR2I> bbCorners;
287 bbCorners.reserve( aFootprints.size() * 4 );
289 for(
auto fp : aFootprints )
295 std::vector<VECTOR2I> hullVertices;
307 using PathAndName = std::pair<wxString, wxString>;
308 std::set<PathAndName> uniqueSheets;
309 std::set<wxString> uniqueComponentClasses;
310 std::set<wxString> uniqueGroups;
316 uniqueSheets.insert( PathAndName( fp->GetSheetname(), fp->GetSheetfile() ) );
321 uniqueComponentClasses.insert( singleClass->GetName() );
323 if( fp->GetParentGroup() && !fp->GetParentGroup()->GetName().IsEmpty() )
324 uniqueGroups.insert( fp->GetParentGroup()->GetName() );
327 for(
const PathAndName& sheet : uniqueSheets )
331 ent.
m_sourceType = RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME;
342 for(
const wxString& compClass : uniqueComponentClasses )
346 ent.
m_sourceType = RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS;
356 for(
const wxString& groupName : uniqueGroups )
360 ent.
m_sourceType = RULE_AREA_PLACEMENT_SOURCE_TYPE::GROUP_PLACEMENT;
378 if( !zone->GetIsRuleArea() )
380 if( !zone->GetRuleAreaPlacementEnabled() )
391 area.
m_center = zone->Outline()->COutline( 0 ).Centre();
421 std::vector<ZONE*> refRAs;
423 auto isSelectedItemAnRA = [](
EDA_ITEM* aItem ) ->
ZONE*
428 ZONE* zone =
static_cast<ZONE*
>( aItem );
441 if(
auto zone = isSelectedItemAnRA( item ) )
443 refRAs.push_back(zone);
451 if(
auto grpZone = isSelectedItemAnRA( grpItem ) )
453 refRAs.push_back( grpZone );
459 if( refRAs.size() != 1 )
464 _(
"Select a reference Rule Area to copy from..." ),
467 return isSelectedItemAnRA( aItem ) !=
nullptr;
483 frame()->ShowInfoBarError(
_(
"No Rule Areas to repeat layout to have been found." ),
504 if( ra.
m_area == aRefZone )
538 if( !targetArea.second.m_doCopy )
541 targetArea.first->m_ruleName );
545 if( !targetArea.second.m_isOk )
551 targetArea.second.m_groupableItems ) )
553 auto errMsg = wxString::Format(
554 _(
"Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
556 targetArea.first->m_area->GetZoneName() );
562 frame()->ShowInfoBarError( errMsg,
true );
571 commit.
Push(
_(
"Repeat layout" ) );
583 grpCommit.
Add( grp );
585 for(
BOARD_ITEM* item : targetArea.second.m_groupableItems )
591 grpCommit.
Push(
_(
"Group repeated items" ) );
597 frame()->ShowInfoBarMsg( wxString::Format(
_(
"Copied to %d Rule Areas." ), totalCopied ),
617 if( ( c >=
'a' && c <=
'z' ) || ( c >=
'A' && c <=
'Z' ) || ( c ==
'_' ) )
628 std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
634 std::set<BOARD_ITEM*> conns;
641 conns.insert( item );
653 std::shared_ptr<SHAPE> effShape = item->GetEffectiveShape( item->GetLayer() );
655 if( effShape->Collide( &aRAPoly, 0 ) )
657 aOutput.insert( item );
669 auto reportError = [&](
const wxString& aMessage,
int aOffset )
678 bool restoreBlankName =
false;
682 restoreBlankName =
true;
686 wxString ruleText = wxString::Format( wxT(
"A.enclosedByArea('%s')" ),
692 if( aOutput.contains( aItem ) )
696 auto val = ucode.
Run( &ctx );
698 if( val->AsDouble() != 0.0 )
700 aOutput.insert( aItem );
705 if( compiler.
Compile( ruleText, &ucode, &preflightCtx ) )
711 if( restoreBlankName )
722 std::unordered_set<BOARD_ITEM*>& aAffectedItems,
723 std::unordered_set<BOARD_ITEM*>& aGroupableItems )
738 newTargetOutline.
Move( disp );
746 aAffectedItems.insert( aTargetArea->
m_area );
747 aGroupableItems.insert( aTargetArea->
m_area );
751 std::set<BOARD_ITEM*> refRouting;
752 std::set<BOARD_ITEM*> targetRouting;
756 for(
auto& fpPair : aMatches )
759 fpPair.second, aOpts );
777 aAffectedItems.insert( item );
798 copied->SetParentGroup(
nullptr );
800 aGroupableItems.insert(
copied );
807 std::set<BOARD_ITEM*> sourceItems;
808 std::set<BOARD_ITEM*> targetItems;
815 if( item->Type() ==
PCB_TEXT_T && item->GetParent()
830 aAffectedItems.insert( item );
836 ZONE* zone =
static_cast<ZONE*
>( item );
839 bool layerMismatch =
false;
845 layerMismatch =
true;
850 aAffectedItems.insert( zone );
858 if( item->Type() ==
PCB_TEXT_T && item->GetParent()
882 ZONE* zone =
static_cast<ZONE*
>( item );
885 bool layerMismatch =
false;
893 layerMismatch =
true;
900 ZONE* targetZone =
static_cast<ZONE*
>( item->Clone() );
901 fixupNet( zone, targetZone, aMatches );
909 copied->SetParentGroup(
nullptr );
912 aGroupableItems.insert(
copied );
925 for(
auto& fpPair : aMatches )
950 aCommit->
Modify( targetFP );
959 if( !refField->IsVisible() )
963 wxCHECK2( targetField,
continue );
966 targetField->
SetPosition( refField->GetPosition() + disp );
970 aAffectedItems.insert( targetFP );
971 aGroupableItems.insert( targetFP );
986 const std::vector<BOARD_CONNECTED_ITEM*> refConnectedPads =
987 connectivity->GetNetItems( aRef->
GetNetCode(), { PCB_PAD_T } );
994 const PAD* refPad =
static_cast<const PAD*
>( refConItem );
997 if( aComponentMatches.contains( sourceFootprint ) )
999 const FOOTPRINT* targetFootprint = aComponentMatches[sourceFootprint];
1000 std::vector<const PAD*> targetFpPads = targetFootprint->
GetPads( refPad->
GetNumber() );
1002 if( !targetFpPads.empty() )
1004 int targetNetCode = targetFpPads[0]->GetNet()->GetNetCode();
1019 std::unique_ptr<CONNECTION_GRAPH> cgRef ( CONNECTION_GRAPH::BuildFromFootprintSet( aRefArea->
m_raFootprints ) );
1020 std::unique_ptr<CONNECTION_GRAPH> cgTarget ( CONNECTION_GRAPH::BuildFromFootprintSet( aTargetArea->
m_raFootprints ) );
1026 case CONNECTION_GRAPH::ST_OK:
1030 case CONNECTION_GRAPH::ST_EMPTY:
1032 aMatches.
m_errorMsg =
_(
"One or both of the areas has no components assigned.");
1034 case CONNECTION_GRAPH::ST_COMPONENT_COUNT_MISMATCH:
1036 aMatches.
m_errorMsg =
_(
"Component count mismatch");
1038 case CONNECTION_GRAPH::ST_ITERATION_COUNT_EXCEEDED:
1040 aMatches.
m_errorMsg =
_(
"Iteration count exceeded (timeout)");
1042 case CONNECTION_GRAPH::ST_TOPOLOGY_MISMATCH:
1055 const std::unordered_set<BOARD_ITEM*>& aItemsToRemove )
1057 std::deque<PCB_GROUP*> pending (
board()->Groups() );
1058 while( !pending.empty() )
1060 auto grp = pending.front();
1061 pending.pop_front();
1063 std::unordered_set<EDA_ITEM*>& grpItems = grp->GetItems();
1064 size_t n_erased = 0;
1066 for(
EDA_ITEM* refItem : grpItems )
1069 pending.push_back(
static_cast<PCB_GROUP*
>(refItem) );
1073 if( refItem->m_Uuid == testItem->m_Uuid )
1081 if( n_erased == grpItems.size() )
1100 frame()->ShowInfoBarError(
_(
"Cannot auto-generate any placement areas because the "
1101 "schematic has only one or no hierarchical sheet(s) or "
1102 "component classes." ),
1110 if( ret != wxID_OK )
1116 if( !zone->GetIsRuleArea() )
1118 if( !zone->GetRuleAreaPlacementEnabled() )
1121 std::set<FOOTPRINT*> components;
1124 if( components.empty() )
1131 if( zone->GetRuleAreaPlacementSourceType()
1132 == RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME )
1136 wxT(
"Placement rule area for sheet '%s' already exists as '%s'\n" ),
1139 else if( zone->GetRuleAreaPlacementSourceType()
1140 == RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS )
1143 wxT(
"Placement rule area for component class '%s' already exists "
1150 wxT(
"Placement rule area for group '%s' already exists "
1162 wxT(
"%d placement areas found\n" ), (
int)
m_areas.
m_areas.size() );
1179 std::unique_ptr<ZONE> newZone(
new ZONE(
board() ) );
1181 if( ra.
m_sourceType == RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME )
1183 newZone->SetZoneName(
1184 wxString::Format( wxT(
"auto-placement-area-%s" ), ra.
m_sheetPath ) );
1186 else if( ra.
m_sourceType == RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS )
1188 newZone->SetZoneName(
1189 wxString::Format( wxT(
"auto-placement-area-%s" ), ra.
m_componentClass ) );
1193 newZone->SetZoneName( wxString::Format( wxT(
"auto-placement-area-%s" ), ra.
m_groupName ) );
1197 newZone->GetZoneName(), (
int) ra.
m_components.size() );
1199 newZone->SetIsRuleArea(
true );
1201 newZone->SetRuleAreaPlacementEnabled(
true );
1202 newZone->SetDoNotAllowZoneFills(
false );
1203 newZone->SetDoNotAllowVias(
false );
1204 newZone->SetDoNotAllowTracks(
false );
1205 newZone->SetDoNotAllowPads(
false );
1206 newZone->SetDoNotAllowFootprints(
false );
1208 if( ra.
m_sourceType == RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME )
1210 newZone->SetRuleAreaPlacementSourceType( RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME );
1211 newZone->SetRuleAreaPlacementSource( ra.
m_sheetPath );
1213 else if( ra.
m_sourceType == RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS )
1215 newZone->SetRuleAreaPlacementSourceType(
1216 RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS );
1221 newZone->SetRuleAreaPlacementSourceType( RULE_AREA_PLACEMENT_SOURCE_TYPE::GROUP_PLACEMENT );
1222 newZone->SetRuleAreaPlacementSource( ra.
m_groupName );
1225 newZone->AddPolygon( raOutline );
1226 newZone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
1233 ra.
m_area = newZone.get();
1234 commit.
Add( newZone.release() );
1237 commit.
Push(
_(
"Auto-generate placement rule areas" ) );
1255 std::unordered_set<BOARD_ITEM*> toPrune;
1258 std::inserter( toPrune, toPrune.begin() ) );
1261 toPrune.insert( ra.
m_area );
1267 grpCommit.
Add( grp );
1275 grpCommit.
Push(
_(
"Group components with their placement rule areas" ) );
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
Add a change of the item aItem of type aChangeType to the change list.
virtual 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,...
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 SetIsKnockout(bool aKnockout)
FOOTPRINT * GetParentFootprint() const
const ZONES & Zones() const
const TRACKS & Tracks() 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.
virtual COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr)
Add a change of the item aItem of type aChangeType to the change list.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
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.
A base class for most all the KiCad significant classes used in schematics and boards.
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
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)
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
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.
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.
A set of BOARD_ITEMs (i.e., without duplicates).
virtual void SetPosition(const VECTOR2I &aPos) override
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
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
wxString GetRuleAreaPlacementSource() const
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
bool GetRuleAreaPlacementEnabled() const
SHAPE_POLY_SET * Outline()
const wxString & GetZoneName() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
RULE_AREA_PLACEMENT_SOURCE_TYPE GetRuleAreaPlacementSourceType() const
void SetZoneName(const wxString &aName)
void UnHatchBorder()
Clear the zone's hatch.
void RemoveAllContours(void)
#define IGNORE_NETS
Function GetConnectedItems() Returns a list of items connected to a source item aItem.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
PCB_LAYER_ID
A quick note on layer IDs:
SHAPE_LINE_CHAIN RectifyPolygon(const SHAPE_LINE_CHAIN &aPoly)
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.
bool m_includeLockedItems
std::unordered_map< RULE_AREA *, RULE_AREA_COMPAT_DATA > m_compatMap
REPEAT_LAYOUT_OPTIONS m_options
std::vector< RULE_AREA > m_areas
TMATCH::COMPONENT_MATCHES m_matchingComponents
RULE_AREA_PLACEMENT_SOURCE_TYPE m_sourceType
wxString m_componentClass
std::set< FOOTPRINT * > m_raFootprints
std::set< FOOTPRINT * > m_components
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper 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_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint