diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index c21c2abca1..4c98c8c77c 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -1140,25 +1140,9 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer, clip_engine.Execute( ClipperLib::ctDifference, thermalShape ); // put thermal shapes (holes) to list: - wxPoint corner_position; - - for( unsigned ii = 0; ii < thermalShape.size(); ii++ ) - { - ClipperLib::Path& polygon = thermalShape[ii]; - - for( unsigned jj = 0; jj < polygon.size(); jj++ ) - { - corner_position.x = int( polygon[jj].X ); - corner_position.y = int( polygon[jj].Y ); - CPolyPt polypoint( corner_position.x, corner_position.y ); - aCornerBuffer.Append( polypoint ); - } - - aCornerBuffer.CloseLastContour(); - } - + aCornerBuffer.ImportFrom( thermalShape ); break; - } + } default: ; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index d2dd9ea6b6..ee8fdbecdf 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -272,14 +272,15 @@ public: * keep arc radius when approximated by segments */ void TransformSolidAreasShapesToPolygonSet( CPOLYGONS_LIST& aCornerBuffer, - int aCircleToSegmentsCount, - double aCorrectionFactor ); + int aCircleToSegmentsCount, + double aCorrectionFactor ); /** * Function BuildFilledSolidAreasPolygons * Build the filled solid areas data from real outlines (stored in m_Poly) - * The solid areas can be more thna one on copper layers, and do not have holes + * The solid areas can be more than one on copper layers, and do not have holes ( holes are linked by overlapping segments to the main outline) * in order to have drawable (and plottable) filled polygons + * @return true if OK, false if the solid polygons cannot be built * @param aPcb: the current board (can be NULL for non copper zones) * @param aCornerBuffer: A reference to a buffer to store polygon corners, or NULL * if NULL (default: @@ -287,13 +288,14 @@ public: * - on copper layers, tracks and other items shapes of other nets are * removed from solid areas * if not null: - * Only the zone outline (with holes, if any) are stored in aCornerBuffer - * with holes linked. Therfore only one polygon is created - * @return true if OK, false if the solid areas cannot be calculated - * This function calls AddClearanceAreasPolygonsToPolysList() - * to add holes for pads and tracks and other items not in net. + * Only the zone outline (with holes, if any) is stored in aOutlineBuffer + * with holes linked. Therefore only one polygon is created + * + * When aOutlineBuffer is not null, his function calls + * AddClearanceAreasPolygonsToPolysList() to add holes for pads and tracks + * and other items not in net. */ - bool BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aCornerBuffer = NULL ); + bool BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aOutlineBuffer = NULL ); /** * Function CopyPolygonsFromKiPolygonListToFilledPolysList diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index 2c6f3654dd..d8fe07b497 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -43,22 +43,19 @@ ( holes are linked by overlapping segments to the main outline) * aPcb: the current board (can be NULL for non copper zones) * aCornerBuffer: A reference to a buffer to store polygon corners, or NULL - * if NULL: + * if aCornerBuffer == NULL: * - m_FilledPolysList is used to store solid areas polygons. * - on copper layers, tracks and other items shapes of other nets are * removed from solid areas * if not null: * Only the zone outline (with holes, if any) are stored in aCornerBuffer - * with holes linked. Therfore only one polygon is created + * with holes linked. Therefore only one polygon is created * This function calls AddClearanceAreasPolygonsToPolysList() * to add holes for pads and tracks and other items not in net. */ -bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aCornerBuffer ) +bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aOutlineBuffer ) { - if( aCornerBuffer == NULL ) - m_FilledPolysList.RemoveAllContours(); - /* 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 @@ -90,47 +87,33 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* break; } - if( aCornerBuffer ) - ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, *aCornerBuffer ); - else - ConvertPolysListWithHolesToOnePolygon( m_smoothedPoly->m_CornersList, m_FilledPolysList ); + if( aOutlineBuffer ) + aOutlineBuffer->Append( m_smoothedPoly->m_CornersList ); /* For copper layers, we now must add holes in the Polygon list. * holes are pads and tracks with their clearance area * for non copper layers just recalculate the m_FilledPolysList * with m_ZoneMinThickness taken in account */ - if( !aCornerBuffer ) + else { + m_FilledPolysList.RemoveAllContours(); + if( IsOnCopperLayer() ) AddClearanceAreasPolygonsToPolysList( aPcb ); else { - // This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2 - KI_POLYGON_SET polyset_zone_solid_areas; int margin = m_ZoneMinThickness / 2; - - /* First, creates the main polygon (i.e. the filled area using only one outline) - * to reserve a m_ZoneMinThickness/2 margin around the outlines and holes - * this margin is the room to redraw outlines with segments having a width set to - * m_ZoneMinThickness - * so m_ZoneMinThickness is the min thickness of the filled zones areas - * the polygon is stored in polyset_zone_solid_areas - */ - CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas ); - polyset_zone_solid_areas -= margin; - // put solid area in m_FilledPolysList: - m_FilledPolysList.RemoveAllContours(); - CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas ); + m_smoothedPoly->m_CornersList.InflateOutline(m_FilledPolysList, margin, true ); } if( m_FillMode ) // if fill mode uses segments, create them: FillZoneAreasWithSegments(); + + m_IsFilled = true; } - m_IsFilled = true; - - return 1; + return true; } 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 20ac77f2d1..a4c22752dc 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -138,6 +138,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) */ s_Correction = 1.0 / cos( M_PI / s_CircleToSegmentsCount ); + // this is a place to store holes (i.e. tracks, pads ... areas as polygons outlines) + // static to avoid unnecessary memory allocation when filling many zones. + static CPOLYGONS_LIST cornerBufferPolysToSubstract; + cornerBufferPolysToSubstract.RemoveAllContours(); + // This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2 KI_POLYGON_SET polyset_zone_solid_areas; int margin = m_ZoneMinThickness / 2; @@ -149,13 +154,35 @@ 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 */ - - CopyPolygonsFromFilledPolysListToKiPolygonList( polyset_zone_solid_areas ); - polyset_zone_solid_areas -= margin; +#if 1 + m_smoothedPoly->m_CornersList.ExportTo( polyset_zone_solid_areas ); if( polyset_zone_solid_areas.size() == 0 ) return; + // Extract holes (cutout areas) and add them to the hole buffer + KI_POLYGON_SET outlineHoles; + + while( polyset_zone_solid_areas.size() > 1 ) + { + outlineHoles.push_back( polyset_zone_solid_areas.back() ); + polyset_zone_solid_areas.pop_back(); + } + + // deflate main outline reserve room for thick outline + polyset_zone_solid_areas -= margin; + // inflate outline holes + if( outlineHoles.size() ) + outlineHoles += margin; + + if( outlineHoles.size() ) + cornerBufferPolysToSubstract.ImportFrom( outlineHoles ); +#else + CPOLYGONS_LIST tmp; + m_smoothedPoly->m_CornersList.InflateOutline( tmp, -margin, true ); + tmp.ExportTo( polyset_zone_solid_areas ); +#endif + /* Calculates the clearance value that meet DRC requirements * from m_ZoneClearance and clearance from the corresponding netclass * We have a "local" clearance in zones because most of time @@ -186,10 +213,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) */ int item_clearance; - // static to avoid unnecessary memory allocation when filling many zones. - static CPOLYGONS_LIST cornerBufferPolysToSubstract; - cornerBufferPolysToSubstract.RemoveAllContours(); - /* Use a dummy pad to calculate hole clerance when a pad is not on all copper layers * and this pad has a hole * This dummy pad has the size and shape of the hole diff --git a/pcbnew/zones_convert_to_polygons_aux_functions.cpp b/pcbnew/zones_convert_to_polygons_aux_functions.cpp index 9861b0d120..985d0db48f 100644 --- a/pcbnew/zones_convert_to_polygons_aux_functions.cpp +++ b/pcbnew/zones_convert_to_polygons_aux_functions.cpp @@ -51,12 +51,13 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer, int aClearanceValue, bool aAddClearance ) { - // Creates the zone outlines polygon (with linked holes if any) - CPOLYGONS_LIST zoneOutines; - BuildFilledSolidAreasPolygons( NULL, &zoneOutines ); + // Creates the zone outline polygon (with linked holes if any) + CPOLYGONS_LIST zoneOutline; + BuildFilledSolidAreasPolygons( NULL, &zoneOutline ); // add clearance to outline int clearance = 0; + if( aAddClearance ) { clearance = GetClearance(); @@ -64,51 +65,11 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon( clearance = aClearanceValue; } // Calculate the polygon with clearance - // holes are linked to the main outline, so only one polygon should be created. - KI_POLYGON_SET polyset_zone_solid_areas; - std::vector cornerslist; - unsigned ic = 0; - unsigned corners_count = zoneOutines.GetCornersCount(); - while( ic < corners_count ) - { - cornerslist.clear(); - KI_POLYGON poly; - { - for( ; ic < corners_count; ic++ ) - { - CPolyPt* corner = &zoneOutines[ic]; - cornerslist.push_back( KI_POLY_POINT( corner->x, corner->y ) ); - if( corner->end_contour ) - { - ic++; - break; - } - } - - bpl::set_points( poly, cornerslist.begin(), cornerslist.end() ); - polyset_zone_solid_areas.push_back( poly ); - } - } - - polyset_zone_solid_areas += clearance; - - // Put the resulting polygon in aCornerBuffer corners list - for( unsigned ii = 0; ii < polyset_zone_solid_areas.size(); ii++ ) - { - KI_POLYGON& poly = polyset_zone_solid_areas[ii]; - CPolyPt corner( 0, 0, false ); - - for( unsigned jj = 0; jj < poly.size(); jj++ ) - { - KI_POLY_POINT point = *(poly.begin() + jj); - corner.x = point.x(); - corner.y = point.y(); - corner.end_contour = false; - aCornerBuffer.Append( corner ); - } - - aCornerBuffer.CloseLastContour(); - } + // holes are linked to the main outline, so only one polygon is created. + if( clearance ) + zoneOutline.InflateOutline( aCornerBuffer, clearance, true ); + else + ConvertPolysListWithHolesToOnePolygon( zoneOutline, aCornerBuffer ); } diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 9c2e78d993..b9b23ef76e 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -1347,6 +1347,44 @@ void CPOLYGONS_LIST::ExportTo( KI_POLYGON_SET& aPolygons ) const } } +/* + * Copy all contours to a ClipperLib::Paths& aPolygons + * Each contour is copied into a ClipperLib::Path, and each ClipperLib::Path + * is append to aPolygons + */ +void CPOLYGONS_LIST::ExportTo( ClipperLib::Paths& aPolygons ) const +{ + unsigned corners_count = GetCornersCount(); + + // Count the number of polygons in aCornersBuffer + int polycount = 0; + + for( unsigned ii = 0; ii < corners_count; ii++ ) + { + if( IsEndContour( ii ) ) + polycount++; + } + + aPolygons.reserve( polycount ); + + for( unsigned icnt = 0; icnt < corners_count; ) + { + ClipperLib::Path poly; + unsigned ii; + + for( ii = icnt; ii < corners_count; ii++ ) + { + poly << ClipperLib::IntPoint( GetX( ii ), GetY( ii ) ); + + if( IsEndContour( ii ) ) + break; + } + + aPolygons.push_back( poly ); + icnt = ii + 1; + } +} + /* Imports all polygons found in a KI_POLYGON_SET in list */ @@ -1372,6 +1410,72 @@ void CPOLYGONS_LIST::ImportFrom( KI_POLYGON_SET& aPolygons ) } +/* Imports all polygons found in a ClipperLib::Paths in list + */ +void CPOLYGONS_LIST::ImportFrom( ClipperLib::Paths& aPolygons ) +{ + CPolyPt corner; + + for( unsigned ii = 0; ii < aPolygons.size(); ii++ ) + { + ClipperLib::Path& polygon = aPolygons[ii]; + + for( unsigned jj = 0; jj < polygon.size(); jj++ ) + { + corner.x = int( polygon[jj].X ); + corner.y = int( polygon[jj].Y ); + corner.end_contour = false; + AddCorner( corner ); + } + + CloseLastContour(); + } +} + +/* Inflate the outline stored in m_cornersList. + * The first polygon is the external outline. It is inflated + * The other polygons are holes. they are deflated + * aResult = the Inflated outline + * 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 + */ +void CPOLYGONS_LIST::InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles ) +{ + KI_POLYGON_SET polyset_outline; + ExportTo( polyset_outline ); + + // Extract holes (cutout areas) and add them to the hole buffer + KI_POLYGON_SET outlineHoles; + + while( polyset_outline.size() > 1 ) + { + outlineHoles.push_back( polyset_outline.back() ); + polyset_outline.pop_back(); + } + + // inflate main outline + if( polyset_outline.size() ) + polyset_outline += aInflateValue; + + // deflate outline holes + if( outlineHoles.size() ) + outlineHoles -= aInflateValue; + + // Copy modified polygons + if( !aLinkHoles ) + { + aResult.ImportFrom( polyset_outline ); + + if( outlineHoles.size() ) + aResult.ImportFrom( outlineHoles ); + } + else + { + polyset_outline -= outlineHoles; + aResult.ImportFrom( polyset_outline ); + } +} /** * Function ConvertPolysListWithHolesToOnePolygon @@ -1438,26 +1542,14 @@ void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWith polysholes.push_back( poly_tmp ); } } + mainpoly -= polysholes; // copy polygon with no holes to destination // Because all holes are now linked to the main outline // by overlapping segments, we should have only one polygon in list wxASSERT( mainpoly.size() == 1 ); - - KI_POLYGON& poly_nohole = mainpoly[0]; - CPolyPt corner( 0, 0, false ); - - for( unsigned jj = 0; jj < poly_nohole.size(); jj++ ) - { - KI_POLY_POINT point = *(poly_nohole.begin() + jj); - corner.x = point.x(); - corner.y = point.y(); - corner.end_contour = false; - aOnePolyList.AddCorner( corner ); - } - - aOnePolyList.CloseLastContour(); + aOnePolyList.ImportFrom( mainpoly ); } /** @@ -1553,3 +1645,22 @@ bool CPolyLine::IsPolygonSelfIntersecting() return false; } + + +/* converts the outline aOnePolyList (only one contour, + * holes are linked by overlapping segments) to + * to one main polygon and holes (polygons inside main polygon) + * aOnePolyList = a only one polygon ( holes are linked ) + * aPolysListWithHoles = the list of corners of contours + * (main outline and holes) + */ +void ConvertOnePolygonToPolysListWithHoles( const CPOLYGONS_LIST& aOnePolyList, + CPOLYGONS_LIST& aPolysListWithHoles ) +{ + ClipperLib::Paths initialPoly; + ClipperLib::Paths modifiedPoly; + + aOnePolyList.ExportTo( initialPoly ); + SimplifyPolygon(initialPoly[0], modifiedPoly ); + aPolysListWithHoles.ImportFrom( modifiedPoly ); +} diff --git a/polygon/PolyLine.h b/polygon/PolyLine.h index 9239bc274d..8abf92461e 100644 --- a/polygon/PolyLine.h +++ b/polygon/PolyLine.h @@ -54,6 +54,7 @@ #include // for LAYER_NUM definition #include // for EDA_RECT definition #include +#include class CSegment { @@ -186,28 +187,6 @@ public: m_cornersList.insert( m_cornersList.begin() + aPosition + 1, aItem ); } - /** - * Function ExportTo - * Copy all contours to a KI_POLYGON_SET - * @param aPolygons = the KI_POLYGON_WITH_HOLES to populate - */ - void ExportTo( KI_POLYGON_SET& aPolygons ) const; - - /** - * Function ExportTo - * Copy the contours to a KI_POLYGON_WITH_HOLES - * The first contour is the main outline, others are holes - * @param aPolygoneWithHole = the KI_POLYGON_WITH_HOLES to populate - */ - void ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const; - - /** - * Function ImportFrom - * Copy all polygons from a KI_POLYGON_SET in list - * @param aPolygons = the KI_POLYGON_SET to import - */ - void ImportFrom( KI_POLYGON_SET& aPolygons ); - /** * function AddCorner * add a corner to the list @@ -226,6 +205,56 @@ public: if( m_cornersList.size() > 0 ) m_cornersList.back().end_contour = true; } + + /** + * Function ExportTo + * Copy all contours to a KI_POLYGON_SET, each contour is exported + * to a KI_POLYGON + * @param aPolygons = the KI_POLYGON_SET to populate + */ + void ExportTo( KI_POLYGON_SET& aPolygons ) const; + + /** + * Function ExportTo + * Copy the contours to a KI_POLYGON_WITH_HOLES + * The first contour is the main outline, others are holes + * @param aPolygoneWithHole = the KI_POLYGON_WITH_HOLES to populate + */ + void ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const; + + /** + * Function ExportTo + * Copy all contours to a ClipperLib::Paths, each contour is exported + * to a ClipperLib::Path + * @param aPolygons = the ClipperLib::Paths to populate + */ + void ExportTo( ClipperLib::Paths& aPolygons ) const; + + /** + * Function ImportFrom + * Copy all polygons from a KI_POLYGON_SET in list + * @param aPolygons = the KI_POLYGON_SET to import + */ + void ImportFrom( KI_POLYGON_SET& aPolygons ); + + /** + * Function ImportFrom + * Copy all polygons from a ClipperLib::Paths in list + * @param aPolygons = the ClipperLib::Paths to import + */ + void ImportFrom( ClipperLib::Paths& aPolygons ); + + /** + * Function InflateOutline + * Inflate the outline stored in m_cornersList. + * The first polygon is the external outline. It is inflated + * The other polygons are holes. they are deflated + * @param aResult = the Inflated outline + * @param aInflateValue = the Inflate value. when < 0, this is a deflate transform + * @param aLinkHoles = if true, aResult contains only one polygon, + * with holes linked by overlapping segments + */ + void InflateOutline( CPOLYGONS_LIST& aResult, int aInflateValue, bool aLinkHoles ); }; class CPolyLine @@ -489,4 +518,17 @@ public: void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWithHoles, CPOLYGONS_LIST& aOnePolyList ); +/** + * Function ConvertOnePolygonToPolysListWithHoles + * converts the outline aOnePolyList (only one contour, + * holes are linked by overlapping segments) to + * to one main polygon and holes (polygons inside main polygon) + * @param aOnePolyList = a polygon with no holes + * @param aPolysListWithHoles = the list of corners of contours + * (main outline and holes) + */ +void ConvertOnePolygonToPolysListWithHoles( const CPOLYGONS_LIST& aOnePolyList, + CPOLYGONS_LIST& aPolysListWithHoles ); + + #endif // #ifndef POLYLINE_H