Pcbnew: Use a better (i.e. more suitable to calculate clearance areas) algorithm to inflate/deflate zones outlines. It fixes bug#1459734.

Previously, acute angles (especially small angles)  in zone outlines create incorrect shapes and sometimes strange shapes for clearance areas, when using generic algorithms.
This happens when zones outlines have "spikes", but not usually for smooth outlines.
This commit is contained in:
jean-pierre charras 2015-05-30 14:02:55 +02:00
parent 2500976e31
commit ba37f33bbb
4 changed files with 87 additions and 7 deletions

View File

@ -304,8 +304,8 @@ bool ReadSchemaDescr( LINE_READER* aLine, wxString& aMsgDiag, SCH_SCREEN* aScree
if( !pageInfo.SetType( pagename ) ) if( !pageInfo.SetType( pagename ) )
{ {
aMsgDiag.Printf( _( "Eeschema file dimension definition error \ aMsgDiag.Printf( _( "Eeschema file dimension definition error line %d,"
line %d,\nAbort reading file.\n" ), "\nAbort reading file.\n" ),
aLine->LineNumber() ); aLine->LineNumber() );
aMsgDiag << FROM_UTF8( line ); aMsgDiag << FROM_UTF8( line );
} }

View File

@ -82,8 +82,12 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST*
break; break;
default: default:
m_smoothedPoly = new CPolyLine; // Acute angles between adjacent edges can create issues in calculations,
m_smoothedPoly->Copy( m_Poly ); // in inflate/deflate outlines transforms, especially when the angle is very small.
// We can avoid issues by creating a very small chamfer which remove acute angles,
// or left it without chamfer and use only CPOLYGONS_LIST::InflateOutline to create
// clearance areas
m_smoothedPoly = m_Poly->Chamfer( Millimeter2iu( 0.0 ) );
break; break;
} }

View File

@ -154,7 +154,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
* so m_ZoneMinThickness is the min thickness of the filled zones areas * so m_ZoneMinThickness is the min thickness of the filled zones areas
* the main polygon is stored in polyset_zone_solid_areas * the main polygon is stored in polyset_zone_solid_areas
*/ */
#if 1 #if 0
m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas ); m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas );
if( polyset_zone_solid_areas.size() == 0 ) if( polyset_zone_solid_areas.size() == 0 )
@ -181,6 +181,9 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
CPOLYGONS_LIST tmp; CPOLYGONS_LIST tmp;
m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true ); m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true );
tmp.ExportTo( polyset_zone_solid_areas ); tmp.ExportTo( polyset_zone_solid_areas );
if( polyset_zone_solid_areas.size() == 0 )
return;
#endif #endif
/* Calculates the clearance value that meet DRC requirements /* Calculates the clearance value that meet DRC requirements

View File

@ -1440,7 +1440,23 @@ void CPOLYGONS_LIST::ImportFrom( ClipperLib::Paths& aPolygons )
* aInflateValue = the Inflate value. when < 0, this is a deflate transform * aInflateValue = the Inflate value. when < 0, this is a deflate transform
* aLinkHoles = if true, aResult contains only one polygon, * aLinkHoles = if true, aResult contains only one polygon,
* with holes linked by overlapping segments * with holes linked by overlapping segments
*
* Important Note:
* Inflating a polygon with acute angles or a non convex polygon gives non optimal shapes
* for your purposes (creating a clearance area from zones).
* So when inflating a polygon, we combine it with a "thick outline"
* with a thickness = aInflateValue*2.
* the inflated polygon shape is much better to build a polygon
* from a polygon + clearance area
*
* Generic algos (Clipper, Boost Polygon) can inflate polygons, but the result is
* not always suitable (they work fine only for polygons with non acute angle)
*
* To deflate polygons, the same calculation is made, but instead of adding the "thick outline"
* we substract it.
*/ */
#include <convert_basic_shapes_to_polygon.h>
void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles ) void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles )
{ {
KI_POLYGON_SET polyset_outline; KI_POLYGON_SET polyset_outline;
@ -1456,12 +1472,68 @@ void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue,
} }
// inflate main outline // inflate main outline
unsigned icnt = 0;
int width = std::abs( aInflateValue * 2 );
if( polyset_outline.size() ) if( polyset_outline.size() )
polyset_outline += aInflateValue; {
CPOLYGONS_LIST outlines;
for( ; icnt < GetCornersCount(); icnt++ )
{
unsigned ii = icnt+1;
if( IsEndContour( icnt ) )
ii = 0;
TransformRoundedEndsSegmentToPolygon( outlines,
GetPos( icnt ), GetPos( ii ), 16, width );
if( IsEndContour( icnt ) )
break;
}
KI_POLYGON_SET thicklines;
outlines.ExportTo( thicklines );
if( aInflateValue > 0 ) // Inflate main outline
polyset_outline += thicklines;
else if( aInflateValue < 0 ) // Actually a deflate transform
polyset_outline -= thicklines; // deflate main outline
}
// deflate outline holes // deflate outline holes
if( outlineHoles.size() ) if( outlineHoles.size() )
outlineHoles -= aInflateValue; {
int deflateValue = -aInflateValue;
CPOLYGONS_LIST outlines;
icnt += 1; // points the first point of the first hole
unsigned firstpoint = icnt;
for( ; icnt < GetCornersCount(); icnt++ )
{
unsigned ii = icnt+1;
if( IsEndContour( icnt ) || ii >= GetCornersCount() )
{
ii = firstpoint;
firstpoint = icnt+1;
}
TransformRoundedEndsSegmentToPolygon( outlines,
GetPos( icnt ), GetPos( ii ), 16, width );
}
KI_POLYGON_SET thicklines;
outlines.ExportTo( thicklines );
if( deflateValue > 0 ) // Inflate holes
outlineHoles += thicklines;
else if( deflateValue < 0 ) // deflate holes
outlineHoles -= thicklines;
}
// Copy modified polygons // Copy modified polygons
if( !aLinkHoles ) if( !aLinkHoles )
@ -1478,6 +1550,7 @@ void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue,
} }
} }
/** /**
* Function ConvertPolysListWithHolesToOnePolygon * Function ConvertPolysListWithHolesToOnePolygon
* converts the outline contours aPolysListWithHoles with holes to one polygon * converts the outline contours aPolysListWithHoles with holes to one polygon