38#include <unordered_map>
39#include <unordered_set>
59 if( a.size() != b.size() )
64 for(
size_t lineChainId = 0; lineChainId < a.size(); lineChainId++ )
82 const auto zonesAreMergeable = [&](
const ZONE& a,
const ZONE& b ) ->
bool
85 if( a.GetIsRuleArea() != b.GetIsRuleArea() )
88 if( a.GetIsRuleArea() )
96 if( a.GetNetCode() != b.GetNetCode() )
117 return polygonsAreMergeable( polyA, polyB );
120 std::vector<std::unique_ptr<ZONE>> deduplicatedZones;
123 std::vector<bool> merged( aZones.size(),
false );
125 for(
size_t i = 0; i < aZones.size(); i++ )
132 ZONE& primary = *aZones[i];
134 std::unordered_map<PCB_LAYER_ID, SHAPE_POLY_SET> mergedFills;
136 for(
size_t j = i + 1; j < aZones.size(); j++ )
143 ZONE& candidate = *aZones[j];
144 bool canMerge = zonesAreMergeable( primary, candidate );
151 mergedFills[layer] = *fill;
164 mergedFills[layer] = *fill;
169 for(
const auto& [layer, fill] : mergedFills )
177 deduplicatedZones.push_back( std::move( aZones[i] ) );
180 return deduplicatedZones;
187struct ZONE_OVERLAP_PAIR
195struct ZONE_PRIORITY_EDGE
208 std::vector<ZONE_OVERLAP_PAIR> pairs;
211 for(
size_t i = 0; i < zones.size(); i++ )
220 for(
size_t j = i + 1; j < zones.size(); j++ )
237 || ( b->
Outline()->TotalVertices() > 0
239 || ( a->
Outline()->TotalVertices() > 0
243 pairs.push_back( { a, b, shared } );
273 if( netCodeA == netCodeB )
281 if( !aPair.sharedLayers.test( aLayer ) )
286 if( aNetCode == netCodeA )
288 else if( aNetCode == netCodeB )
295 for(
PAD*
pad : fp->Pads() )
299 if(
pad->IsOnLayer( layer ) )
301 countIfInOverlap(
pad->GetPosition(),
pad->GetNetCode(), layer );
317 if(
via->IsOnLayer( layer ) )
319 countIfInOverlap(
via->GetPosition(),
via->GetNetCode(), layer );
325 if( countA == 0 && countB == 0 )
333 ZONE* higher = ( areaA < areaB ) ? aPair.zoneA : aPair.zoneB;
334 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
335 return ZONE_PRIORITY_EDGE{ higher, lower, 0,
true };
338 int maxCount = std::max( countA, countB );
339 int diff =
std::abs( countA - countB );
340 double ratio =
static_cast<double>( diff ) / maxCount;
342 constexpr double SIMILARITY_THRESHOLD = 0.20;
344 if( ratio < SIMILARITY_THRESHOLD )
352 ZONE* higher = ( areaA < areaB ) ? aPair.zoneA : aPair.zoneB;
353 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
354 return ZONE_PRIORITY_EDGE{ higher, lower, diff,
true };
357 ZONE* higher = ( countA > countB ) ? aPair.zoneA : aPair.zoneB;
358 ZONE* lower = ( higher == aPair.zoneA ) ? aPair.zoneB : aPair.zoneA;
359 return ZONE_PRIORITY_EDGE{ higher, lower, diff,
false };
364 std::vector<ZONE*>& aAllZones )
366 std::unordered_map<ZONE*, std::vector<ZONE*>> adj;
367 std::unordered_map<ZONE*, int> inDegree;
368 std::unordered_set<ZONE*> inGraph;
370 for(
ZONE* z : aAllZones )
377 std::vector<ZONE_PRIORITY_EDGE> sortedEdges = aEdges;
379 std::sort( sortedEdges.begin(), sortedEdges.end(),
380 [](
const ZONE_PRIORITY_EDGE& a,
const ZONE_PRIORITY_EDGE& b )
382 if( a.fromArea != b.fromArea )
385 return a.countDiff < b.countDiff;
388 for(
const ZONE_PRIORITY_EDGE& edge : sortedEdges )
390 adj[edge.higher].push_back( edge.lower );
391 inDegree[edge.lower]++;
396 std::vector<ZONE*> queue;
398 for(
ZONE* z : aAllZones )
400 if( inDegree[z] == 0 )
401 queue.push_back( z );
404 std::sort( queue.begin(), queue.end(),
407 return a->GetAssignedPriority() < b->GetAssignedPriority();
410 std::vector<ZONE*> topoOrder;
411 topoOrder.reserve( aAllZones.size() );
413 while( !queue.empty() )
415 ZONE* current = queue.front();
416 queue.erase( queue.begin() );
417 topoOrder.push_back( current );
419 auto& neighbors = adj[current];
421 std::sort( neighbors.begin(), neighbors.end(),
424 return a->GetAssignedPriority() < b->GetAssignedPriority();
427 for(
ZONE* neighbor : neighbors )
429 inDegree[neighbor]--;
431 if( inDegree[neighbor] == 0 )
432 queue.push_back( neighbor );
435 std::sort( queue.begin(), queue.end(),
438 return a->GetAssignedPriority() < b->GetAssignedPriority();
443 if( topoOrder.size() < aAllZones.size() )
445 std::unordered_set<ZONE*> ordered( topoOrder.begin(), topoOrder.end() );
446 std::vector<ZONE*> remaining;
448 for(
ZONE* z : aAllZones )
450 if( ordered.find( z ) == ordered.end() )
451 remaining.push_back( z );
454 std::sort( remaining.begin(), remaining.end(),
457 return a->GetAssignedPriority() < b->GetAssignedPriority();
460 for(
ZONE* z : remaining )
461 topoOrder.push_back( z );
465 for(
size_t i = 0; i < topoOrder.size(); i++ )
466 topoOrder[i]->SetAssignedPriority(
static_cast<unsigned>( topoOrder.size() - 1 - i ) );
472 ZONE*& parent = aParent[aZone];
474 if( parent != aZone )
475 parent =
ufFind( aParent, parent );
481static void ufUnion( std::unordered_map<ZONE*, ZONE*>& aParent,
482 std::unordered_map<ZONE*, int>& aRank,
491 if( aRank[rootA] < aRank[rootB] )
492 std::swap( rootA, rootB );
494 aParent[rootB] = rootA;
496 if( aRank[rootA] == aRank[rootB] )
503 std::vector<ZONE*> eligibleZones;
507 if( !zone->GetIsRuleArea() && !zone->IsTeardropArea() && zone->IsOnCopperLayer() )
508 eligibleZones.push_back( zone );
511 if( eligibleZones.size() < 2 )
514 std::unordered_map<ZONE*, unsigned> originalPriorities;
516 for(
ZONE* z : eligibleZones )
517 originalPriorities[z] = z->GetAssignedPriority();
526 std::unordered_map<ZONE*, ZONE*> ufParent;
527 std::unordered_map<ZONE*, int> ufRank;
529 for(
ZONE* z : eligibleZones )
535 for(
const ZONE_OVERLAP_PAIR& pair : pairs )
537 if( pair.zoneA->GetNetCode() == pair.zoneB->GetNetCode() )
538 ufUnion( ufParent, ufRank, pair.zoneA, pair.zoneB );
542 std::vector<std::future<std::optional<ZONE_PRIORITY_EDGE>>> futures;
543 futures.reserve( pairs.size() );
545 for(
const ZONE_OVERLAP_PAIR& pair : pairs )
547 if( pair.zoneA->GetNetCode() == pair.zoneB->GetNetCode() )
550 futures.emplace_back(
tp.submit_task(
553 return computeConstraint( pair, aBoard );
557 std::vector<ZONE_PRIORITY_EDGE> edges;
559 for(
auto& future : futures )
561 std::optional<ZONE_PRIORITY_EDGE>
result = future.get();
564 edges.push_back(
result.value() );
573 std::unordered_map<ZONE*, unsigned> groupMax;
575 for(
ZONE* z : eligibleZones )
578 unsigned pri = z->GetAssignedPriority();
579 auto& maxPri = groupMax[root];
585 for(
ZONE* z : eligibleZones )
588 z->SetAssignedPriority( groupMax[root] );
591 for(
ZONE* z : eligibleZones )
593 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,...
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.
SHAPE_POLY_SET CloneDropTriangulation() const
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.
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)