55#define MULTICHANNEL_EXTRA_DEBUG
79 std::set<FOOTPRINT*>& aComponents )
81 if( !aRuleArea || !aRuleArea->
m_zone )
92 aComponents.insert(
static_cast<FOOTPRINT*
>( item ) );
95 return (
int) aComponents.size();
104 [&](
const wxString& aMessage,
int aOffset )
134 auto ok = compiler.
Compile( ruleText, &ucode, &preflightCtx );
148 fp->GetSheetname() );
150 aComponents.insert( fp );
160 if( !aRuleArea || !aRuleArea->
m_zone )
178 aItems.insert(
static_cast<BOARD_ITEM*
>( item ) );
181 return (
int) aItems.size();
184 std::vector<BOARD_ITEM*>
result;
191 [&](
const wxString& aMessage,
int aOffset )
200 bool restoreBlankName =
false;
204 restoreBlankName =
true;
208 wxString ruleText = wxString::Format( wxT(
"A.enclosedByArea('%s')" ), aRuleArea->
m_zone->
GetZoneName() );
210 if( !compiler.
Compile( ruleText, &ucode, &preflightCtx ) )
212 if( restoreBlankName )
222 auto val = ucode.
Run( &ctx );
224 if( val->AsDouble() != 0.0 )
225 aItems.insert( aItem );
230 if( zone == aRuleArea->
m_zone )
237 testAndAdd( drawing );
242 bool addGroup =
true;
244 group->RunOnChildren(
247 if( aItem->
IsType( { PCB_ZONE_T, PCB_SHAPE_T, PCB_DIMENSION_T } ) )
259 aItems.insert(
group );
262 if( restoreBlankName )
271 std::set<FOOTPRINT*> rv;
273 if( aSheetName.EndsWith( wxT(
"/" ) ) )
274 aSheetName.RemoveLast();
278 auto sn = fp->GetSheetname();
279 if( sn.EndsWith( wxT(
"/" ) ) )
282 if( sn == aSheetName )
293 std::set<FOOTPRINT*> rv;
297 if( fp->GetComponentClass()->ContainsClassName( aComponentClassName ) )
307 std::set<FOOTPRINT*> rv;
311 if(
group->GetName() == aGroupName )
316 rv.insert(
static_cast<FOOTPRINT*
>( item ) );
328 std::vector<VECTOR2I> bbCorners;
329 bbCorners.reserve( aFootprints.size() * 4 );
333 const BOX2I bb = fp->GetBoundingBox(
false ).GetInflated( aMargin );
337 std::vector<VECTOR2I> hullVertices;
349 using PathAndName = std::pair<wxString, wxString>;
350 std::set<PathAndName> uniqueSheets;
351 std::set<wxString> uniqueComponentClasses;
352 std::set<wxString> uniqueGroups;
358 uniqueSheets.insert( PathAndName( fp->GetSheetname(), fp->GetSheetfile() ) );
363 uniqueComponentClasses.insert( singleClass->GetName() );
365 if( fp->GetParentGroup() && !fp->GetParentGroup()->GetName().IsEmpty() )
366 uniqueGroups.insert( fp->GetParentGroup()->GetName() );
369 for(
const PathAndName& sheet : uniqueSheets )
378 m_areas.m_areas.push_back( ent );
383 (
int)
m_areas.m_areas.size() );
386 for(
const wxString& compClass : uniqueComponentClasses )
394 m_areas.m_areas.push_back( ent );
398 static_cast<int>(
m_areas.m_areas.size() ) );
401 for(
const wxString& groupName : uniqueGroups )
409 m_areas.m_areas.push_back( ent );
413 static_cast<int>(
m_areas.m_areas.size() ) );
424 if( !zone->GetIsRuleArea() )
427 if( !zone->GetPlacementAreaEnabled() )
435 area.
m_center = zone->Outline()->COutline( 0 ).Centre();
439 m_areas.m_areas.push_back( area );
469 std::vector<ZONE*> refRAs;
471 auto isSelectedItemAnRA =
477 ZONE* zone =
static_cast<ZONE*
>( aItem );
490 if(
auto zone = isSelectedItemAnRA( item ) )
492 refRAs.push_back(zone);
500 if(
auto grpZone = isSelectedItemAnRA( grpItem ) )
501 refRAs.push_back( grpZone );
506 if( refRAs.size() != 1 )
511 _(
"Select a reference Rule Area to copy from..." ),
514 return isSelectedItemAnRA( aItem ) !=
nullptr;
528 if(
m_areas.m_areas.size() <= 1 )
530 frame()->ShowInfoBarError(
_(
"No Rule Areas to repeat layout to have been found." ),
true );
550 if( ra.
m_zone == aRefZone )
584 auto errMsg = wxString::Format(
_(
"Rule Area topologies do not match: %s" ), compat.
m_errorMsg );
585 frame()->ShowInfoBarError( errMsg,
true );
594 auto errMsg = wxString::Format(
_(
"Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
601 frame()->ShowInfoBarError( errMsg,
true );
615 frame()->ShowInfoBarError(
_(
"Target group does not have a group." ),
true );
628 group->AddItem( item );
632 commit.
Push(
_(
"Repeat layout" ) );
643 for(
auto& targetArea :
m_areas.m_compatMap )
645 if( !targetArea.second.m_doCopy )
648 targetArea.first->m_ruleName );
652 if( !targetArea.second.m_isOk )
657 auto errMsg = wxString::Format(
658 _(
"Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
659 m_areas.m_refRA->m_zone->GetZoneName(),
660 targetArea.first->m_zone->GetZoneName() );
665 frame()->ShowInfoBarError( errMsg,
true );
673 if(
m_areas.m_options.m_groupItems )
675 for(
const auto& [targetArea, compatData] :
m_areas.m_compatMap )
683 for(
BOARD_ITEM* item : compatData.m_groupableItems )
686 group->AddItem( item );
691 commit.
Push(
_(
"Repeat layout" ) );
694 frame()->ShowInfoBarMsg( wxString::Format(
_(
"Copied to %d Rule Areas." ), totalCopied ),
true );
714 if( ( c >=
'a' && c <=
'z' ) || ( c >=
'A' && c <=
'Z' ) || ( c ==
'_' ) )
725 std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
728 if( !aRuleArea || !aRuleArea->
m_zone )
749 aOutput.insert( bci );
752 return (
int) aOutput.size();
759 auto reportError = [&](
const wxString& aMessage,
int aOffset )
768 bool restoreBlankName =
false;
772 restoreBlankName =
true;
776 wxString ruleText = wxString::Format( wxT(
"A.enclosedByArea('%s')" ), aRuleArea->
m_zone->
GetZoneName() );
781 if( aOutput.contains( aItem ) )
789 aOutput.insert( aItem );
794 if( compiler.
Compile( ruleText, &ucode, &preflightCtx ) )
800 if( restoreBlankName )
824 targetAnchorFp = fpPair.second;
834 disp = newpos - oldpos;
847 newTargetOutline.
Move( disp );
856 bool targetZoneOnBoard =
false;
862 if( z == aTargetArea->
m_zone )
864 targetZoneOnBoard =
true;
870 if( targetZoneOnBoard )
879 std::set<BOARD_CONNECTED_ITEM*> refRouting;
880 std::set<BOARD_CONNECTED_ITEM*> targetRouting;
890 for(
PAD*
pad : fpPair.first->Pads() )
891 refc.insert(
pad->GetNetCode() );
893 for(
PAD*
pad : fpPair.second->Pads() )
894 targc.insert(
pad->GetNetCode() );
941 copied->SetParentGroup(
nullptr );
950 std::set<BOARD_ITEM*> sourceItems;
951 std::set<BOARD_ITEM*> targetItems;
978 ZONE* zone =
static_cast<ZONE*
>( item );
981 bool layerMismatch =
false;
987 layerMismatch =
true;
1022 ZONE* zone =
static_cast<ZONE*
>( item );
1025 bool layerMismatch =
false;
1033 layerMismatch =
true;
1040 ZONE* targetZone =
static_cast<ZONE*
>( item->Clone() );
1049 copied->SetParentGroup(
nullptr );
1086 aCommit->
Modify( targetFP );
1092 targetFP->
Move( disp );
1095 if( !refField->IsVisible() )
1099 wxCHECK2( targetField,
continue );
1102 targetField->
SetPosition( refField->GetPosition() );
1104 targetField->
Move( disp );
1129 const std::vector<BOARD_CONNECTED_ITEM*> refConnectedPads = connectivity->
GetNetItems( aRef->
GetNetCode(),
1137 const PAD* refPad =
static_cast<const PAD*
>( refConItem );
1140 if( aComponentMatches.contains( sourceFootprint ) )
1142 const FOOTPRINT* targetFootprint = aComponentMatches[sourceFootprint];
1143 std::vector<const PAD*> targetFpPads = targetFootprint->
GetPads( refPad->
GetNumber() );
1145 if( !targetFpPads.empty() )
1147 int targetNetCode = targetFpPads[0]->GetNet()->GetNetCode();
1175 aMatches.
m_errorMsg =
_(
"One or both of the areas has no components assigned." );
1179 aMatches.
m_errorMsg =
_(
"Component count mismatch" );
1183 aMatches.
m_errorMsg =
_(
"Iteration count exceeded (timeout)" );
1198 const std::unordered_set<BOARD_ITEM*>& aItemsToRemove )
1204 std::vector<EDA_ITEM*> pruneList;
1210 if( refItem->m_Uuid == testItem->m_Uuid )
1211 pruneList.push_back( refItem );
1215 if( !pruneList.empty() )
1220 group->RemoveItem( item );
1222 if(
group->GetItems().empty() )
1237 if(
m_areas.m_areas.size() <= 1 )
1239 frame()->ShowInfoBarError(
_(
"Cannot auto-generate any placement areas because the "
1240 "schematic has only one or no hierarchical sheets, "
1241 "groups, or component classes." ),
1249 if( ret != wxID_OK )
1255 if( !zone->GetIsRuleArea() )
1258 if( !zone->GetPlacementAreaEnabled() )
1261 std::set<FOOTPRINT*> components;
1264 zoneRA.
m_sourceType = zone->GetPlacementAreaSourceType();
1267 if( components.empty() )
1277 wxT(
"Placement rule area for sheet '%s' already exists as '%s'\n" ),
1283 wxT(
"Placement rule area for component class '%s' already exists as '%s'\n" ),
1289 wxT(
"Placement rule area for group '%s' already exists as '%s'\n" ),
1316 std::unique_ptr<ZONE> newZone(
new ZONE(
board() ) );
1319 newZone->SetZoneName( wxString::Format( wxT(
"auto-placement-area-%s" ), ra.
m_sheetPath ) );
1321 newZone->SetZoneName( wxString::Format( wxT(
"auto-placement-area-%s" ), ra.
m_componentClass ) );
1323 newZone->SetZoneName( wxString::Format( wxT(
"auto-placement-area-%s" ), ra.
m_groupName ) );
1326 newZone->GetZoneName(),
1329 newZone->SetIsRuleArea(
true );
1331 newZone->SetPlacementAreaEnabled(
true );
1332 newZone->SetDoNotAllowZoneFills(
false );
1333 newZone->SetDoNotAllowVias(
false );
1334 newZone->SetDoNotAllowTracks(
false );
1335 newZone->SetDoNotAllowPads(
false );
1336 newZone->SetDoNotAllowFootprints(
false );
1341 newZone->SetPlacementAreaSource( ra.
m_sheetPath );
1351 newZone->SetPlacementAreaSource( ra.
m_groupName );
1354 newZone->AddPolygon( raOutline );
1362 ra.
m_zone = newZone.release();
1369 if(
m_areas.m_options.m_groupItems )
1379 std::unordered_set<BOARD_ITEM*> toPrune;
1384 toPrune.insert( ra.
m_zone );
1398 group->AddItem( fp );
1403 commit.
Push(
_(
"Auto-generate placement rule areas" ) );
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
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
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
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
Function GetNetItems() Returns the list of items that belong to a certain net.
A set of EDA_ITEMs (i.e., without duplicates).
A base class for most all the KiCad significant classes used in schematics and boards.
KICAD_T Type() const
Returns the type of object.
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.
bool IsBOARD_ITEM() 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.
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.
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
void Move(const VECTOR2I &aMoveVector) override
Move this object.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
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.
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
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
@ ST_COMPONENT_COUNT_MISMATCH
@ ST_ITERATION_COUNT_EXCEEDED
static std::unique_ptr< CONNECTION_GRAPH > BuildFromFootprintSet(const std::set< FOOTPRINT * > &aFps)
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 SetZoneName(const wxString &aName)
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.
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_connectedRoutingOnly
bool m_includeLockedItems
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
wxString result
Test unit parsing edge cases and error handling.
@ 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
VECTOR2< int32_t > VECTOR2I