Commit cf9a885c authored by jean-pierre charras's avatar jean-pierre charras

Modify usage of Inflate/deflate polygon in zone calculations, in order to be...

Modify usage of Inflate/deflate polygon in zone calculations, in order to be compatible with boost::polygon >= 1.56
 Inflate/deflate polygons does not work very well (neither with  boost::polygon >= 1.56 nor with Clipper) for polygons which have holes linked by overlapping segments
(i.e. polygons with holes which can be drawn, because they are see as only one polygon)
Some code cleanup.
parents 4bba4b87 25a801ed
......@@ -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:
;
......
......@@ -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.
*/
bool BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aCornerBuffer = NULL );
* 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* aOutlineBuffer = NULL );
/**
* Function CopyPolygonsFromKiPolygonListToFilledPolysList
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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<KI_POLY_POINT> 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 );
}
......
......@@ -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 );
}
......@@ -54,6 +54,7 @@
#include <layers_id_colors_and_visibility.h> // for LAYER_NUM definition
#include <class_eda_rect.h> // for EDA_RECT definition
#include <polygons_defs.h>
#include <clipper.hpp>
class CSegment
{
......@@ -186,10 +187,30 @@ public:
m_cornersList.insert( m_cornersList.begin() + aPosition + 1, aItem );
}
/**
* function AddCorner
* add a corner to the list
*/
void AddCorner( const CPolyPt& aCorner )
{
m_cornersList.push_back( aCorner );
}
/**
* function CloseLastContour
* Set the .end_contour member of the last corner in list to true
*/
void CloseLastContour()
{
if( m_cornersList.size() > 0 )
m_cornersList.back().end_contour = true;
}
/**
* Function ExportTo
* Copy all contours to a KI_POLYGON_SET
* @param aPolygons = the KI_POLYGON_WITH_HOLES to populate
* 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;
......@@ -201,6 +222,14 @@ public:
*/
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
......@@ -209,23 +238,23 @@ public:
void ImportFrom( KI_POLYGON_SET& aPolygons );
/**
* function AddCorner
* add a corner to the list
* Function ImportFrom
* Copy all polygons from a ClipperLib::Paths in list
* @param aPolygons = the ClipperLib::Paths to import
*/
void AddCorner( const CPolyPt& aCorner )
{
m_cornersList.push_back( aCorner );
}
void ImportFrom( ClipperLib::Paths& aPolygons );
/**
* function CloseLastContour
* Set the .end_contour member of the last corner in list to true
* 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 CloseLastContour()
{
if( m_cornersList.size() > 0 )
m_cornersList.back().end_contour = true;
}
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment