Allow chamfering/filleting of zone/board edge intersections.

Fixes https://gitlab.com/kicad/code/kicad/issues/5947
This commit is contained in:
Jeff Young 2020-10-10 23:09:00 +01:00
parent a8bd0a9b84
commit 22cde88ba9
7 changed files with 58 additions and 28 deletions

View File

@ -1159,11 +1159,19 @@ void ZONE_CONTAINER::GetInteractingZones( PCB_LAYER_ID aLayer,
}
bool ZONE_CONTAINER::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer ) const
bool ZONE_CONTAINER::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET* aBoardOutline ) const
{
if( GetNumCorners() <= 2 ) // malformed zone. polygon calculations will not like it ...
return false;
if( GetIsRuleArea() )
{
// We like keepouts just the way they are....
aSmoothedPoly = *m_Poly;
return true;
}
BOARD* board = GetBoard();
int maxError = ARC_HIGH_DEF;
bool keepExternalFillets = false;
@ -1215,6 +1223,9 @@ bool ZONE_CONTAINER::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER
for( ZONE_CONTAINER* zone : interactingZones )
aSmoothedPoly.BooleanAdd( *zone->Outline(), SHAPE_POLY_SET::PM_FAST );
if( !GetIsRuleArea() && aBoardOutline )
aSmoothedPoly.BooleanIntersection( *aBoardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
smooth( aSmoothedPoly );
aSmoothedPoly.BooleanIntersection( *maxExtents, SHAPE_POLY_SET::PM_FAST );
@ -1247,16 +1258,17 @@ double ZONE_CONTAINER::CalculateFilledArea()
/**
* Function TransformSmoothedOutlineWithClearanceToPolygon
* Function TransformSmoothedOutlineToPolygon
* Convert the smoothed outline to polygons (optionally inflated by \a aClearance) and copy them
* into \a aCornerBuffer.
*/
void ZONE_CONTAINER::TransformSmoothedOutlineWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance ) const
void ZONE_CONTAINER::TransformSmoothedOutlineToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance,
SHAPE_POLY_SET* aBoardOutline ) const
{
// Creates the zone outline polygon (with holes if any)
SHAPE_POLY_SET polybuffer;
BuildSmoothedPoly( polybuffer, GetLayer() );
BuildSmoothedPoly( polybuffer, GetLayer(), aBoardOutline );
// Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon is created.

View File

@ -361,7 +361,7 @@ public:
int aError = ARC_HIGH_DEF ) const;
/**
* Function TransformSmoothedOutlineWithClearanceToPolygon
* Function TransformSmoothedOutlineToPolygon
* Convert the outlines shape to a polygon with no holes
* inflated (optional) by max( aClearanceValue, the zone clearance)
* (holes are linked to external outline by overlapping segments)
@ -369,9 +369,10 @@ public:
* Circles (vias) and arcs (ends of tracks) are approximated by segments
* @param aCornerBuffer = a buffer to store the polygon
* @param aClearance = the min clearance around outlines
* @param aBoardOutline = the board outline (if a valid one exists; nullptr otherwise)
*/
void TransformSmoothedOutlineWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearance ) const;
void TransformSmoothedOutlineToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearance,
SHAPE_POLY_SET* aBoardOutline ) const;
/**
* Function TransformShapeWithClearanceToPolygon
@ -669,7 +670,8 @@ public:
/**
* Function GetSmoothedPoly
*/
bool BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer ) const;
bool BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET* aBoardOutline ) const;
void SetCornerSmoothingType( int aType ) { m_cornerSmoothingType = aType; };

View File

@ -758,6 +758,12 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
{
const int delta = 50; // This is the number of tests between 2 calls to the progress bar
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET* boardOutline = nullptr;
if( m_board->GetBoardPolygonOutlines( buffer ) )
boardOutline = &buffer;
// Test copper areas for valid netcodes -> fixme, goes to connectivity checks
for( int layer_id = F_Cu; layer_id <= B_Cu; ++layer_id )
@ -775,7 +781,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZones()
ZONE_CONTAINER* zoneRef = m_board->GetArea( ii );
if( zoneRef->IsOnLayer( layer ) )
zoneRef->BuildSmoothedPoly( smoothed_polys[ii], layer );
zoneRef->BuildSmoothedPoly( smoothed_polys[ii], layer, boardOutline );
}
// iterate through all areas

View File

