34#include <unordered_map>
35#include <unordered_set>
55 if( a.size() != b.size() )
60 for(
size_t lineChainId = 0; lineChainId < a.size(); lineChainId++ )
78 const auto zonesAreMergeable = [&](
const ZONE& a,
const ZONE& b ) ->
bool
81 if( a.GetIsRuleArea() != b.GetIsRuleArea() )
84 if( a.GetIsRuleArea() )
92 if( a.GetNetCode() != b.GetNetCode() )
113 return polygonsAreMergeable( polyA, polyB );
116 std::vector<std::unique_ptr<ZONE>> deduplicatedZones;
119 std::vector<bool> merged( aZones.size(),
false );
121 for(
size_t i = 0; i < aZones.size(); i++ )
128 ZONE& primary = *aZones[i];
130 std::unordered_map<PCB_LAYER_ID, SHAPE_POLY_SET> mergedFills;
132 for(
size_t j = i + 1; j < aZones.size(); j++ )
139 ZONE& candidate = *aZones[j];
140 bool canMerge = zonesAreMergeable( primary, candidate );
147 mergedFills[layer] = *fill;
160 mergedFills[layer] = *fill;
165 for(
const auto& [layer, fill] : mergedFills )
173 deduplicatedZones.push_back( std::move( aZones[i] ) );
176 return deduplicatedZones;
183struct ZONE_OVERLAP_PAIR
191struct ZONE_PRIORITY_EDGE
204 std::vector<ZONE_OVERLAP_PAIR> pairs;
207 for(
size_t i = 0; i < zones.size(); i++ )
216 for(
size_t j = i + 1; j < zones.size(); j++ )
247 bool overlaps = aOutline->
Collide( bOutline )
252 pairs.push_back( { a, b, shared } );
281 if( netCodeA == netCodeB )
287 auto countIfInOverlap =
290 if( !aPair.sharedLayers.test( aLayer ) )
295 if( aNetCode == netCodeA )
297 else if( aNetCode == netCodeB )
304 for(
PAD*
pad : fp->Pads() )
308 if(
pad->IsOnLayer( layer ) )
310 countIfInOverlap(
pad->GetPosition(),
pad->GetNetCode(), layer );
326 if(
via->IsOnLayer( layer ) )
328 countIfInOverlap(
via->GetPosition(),
via->GetNetCode(), layer );
334 if( countA == 0 && countB == 0 )
344 ZONE* higher = ( areaA < areaB ) ? aPair.zoneA : aPair.zoneB;
345 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
346 return ZONE_PRIORITY_EDGE{ higher, lower, 0,
true };
349 int maxCount = std::max( countA, countB );
350 int diff =
std::abs( countA - countB );
351 double ratio =
static_cast<double>( diff ) / maxCount;
353 constexpr double SIMILARITY_THRESHOLD = 0.20;
355 if( ratio < SIMILARITY_THRESHOLD )
365 ZONE* higher = ( areaA < areaB ) ? aPair.zoneA : aPair.zoneB;
366 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
367 return ZONE_PRIORITY_EDGE{ higher, lower, diff,
true };
370 ZONE* higher = ( countA > countB ) ? aPair.zoneA : aPair.zoneB;
371 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
372 return ZONE_PRIORITY_EDGE{ higher, lower, diff,
false };
378 std::unordered_map<ZONE*, std::vector<ZONE*>> adj;
379 std::unordered_map<ZONE*, int> inDegree;
380 std::unordered_set<ZONE*> inGraph;
382 for(
ZONE* z : aAllZones )
389 std::vector<ZONE_PRIORITY_EDGE> sortedEdges = aEdges;
391 std::sort( sortedEdges.begin(), sortedEdges.end(),
392 [](
const ZONE_PRIORITY_EDGE& a,
const ZONE_PRIORITY_EDGE& b )
394 if( a.fromArea != b.fromArea )
397 return a.countDiff < b.countDiff;
400 for(
const ZONE_PRIORITY_EDGE& edge : sortedEdges )
402 adj[edge.higher].push_back( edge.lower );
403 inDegree[edge.lower]++;
408 std::vector<ZONE*> queue;
410 for(
ZONE* z : aAllZones )
412 if( inDegree[z] == 0 )
413 queue.push_back( z );
416 std::sort( queue.begin(), queue.end(),
419 return a->GetAssignedPriority() < b->GetAssignedPriority();
422 std::vector<ZONE*> topoOrder;
423 topoOrder.reserve( aAllZones.size() );
425 while( !queue.empty() )
427 ZONE* current = queue.front();
428 queue.erase( queue.begin() );
429 topoOrder.push_back( current );
431 auto& neighbors = adj[current];
433 std::sort( neighbors.begin(), neighbors.end(),
436 return a->GetAssignedPriority() < b->GetAssignedPriority();
439 for(
ZONE* neighbor : neighbors )
441 inDegree[neighbor]--;
443 if( inDegree[neighbor] == 0 )
444 queue.push_back( neighbor );
447 std::sort( queue.begin(), queue.end(),
450 return a->GetAssignedPriority() < b->GetAssignedPriority();
455 if( topoOrder.size() < aAllZones.size() )
457 std::unordered_set<ZONE*> ordered( topoOrder.begin(), topoOrder.end() );
458 std::vector<ZONE*> remaining;
460 for(
ZONE* z : aAllZones )
462 if( ordered.find( z ) == ordered.end() )
463 remaining.push_back( z );
466 std::sort( remaining.begin(), remaining.end(),
469 return a->GetAssignedPriority() < b->GetAssignedPriority();
472 for(
ZONE* z : remaining )
473 topoOrder.push_back( z );
477 for(
size_t i = 0; i < topoOrder.size(); i++ )
478 topoOrder[i]->SetAssignedPriority(
static_cast<unsigned>( topoOrder.size() - 1 - i ) );
484 ZONE*& parent = aParent[aZone];
486 if( parent != aZone )
487 parent =
ufFind( aParent, parent );
493static void ufUnion( std::unordered_map<ZONE*, ZONE*>& aParent, std::unordered_map<ZONE*, int>& aRank,
502 if( aRank[rootA] < aRank[rootB] )
503 std::swap( rootA, rootB );
505 aParent[rootB] = rootA;
507 if( aRank[rootA] == aRank[rootB] )
514 std::vector<ZONE*> eligibleZones;
518 if( !zone->GetIsRuleArea() && !zone->IsTeardropArea() && zone->IsOnCopperLayer() )
519 eligibleZones.push_back( zone );
522 if( eligibleZones.size() < 2 )
525 std::unordered_map<ZONE*, unsigned> originalPriorities;
527 for(
ZONE* z : eligibleZones )
528 originalPriorities[z] = z->GetAssignedPriority();
537 std::unordered_map<ZONE*, ZONE*> ufParent;
538 std::unordered_map<ZONE*, int> ufRank;
540 for(
ZONE* z : eligibleZones )
546 for(
const ZONE_OVERLAP_PAIR& pair : pairs )
548 if( pair.zoneA->GetNetCode() == pair.zoneB->GetNetCode() )
549 ufUnion( ufParent, ufRank, pair.zoneA, pair.zoneB );
553 std::vector<std::future<std::optional<ZONE_PRIORITY_EDGE>>> futures;
554 futures.reserve( pairs.size() );
556 for(
const ZONE_OVERLAP_PAIR& pair : pairs )
558 if( pair.zoneA->GetNetCode() == pair.zoneB->GetNetCode() )
561 futures.emplace_back(
tp.submit_task(
564 return computeConstraint( pair, aBoard );
568 std::vector<ZONE_PRIORITY_EDGE> edges;
570 for(
auto& future : futures )
572 std::optional<ZONE_PRIORITY_EDGE>
result = future.get();
575 edges.push_back(
result.value() );
584 std::unordered_map<ZONE*, unsigned> groupMax;
586 for(
ZONE* z : eligibleZones )
589 unsigned pri = z->GetAssignedPriority();
590 auto& maxPri = groupMax[root];
596 for(
ZONE* z : eligibleZones )
599 z->SetAssignedPriority( groupMax[root] );
602 for(
ZONE* z : eligibleZones )
604 if( z->GetAssignedPriority() != originalPriorities[z] )
FOOTPRINT * GetParentFootprint() const
Information pertinent to a Pcbnew printed circuit board.
const ZONES & Zones() const
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
constexpr bool Intersects(const BOX2< Vec > &aRect) const
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
A progress reporter interface for use in multi-threaded environments.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int PointCount() const
Return the number of points (vertices) in this line chain.
bool CompareGeometry(const SHAPE_LINE_CHAIN &aOther, bool aCyclicalCompare=false, int aEpsilon=0) const
Compare this line chain with another one.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
double Area()
Return the area of this poly set.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int TotalVertices() const
Return total number of vertices stored in the set.
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
int OutlineCount() const
Return the number of outlines in the set.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
const POLYGON & CPolygon(int aIndex) const
Handle a list of polygons defining a copper zone.
void SetNeedRefill(bool aNeedRefill)
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
bool GetDoNotAllowVias() const
bool GetDoNotAllowPads() const
const BOX2I GetBoundingBox() const override
bool GetDoNotAllowTracks() const
SHAPE_POLY_SET * Outline()
SHAPE_POLY_SET * GetFill(PCB_LAYER_ID aLayer)
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
SHAPE_POLY_SET GetBoardOutline() const
void SetIsFilled(bool isFilled)
void SetLayerSet(const LSET &aLayerSet) override
bool IsTeardropArea() const
bool GetDoNotAllowFootprints() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool GetDoNotAllowZoneFills() const
bool IsOnCopperLayer() const override
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::vector< ZONE * > ZONES
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_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
VECTOR2< int32_t > VECTOR2I
static void assignPrioritiesFromGraph(const std::vector< ZONE_PRIORITY_EDGE > &aEdges, std::vector< ZONE * > &aAllZones)
static ZONE * ufFind(std::unordered_map< ZONE *, ZONE * > &aParent, ZONE *aZone)
static bool RuleAreasHaveSameProps(const ZONE &a, const ZONE &b)
std::vector< std::unique_ptr< ZONE > > MergeZonesWithSameOutline(std::vector< std::unique_ptr< ZONE > > &&aZones)
Merges zones with identical outlines and nets on different layers into single multi-layer zones.
static void ufUnion(std::unordered_map< ZONE *, ZONE * > &aParent, std::unordered_map< ZONE *, int > &aRank, ZONE *aA, ZONE *aB)
static std::vector< ZONE_OVERLAP_PAIR > findOverlappingPairs(BOARD *aBoard)
bool AutoAssignZonePriorities(BOARD *aBoard, PROGRESS_REPORTER *aReporter)
Automatically assign zone priorities based on connectivity analysis of overlapping regions.
static std::optional< ZONE_PRIORITY_EDGE > computeConstraint(const ZONE_OVERLAP_PAIR &aPair, BOARD *aBoard)