From a09a3dfe683859e32c326da005441d9015c1c5c2 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 1 Nov 2022 10:55:35 +0000 Subject: [PATCH] Be careful of interveneing priority zones when doing divot prevention. Fixes https://gitlab.com/kicad/code/kicad/issues/12797 (cherry picked from commit 1f4e51b0080557d3ba6eda1c41b2d2d53818189b) --- pcbnew/zone.cpp | 74 +++++++++++++++++++++++++++++++++++++++---------- pcbnew/zone.h | 7 ++++- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index f897006309..42931f2fd5 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -189,6 +189,21 @@ EDA_ITEM* ZONE::Clone() const } +bool ZONE::HigherPriority( const ZONE* aOther ) const +{ + if( m_priority != aOther->m_priority ) + return m_priority > aOther->m_priority; + + return m_Uuid > aOther->m_Uuid; +} + + +bool ZONE::SameNet( const ZONE* aOther ) const +{ + return GetNetCode() == aOther->GetNetCode(); +} + + bool ZONE::UnFill() { bool change = false; @@ -1084,9 +1099,13 @@ bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const } -void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector* aZones ) const +void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector* aSameNetCollidingZones, + std::vector* aOtherNetIntersectingZones ) const { - int epsilon = Millimeter2iu( 0.001 ); + int epsilon = Millimeter2iu( 0.001 ); + BOX2I bbox = GetBoundingBox(); + + bbox.Inflate( epsilon ); for( ZONE* candidate : GetBoard()->Zones() ) { @@ -1099,17 +1118,24 @@ void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector* aZones if( candidate->GetIsRuleArea() ) continue; - if( candidate->GetNetCode() != GetNetCode() ) + if( !candidate->GetBoundingBox().Intersects( bbox ) ) continue; - for( auto iter = m_Poly->CIterate(); iter; iter++ ) + if( candidate->GetNetCode() == GetNetCode() ) { - if( candidate->m_Poly->Collide( iter.Get(), epsilon ) ) + for( auto iter = m_Poly->CIterate(); iter; iter++ ) { - aZones->push_back( candidate ); - break; + if( candidate->m_Poly->Collide( iter.Get(), epsilon ) ) + { + aSameNetCollidingZones->push_back( candidate ); + break; + } } } + else + { + aOtherNetIntersectingZones->push_back( candidate ); + } } } @@ -1164,9 +1190,6 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer } }; - std::vector interactingZones; - GetInteractingZones( aLayer, &interactingZones ); - SHAPE_POLY_SET* maxExtents = &flattened; SHAPE_POLY_SET withFillets; @@ -1183,11 +1206,34 @@ bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer maxExtents = &withFillets; } - for( ZONE* zone : interactingZones ) + // We now add in the areas of any same-net, intersecting zones. This keeps us from smoothing + // corners at an intersection (which often produces undesired divots between the intersecting + // zones -- see #2752). + // + // After smoothing, we'll subtract back out everything outside of our zone. + std::vector sameNetCollidingZones; + std::vector otherNetIntersectingZones; + GetInteractingZones( aLayer, &sameNetCollidingZones, &otherNetIntersectingZones ); + + for( ZONE* sameNetZone : sameNetCollidingZones ) { - SHAPE_POLY_SET flattened_outline = *zone->Outline(); - flattened_outline.ClearArcs(); - aSmoothedPoly.BooleanAdd( flattened_outline, SHAPE_POLY_SET::PM_FAST ); + BOX2I sameNetBoundingBox = sameNetZone->GetBoundingBox(); + SHAPE_POLY_SET sameNetPoly = *sameNetZone->Outline(); + + sameNetPoly.ClearArcs(); + + // Of course there's always a wrinkle. The same-net intersecting zone *might* get knocked + // out along the border by a higher-priority, different-net zone. #12797 + for( ZONE* otherNetZone : otherNetIntersectingZones ) + { + if( otherNetZone->HigherPriority( sameNetZone ) + && otherNetZone->GetBoundingBox().Intersects( sameNetBoundingBox ) ) + { + sameNetPoly.BooleanSubtract( *otherNetZone->Outline(), SHAPE_POLY_SET::PM_FAST ); + } + } + + aSmoothedPoly.BooleanAdd( sameNetPoly, SHAPE_POLY_SET::PM_FAST ); } if( aBoardOutline ) diff --git a/pcbnew/zone.h b/pcbnew/zone.h index 1dc78d9795..3cb0a003e6 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -121,6 +121,10 @@ public: */ unsigned GetPriority() const { return m_priority; } + bool HigherPriority( const ZONE* aOther ) const; + + bool SameNet( const ZONE* aOther ) const; + void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector& aList ) override; void SetLayerSet( LSET aLayerSet ) override; @@ -367,7 +371,8 @@ public: * merged due to other parameters such as fillet radius. The copper pour will end up * effectively merged though, so we need to do some calculations with them in mind. */ - void GetInteractingZones( PCB_LAYER_ID aLayer, std::vector* aZones ) const; + void GetInteractingZones( PCB_LAYER_ID aLayer, std::vector* aSameNetCollidingZones, + std::vector* aOtherNetIntersectingZones ) const; /** * Convert solid areas full shapes to polygon set