@ -757,6 +757,11 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness )
{
PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET* boardOutline = nullptr;
if( aBoard->GetBoardPolygonOutlines( buffer ) )
boardOutline = &buffer;
// Set the current arc to segment max approx error
int currMaxError = aBoard->GetDesignSettings().m_MaxError;
@ -776,9 +781,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
itemplotter.PlotBoardGraphicItems();
for( auto module : aBoard->Modules() )
for( MODULE* module : aBoard->Modules() )
{
for( auto item : module->GraphicalItems() )
for( BOARD_ITEM* item : module->GraphicalItems() )
{
itemplotter.PlotFootprintTextItems( module );
@ -806,7 +811,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
#endif
{
// Plot pads
for( auto module : aBoard->Modules() )
for( MODULE* module : aBoard->Modules() )
{
// add shapes with their exact mask layer size in initialPolys
module->TransformPadsShapesWithClearanceToPolygon( layer, initialPolys, 0 );
@ -821,7 +826,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
int via_clearance = aBoard->GetDesignSettings().m_SolderMaskMargin;
int via_margin = via_clearance + inflate;
for( auto track : aBoard->Tracks() )
for( TRACK* track : aBoard->Tracks() )
{
const VIA* via = dyn_cast<const VIA*>( track );
@ -860,9 +865,9 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
continue;
// add shapes inflated by aMinThickness/2 in areas
zone->TransformSmoothedOutlineWithClearanceToPolygon( areas, inflate + zone_margin );
zone->TransformSmoothedOutlineToPolygon( areas, inflate + zone_margin, boardOutline );
// add shapes with their exact mask layer size in initialPolys
zone->TransformSmoothedOutlineWithClearanceToPolygon( initialPolys, zone_margin );
zone->TransformSmoothedOutlineToPolygon( initialPolys, zone_margin, boardOutline );
}
int maxError = aBoard->GetDesignSettings().m_MaxError;

View File

@ -879,7 +879,8 @@ std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE_BASE::syncVia( VIA* aVia )
}
bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE_CONTAINER* aZone )
bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE_CONTAINER* aZone,
SHAPE_POLY_SET* aBoardOutline )
{
SHAPE_POLY_SET poly;
@ -894,7 +895,7 @@ bool PNS_KICAD_IFACE_BASE::syncZone( PNS::NODE* aWorld, ZONE_CONTAINER* aZone )
if( ! layers[ layer ] )
continue;
aZone->BuildSmoothedPoly( poly, ToLAYER_ID( layer ) );
aZone->BuildSmoothedPoly( poly, ToLAYER_ID( layer ), aBoardOutline );
poly.CacheTriangulation();
if( !poly.IsTriangulationUpToDate() )
@ -1143,9 +1144,15 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
}
}
SHAPE_POLY_SET buffer;
SHAPE_POLY_SET* boardOutline = nullptr;
if( m_board->GetBoardPolygonOutlines( buffer ) )
boardOutline = &buffer;
for( ZONE_CONTAINER* zone : m_board->Zones() )
{
syncZone( aWorld, zone );
syncZone( aWorld, zone, boardOutline );
}
for( MODULE* module : m_board->Modules() )
@ -1162,7 +1169,7 @@ void PNS_KICAD_IFACE_BASE::SyncWorld( PNS::NODE *aWorld )
syncTextItem( aWorld, &module->Value(), module->Value().GetLayer() );
for( MODULE_ZONE_CONTAINER* zone : module->Zones() )
syncZone( aWorld, zone );
syncZone( aWorld, zone, boardOutline );
if( module->IsNetTie() )
continue;

View File

@ -94,7 +94,7 @@ protected:
std::unique_ptr<PNS::VIA> syncVia( VIA* aVia );
bool syncTextItem( PNS::NODE* aWorld, EDA_TEXT* aText, PCB_LAYER_ID aLayer );
bool syncGraphicalItem( PNS::NODE* aWorld, PCB_SHAPE* aItem );
bool syncZone( PNS::NODE* aWorld, ZONE_CONTAINER* aZone );
bool syncZone( PNS::NODE* aWorld, ZONE_CONTAINER* aZone, SHAPE_POLY_SET* aBoardOutline );
int inheritTrackWidth( PNS::ITEM* aItem );

View File

@ -843,7 +843,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
|| aZone->GetNetCode() == aKnockout->GetNetCode() )
{
// Keepouts and same-net zones use outline with no clearance
aKnockout->TransformSmoothedOutlineWithClearanceToPolygon( aHoles, 0 );
aKnockout->TransformSmoothedOutlineToPolygon( aHoles, 0, nullptr );
}
else
{
@ -852,7 +852,7 @@ void ZONE_FILLER::buildCopperItemClearances( const ZONE_CONTAINER* aZone, PCB_LA
if( bds.m_ZoneFillVersion == 5 )
{
// 5.x used outline with clearance
aKnockout->TransformSmoothedOutlineWithClearanceToPolygon( aHoles, gap );
aKnockout->TransformSmoothedOutlineToPolygon( aHoles, gap, nullptr );
}
else
{
@ -1096,14 +1096,15 @@ void ZONE_FILLER::computeRawFilledArea( const ZONE_CONTAINER* aZone, PCB_LAYER_I
bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
SHAPE_POLY_SET& aRawPolys, SHAPE_POLY_SET& aFinalPolys )
{
SHAPE_POLY_SET smoothedPoly;
SHAPE_POLY_SET* boardOutline = m_brdOutlinesValid ? &m_boardOutline : nullptr;
SHAPE_POLY_SET smoothedPoly;
/*
* convert outlines + holes to outlines without holes (adding extra segments if necessary)
* m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
* this zone
*/
if ( !aZone->BuildSmoothedPoly( smoothedPoly, aLayer ) )
if ( !aZone->BuildSmoothedPoly( smoothedPoly, aLayer, boardOutline ) )
return false;
if( m_progressReporter && m_progressReporter->IsCancelled() )
@ -1122,9 +1123,6 @@ bool ZONE_FILLER::fillSingleZone( ZONE_CONTAINER* aZone, PCB_LAYER_ID aLayer,
int epsilon = Millimeter2iu( 0.001 );
int numSegs = GetArcToSegmentCount( half_min_width, m_maxError, 360.0 );
if( m_brdOutlinesValid )
smoothedPoly.BooleanIntersection( m_boardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
// Remove the non filled areas due to the hatch pattern