Be careful of interveneing priority zones when doing divot prevention.

Fixes https://gitlab.com/kicad/code/kicad/issues/12797

(cherry picked from commit 1f4e51b008)
This commit is contained in:
Jeff Young 2022-11-01 10:55:35 +00:00
parent e083cbaf50
commit a09a3dfe68
2 changed files with 66 additions and 15 deletions

View File

@ -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<ZONE*>* aZones ) const
void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aSameNetCollidingZones,
std::vector<ZONE*>* aOtherNetIntersectingZones ) const
{
int epsilon = Millimeter2iu( 0.001 );
BOX2I bbox = GetBoundingBox();
bbox.Inflate( epsilon );
for( ZONE* candidate : GetBoard()->Zones() )
{
@ -1099,18 +1118,25 @@ void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aZones
if( candidate->GetIsRuleArea() )
continue;
if( candidate->GetNetCode() != GetNetCode() )
if( !candidate->GetBoundingBox().Intersects( bbox ) )
continue;
if( candidate->GetNetCode() == GetNetCode() )
{
for( auto iter = m_Poly->CIterate(); iter; iter++ )
{
if( candidate->m_Poly->Collide( iter.Get(), epsilon ) )
{
aZones->push_back( candidate );
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<ZONE*> 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<ZONE*> sameNetCollidingZones;
std::vector<ZONE*> 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 )

View File

@ -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<MSG_PANEL_ITEM>& 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<ZONE*>* aZones ) const;
void GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aSameNetCollidingZones,
std::vector<ZONE*>* aOtherNetIntersectingZones ) const;
/**
* Convert solid areas full shapes to polygon set