From ba37f33bbb74769b184383ace19e8f017bb4add5 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 30 May 2015 14:02:55 +0200 Subject: [PATCH] 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. --- eeschema/load_one_schematic_file.cpp | 4 +- pcbnew/zone_filling_algorithm.cpp | 8 +- ...nvert_brd_items_to_polygons_with_Boost.cpp | 5 +- polygon/PolyLine.cpp | 77 ++++++++++++++++++- 4 files changed, 87 insertions(+), 7 deletions(-) diff --git a/eeschema/load_one_schematic_file.cpp b/eeschema/load_one_schematic_file.cpp index 1bca27f4a7..b1aeb0ab5d 100644 --- a/eeschema/load_one_schematic_file.cpp +++ b/eeschema/load_one_schematic_file.cpp @@ -304,8 +304,8 @@ bool ReadSchemaDescr( LINE_READER* aLine, wxString& aMsgDiag, SCH_SCREEN* aScree if( !pageInfo.SetType( pagename ) ) { - aMsgDiag.Printf( _( "Eeschema file dimension definition error \ -line %d,\nAbort reading file.\n" ), + aMsgDiag.Printf( _( "Eeschema file dimension definition error line %d," + "\nAbort reading file.\n" ), aLine->LineNumber() ); aMsgDiag << FROM_UTF8( line ); } diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index 589c031e5e..3779e7b433 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -82,8 +82,12 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* break; default: - m_smoothedPoly = new CPolyLine; - m_smoothedPoly->Copy( m_Poly ); + // Acute angles between adjacent edges can create issues in calculations, + // 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; } diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp index 0316d473a3..d527206a96 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -154,7 +154,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) * so m_ZoneMinThickness is the min thickness of the filled zones areas * the main polygon is stored in polyset_zone_solid_areas */ -#if 1 +#if 0 m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas ); if( polyset_zone_solid_areas.size() == 0 ) @@ -181,6 +181,9 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) CPOLYGONS_LIST tmp; m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true ); tmp.ExportTo( polyset_zone_solid_areas ); + + if( polyset_zone_solid_areas.size() == 0 ) + return; #endif /* Calculates the clearance value that meet DRC requirements diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 47d29e3843..8e8714bcdd 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -1440,7 +1440,23 @@ void CPOLYGONS_LIST::ImportFrom( ClipperLib::Paths& aPolygons ) * aInflateValue = the Inflate value. when < 0, this is a deflate transform * aLinkHoles = if true, aResult contains only one polygon, * 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 + void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles ) { KI_POLYGON_SET polyset_outline; @@ -1456,12 +1472,68 @@ void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, } // inflate main outline + unsigned icnt = 0; + int width = std::abs( aInflateValue * 2 ); + 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 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 if( !aLinkHoles ) @@ -1478,6 +1550,7 @@ void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, } } + /** * Function ConvertPolysListWithHolesToOnePolygon * converts the outline contours aPolysListWithHoles with holes to one polygon