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++ )
235 bool overlaps = aOutline.
Collide( &bOutline )
240 pairs.push_back( { a, b, shared } );
270 if( netCodeA == netCodeB )
278 if( !aPair.sharedLayers.test( aLayer ) )
283 if( aNetCode == netCodeA )
285 else if( aNetCode == netCodeB )
292 for(
PAD*
pad : fp->Pads() )
296 if(
pad->IsOnLayer( layer ) )
298 countIfInOverlap(
pad->GetPosition(),
pad->GetNetCode(), layer );
314 if(
via->IsOnLayer( layer ) )
316 countIfInOverlap(
via->GetPosition(),
via->GetNetCode(), layer );
322 if( countA == 0 && countB == 0 )
330 ZONE* higher = ( areaA < areaB ) ? aPair.zoneA : aPair.zoneB;
331 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
332 return ZONE_PRIORITY_EDGE{ higher, lower, 0,
true };
335 int maxCount = std::max( countA, countB );
336 int diff =
std::abs( countA - countB );
337 double ratio =
static_cast<double>( diff ) / maxCount;
339 constexpr double SIMILARITY_THRESHOLD = 0.20;
341 if( ratio < SIMILARITY_THRESHOLD )
349 ZONE* higher = ( areaA < areaB ) ? aPair.zoneA : aPair.zoneB;
350 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
351 return ZONE_PRIORITY_EDGE{ higher, lower, diff,
true };
354 ZONE* higher = ( countA > countB ) ? aPair.zoneA : aPair.zoneB;
355 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
356 return ZONE_PRIORITY_EDGE{ higher, lower, diff,
false };
361 std::vector<ZONE*>& aAllZones )
363 std::unordered_map<ZONE*, std::vector<ZONE*>> adj;
364 std::unordered_map<ZONE*, int> inDegree;
365 std::unordered_set<ZONE*> inGraph;
367 for(
ZONE* z : aAllZones )
374 std::vector<ZONE_PRIORITY_EDGE> sortedEdges = aEdges;
376 std::sort( sortedEdges.begin(), sortedEdges.end(),
377 [](
const ZONE_PRIORITY_EDGE& a,
const ZONE_PRIORITY_EDGE& b )
379 if( a.fromArea != b.fromArea )
382 return a.countDiff < b.countDiff;
385 for(
const ZONE_PRIORITY_EDGE& edge : sortedEdges )
387 adj[edge.higher].push_back( edge.lower );
388 inDegree[edge.lower]++;
393 std::vector<ZONE*> queue;
395 for(
ZONE* z : aAllZones )
397 if( inDegree[z] == 0 )
398 queue.push_back( z );
401 std::sort( queue.begin(), queue.end(),
404 return a->GetAssignedPriority() < b->GetAssignedPriority();
407 std::vector<ZONE*> topoOrder;
408 topoOrder.reserve( aAllZones.size() );
410 while( !queue.empty() )
412 ZONE* current = queue.front();
413 queue.erase( queue.begin() );
414 topoOrder.push_back( current );
416 auto& neighbors = adj[current];
418 std::sort( neighbors.begin(), neighbors.end(),
421 return a->GetAssignedPriority() < b->GetAssignedPriority();
424 for(
ZONE* neighbor : neighbors )
426 inDegree[neighbor]--;
428 if( inDegree[neighbor] == 0 )
429 queue.push_back( neighbor );
432 std::sort( queue.begin(), queue.end(),
435 return a->GetAssignedPriority() < b->GetAssignedPriority();
440 if( topoOrder.size() < aAllZones.size() )
442 std::unordered_set<ZONE*> ordered( topoOrder.begin(), topoOrder.end() );
443 std::vector<ZONE*> remaining;
445 for(
ZONE* z : aAllZones )
447 if( ordered.find( z ) == ordered.end() )
448 remaining.push_back( z );
451 std::sort( remaining.begin(), remaining.end(),
454 return a->GetAssignedPriority() < b->GetAssignedPriority();
457 for(
ZONE* z : remaining )
458 topoOrder.push_back( z );
462 for(
size_t i = 0; i < topoOrder.size(); i++ )
463 topoOrder[i]->SetAssignedPriority(
static_cast<unsigned>( topoOrder.size() - 1 - i ) );
469 ZONE*& parent = aParent[aZone];
471 if( parent != aZone )
472 parent =
ufFind( aParent, parent );
478static void ufUnion( std::unordered_map<ZONE*, ZONE*>& aParent,
479 std::unordered_map<ZONE*, int>& aRank,
488 if( aRank[rootA] < aRank[rootB] )
489 std::swap( rootA, rootB );
491 aParent[rootB] = rootA;
493 if( aRank[rootA] == aRank[rootB] )
500 std::vector<ZONE*> eligibleZones;
504 if( !zone->GetIsRuleArea() && !zone->IsTeardropArea() && zone->IsOnCopperLayer() )
505 eligibleZones.push_back( zone );
508 if( eligibleZones.size() < 2 )
511 std::unordered_map<ZONE*, unsigned> originalPriorities;
513 for(
ZONE* z : eligibleZones )
514 originalPriorities[z] = z->GetAssignedPriority();
523 std::unordered_map<ZONE*, ZONE*> ufParent;
524 std::unordered_map<ZONE*, int> ufRank;
526 for(
ZONE* z : eligibleZones )
532 for(
const ZONE_OVERLAP_PAIR& pair : pairs )
534 if( pair.zoneA->GetNetCode() == pair.zoneB->GetNetCode() )
535 ufUnion( ufParent, ufRank, pair.zoneA, pair.zoneB );
539 std::vector<std::future<std::optional<ZONE_PRIORITY_EDGE>>> futures;
540 futures.reserve( pairs.size() );
542 for(
const ZONE_OVERLAP_PAIR& pair : pairs )
544 if( pair.zoneA->GetNetCode() == pair.zoneB->GetNetCode() )
547 futures.emplace_back(
tp.submit_task(
550 return computeConstraint( pair, aBoard );
554 std::vector<ZONE_PRIORITY_EDGE> edges;
556 for(
auto& future : futures )
558 std::optional<ZONE_PRIORITY_EDGE>
result = future.get();
561 edges.push_back(
result.value() );
570 std::unordered_map<ZONE*, unsigned> groupMax;
572 for(
ZONE* z : eligibleZones )
575 unsigned pri = z->GetAssignedPriority();
576 auto& maxPri = groupMax[root];
582 for(
ZONE* z : eligibleZones )
585 z->SetAssignedPriority( groupMax[root] );
588 for(
ZONE* z : eligibleZones )
590 if( z->GetAssignedPriority() != originalPriorities[z] )
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 * 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)