diff --git a/pcbnew/zone.cpp b/pcbnew/zone.cpp index 5e49a71da8..ed725e0b0f 100644 --- a/pcbnew/zone.cpp +++ b/pcbnew/zone.cpp @@ -1007,7 +1007,8 @@ 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 = pcbIUScale.mmToIU( 0.001 ); BOX2I bbox = GetBoundingBox(); @@ -1022,23 +1023,27 @@ void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector* aZones if( !candidate->GetLayerSet().test( aLayer ) ) continue; - if( candidate->GetIsRuleArea() ) - continue; - - if( candidate->GetNetCode() != GetNetCode() ) + if( candidate->GetIsRuleArea() || candidate->IsTeardropArea() ) continue; 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 ); + } } } @@ -1105,9 +1110,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; @@ -1124,11 +1126,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()->CloneDropTriangulation(); - flattened_outline.ClearArcs(); - aSmoothedPoly.BooleanAdd( flattened_outline, SHAPE_POLY_SET::PM_FAST ); + BOX2I sameNetBoundingBox = sameNetZone->GetBoundingBox(); + SHAPE_POLY_SET sameNetPoly = sameNetZone->Outline()->CloneDropTriangulation(); + + 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 9ce3085a6a..dbcb1dd9f4 100644 --- a/pcbnew/zone.h +++ b/pcbnew/zone.h @@ -352,7 +352,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