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