Removed all dependencies on boost::polygon except for bitmap2component. Replaced almost all instances of CPOLYGONS_LIST with SHAPE_POLY_SET.

This commit is contained in:
Tomasz Wlostowski 2015-07-27 21:45:57 +02:00 committed by Maciej Suminski
parent a30a2d72e8
commit 63b35f40a7
44 changed files with 1221 additions and 2006 deletions

View File

@ -49,7 +49,7 @@
class BOARD_DESIGN_SETTINGS;
class EDA_3D_FRAME;
class CPOLYGONS_LIST;
class SHAPE_POLY_SET;
class REPORTER;
class VIA;
@ -306,7 +306,7 @@ private:
* Used only to draw pads outlines on silkscreen layers.
*/
void buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor );

View File

@ -637,9 +637,7 @@ void EDA_3D_CANVAS::buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* a
double correctionFactor = 1.0 / cos( M_PI / (segcountforcircle * 2) );
BOARD* pcb = GetBoard();
CPOLYGONS_LIST bufferPolys;
bufferPolys.reserve( 5000 ); // Reserve for items not on board
SHAPE_POLY_SET bufferPolys;
static const LAYER_ID sequence[] = {
Dwgs_User,
@ -701,12 +699,10 @@ void EDA_3D_CANVAS::buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* a
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons and remove pads and vias holes
if( bufferPolys.GetCornersCount() == 0 )
if( bufferPolys.IsEmpty() )
continue;
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polyset;
bufferPolys.ExportTo( polyset );
currLayerPolyset += polyset;
bufferPolys.Fracture();
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
@ -719,9 +715,6 @@ void EDA_3D_CANVAS::buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* a
else
zpos -= thickness/2 ;
bufferPolys.RemoveAllContours();
bufferPolys.ImportFrom( currLayerPolyset );
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)
// If we are not using thickness, then the znormal must face the layer direction

View File

@ -62,7 +62,7 @@ void TransfertToGLlist( std::vector< S3D_VERTEX >& aVertices, double aBiuTo3DUni
* from Z position = aZpos to aZpos + aHeight
* Used to create the vertical sides of 3D horizontal shapes with thickness.
*/
static void Draw3D_VerticalPolygonalCylinder( const CPOLYGONS_LIST& aPolysList,
static void Draw3D_VerticalPolygonalCylinder( const SHAPE_POLY_SET& aPolysList,
int aHeight, int aZpos,
bool aInside, double aBiuTo3DUnits )
{
@ -87,29 +87,28 @@ static void Draw3D_VerticalPolygonalCylinder( const CPOLYGONS_LIST& aPolysList,
coords[3].z = coords[0].z;
// Draw the vertical polygonal side
int startContour = 0;
for( unsigned ii = 0; ii < aPolysList.GetCornersCount(); ii++ )
for( int ii = 0; ii < aPolysList.OutlineCount(); ii++ )
{
unsigned jj = ii + 1;
const SHAPE_LINE_CHAIN& path = aPolysList.COutline( ii );
if( aPolysList.IsEndContour( ii ) || jj >= aPolysList.GetCornersCount() )
for( int jj = 0; jj < path.PointCount(); jj++ )
{
jj = startContour;
startContour = ii + 1;
const VECTOR2I& a = path.CPoint( jj );
const VECTOR2I& b = path.CPoint( jj + 1 );
// Build the 4 vertices of each GL_QUAD
coords[0].x = a.x;
coords[0].y = -a.y;
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = b.x;
coords[2].y = -b.y;
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
// Creates the GL_QUAD
TransfertToGLlist( coords, aBiuTo3DUnits );
}
// Build the 4 vertices of each GL_QUAD
coords[0].x = aPolysList.GetX( ii );
coords[0].y = -aPolysList.GetY( ii );
coords[1].x = coords[0].x;
coords[1].y = coords[0].y; // only z change
coords[2].x = aPolysList.GetX( jj );
coords[2].y = -aPolysList.GetY( jj );
coords[3].x = coords[2].x;
coords[3].y = coords[2].y; // only z change
// Creates the GL_QUAD
TransfertToGLlist( coords, aBiuTo3DUnits );
}
}
@ -147,7 +146,7 @@ void SetGLTexture( GLuint text_id, float scale )
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation )
@ -176,7 +175,7 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
glNormal3f( 0.0, 0.0, aNormal_Z_Orientation );
// Draw solid areas contained in this list
CPOLYGONS_LIST polylist = aPolysList; // temporary copy for gluTessVertex
SHAPE_POLY_SET polylist = aPolysList; // temporary copy for gluTessVertex
int startContour;
@ -184,7 +183,7 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
{
startContour = 1;
for( unsigned ii = 0; ii < polylist.GetCornersCount(); ii++ )
for ( SHAPE_POLY_SET::ITERATOR ii = polylist.Iterate(); ii; ++ii )
{
if( startContour == 1 )
{
@ -193,16 +192,16 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
startContour = 0;
}
v_data[0] = polylist.GetX( ii ) * aBiuTo3DUnits;
v_data[1] = -polylist.GetY( ii ) * aBiuTo3DUnits;
v_data[0] = ii->x * aBiuTo3DUnits;
v_data[1] = -ii->y * aBiuTo3DUnits;
// gluTessVertex store pointers on data, not data, so do not store
// different corners values in a temporary variable
// but send pointer on each CPolyPt value in polylist
// before calling gluDeleteTess
gluTessVertex( tess, v_data, &polylist[ii] );
gluTessVertex( tess, v_data, &ii.Get() );
if( polylist.IsEndContour( ii ) )
if( ii.IsEndContour() )
{
gluTessEndContour( tess );
gluTessEndPolygon( tess );
@ -242,14 +241,15 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
* The first polygon is the main polygon, others are holes
* See Draw3D_SolidHorizontalPolyPolygons for more info
*/
void Draw3D_SolidHorizontalPolygonWithHoles( const CPOLYGONS_LIST& aPolysList,
void Draw3D_SolidHorizontalPolygonWithHoles( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness,
double aBiuTo3DUnits, bool aUseTextures,
float aNormal_Z_Orientation )
{
CPOLYGONS_LIST polygon;
SHAPE_POLY_SET polygon( aPolysList );
polygon.Fracture();
ConvertPolysListWithHolesToOnePolygon( aPolysList, polygon );
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos, aThickness, aBiuTo3DUnits, aUseTextures,
aNormal_Z_Orientation );
}
@ -265,7 +265,7 @@ void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
int aZpos, double aBiuTo3DUnits )
{
const int slice = SEGM_PER_CIRCLE;
CPOLYGONS_LIST outer_cornerBuffer;
SHAPE_POLY_SET outer_cornerBuffer;
TransformCircleToPolygon( outer_cornerBuffer, aCenterPos,
aRadius + (aThickness / 2), slice );
@ -273,7 +273,7 @@ void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
std::vector<S3D_VERTEX> coords;
coords.resize( 4 );
CPOLYGONS_LIST inner_cornerBuffer;
SHAPE_POLY_SET inner_cornerBuffer;
if( aThickness ) // build the the vertical inner polygon (hole)
TransformCircleToPolygon( inner_cornerBuffer, aCenterPos,
aRadius - (aThickness / 2), slice );
@ -294,10 +294,11 @@ void Draw3D_ZaxisCylinder( wxPoint aCenterPos, int aRadius,
if( aThickness )
{
// draw top (front) and bottom (back) horizontal sides (rings)
outer_cornerBuffer.Append( inner_cornerBuffer );
CPOLYGONS_LIST polygon;
outer_cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
SHAPE_POLY_SET polygon = outer_cornerBuffer;
polygon.Fracture();
ConvertPolysListWithHolesToOnePolygon( outer_cornerBuffer, polygon );
// draw top (front) horizontal ring
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos + aHeight, 0, aBiuTo3DUnits, false,
1.0f );
@ -326,7 +327,7 @@ void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
const int slice = SEGM_PER_CIRCLE;
// Build the points to approximate oblong cylinder by segments
CPOLYGONS_LIST outer_cornerBuffer;
SHAPE_POLY_SET outer_cornerBuffer;
int segm_width = (aRadius * 2) + aThickness;
TransformRoundedEndsSegmentToPolygon( outer_cornerBuffer, aAxis1Pos,
@ -339,7 +340,7 @@ void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
if( aThickness )
{
CPOLYGONS_LIST inner_cornerBuffer;
SHAPE_POLY_SET inner_cornerBuffer;
segm_width = aRadius * 2;
TransformRoundedEndsSegmentToPolygon( inner_cornerBuffer, aAxis1Pos,
aAxis2Pos, slice, segm_width );
@ -351,10 +352,10 @@ void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
// Build the horizontal full polygon shape
// (outer polygon shape - inner polygon shape)
outer_cornerBuffer.Append( inner_cornerBuffer );
outer_cornerBuffer.AddHole( inner_cornerBuffer.COutline( 0 ) );
CPOLYGONS_LIST polygon;
ConvertPolysListWithHolesToOnePolygon( outer_cornerBuffer, polygon );
SHAPE_POLY_SET polygon( outer_cornerBuffer );
polygon.Fracture();
// draw top (front) horizontal side (ring)
Draw3D_SolidHorizontalPolyPolygons( polygon, aZpos + aHeight, 0, aBiuTo3DUnits, false,
@ -379,8 +380,8 @@ void Draw3D_ZaxisOblongCylinder( wxPoint aAxis1Pos, wxPoint aAxis2Pos,
void Draw3D_SolidSegment( const wxPoint& aStart, const wxPoint& aEnd,
int aWidth, int aThickness, int aZpos, double aBiuTo3DUnits )
{
CPOLYGONS_LIST cornerBuffer;
const int slice = SEGM_PER_CIRCLE;
SHAPE_POLY_SET cornerBuffer;
const int slice = SEGM_PER_CIRCLE;
TransformRoundedEndsSegmentToPolygon( cornerBuffer, aStart, aEnd, slice, aWidth );
@ -394,7 +395,7 @@ void Draw3D_ArcSegment( const wxPoint& aCenterPos, const wxPoint& aStartPoint,
{
const int slice = SEGM_PER_CIRCLE;
CPOLYGONS_LIST cornerBuffer;
SHAPE_POLY_SET cornerBuffer;
TransformArcToPolygon( cornerBuffer, aCenterPos, aStartPoint, aArcAngle,
slice, aWidth );
@ -421,7 +422,7 @@ void CALLBACK tessEndCB()
void CALLBACK tessCPolyPt2Vertex( const GLvoid* data )
{
// cast back to double type
const CPolyPt* ptr = (const CPolyPt*) data;
const VECTOR2I* ptr = (const VECTOR2I*) data;
if( s_useTextures )
{

View File

@ -43,7 +43,7 @@
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
void Draw3D_SolidHorizontalPolyPolygons( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation );
@ -61,7 +61,7 @@ void Draw3D_SolidHorizontalPolyPolygons( const CPOLYGONS_LIST& aPolysList,
* The top side is located at aZpos + aThickness / 2
* The bottom side is located at aZpos - aThickness / 2
*/
void Draw3D_SolidHorizontalPolygonWithHoles( const CPOLYGONS_LIST& aPolysList,
void Draw3D_SolidHorizontalPolygonWithHoles( const SHAPE_POLY_SET& aPolysList,
int aZpos, int aThickness, double aBiuTo3DUnits,
bool aUseTextures,
float aNormal_Z_Orientation );

View File

@ -57,6 +57,8 @@
#include <trackball.h>
#include <3d_draw_basic_functions.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_file_io.h>
#include <CImage.h>
#include <reporter.h>
@ -68,6 +70,7 @@
*/
GLfloat Get3DLayer_Z_Orientation( LAYER_NUM aLayer );
#if 0
// FIX ME: these 2 functions are fully duplicate of the same 2 functions in
// pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp
@ -88,7 +91,7 @@ static const SHAPE_POLY_SET convertPolyListToPolySet(const CPOLYGONS_LIST& aList
while( ic < corners_count )
{
rv.AppendVertex( aList.GetX(ic), aList.GetY(ic) );
rv.Append( aList.GetX(ic), aList.GetY(ic) );
if( aList.IsEndContour( ic ) )
break;
@ -128,6 +131,7 @@ static const CPOLYGONS_LIST convertPolySetToPolyList(const SHAPE_POLY_SET& aPoly
return list;
}
#endif
void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
REPORTER* aErrorMessages, REPORTER* aActivity )
@ -156,13 +160,11 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
// a fine representation
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2.0) );
CPOLYGONS_LIST bufferPolys;
bufferPolys.reserve( 500000 ); // Reserve for large board: tracks mainly
// + zones when holes are removed from zones
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
allLayerHoles.reserve( 20000 );
SHAPE_POLY_SET bufferPolys;
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
SHAPE_POLY_SET bufferZonesPolys;
SHAPE_POLY_SET currLayerHoles, allLayerHoles; // Contains holes for the current layer
// + zones when holes are removed from zones
// Build a polygon from edge cut items
wxString msg;
@ -179,12 +181,7 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
}
}
CPOLYGONS_LIST bufferZonesPolys;
bufferZonesPolys.reserve( 300000 ); // Reserve for large board ( copper zones mainly )
// when holes are not removed from zones
CPOLYGONS_LIST currLayerHoles; // Contains holes for the current layer
bool throughHolesListBuilt = false; // flag to build the through hole polygon list only once
bool throughHolesListBuilt = false; // flag to build the through hole polygon list only once
LSET cu_set = LSET::AllCuMask( GetPrm3DVisu().m_CopperLayersCount );
@ -351,47 +348,35 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons
if( bufferPolys.GetCornersCount() == 0 )
if( bufferPolys.IsEmpty() )
continue;
#if 0
// Set to 1 to use boost::polygon to subtract holes to copper areas
// (due to bugs in boost::polygon, this is deprecated and Clipper is used instead
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polysetHoles;
std::auto_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO( "poly_dump.txt", true ) );
// Add polygons, without holes
bufferPolys.ExportTo( currLayerPolyset );
// Add through holes (created only once) in current polygon holes list
currLayerHoles.Append( allLayerHoles );
if( currLayerHoles.GetCornersCount() > 0 )
currLayerHoles.ExportTo( polysetHoles );
// Merge polygons, and remove holes
currLayerPolyset -= polysetHoles;
bufferPolys.RemoveAllContours();
bufferPolys.ImportFrom( currLayerPolyset );
#else
// Use Clipper lib to subtract holes to copper areas
SHAPE_POLY_SET solidAreas = convertPolyListToPolySet( bufferPolys );
solidAreas.Simplify();
dumper->BeginGroup( "clipper-zone" );
dumper->Write( &bufferPolys, "pre-simplify" );
bufferPolys.Simplify();
dumper->Write( &bufferPolys, "post-simplify" );
currLayerHoles.Simplify();
allLayerHoles.Simplify();
//dumper->Write(&bufferPolys, "pre-sub");
//dumper->Write(&allLayerHoles, "holes");
// Add through holes (created only once) in current polygon holes list
currLayerHoles.Append( allLayerHoles );
if( currLayerHoles.GetCornersCount() > 0 )
{
SHAPE_POLY_SET holes = convertPolyListToPolySet( currLayerHoles );
holes.Simplify();
solidAreas.Subtract ( holes );
}
SHAPE_POLY_SET fractured = solidAreas;
fractured.Fracture();
bufferPolys.RemoveAllContours();
bufferPolys = convertPolySetToPolyList( fractured );
#endif
//bufferPolys.BooleanSubtract( currLayerHoles );
//bufferPolys.Simplify();
bufferPolys.BooleanSubtract( allLayerHoles );
//dumper->Write(&bufferPolys, "post-sub");
dumper->EndGroup();
bufferPolys.Fracture();
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
@ -421,7 +406,7 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
// If holes are not removed from copper zones (for calculation time reasons,
// the zone polygons are stored in bufferZonesPolys and have to be drawn now:
if( bufferZonesPolys.GetCornersCount() )
if( !bufferZonesPolys.IsEmpty() )
{
Draw3D_SolidHorizontalPolyPolygons( bufferZonesPolys, zpos, thickness,
GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
@ -490,22 +475,10 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
zpos += (copper_thickness + epsilon) / 2.0f;
board_thickness -= copper_thickness + epsilon;
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polysetHoles;
bufferPcbOutlines.BooleanSubtract( allLayerHoles );
bufferPcbOutlines.Fracture();
// Add polygons, without holes
bufferPcbOutlines.ExportTo( currLayerPolyset );
// Build holes list
allLayerHoles.ExportTo( polysetHoles );
// remove holes
currLayerPolyset -= polysetHoles;
bufferPcbOutlines.RemoveAllContours();
bufferPcbOutlines.ImportFrom( currLayerPolyset );
if( bufferPcbOutlines.GetCornersCount() )
if( !bufferPcbOutlines.IsEmpty() )
{
Draw3D_SolidHorizontalPolyPolygons( bufferPcbOutlines, zpos + board_thickness / 2.0,
board_thickness, GetPrm3DVisu().m_BiuTo3Dunits, useTextures,
@ -531,12 +504,9 @@ void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* a
double correctionFactorLQ = 1.0 / cos( M_PI / (segcountLowQuality * 2) );
CPOLYGONS_LIST bufferPolys;
bufferPolys.reserve( 100000 ); // Reserve for large board
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
allLayerHoles.reserve( 20000 );
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
SHAPE_POLY_SET bufferPolys;
SHAPE_POLY_SET allLayerHoles; // Contains through holes, calculated only once
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
// Build a polygon from edge cut items
wxString msg;
@ -581,9 +551,6 @@ void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* a
// draw graphic items, on technical layers
KI_POLYGON_SET brdpolysetHoles;
allLayerHoles.ExportTo( brdpolysetHoles );
static const LAYER_ID teckLayerList[] = {
B_Adhes,
F_Adhes,
@ -675,33 +642,34 @@ void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* a
// bufferPolys contains polygons to merge. Many overlaps .
// Calculate merged polygons and remove pads and vias holes
if( bufferPolys.GetCornersCount() == 0 )
if( bufferPolys.IsEmpty() )
continue;
KI_POLYGON_SET currLayerPolyset;
KI_POLYGON_SET polyset;
allLayerHoles.Simplify();
// Solder mask layers are "negative" layers.
// Shapes should be removed from the full board area.
if( layer == B_Mask || layer == F_Mask )
{
bufferPcbOutlines.ExportTo( currLayerPolyset );
bufferPolys.Append( allLayerHoles );
bufferPolys.ExportTo( polyset );
currLayerPolyset -= polyset;
SHAPE_POLY_SET cuts = bufferPolys;
bufferPolys = bufferPcbOutlines;
cuts.Append(allLayerHoles);
cuts.Simplify();
bufferPolys.BooleanSubtract( cuts );
}
// Remove holes from Solder paste layers and siklscreen
else if( layer == B_Paste || layer == F_Paste
|| layer == B_SilkS || layer == F_SilkS )
{
bufferPolys.ExportTo( currLayerPolyset );
currLayerPolyset -= brdpolysetHoles;
}
else // usuall layers, merge polys built from each item shape:
{
bufferPolys.ExportTo( polyset );
currLayerPolyset += polyset;
bufferPolys.BooleanSubtract( allLayerHoles );
}
bufferPolys.Fracture();
int thickness = 0;
if( layer != B_Mask && layer != F_Mask )
@ -728,8 +696,6 @@ void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* a
zpos -= thickness/2 ;
}
bufferPolys.RemoveAllContours();
bufferPolys.ImportFrom( currLayerPolyset );
float zNormal = 1.0f; // When using thickness it will draw first the top and then botton (with z inverted)

View File

@ -366,7 +366,7 @@ void EDA_3D_CANVAS::draw3DPadHole( const D_PAD* aPad )
return;
// Store here the points to approximate hole by segments
CPOLYGONS_LIST holecornersBuffer;
SHAPE_POLY_SET holecornersBuffer;
int thickness = GetPrm3DVisu().GetCopperThicknessBIU();
int height = GetPrm3DVisu().GetLayerZcoordBIU( F_Cu ) -
GetPrm3DVisu().GetLayerZcoordBIU( B_Cu );
@ -444,7 +444,7 @@ void EDA_3D_CANVAS::draw3DViaHole( const VIA* aVia )
* Used only to draw pads outlines on silkscreen layers.
*/
void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aWidth,
int aCircleToSegmentsCount,
double aCorrectionFactor )
@ -457,17 +457,22 @@ void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad,
}
// For other shapes, draw polygon outlines
CPOLYGONS_LIST corners;
SHAPE_POLY_SET corners;
aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ),
aCircleToSegmentsCount, aCorrectionFactor );
// Add outlines as thick segments in polygon buffer
for( unsigned ii = 0, jj = corners.GetCornersCount() - 1;
ii < corners.GetCornersCount(); jj = ii, ii++ )
const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
for( int ii = 0; ii < path.PointCount(); ii++ )
{
const VECTOR2I& a = path.CPoint( ii );
const VECTOR2I& b = path.CPoint( ii + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
corners.GetPos( jj ),
corners.GetPos( ii ),
wxPoint( a.x, a.y ),
wxPoint( b.x, b.y ),
aCircleToSegmentsCount, aWidth );
}
}

View File

@ -346,8 +346,7 @@ void DXF_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, int
* It does not know thhick segments, therefore filled polygons with thick outline
* are converted to inflated polygon by aWidth/2
*/
#include "clipper.hpp"
void DXF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
void DXF_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList,
FILL_T aFill, int aWidth)
{
if( aCornerList.size() <= 1 )
@ -392,10 +391,12 @@ void DXF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
// The polygon outline has thickness, and is filled
// Build and plot the polygon which contains the initial
// polygon and its thick outline
CPOLYGONS_LIST bufferOutline;
CPOLYGONS_LIST bufferPolybase;
SHAPE_POLY_SET bufferOutline;
SHAPE_POLY_SET bufferPolybase;
const int circleToSegmentsCount = 16;
bufferPolybase.NewOutline();
// enter outline as polygon:
for( unsigned ii = 1; ii < aCornerList.size(); ii++ )
{
@ -406,47 +407,40 @@ void DXF_PLOTTER::PlotPoly( const std::vector< wxPoint >& aCornerList,
// enter the initial polygon:
for( unsigned ii = 0; ii < aCornerList.size(); ii++ )
{
CPolyPt polypoint( aCornerList[ii].x, aCornerList[ii].y );
bufferPolybase.Append( polypoint );
bufferPolybase.Append( aCornerList[ii] );
}
bufferPolybase.CloseLastContour();
// Merge polygons to build the polygon which contains the initial
// polygon and its thick outline
KI_POLYGON_SET polysBase; // Store the main outline and the final outline
KI_POLYGON_SET polysOutline; // Store the thick segments to draw the outline
bufferPolybase.ExportTo( polysBase );
bufferOutline.ExportTo( polysOutline );
polysBase += polysOutline; // create the outline which contains thick outline
bufferPolybase.BooleanAdd( bufferOutline ); // create the outline which contains thick outline
bufferPolybase.Fracture();
// We should have only one polygon in list, now.
wxASSERT( polysBase.size() == 1 );
if( polysBase.size() < 1 ) // should not happen
if( bufferPolybase.OutlineCount() < 1 ) // should not happen
return;
KI_POLYGON poly = polysBase[0]; // Expected only one polygon here
const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 );
if( poly.size() < 2 ) // should not happen
if( path.PointCount() < 2 ) // should not happen
return;
// Now, output the final polygon to DXF file:
last = poly.size() - 1;
KI_POLY_POINT point = *(poly.begin());
wxPoint startPoint( point.x(), point.y() );
last = path.PointCount() - 1;
VECTOR2I point = path.CPoint( 0 );
wxPoint startPoint( point.x, point.y );
MoveTo( startPoint );
for( unsigned ii = 1; ii < poly.size(); ii++ )
for( int ii = 1; ii < path.PointCount(); ii++ )
{
point = *( poly.begin() + ii );
LineTo( wxPoint( point.x(), point.y() ) );
point = path.CPoint( ii );
LineTo( wxPoint( point.x, point.y ) );
}
// Close polygon, if needed
point = *(poly.begin() + last);
wxPoint endPoint( point.x(), point.y() );
point = path.CPoint( last );
wxPoint endPoint( point.x, point.y );
if( endPoint != startPoint )
LineTo( startPoint );

View File

@ -43,7 +43,7 @@
* Note: the polygon is inside the circle, so if you want to have the polygon
* outside the circle, you should give aRadius calculated with a corrrection factor
*/
void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aCenter, int aRadius,
int aCircleToSegmentsCount )
{
@ -51,6 +51,8 @@ void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
int halfstep = 1800 / aCircleToSegmentsCount; // the starting value for rot angles
aCornerBuffer.NewOutline();
for( int ii = 0; ii < aCircleToSegmentsCount; ii++ )
{
corner_position.x = aRadius;
@ -58,11 +60,8 @@ void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
int angle = (ii * delta) + halfstep;
RotatePoint( &corner_position.x, &corner_position.y, angle );
corner_position += aCenter;
CPolyPt polypoint( corner_position.x, corner_position.y );
aCornerBuffer.Append( polypoint );
aCornerBuffer.Append( corner_position.x, corner_position.y );
}
aCornerBuffer.CloseLastContour();
}
@ -78,7 +77,7 @@ void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
* Note: the polygon is inside the arc ends, so if you want to have the polygon
* outside the circle, you should give aStart and aEnd calculated with a correction factor
*/
void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformRoundedEndsSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aStart, wxPoint aEnd,
int aCircleToSegmentsCount,
int aWidth )
@ -87,7 +86,9 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
wxPoint endp = aEnd - aStart; // end point coordinate for the same segment starting at (0,0)
wxPoint startp = aStart;
wxPoint corner;
CPolyPt polypoint;
VECTOR2I polypoint;
aCornerBuffer.NewOutline();
// normalize the position in order to have endp.x >= 0;
if( endp.x < 0 )
@ -112,7 +113,7 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
corner += startp;
polypoint.x = corner.x;
polypoint.y = corner.y;
aCornerBuffer.Append( polypoint );
aCornerBuffer.Append( polypoint.x, polypoint.y );
}
// Finish arc:
@ -121,7 +122,7 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
corner += startp;
polypoint.x = corner.x;
polypoint.y = corner.y;
aCornerBuffer.Append( polypoint );
aCornerBuffer.Append( polypoint.x, polypoint.y );
// add left rounded end:
for( int ii = 0; ii < 1800; ii += delta )
@ -132,7 +133,7 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
corner += startp;
polypoint.x = corner.x;
polypoint.y = corner.y;
aCornerBuffer.Append( polypoint );
aCornerBuffer.Append( polypoint.x, polypoint.y );
}
// Finish arc:
@ -141,9 +142,7 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
corner += startp;
polypoint.x = corner.x;
polypoint.y = corner.y;
aCornerBuffer.Append( polypoint );
aCornerBuffer.CloseLastContour();
aCornerBuffer.Append( polypoint.x, polypoint.y );
}
@ -158,7 +157,7 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aWidth = width (thickness) of the line
*/
void TransformArcToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aCentre, wxPoint aStart, double aArcAngle,
int aCircleToSegmentsCount, int aWidth )
{
@ -208,7 +207,7 @@ void TransformArcToPolygon( CPOLYGONS_LIST& aCornerBuffer,
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aWidth = width (thickness) of the ring
*/
void TransformRingToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aCentre, int aRadius,
int aCircleToSegmentsCount, int aWidth )
{
@ -218,7 +217,8 @@ void TransformRingToPolygon( CPOLYGONS_LIST& aCornerBuffer,
wxPoint curr_point;
int inner_radius = aRadius - ( aWidth / 2 );
int outer_radius = inner_radius + aWidth;
CPolyPt polycorner;
aCornerBuffer.NewOutline();
// Draw the inner circle of the ring
for( int ii = 0; ii < 3600; ii += delta )
@ -227,15 +227,11 @@ void TransformRingToPolygon( CPOLYGONS_LIST& aCornerBuffer,
curr_point.y = 0;
RotatePoint( &curr_point, ii );
curr_point += aCentre;
polycorner.x = curr_point.x;
polycorner.y = curr_point.y;
aCornerBuffer.Append( polycorner );
aCornerBuffer.Append( curr_point.x, curr_point.y );
}
// Draw the last point of inner circle
polycorner.x = aCentre.x + inner_radius;
polycorner.y = aCentre.y;
aCornerBuffer.Append( polycorner );
aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
// Draw the outer circle of the ring
for( int ii = 0; ii < 3600; ii += delta )
@ -244,18 +240,10 @@ void TransformRingToPolygon( CPOLYGONS_LIST& aCornerBuffer,
curr_point.y = 0;
RotatePoint( &curr_point, -ii );
curr_point += aCentre;
polycorner.x = curr_point.x;
polycorner.y = curr_point.y;
aCornerBuffer.Append( polycorner );
aCornerBuffer.Append( curr_point.x, curr_point.y );
}
// Draw the last point of outer circle
polycorner.x = aCentre.x + outer_radius;
polycorner.y = aCentre.y;
aCornerBuffer.Append( polycorner );
// Close the polygon
polycorner.x = aCentre.x + inner_radius;
polycorner.end_contour = true;
aCornerBuffer.Append( polycorner );
aCornerBuffer.Append( aCentre.x + outer_radius, aCentre.y );
aCornerBuffer.Append( aCentre.x + inner_radius, aCentre.y );
}

View File

@ -4,6 +4,9 @@
* Copyright (C) 2015 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* Point in polygon algorithm adapted from Clipper Library (C) Angus Johnson,
* subject to Clipper library license.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@ -25,22 +28,34 @@
#include <vector>
#include <cstdio>
#include <geometry/shape.h>
#include <geometry/shape_line_chain.h>
#include <set>
#include <list>
#include <algorithm>
#include <boost/foreach.hpp>
#include "geometry/shape_poly_set.h"
#include <geometry/shape.h>
#include <geometry/shape_line_chain.h>
#include <geometry/shape_poly_set.h>
using namespace ClipperLib;
SHAPE_POLY_SET::SHAPE_POLY_SET() :
SHAPE( SH_POLY_SET )
{
}
SHAPE_POLY_SET::~SHAPE_POLY_SET()
{
}
int SHAPE_POLY_SET::NewOutline()
{
Path empty_path;
Paths poly;
SHAPE_LINE_CHAIN empty_path;
POLYGON poly;
poly.push_back( empty_path );
m_polys.push_back( poly );
return m_polys.size() - 1;
@ -49,12 +64,13 @@ int SHAPE_POLY_SET::NewOutline()
int SHAPE_POLY_SET::NewHole( int aOutline )
{
assert( false );
return -1;
m_polys.back().push_back( SHAPE_LINE_CHAIN() );
return m_polys.back().size() - 2;
}
int SHAPE_POLY_SET::AppendVertex( int x, int y, int aOutline, int aHole )
int SHAPE_POLY_SET::Append( int x, int y, int aOutline, int aHole )
{
if( aOutline < 0 )
aOutline += m_polys.size();
@ -69,13 +85,13 @@ int SHAPE_POLY_SET::AppendVertex( int x, int y, int aOutline, int aHole )
assert( aOutline < (int)m_polys.size() );
assert( idx < (int)m_polys[aOutline].size() );
m_polys[aOutline][idx].push_back( IntPoint( x, y ) );
m_polys[aOutline][idx].Append( x, y );
return m_polys[aOutline][idx].size();
return m_polys[aOutline][idx].PointCount();
}
int SHAPE_POLY_SET::VertexCount( int aOutline, int aHole ) const
int SHAPE_POLY_SET::VertexCount( int aOutline , int aHole ) const
{
if( aOutline < 0 )
aOutline += m_polys.size();
@ -90,11 +106,11 @@ int SHAPE_POLY_SET::VertexCount( int aOutline, int aHole ) const
assert ( aOutline < (int)m_polys.size() );
assert ( idx < (int)m_polys[aOutline].size() );
return m_polys[aOutline][idx].size();
return m_polys[aOutline][idx].PointCount();
}
const VECTOR2I SHAPE_POLY_SET::GetVertex( int index, int aOutline, int aHole ) const
const VECTOR2I& SHAPE_POLY_SET::CVertex( int index, int aOutline , int aHole ) const
{
if( aOutline < 0 )
aOutline += m_polys.size();
@ -109,8 +125,26 @@ const VECTOR2I SHAPE_POLY_SET::GetVertex( int index, int aOutline, int aHole ) c
assert( aOutline < (int)m_polys.size() );
assert( idx < (int)m_polys[aOutline].size() );
IntPoint p = m_polys[aOutline][idx][index];
return VECTOR2I (p.X, p.Y);
return m_polys[aOutline][idx].CPoint( index );
}
VECTOR2I& SHAPE_POLY_SET::Vertex( int index, int aOutline , int aHole )
{
if( aOutline < 0 )
aOutline += m_polys.size();
int idx;
if( aHole < 0 )
idx = 0;
else
idx = aHole + 1;
assert( aOutline < (int)m_polys.size() );
assert( idx < (int)m_polys[aOutline].size() );
return m_polys[aOutline][idx].Point( index );
}
@ -118,13 +152,9 @@ int SHAPE_POLY_SET::AddOutline( const SHAPE_LINE_CHAIN& aOutline )
{
assert( aOutline.IsClosed() );
Path p = convert( aOutline );
Paths poly;
POLYGON poly;
if( !Orientation( p ) )
ReversePath( p ); // outlines are always CW
poly.push_back( p );
poly.push_back( aOutline );
m_polys.push_back( poly );
@ -139,49 +169,60 @@ int SHAPE_POLY_SET::AddHole( const SHAPE_LINE_CHAIN& aHole, int aOutline )
if( aOutline < 0 )
aOutline += m_polys.size();
Paths& poly = m_polys[aOutline];
POLYGON& poly = m_polys[aOutline];
assert( poly.size() );
Path p = convert( aHole );
if( Orientation( p ) )
ReversePath( p ); // holes are always CCW
poly.push_back( p );
poly.push_back( aHole );
return poly.size() - 1;
}
const ClipperLib::Path SHAPE_POLY_SET::convert( const SHAPE_LINE_CHAIN& aPath )
const Path SHAPE_POLY_SET::convertToClipper( const SHAPE_LINE_CHAIN& aPath, bool aRequiredOrientation )
{
Path c_path;
for( int i = 0; i < aPath.PointCount(); i++ )
{
const VECTOR2I& vertex = aPath.CPoint( i );
c_path.push_back( ClipperLib::IntPoint( vertex.x, vertex.y ) );
c_path.push_back( IntPoint( vertex.x, vertex.y ) );
}
if( Orientation( c_path ) != aRequiredOrientation )
ReversePath( c_path );
return c_path;
}
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType type, const SHAPE_POLY_SET& b )
const SHAPE_LINE_CHAIN SHAPE_POLY_SET::convertFromClipper( const Path& aPath )
{
SHAPE_LINE_CHAIN lc;
for( unsigned int i = 0; i < aPath.size(); i++ )
lc.Append( aPath[i].X, aPath[i].Y );
return lc;
}
void SHAPE_POLY_SET::booleanOp( ClipType type, const SHAPE_POLY_SET& b )
{
Clipper c;
c.StrictlySimple( true );
BOOST_FOREACH( Paths& subject, m_polys )
BOOST_FOREACH( const POLYGON& poly, m_polys )
{
c.AddPaths( subject, ptSubject, true );
for( unsigned int i = 0; i < poly.size(); i++ )
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true );
}
BOOST_FOREACH( const Paths& clip, b.m_polys )
BOOST_FOREACH( const POLYGON& poly, b.m_polys )
{
c.AddPaths( clip, ptClip, true );
for( unsigned int i = 0; i < poly.size(); i++ )
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true );
}
PolyTree solution;
@ -192,41 +233,39 @@ void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType type, const SHAPE_POLY_SET&
}
void SHAPE_POLY_SET::Add( const SHAPE_POLY_SET& b )
void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& b )
{
booleanOp( ctUnion, b );
}
void SHAPE_POLY_SET::Subtract( const SHAPE_POLY_SET& b )
void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& b )
{
booleanOp( ctDifference, b );
}
void SHAPE_POLY_SET::Erode( int aFactor )
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
{
ClipperOffset c;
BOOST_FOREACH( Paths& p, m_polys )
c.AddPaths(p, jtRound, etClosedPolygon );
BOOST_FOREACH( const POLYGON& poly, m_polys )
{
for( unsigned int i = 0; i < poly.size(); i++ )
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), jtRound, etClosedPolygon );
}
PolyTree solution;
c.ArcTolerance = (double)aFactor / M_PI / aCircleSegmentsCount;
c.Execute( solution, aFactor );
m_polys.clear();
for( PolyNode* n = solution.GetFirst(); n; n = n->GetNext() )
{
Paths ps;
ps.push_back( n->Contour );
m_polys.push_back( ps );
}
importTree( &solution );
}
void SHAPE_POLY_SET::importTree( ClipperLib::PolyTree* tree )
void SHAPE_POLY_SET::importTree( PolyTree* tree)
{
m_polys.clear();
@ -234,37 +273,37 @@ void SHAPE_POLY_SET::importTree( ClipperLib::PolyTree* tree )
{
if( !n->IsHole() )
{
Paths paths;
paths.push_back( n->Contour );
POLYGON paths;
paths.push_back( convertFromClipper( n->Contour ) );
for( unsigned i = 0; i < n->Childs.size(); i++ )
paths.push_back( n->Childs[i]->Contour );
for( unsigned int i = 0; i < n->Childs.size(); i++ )
paths.push_back( convertFromClipper( n->Childs[i]->Contour ) );
m_polys.push_back( paths );
m_polys.push_back(paths);
}
}
}
// Polygon fracturing code. Work in progress.
struct FractureEdge
{
FractureEdge( bool connected, Path* owner, int index ) :
FractureEdge( bool connected, SHAPE_LINE_CHAIN* owner, int index ) :
m_connected( connected ),
m_next( NULL )
{
m_p1 = (*owner)[index];
m_p2 = (*owner)[(index + 1) % owner->size()];
m_p1 = owner->CPoint( index );
m_p2 = owner->CPoint( index + 1 );
}
FractureEdge( int64_t y = 0 ) :
FractureEdge( int y = 0 ) :
m_connected( false ),
m_next( NULL )
{
m_p1.Y = m_p2.Y = y;
m_p1.x = m_p2.y = y;
}
FractureEdge( bool connected, const IntPoint& p1, const IntPoint& p2 ) :
FractureEdge( bool connected, const VECTOR2I& p1, const VECTOR2I& p2 ) :
m_connected( connected ),
m_p1( p1 ),
m_p2( p2 ),
@ -274,14 +313,14 @@ struct FractureEdge
bool matches( int y ) const
{
int y_min = std::min( m_p1.Y, m_p2.Y );
int y_max = std::max( m_p1.Y, m_p2.Y );
int y_min = std::min( m_p1.y, m_p2.y );
int y_max = std::max( m_p1.y, m_p2.y );
return ( y >= y_min ) && ( y <= y_max );
}
bool m_connected;
IntPoint m_p1, m_p2;
VECTOR2I m_p1, m_p2;
FractureEdge* m_next;
};
@ -290,10 +329,10 @@ typedef std::vector<FractureEdge*> FractureEdgeSet;
static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
{
int64_t x = edge->m_p1.X;
int64_t y = edge->m_p1.Y;
int64_t min_dist = std::numeric_limits<int64_t>::max();
int64_t x_nearest = 0;
int x = edge->m_p1.x;
int y = edge->m_p1.y;
int min_dist = std::numeric_limits<int>::max();
int x_nearest = 0;
FractureEdge* e_nearest = NULL;
@ -302,15 +341,14 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
if( !(*i)->matches( y ) )
continue;
int64_t x_intersect;
int x_intersect;
if( (*i)->m_p1.Y == (*i)->m_p2.Y ) // horizontal edge
x_intersect = std::max( (*i)->m_p1.X, (*i)->m_p2.X );
if( (*i)->m_p1.y == (*i)->m_p2.y ) // horizontal edge
x_intersect = std::max ( (*i)->m_p1.x, (*i)->m_p2.x );
else
x_intersect = (*i)->m_p1.X + rescale((*i)->m_p2.X - (*i)->m_p1.X,
y - (*i)->m_p1.Y, (*i)->m_p2.Y - (*i)->m_p1.Y );
x_intersect = (*i)->m_p1.x + rescale((*i)->m_p2.x - (*i)->m_p1.x, y - (*i)->m_p1.y, (*i)->m_p2.y - (*i)->m_p1.y );
int64_t dist = ( x - x_intersect );
int dist = ( x - x_intersect );
if( dist > 0 && dist < min_dist )
{
@ -324,9 +362,9 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
{
int count = 0;
FractureEdge* lead1 = new FractureEdge( true, IntPoint( x_nearest, y), IntPoint( x, y ) );
FractureEdge* lead2 = new FractureEdge( true, IntPoint( x, y), IntPoint( x_nearest, y ) );
FractureEdge* split_2 = new FractureEdge( true, IntPoint( x_nearest, y ), e_nearest->m_p2 );
FractureEdge* lead1 = new FractureEdge( true, VECTOR2I( x_nearest, y ), VECTOR2I( x, y ) );
FractureEdge* lead2 = new FractureEdge( true, VECTOR2I( x, y ), VECTOR2I( x_nearest, y ) );
FractureEdge* split_2 = new FractureEdge( true, VECTOR2I( x_nearest, y ), e_nearest->m_p2 );
edges.push_back( split_2 );
edges.push_back( lead1 );
@ -334,11 +372,11 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
FractureEdge* link = e_nearest->m_next;
e_nearest->m_p2 = IntPoint( x_nearest, y );
e_nearest->m_p2 = VECTOR2I( x_nearest, y );
e_nearest->m_next = lead1;
lead1->m_next = edge;
FractureEdge* last;
FractureEdge*last;
for( last = edge; last->m_next != edge; last = last->m_next )
{
last->m_connected = true;
@ -356,8 +394,7 @@ static int processEdge( FractureEdgeSet& edges, FractureEdge* edge )
return 0;
}
void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
{
FractureEdgeSet edges;
FractureEdgeSet border_edges;
@ -370,21 +407,23 @@ void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
int num_unconnected = 0;
BOOST_FOREACH( Path& path, paths )
BOOST_FOREACH( SHAPE_LINE_CHAIN& path, paths )
{
int index = 0;
FractureEdge *prev = NULL, *first_edge = NULL;
int64_t x_min = std::numeric_limits<int64_t>::max();
int x_min = std::numeric_limits<int>::max();
for( unsigned i = 0; i < path.size(); i++ )
for( int i = 0; i < path.PointCount(); i++ )
{
if( path[i].X < x_min )
x_min = path[i].X;
const VECTOR2I& p = path.CPoint( i );
if( p.x < x_min )
x_min = p.x;
}
for( unsigned i = 0; i < path.size(); i++ )
for( int i = 0; i < path.PointCount(); i++ )
{
FractureEdge* fe = new FractureEdge( first, &path, index++ );
@ -397,7 +436,7 @@ void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
if( prev )
prev->m_next = fe;
if( i == path.size() - 1 )
if( i == path.PointCount() - 1 )
fe->m_next = first_edge;
prev = fe;
@ -405,27 +444,27 @@ void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
if( !first )
{
if( fe->m_p1.X == x_min )
if( fe->m_p1.x == x_min )
border_edges.push_back( fe );
}
if( !fe->m_connected )
num_unconnected++;
}
first = false; // first path is always the outline
}
// keep connecting holes to the main outline, until there's no holes left...
while( num_unconnected > 0 )
{
int64_t x_min = std::numeric_limits<int64_t>::max();
int x_min = std::numeric_limits<int>::max();
FractureEdge* smallestX = NULL;
// find the left-most hole edge and merge with the outline
for( FractureEdgeSet::iterator i = border_edges.begin(); i != border_edges.end(); ++i )
{
int64_t xt = (*i)->m_p1.X;
int xt = (*i)->m_p1.x;
if( ( xt < x_min ) && ! (*i)->m_connected )
{
@ -438,13 +477,16 @@ void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
}
paths.clear();
Path newPath;
SHAPE_LINE_CHAIN newPath;
newPath.SetClosed( true );
FractureEdge* e;
for( e = root; e->m_next != root; e = e->m_next )
newPath.push_back( e->m_p1 );
newPath.Append( e->m_p1 );
newPath.push_back( e->m_p1 );
newPath.Append( e->m_p1 );
for( FractureEdgeSet::iterator i = edges.begin(); i != edges.end(); ++i )
delete *i;
@ -455,7 +497,9 @@ void SHAPE_POLY_SET::fractureSingle( ClipperLib::Paths& paths )
void SHAPE_POLY_SET::Fracture()
{
BOOST_FOREACH( Paths& paths, m_polys )
Simplify(); // remove overlallping holes/degeneracy
BOOST_FOREACH( POLYGON& paths, m_polys )
{
fractureSingle( paths );
}
@ -464,12 +508,9 @@ void SHAPE_POLY_SET::Fracture()
void SHAPE_POLY_SET::Simplify()
{
for( unsigned i = 0; i < m_polys.size(); i++ )
{
Paths out;
SimplifyPolygons( m_polys[i], out, pftNonZero );
m_polys[i] = out;
}
SHAPE_POLY_SET empty;
booleanOp( ctUnion, empty );
}
@ -482,13 +523,11 @@ const std::string SHAPE_POLY_SET::Format() const
for( unsigned i = 0; i < m_polys.size(); i++ )
{
ss << "poly " << m_polys[i].size() << "\n";
for( unsigned j = 0; j < m_polys[i].size(); j++)
{
ss << m_polys[i][j].size() << "\n";
for( unsigned v = 0; v < m_polys[i][j].size(); v++)
ss << m_polys[i][j][v].X << " " << m_polys[i][j][v].Y << "\n";
ss << m_polys[i][j].PointCount() << "\n";
for( int v = 0; v < m_polys[i][j].PointCount(); v++)
ss << m_polys[i][j].CPoint( v ).x << " " << m_polys[i][j].CPoint( v ).y << "\n";
}
ss << "\n";
}
@ -515,7 +554,8 @@ bool SHAPE_POLY_SET::Parse( std::stringstream& aStream )
for( int i = 0; i < n_polys; i++ )
{
ClipperLib::Paths paths;
POLYGON paths;
aStream >> tmp;
if( tmp != "poly" )
@ -529,23 +569,26 @@ bool SHAPE_POLY_SET::Parse( std::stringstream& aStream )
for( int j = 0; j < n_outlines; j++ )
{
ClipperLib::Path outline;
SHAPE_LINE_CHAIN outline;
outline.SetClosed( true );
aStream >> tmp;
int n_vertices = atoi( tmp.c_str() );
for( int v = 0; v < n_vertices; v++ )
{
ClipperLib::IntPoint p;
VECTOR2I p;
aStream >> tmp; p.X = atoi( tmp.c_str() );
aStream >> tmp; p.Y = atoi( tmp.c_str() );
outline.push_back( p );
aStream >> tmp; p.x = atoi( tmp.c_str() );
aStream >> tmp; p.y = atoi( tmp.c_str() );
outline.Append( p );
}
paths.push_back( outline );
}
m_polys.push_back( paths );
}
return true;
}
@ -557,22 +600,146 @@ const BOX2I SHAPE_POLY_SET::BBox( int aClearance ) const
for( unsigned i = 0; i < m_polys.size(); i++ )
{
for( unsigned j = 0; j < m_polys[i].size(); j++)
{
for( unsigned v = 0; v < m_polys[i][j].size(); v++)
{
VECTOR2I p( m_polys[i][j][v].X, m_polys[i][j][v].Y );
if( first )
bb = BOX2I( p, VECTOR2I( 0, 0 ) );
else
bb.Merge( p );
first = false;
}
}
if( first )
bb = m_polys[i][0].BBox();
else
bb.Merge( m_polys[i][0].BBox() );
}
bb.Inflate( aClearance );
return bb;
}
void SHAPE_POLY_SET::RemoveAllContours()
{
m_polys.clear();
}
void SHAPE_POLY_SET::DeletePolygon( int aIdx )
{
m_polys.erase( m_polys.begin() + aIdx );
}
void SHAPE_POLY_SET::Append( const SHAPE_POLY_SET& aSet )
{
m_polys.insert( m_polys.end(), aSet.m_polys.begin(), aSet.m_polys.end() );
}
void SHAPE_POLY_SET::Append( const VECTOR2I& aP, int aOutline, int aHole )
{
Append( aP.x, aP.y, aOutline, aHole );
}
bool SHAPE_POLY_SET::Contains( const VECTOR2I& aP, int aSubpolyIndex ) const
{
// fixme: support holes!
if( aSubpolyIndex >= 0 )
return pointInPolygon( aP, m_polys[aSubpolyIndex][0] );
BOOST_FOREACH ( const POLYGON& polys, m_polys )
{
if( pointInPolygon( aP, polys[0] ) )
return true;
}
return false;
}
bool SHAPE_POLY_SET::pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath ) const
{
int result = 0;
int cnt = aPath.PointCount();
if ( !aPath.BBox().Contains( aP ) ) // test with bounding box first
return false;
if( cnt < 3 )
return false;
VECTOR2I ip = aPath.CPoint( 0 );
for( int i = 1; i <= cnt; ++i )
{
VECTOR2I ipNext = ( i == cnt ? aPath.CPoint( 0 ) : aPath.CPoint( i ) );
if( ipNext.y == aP.y )
{
if( ( ipNext.x == aP.x ) || ( ip.y == aP.y &&
( ( ipNext.x > aP.x ) == ( ip.x < aP.x ) ) ) )
return true;
}
if( ( ip.y < aP.y ) != ( ipNext.y < aP.y ) )
{
if( ip.x >= aP.x )
{
if( ipNext.x > aP.x )
result = 1 - result;
else
{
int64_t d = (int64_t)( ip.x - aP.x ) * (int64_t)( ipNext.y - aP.y ) -
(int64_t)( ipNext.x - aP.x ) * (int64_t)( ip.y - aP.y );
if( !d )
return true;
if( ( d > 0 ) == ( ipNext.y > ip.y ) )
result = 1 - result;
}
}
else
{
if( ipNext.x > aP.x )
{
int64_t d = (int64_t)( ip.x - aP.x ) * (int64_t)( ipNext.y - aP.y ) -
(int64_t)( ipNext.x - aP.x ) * (int64_t)( ip.y - aP.y );
if( !d )
return -1;
if( ( d > 0 ) == ( ipNext.y > ip.y ) )
result = 1 - result;
}
}
}
ip = ipNext;
}
return result ? true : false;
}
void SHAPE_POLY_SET::Move( const VECTOR2I& aVector )
{
BOOST_FOREACH( POLYGON &poly, m_polys )
{
BOOST_FOREACH( SHAPE_LINE_CHAIN &path, poly )
{
path.Move( aVector );
}
}
}
int SHAPE_POLY_SET::TotalVertices() const
{
int c = 0;
BOOST_FOREACH( const POLYGON& poly, m_polys )
{
BOOST_FOREACH ( const SHAPE_LINE_CHAIN& path, poly )
{
c += path.PointCount();
}
}
return c;
}

View File

@ -27,7 +27,6 @@
*/
#include <fctsys.h>
#include <polygons_defs.h>
#include <gr_basic.h>
#include <common.h>
#include <trigo.h>

View File

@ -33,8 +33,8 @@
#include <fctsys.h>
#include <trigo.h>
#include <macros.h>
#include <PolyLine.h>
#include <geometry/shape_poly_set.h>
/**
* Function TransformCircleToPolygon
* convert a circle to a polygon, using multiple straight lines
@ -45,9 +45,9 @@
* Note: the polygon is inside the circle, so if you want to have the polygon
* outside the circle, you should give aRadius calculated with a correction factor
*/
void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
wxPoint aCenter, int aRadius,
int aCircleToSegmentsCount );
void TransformCircleToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aCenter, int aRadius,
int aCircleToSegmentsCount );
/**
* Function TransformRoundedEndsSegmentToPolygon
@ -61,7 +61,7 @@ void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
* Note: the polygon is inside the arc ends, so if you want to have the polygon
* outside the circle, you should give aStart and aEnd calculated with a correction factor
*/
void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformRoundedEndsSegmentToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aStart, wxPoint aEnd,
int aCircleToSegmentsCount,
int aWidth );
@ -78,7 +78,7 @@ void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aWidth = width (thickness) of the line
*/
void TransformArcToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformArcToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aCentre, wxPoint aStart, double aArcAngle,
int aCircleToSegmentsCount, int aWidth );
@ -92,7 +92,7 @@ void TransformArcToPolygon( CPOLYGONS_LIST& aCornerBuffer,
* @param aCircleToSegmentsCount = the number of segments to approximate a circle
* @param aWidth = width (thickness) of the ring
*/
void TransformRingToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformRingToPolygon( SHAPE_POLY_SET& aCornerBuffer,
wxPoint aCentre, int aRadius,
int aCircleToSegmentsCount, int aWidth );

View File

@ -255,6 +255,9 @@ public:
if( aIndex < 0 )
aIndex += PointCount();
if( aIndex >= PointCount() )
aIndex -= PointCount();
return m_points[aIndex];
}
@ -578,6 +581,7 @@ public:
{
return false;
}
private:
/// array of vertices
std::vector<VECTOR2I> m_points;

View File

@ -32,25 +32,103 @@
#include "clipper.hpp"
/**
* Class SHAPE_POLY_SET
*
* Represents a set of closed polygons. Polygons may be nonconvex, self-intersecting
* and have holes. Provides boolean operations (using Clipper library as the backend).
*
* TODO: document, derive from class SHAPE, add convex partitioning & spatial index
* TODO: add convex partitioning & spatial index
*/
class SHAPE_POLY_SET : public SHAPE
{
public:
SHAPE_POLY_SET() : SHAPE( SH_POLY_SET ) {};
~SHAPE_POLY_SET() {};
///> represents a single polygon outline with holes. The first entry is the outline,
///> the remaining (if any), are the holes
typedef std::vector<SHAPE_LINE_CHAIN> POLYGON;
/**
* Class ITERATOR_TEMPLATE
*
* Base class for iterating over all vertices in a given SHAPE_POLY_SET
*/
template <class T>
class ITERATOR_TEMPLATE {
public:
bool IsEndContour() const
{
return m_currentVertex + 1 == m_poly->CPolygon( m_currentOutline )[0].PointCount();
}
bool IsLastContour() const
{
return m_currentOutline == m_lastOutline;
}
operator bool() const
{
return m_currentOutline <= m_lastOutline;
}
void Advance()
{
m_currentVertex ++;
if( m_currentVertex >= m_poly->CPolygon( m_currentOutline )[0].PointCount() )
{
m_currentVertex = 0;
m_currentOutline++;
}
}
void operator++( int dummy )
{
Advance();
}
void operator++()
{
Advance();
}
T& Get()
{
return m_poly->Polygon( m_currentOutline )[0].Point( m_currentVertex );
}
T& operator*()
{
return Get();
}
T* operator->()
{
return &Get();
}
private:
friend class SHAPE_POLY_SET;
SHAPE_POLY_SET* m_poly;
int m_currentOutline;
int m_lastOutline;
int m_currentVertex;
};
typedef ITERATOR_TEMPLATE<VECTOR2I> ITERATOR;
typedef ITERATOR_TEMPLATE<const VECTOR2I> CONST_ITERATOR;
SHAPE_POLY_SET();
~SHAPE_POLY_SET();
///> Creates a new empty polygon in the set and returns its index
int NewOutline();
///> Cretes a new empty hole in the given outline (default: last one) and returns its index
int NewHole( int aOutline = -1);
///> Creates a new hole in a given outline
int NewHole( int aOutline = -1 );
///> Adds a new outline to the set and returns its index
int AddOutline( const SHAPE_LINE_CHAIN& aOutline );
@ -58,11 +136,20 @@ class SHAPE_POLY_SET : public SHAPE
///> Adds a new hole to the given outline (default: last) and returns its index
int AddHole( const SHAPE_LINE_CHAIN& aHole, int aOutline = -1 );
///> Appends a vertex at the end of the given outline/hole (default: last hole in the last outline)
int AppendVertex( int x, int y, int aOutline = -1, int aHole = -1 );
///> Appends a vertex at the end of the given outline/hole (default: the last outline)
int Append( int x, int y, int aOutline = -1, int aHole = -1 );
///> Merges polygons from two sets.
void Append( const SHAPE_POLY_SET& aSet );
///> Appends a vertex at the end of the given outline/hole (default: the last outline)
void Append( const VECTOR2I& aP, int aOutline = -1, int aHole = -1 );
///> Returns the index-th vertex in a given hole outline within a given outline
const VECTOR2I GetVertex( int index, int aOutline = -1, int aHole = -1) const;
VECTOR2I& Vertex( int index, int aOutline = -1, int aHole = -1 );
///> Returns the index-th vertex in a given hole outline within a given outline
const VECTOR2I& CVertex( int index, int aOutline = -1, int aHole = -1 ) const;
///> Returns true if any of the outlines is self-intersecting
bool IsSelfIntersecting();
@ -73,28 +160,109 @@ class SHAPE_POLY_SET : public SHAPE
///> Returns the number of vertices in a given outline/hole
int VertexCount( int aOutline = -1, int aHole = -1 ) const;
///> Returns the internal representation (ClipperLib) of a given polygon (outline + holes)
const ClipperLib::Paths& GetPoly( int aIndex ) const
///> Returns the number of holes in a given outline
int HoleCount( int aOutline ) const;
///> Returns the reference to aIndex-th outline in the set
SHAPE_LINE_CHAIN& Outline( int aIndex )
{
return m_polys[aIndex][0];
}
///> Returns the reference to aHole-th hole in the aIndex-th outline
SHAPE_LINE_CHAIN& Hole( int aOutline, int aHole )
{
return m_polys[aOutline][aHole + 1];
}
///> Returns the aIndex-th subpolygon in the set
POLYGON& Polygon( int aIndex )
{
return m_polys[aIndex];
}
///> Performs boolean polyset difference
void Subtract( const SHAPE_POLY_SET& b );
const SHAPE_LINE_CHAIN& COutline( int aIndex ) const
{
return m_polys[aIndex][0];
}
const SHAPE_LINE_CHAIN& CHole( int aOutline, int aHole ) const
{
return m_polys[aOutline][aHole + 1];
}
const POLYGON& CPolygon( int aIndex ) const
{
return m_polys[aIndex];
}
///> Returns an iterator object, for iterating between aFirst and aLast outline.
ITERATOR Iterate( int aFirst, int aLast )
{
ITERATOR iter;
iter.m_poly = this;
iter.m_currentOutline = aFirst;
iter.m_lastOutline = aLast < 0 ? OutlineCount() - 1 : aLast;
iter.m_currentVertex = 0;
return iter;
}
///> Returns an iterator object, for iterating aOutline-th outline
ITERATOR Iterate( int aOutline )
{
return Iterate( aOutline, aOutline );
}
///> Returns an iterator object, for all outlines in the set (no holes)
ITERATOR Iterate()
{
return Iterate( 0, OutlineCount() - 1 );
}
CONST_ITERATOR CIterate( int aFirst, int aLast ) const
{
CONST_ITERATOR iter;
iter.m_poly = const_cast<SHAPE_POLY_SET*>( this );
iter.m_currentOutline = aFirst;
iter.m_lastOutline = aLast < 0 ? OutlineCount() - 1 : aLast;
iter.m_currentVertex = 0;
return iter;
}
CONST_ITERATOR CIterate( int aOutline ) const
{
return CIterate( aOutline, aOutline );
}
CONST_ITERATOR CIterate() const
{
return CIterate( 0, OutlineCount() - 1 );
}
///> Performs boolean polyset union
void Add( const SHAPE_POLY_SET& b );
void BooleanAdd( const SHAPE_POLY_SET& b );
///> Performs smooth outline inflation (Minkowski sum of the outline and a circle of a given radius)
void SmoothInflate( int aFactor );
///> Performs boolean polyset difference
void BooleanSubtract( const SHAPE_POLY_SET& b );
///> Performs outline erosion/shrinking
void Erode( int aFactor );
///> Performs outline inflation/deflation, using round corners.
void Inflate ( int aFactor, int aCircleSegmentsCount = 32 );
///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the outer ring
///> to the inner holes
void Fracture();
///> Converts a set of slitted polygons to a set of polygons with holes
void Unfracture();
///> Returns true if the polygon set has any holes.
bool HasHoles() const;
///> Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void Simplify();
@ -104,8 +272,10 @@ class SHAPE_POLY_SET : public SHAPE
/// @copydoc SHAPE::Parse()
bool Parse( std::stringstream& aStream );
void Move( const VECTOR2I& aVector ) { assert(false ); };
/// @copydoc SHAPE::Move()
void Move( const VECTOR2I& aVector );
/// @copydoc SHAPE::IsSolid()
bool IsSolid() const
{
return true;
@ -117,15 +287,43 @@ class SHAPE_POLY_SET : public SHAPE
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const { return false; }
bool Collide( const SEG& aSeg, int aClearance = 0 ) const { return false; }
///> Returns true is a given subpolygon contains the point aP. If aSubpolyIndex < 0 (default value),
///> checks all polygons in the set
bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1 ) const;
///> Returns true if the set is empty (no polygons at all)
bool IsEmpty() const
{
return m_polys.size() == 0;
}
///> Removes all outlines & holes (clears) the polygon set.
void RemoveAllContours();
///> Returns total number of vertices stored in the set.
int TotalVertices() const;
///> Deletes aIdx-th polygon from the set
void DeletePolygon( int aIdx );
private:
void fractureSingle( ClipperLib::Paths& paths );
void importTree( ClipperLib::PolyTree* tree);
SHAPE_LINE_CHAIN& getContourForCorner( int aCornerId, int& aIndexWithinContour );
VECTOR2I& vertex( int aCornerId );
const VECTOR2I& cvertex( int aCornerId ) const;
void fractureSingle( POLYGON& paths );
void importTree( ClipperLib::PolyTree* tree );
void booleanOp( ClipperLib::ClipType type, const SHAPE_POLY_SET& b );
const ClipperLib::Path convert( const SHAPE_LINE_CHAIN& aPath );
bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath ) const;
typedef std::vector<ClipperLib::Paths> Polyset;
const ClipperLib::Path convertToClipper( const SHAPE_LINE_CHAIN& aPath, bool aRequiredOrientation );
const SHAPE_LINE_CHAIN convertFromClipper( const ClipperLib::Path& aPath );
typedef std::vector<POLYGON> Polyset;
Polyset m_polys;
};

View File

@ -33,7 +33,6 @@
#include <vector>
#include <fctsys.h>
#include <polygons_defs.h>
#include <drawtxt.h>
#include <pcbnew.h>
#include <wxPcbStruct.h>
@ -51,9 +50,9 @@
// These variables are parameters used in addTextSegmToPoly.
// But addTextSegmToPoly is a call-back function,
// so we cannot send them as arguments.
int s_textWidth;
int s_textCircle2SegmentCount;
CPOLYGONS_LIST* s_cornerBuffer;
static int s_textWidth;
static int s_textCircle2SegmentCount;
static SHAPE_POLY_SET* s_cornerBuffer;
// This is a call back function, used by DrawGraphicText to draw the 3D text shape:
static void addTextSegmToPoly( int x0, int y0, int xf, int yf )
@ -64,7 +63,7 @@ static void addTextSegmToPoly( int x0, int y0, int xf, int yf )
}
void BOARD::ConvertBrdLayerToPolygonalContours( LAYER_ID aLayer, CPOLYGONS_LIST& aOutlines )
void BOARD::ConvertBrdLayerToPolygonalContours( LAYER_ID aLayer, SHAPE_POLY_SET& aOutlines )
{
// Number of segments to convert a circle to a polygon
const int segcountforcircle = 18;
@ -128,7 +127,7 @@ void BOARD::ConvertBrdLayerToPolygonalContours( LAYER_ID aLayer, CPOLYGONS_LIST&
void MODULE::TransformPadsShapesWithClearanceToPolygon( LAYER_ID aLayer,
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
@ -203,7 +202,7 @@ void MODULE::TransformPadsShapesWithClearanceToPolygon( LAYER_ID aLayer,
*/
void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
LAYER_ID aLayer,
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor )
@ -280,43 +279,30 @@ void MODULE::TransformGraphicShapesWithClearanceToPolygonSet(
* keep arc radius when approximated by segments
*/
void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aCircleToSegmentsCount,
double aCorrectionFactor )
{
unsigned cornerscount = GetFilledPolysList().GetCornersCount();
if( cornerscount == 0 )
if( GetFilledPolysList().IsEmpty() )
return;
// add filled areas polygons
aCornerBuffer.Append( m_FilledPolysList );
// add filled areas outlines, which are drawn with thick lines
wxPoint seg_start, seg_end;
int i_start_contour = 0;
for( unsigned ic = 0; ic < cornerscount; ic++ )
for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ )
{
seg_start.x = m_FilledPolysList[ ic ].x;
seg_start.y = m_FilledPolysList[ ic ].y;
unsigned ic_next = ic+1;
const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( i );
if( !m_FilledPolysList[ic].end_contour &&
ic_next < cornerscount )
for( int j = 0; j < path.PointCount(); j++ )
{
seg_end.x = m_FilledPolysList[ ic_next ].x;
seg_end.y = m_FilledPolysList[ ic_next ].y;
}
else
{
seg_end.x = m_FilledPolysList[ i_start_contour ].x;
seg_end.y = m_FilledPolysList[ i_start_contour ].y;
i_start_contour = ic_next;
}
const VECTOR2I& a = path.CPoint( j );
const VECTOR2I& b = path.CPoint( j + 1 );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, seg_start, seg_end,
aCircleToSegmentsCount,
GetMinThickness() );
TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ),
aCircleToSegmentsCount,
GetMinThickness() );
}
}
}
@ -329,13 +315,13 @@ void ZONE_CONTAINER::TransformSolidAreasShapesToPolygonSet(
* @param aClearanceValue = the clearance around the text bounding box
*/
void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
CPOLYGONS_LIST& aCornerBuffer,
int aClearanceValue ) const
SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue ) const
{
if( GetText().Length() == 0 )
return;
CPolyPt corners[4]; // Buffer of polygon corners
wxPoint corners[4]; // Buffer of polygon corners
EDA_RECT rect = GetTextBox( -1 );
rect.Inflate( aClearanceValue );
@ -348,14 +334,14 @@ void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
corners[3].y = corners[2].y;
corners[3].x = corners[0].x;
aCornerBuffer.NewOutline();
for( int ii = 0; ii < 4; ii++ )
{
// Rotate polygon
RotatePoint( &corners[ii].x, &corners[ii].y, m_Pos.x, m_Pos.y, m_Orient );
aCornerBuffer.Append( corners[ii] );
aCornerBuffer.Append( corners[ii].x, corners[ii].y );
}
aCornerBuffer.CloseLastContour();
}
@ -363,7 +349,7 @@ void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
* Convert the text shape to a set of polygons (one by segment)
* Used in filling zones calculations and 3D view
* Circles and arcs are approximated by segments
* aCornerBuffer = CPOLYGONS_LIST to store the polygon corners
* aCornerBuffer = SHAPE_POLY_SET to store the polygon corners
* aClearanceValue = the clearance around the text
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to circles radius to keep
@ -372,7 +358,7 @@ void TEXTE_PCB::TransformBoundingBoxWithClearanceToPolygon(
*/
void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet(
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
@ -428,7 +414,7 @@ void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet(
* clearance when the circle is approxiamted by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
@ -463,6 +449,8 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerB
MODULE* module = GetParentModule(); // NULL for items not in footprints
double orientation = module ? module->GetOrientation() : 0.0;
aCornerBuffer.NewOutline();
// Build the polygon with the actual position and orientation:
std::vector< wxPoint> poly;
poly = GetPolyPoints();
@ -498,9 +486,8 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerB
for( unsigned ii = 0; ii < poly.size(); ii++ )
{
CPolyPt corner( poly[ii] );
aCornerBuffer.Append( corner );
aCornerBuffer.Append( corner.x, corner.y );
}
aCornerBuffer.CloseLastContour();
}
break;
@ -525,7 +512,7 @@ void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerB
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
@ -554,15 +541,14 @@ void TRACK:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
* Convert the pad shape to a closed polygon
* Used in filling zones calculations and 3D view generation
* Circles and arcs are approximated by segments
* aCornerBuffer = a CPOLYGONS_LIST to store the polygon corners
* aCornerBuffer = a SHAPE_POLY_SET to store the polygon corners
* aClearanceValue = the clearance around the pad
* aCircleToSegmentsCount = the number of segments to approximate a circle
* aCorrectionFactor = the correction to apply to circles radius to keep
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
#include <clipper.hpp>
void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void D_PAD:: TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const
@ -615,36 +601,21 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
wxPoint corners[4];
BuildPadPolygon( corners, wxSize( 0, 0 ), angle );
// We are using ClipperLib to inflate the polygon shape, using
// arcs to connect moved segments.
ClipperLib::Path outline;
ClipperLib::Paths shapeWithClearance;
SHAPE_POLY_SET outline;
outline.NewOutline();
for( int ii = 0; ii < 4; ii++ )
{
corners[ii] += PadShapePos;
outline << ClipperLib::IntPoint( corners[ii].x, corners[ii].y );
outline.Append( corners[ii].x, corners[ii].y );
}
ClipperLib::ClipperOffset offset_engine;
// Prepare an offset (inflate) transform, with edges connected by arcs
offset_engine.AddPath( outline, ClipperLib::jtRound, ClipperLib::etClosedPolygon );
// Clipper approximates arcs by segments
// It uses a value called ArcTolerance which is the max error between the arc
// and segments created to approximate this arc
// the number of segm per circle is:
// n = PI / acos(1 - arc_tolerance / (arc radius))
// the arc radius is aClearanceValue
// because arc_tolerance is << aClearanceValue and aClearanceValue >= 0
// n = PI / (arc_tolerance / aClearanceValue )
offset_engine.ArcTolerance = (double)aClearanceValue / 3.14 / aCircleToSegmentsCount;
double rounding_radius = aClearanceValue * aCorrectionFactor;
offset_engine.Execute( shapeWithClearance, rounding_radius );
// get new outline (only one polygon is expected)
aCornerBuffer.ImportFrom( shapeWithClearance );
outline.Inflate( (int) rounding_radius, aCircleToSegmentsCount );
aCornerBuffer.Append( outline );
}
break;
}
@ -657,7 +628,7 @@ void D_PAD:: TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer
* Note: for Round and oval pads this function is equivalent to
* TransformShapeWithClearanceToPolygon, but not for other shapes
*/
void D_PAD::BuildPadShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
void D_PAD::BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
wxSize aInflateValue, int aSegmentsPerCircle,
double aCorrectionFactor ) const
{
@ -674,15 +645,15 @@ void D_PAD::BuildPadShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
case PAD_TRAPEZOID:
case PAD_RECT:
aCornerBuffer.NewOutline();
BuildPadPolygon( corners, aInflateValue, m_Orient );
for( int ii = 0; ii < 4; ii++ )
{
corners[ii] += PadShapePos; // Shift origin to position
CPolyPt polypoint( corners[ii].x, corners[ii].y );
aCornerBuffer.Append( polypoint );
aCornerBuffer.Append( corners[ii].x, corners[ii].y );
}
aCornerBuffer.CloseLastContour();
break;
}
}
@ -693,7 +664,7 @@ void D_PAD::BuildPadShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
* depending on shape pad hole and orientation
* return false if the pad has no hole, true otherwise
*/
bool D_PAD::BuildPadDrillShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
bool D_PAD::BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue, int aSegmentsPerCircle ) const
{
wxSize drillsize = GetDrillSize();
@ -750,7 +721,7 @@ bool D_PAD::BuildPadDrillShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
* and are used in microwave applications and they *DO NOT* have a thermal relief that
* change the shape by creating stubs and destroy their properties.
*/
void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
D_PAD& aPad,
int aThermalGap,
int aCopperThickness,
@ -856,15 +827,16 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
for( unsigned ihole = 0; ihole < 4; ihole++ )
{
aCornerBuffer.NewOutline();
for( unsigned ii = 0; ii < corners_buffer.size(); ii++ )
{
corner = corners_buffer[ii];
RotatePoint( &corner, th_angle + angle_pad ); // Rotate by segment angle and pad orientation
corner += PadShapePos;
aCornerBuffer.Append( CPolyPt( corner.x, corner.y ) );
aCornerBuffer.Append( corner.x, corner.y );
}
aCornerBuffer.CloseLastContour();
th_angle += 900; // Note: th_angle in in 0.1 deg.
}
}
@ -960,15 +932,15 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
for( int irect = 0; irect < 2; irect++ )
{
aCornerBuffer.NewOutline();
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
aCornerBuffer.Append( cpos.x, cpos.y );
}
aCornerBuffer.CloseLastContour();
angle = AddAngles( angle, 1800 ); // this is calculate hole 3
}
@ -985,15 +957,16 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
for( int irect = 0; irect < 2; irect++ )
{
aCornerBuffer.NewOutline();
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
aCornerBuffer.Append( cpos.x, cpos.y );
}
aCornerBuffer.CloseLastContour();
angle = AddAngles( angle, 1800 );
}
}
@ -1057,15 +1030,16 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
for( int irect = 0; irect < 2; irect++ )
{
aCornerBuffer.NewOutline();
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle ); // Rotate according to module orientation
cpos += PadShapePos; // Shift origin to position
aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
aCornerBuffer.Append( cpos.x, cpos.y );
}
aCornerBuffer.CloseLastContour();
angle = AddAngles( angle, 1800 ); // this is calculate hole 3
}
@ -1080,15 +1054,16 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
// Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
for( int irect = 0; irect < 2; irect++ )
{
aCornerBuffer.NewOutline();
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
{
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, angle );
cpos += PadShapePos;
aCornerBuffer.Append( CPolyPt( cpos.x, cpos.y ) );
aCornerBuffer.Append( cpos.x, cpos.y );
}
aCornerBuffer.CloseLastContour();
angle = AddAngles( angle, 1800 );
}
}
@ -1096,30 +1071,25 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
case PAD_TRAPEZOID:
{
CPOLYGONS_LIST cbuffer;
SHAPE_POLY_SET antipad; // The full antipad area
// We need a length to build the stubs of the thermal reliefs
// the value is not very important. The pad bounding box gives a reasonable value
EDA_RECT bbox = aPad.GetBoundingBox();
int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() );
aPad.TransformShapeWithClearanceToPolygon( cbuffer, aThermalGap,
aPad.TransformShapeWithClearanceToPolygon( antipad, aThermalGap,
aCircleToSegmentsCount, aCorrectionFactor );
// We are using ClipperLib to substract stubs to clearance area (antipad area).
ClipperLib::Path antipad; // The full antipad area
ClipperLib::Path stub; // A basic stub ( a rectangle)
ClipperLib::Paths stubs; // the full stubs shape
ClipperLib::Paths thermalShape; // the holes in copper zone
SHAPE_POLY_SET stub; // A basic stub ( a rectangle)
SHAPE_POLY_SET stubs; // the full stubs shape
SHAPE_POLY_SET thermalShape; // the holes in copper zone
// cbuffer is expected to contain only one polygon, which is
// area of the pad + the thermal gap (the antipad)
for( unsigned ii = 0; ii < cbuffer.GetCornersCount(); ii++ )
antipad << ClipperLib::IntPoint( cbuffer.GetPos(ii).x, cbuffer.GetPos(ii).y );
// We now substract the stubs (connections to the copper zone)
ClipperLib::Clipper clip_engine;
//ClipperLib::Clipper clip_engine;
// Prepare a clipping transform
clip_engine.AddPath( antipad, ClipperLib::ptSubject, true );
//clip_engine.AddPath( antipad, ClipperLib::ptSubject, true );
// Create stubs and add them to clipper engine
wxPoint stubBuffer[4];
@ -1132,16 +1102,17 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
stubBuffer[3] = stubBuffer[2];
stubBuffer[3].y = copper_thickness.y/2;
stub.NewOutline();
for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
{
wxPoint cpos = stubBuffer[ii];
RotatePoint( &cpos, aPad.GetOrientation() );
cpos += PadShapePos;
stub << ClipperLib::IntPoint( cpos.x, cpos.y );
stub.Append( cpos.x, cpos.y );
}
ClipperLib::Clipper stubs_engine;
stubs_engine.AddPath( stub, ClipperLib::ptSubject, true );
stubs.Append( stub );
stubBuffer[0].y = stub_len;
stubBuffer[0].x = copper_thickness.x/2;
@ -1151,27 +1122,24 @@ void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
stubBuffer[2].y = -stub_len;
stubBuffer[3] = stubBuffer[2];
stubBuffer[3].x = copper_thickness.x/2;
stub.clear();
stub.RemoveAllContours();
stub.NewOutline();
for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
{
wxPoint cpos = stubBuffer[ii];
RotatePoint( &cpos, aPad.GetOrientation() );
cpos += PadShapePos;
stub << ClipperLib::IntPoint( cpos.x, cpos.y );
stub.Append( cpos.x, cpos.y );
}
stubs_engine.AddPath( stub, ClipperLib::ptClip, true );
stubs.Append( stub );
stubs.Simplify();
// Build the full stubs shape:
stubs_engine.Execute( ClipperLib::ctUnion, stubs );
antipad.BooleanSubtract( stubs );
aCornerBuffer.Append( antipad );
// remove stubs to antipad area (i.e. add copper stubs)
clip_engine.AddPath( stubs[0], ClipperLib::ptClip, true );
clip_engine.Execute( ClipperLib::ctDifference, thermalShape );
// put thermal shapes (holes) to list:
aCornerBuffer.ImportFrom( thermalShape );
break;
}

View File

@ -2741,8 +2741,8 @@ wxString BOARD::GetNextModuleReferenceWithPrefix( const wxString& aPrefix,
* return true if success, false if a contour is not valid
*/
#include <specctra.h>
bool BOARD::GetBoardPolygonOutlines( CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
bool BOARD::GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
SHAPE_POLY_SET& aHoles,
wxString* aErrorText )
{
// the SPECCTRA_DB function to extract board outlines:

View File

@ -57,7 +57,7 @@ class MSG_PANEL_ITEM;
class NETLIST;
class REPORTER;
class RN_DATA;
class SHAPE_POLY_SET;
// non-owning container of item candidates when searching for items on the same track.
typedef std::vector< TRACK* > TRACK_PTRS;
@ -600,15 +600,14 @@ public:
* from lines, arcs and circle items on edge cut layer
* Any closed outline inside the main outline is a hole
* All contours should be closed, i.e. have valid vertices to build a closed polygon
* @param aOutlines The CPOLYGONS_LIST to fill in with main outlines.
* @param aHoles The empty CPOLYGONS_LIST to fill in with holes, if any.
* @param aPoly The SHAPE_POLY_SET to fill in with outlines/holes.
* @param aErrorText = a wxString reference to display an error message
* with the coordinate of the point which creates the error
* (default = NULL , no message returned on error)
* @return true if success, false if a contour is not valid
*/
bool GetBoardPolygonOutlines( CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
bool GetBoardPolygonOutlines( SHAPE_POLY_SET& aOutlines,
SHAPE_POLY_SET& aHoles,
wxString* aErrorText = NULL );
/**
@ -620,9 +619,9 @@ public:
* or 3D viewer
* the polygons are not merged.
* @param aLayer = A copper layer, like B_Cu, etc.
* @param aOutlines The CPOLYGONS_LIST to fill in with items outline.
* @param aOutlines The SHAPE_POLY_SET to fill in with items outline.
*/
void ConvertBrdLayerToPolygonalContours( LAYER_ID aLayer, CPOLYGONS_LIST& aOutlines );
void ConvertBrdLayerToPolygonalContours( LAYER_ID aLayer, SHAPE_POLY_SET& aOutlines );
/**
* Function GetLayerID

View File

@ -231,7 +231,7 @@ public:
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const;

View File

@ -336,7 +336,7 @@ public:
* default = false
*/
void TransformPadsShapesWithClearanceToPolygon( LAYER_ID aLayer,
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor,
@ -361,7 +361,7 @@ public:
*/
void TransformGraphicShapesWithClearanceToPolygonSet(
LAYER_ID aLayer,
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue,
int aCircleToSegmentsCount,
double aCorrectionFactor );

View File

@ -227,7 +227,7 @@ public:
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const;
@ -324,7 +324,7 @@ public:
* @param aCorrectionFactor = the correction to apply to circles radius to keep
* the pad size when the circle is approximated by segments
*/
void BuildPadShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
void BuildPadShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
wxSize aInflateValue, int aSegmentsPerCircle,
double aCorrectionFactor ) const;
@ -339,7 +339,7 @@ public:
* (used for round and oblong shapes only(16 to 32 is a good value)
* @return false if the pad has no hole, true otherwise
*/
bool BuildPadDrillShapePolygon( CPOLYGONS_LIST& aCornerBuffer,
bool BuildPadDrillShapePolygon( SHAPE_POLY_SET& aCornerBuffer,
int aInflateValue, int aSegmentsPerCircle ) const;
/**

View File

@ -111,7 +111,7 @@ public:
* to the real clearance value (usually near from 1.0)
*/
void TransformBoundingBoxWithClearanceToPolygon(
CPOLYGONS_LIST& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue ) const;
/**
@ -126,7 +126,7 @@ public:
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TransformShapeWithClearanceToPolygonSet( CPOLYGONS_LIST& aCornerBuffer,
void TransformShapeWithClearanceToPolygonSet( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const;

View File

@ -178,7 +178,7 @@ public:
* clearance when the circle is approximated by segment bigger or equal
* to the real clearance value (usually near from 1.0)
*/
void TransformShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aClearanceValue,
int aCircleToSegmentsCount,
double aCorrectionFactor ) const;

View File

@ -120,7 +120,7 @@ EDA_ITEM* ZONE_CONTAINER::Clone() const
bool ZONE_CONTAINER::UnFill()
{
bool change = ( m_FilledPolysList.GetCornersCount() > 0 ) ||
bool change = ( !m_FilledPolysList.IsEmpty() ) ||
( m_FillSegmList.size() > 0 );
m_FilledPolysList.RemoveAllContours();
@ -228,7 +228,7 @@ void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
if( displ_opts->m_DisplayZonesMode == 1 ) // Do not show filled areas
return;
if( m_FilledPolysList.GetCornersCount() == 0 ) // Nothing to draw
if( m_FilledPolysList.IsEmpty() ) // Nothing to draw
return;
BOARD* brd = GetBoard();
@ -253,69 +253,57 @@ void ZONE_CONTAINER::DrawFilledArea( EDA_DRAW_PANEL* panel,
SetAlpha( &color, 150 );
CornersTypeBuffer.clear();
CornersBuffer.clear();
// Draw all filled areas
int imax = m_FilledPolysList.GetCornersCount() - 1;
for( int ic = 0; ic <= imax; ic++ )
for ( int ic = 0; ic < m_FilledPolysList.OutlineCount(); ic++ )
{
const CPolyPt& corner = m_FilledPolysList.GetCorner( ic );
wxPoint coord( corner.x + offset.x, corner.y + offset.y );
CornersBuffer.push_back( coord );
CornersTypeBuffer.push_back( (char) corner.m_flags );
const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( ic );
// the last corner of a filled area is found: draw it
if( (corner.end_contour) || (ic == imax) )
CornersBuffer.clear();
wxPoint p0;
for( int j = 0; j < path.PointCount(); j++ )
{
/* Draw the current filled area: draw segments outline first
* Curiously, draw segments outline first and after draw filled polygons
* with outlines thickness = 0 is a faster than
* just draw filled polygons but with outlines thickness = m_ZoneMinThickness
* So DO NOT use draw filled polygons with outlines having a thickness > 0
* Note: Extra segments ( added to joint holes with external outline) flagged by
* m_flags != 0 are not drawn
* Note not all polygon libraries provide a flag for these extra-segments, therefore
* the m_flags member can be always 0
*/
{
// Draw outlines:
if( (m_ZoneMinThickness > 1) || outline_mode )
{
int ilim = CornersBuffer.size() - 1;
const VECTOR2I& corner = path.CPoint( j );
for( int is = 0, ie = ilim; is <= ilim; ie = is, is++ )
{
int x0 = CornersBuffer[is].x;
int y0 = CornersBuffer[is].y;
int x1 = CornersBuffer[ie].x;
int y1 = CornersBuffer[ie].y;
wxPoint coord( corner.x + offset.x, corner.y + offset.y );
// Draw only basic outlines, not extra segments.
if( CornersTypeBuffer[ie] == 0 )
{
if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) )
GRCSegm( panel->GetClipBox(), DC,
x0, y0, x1, y1,
m_ZoneMinThickness, color );
else
GRFillCSegm( panel->GetClipBox(), DC,
x0, y0, x1, y1,
m_ZoneMinThickness, color );
}
}
}
if( j == 0 )
p0 = coord;
// Draw areas:
if( m_FillMode == 0 && !outline_mode )
GRPoly( panel->GetClipBox(), DC, CornersBuffer.size(), &CornersBuffer[0],
true, 0, color, color );
}
CornersTypeBuffer.clear();
CornersBuffer.clear();
CornersBuffer.push_back( coord );
}
CornersBuffer.push_back( p0 );
// Draw outlines:
if( ( m_ZoneMinThickness > 1 ) || outline_mode )
{
int ilim = CornersBuffer.size() - 1;
for( int is = 0, ie = ilim; is <= ilim; ie = is, is++ )
{
int x0 = CornersBuffer[is].x;
int y0 = CornersBuffer[is].y;
int x1 = CornersBuffer[ie].x;
int y1 = CornersBuffer[ie].y;
// Draw only basic outlines, not extra segments.
if( !displ_opts->m_DisplayPcbTrackFill || GetState( FORCE_SKETCH ) )
GRCSegm( panel->GetClipBox(), DC,
x0, y0, x1, y1,
m_ZoneMinThickness, color );
else
GRFillCSegm( panel->GetClipBox(), DC,
x0, y0, x1, y1,
m_ZoneMinThickness, color );
}
}
// Draw areas:
if( m_FillMode == 0 && !outline_mode )
GRPoly( panel->GetClipBox(), DC, CornersBuffer.size(), &CornersBuffer[0],
true, 0, color, color );
}
if( m_FillMode == 1 && !outline_mode ) // filled with segments
@ -576,26 +564,7 @@ int ZONE_CONTAINER::GetClearance( BOARD_CONNECTED_ITEM* aItem ) const
bool ZONE_CONTAINER::HitTestFilledArea( const wxPoint& aRefPos ) const
{
unsigned indexstart = 0, indexend;
bool inside = false;
for( indexend = 0; indexend < m_FilledPolysList.GetCornersCount(); indexend++ )
{
if( m_FilledPolysList.IsEndContour( indexend ) ) // end of a filled sub-area found
{
if( TestPointInsidePolygon( m_FilledPolysList, indexstart, indexend,
aRefPos.x, aRefPos.y ) )
{
inside = true;
break;
}
// Prepare test of next area which starts after the current index end (if exists)
indexstart = indexend + 1;
}
}
return inside;
return m_FilledPolysList.Contains( VECTOR2I( aRefPos.x, aRefPos.y ) );
}
@ -674,9 +643,9 @@ void ZONE_CONTAINER::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList )
msg.Printf( wxT( "%d" ), (int) m_Poly->m_HatchLines.size() );
aList.push_back( MSG_PANEL_ITEM( _( "Hatch Lines" ), msg, BLUE ) );
if( m_FilledPolysList.GetCornersCount() )
if( !m_FilledPolysList.IsEmpty() )
{
msg.Printf( wxT( "%d" ), (int) m_FilledPolysList.GetCornersCount() );
msg.Printf( wxT( "%d" ), (int) m_FilledPolysList.TotalVertices() );
aList.push_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg, BLUE ) );
}
}
@ -694,12 +663,7 @@ void ZONE_CONTAINER::Move( const wxPoint& offset )
m_Poly->Hatch();
/* move filled areas: */
for( unsigned ic = 0; ic < m_FilledPolysList.GetCornersCount(); ic++ )
{
m_FilledPolysList.SetX( ic, m_FilledPolysList.GetX( ic ) + offset.x );
m_FilledPolysList.SetY( ic, m_FilledPolysList.GetY( ic ) + offset.y );
}
m_FilledPolysList.Move( VECTOR2I( offset.x, offset.y ) );
for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
{
@ -746,13 +710,8 @@ void ZONE_CONTAINER::Rotate( const wxPoint& centre, double angle )
m_Poly->Hatch();
/* rotate filled areas: */
for( unsigned ic = 0; ic < m_FilledPolysList.GetCornersCount(); ic++ )
{
pos = m_FilledPolysList.GetPos( ic );
RotatePoint( &pos, centre, angle );
m_FilledPolysList.SetX( ic, pos.x );
m_FilledPolysList.SetY( ic, pos.y );
}
for( SHAPE_POLY_SET::ITERATOR ic = m_FilledPolysList.Iterate(); ic; ++ic )
RotatePoint( &ic->x, &ic->y, centre.x, centre.y, angle );
for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
{
@ -779,11 +738,10 @@ void ZONE_CONTAINER::Mirror( const wxPoint& mirror_ref )
m_Poly->Hatch();
/* mirror filled areas: */
for( unsigned ic = 0; ic < m_FilledPolysList.GetCornersCount(); ic++ )
for( SHAPE_POLY_SET::ITERATOR ic = m_FilledPolysList.Iterate(); ic; ++ic )
{
int py = mirror_ref.y - m_FilledPolysList.GetY( ic );
m_FilledPolysList.SetY( ic, py + mirror_ref.y );
int py = mirror_ref.y - ic->y;
ic->y = py + mirror_ref.y;
}
for( unsigned ic = 0; ic < m_FillSegmList.size(); ic++ )
@ -896,15 +854,4 @@ wxString ZONE_CONTAINER::GetSelectMenuText() const
GetChars( GetLayerName() ) );
return msg;
}
/* Copy polygons stored in aKiPolyList to m_FilledPolysList
* The previous m_FilledPolysList contents is replaced.
*/
void ZONE_CONTAINER::CopyPolygonsFromClipperPathsToFilledPolysList(
ClipperLib::Paths& aClipperPolyList )
{
m_FilledPolysList.RemoveAllContours();
m_FilledPolysList.ImportFrom( aClipperPolyList );
}
}

View File

@ -165,18 +165,6 @@ public:
*/
void TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb );
/**
* Function CalculateSubAreaBoundaryBox
* Calculates the bounding box of a a filled area ( list of CPolyPt )
* use m_FilledPolysList as list of CPolyPt (that are the corners of one or more
* polygons or filled areas )
* @return an EDA_RECT as bounding box
* @param aIndexStart = index of the first corner of a polygon (filled area)
* in m_FilledPolysList
* @param aIndexEnd = index of the last corner of a polygon in m_FilledPolysList
*/
EDA_RECT CalculateSubAreaBoundaryBox( int aIndexStart, int aIndexEnd );
/**
* Function IsOnCopperLayer
* @return true if this zone is on a copper layer, false if on a technical layer
@ -271,7 +259,7 @@ public:
* @param aCorrectionFactor = the correction to apply to arcs radius to roughly
* keep arc radius when approximated by segments
*/
void TransformSolidAreasShapesToPolygonSet( CPOLYGONS_LIST& aCornerBuffer,
void TransformSolidAreasShapesToPolygonSet( SHAPE_POLY_SET& aCornerBuffer,
int aCircleToSegmentsCount,
double aCorrectionFactor );
/**
@ -295,32 +283,7 @@ public:
* AddClearanceAreasPolygonsToPolysList() to add holes for pads and tracks
* and other items not in net.
*/
bool BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aOutlineBuffer = NULL );
/**
* Function CopyPolygonsFromKiPolygonListToFilledPolysList
* Copy polygons stored in aKiPolyList to m_FilledPolysList
* The previous m_FilledPolysList contents is replaced.
* @param aKiPolyList = a KI_POLYGON_SET containing polygons.
*/
void CopyPolygonsFromKiPolygonListToFilledPolysList( KI_POLYGON_SET& aKiPolyList );
/**
* Function CopyPolygonsFromClipperPathsToFilledPolysList
* Copy polygons stored in aKiPolyList to m_FilledPolysList
* The previous m_FilledPolysList contents is replaced.
* @param aClipperPolyList = a ClipperLib::Paths containing polygons.
*/
void CopyPolygonsFromClipperPathsToFilledPolysList( ClipperLib::Paths& aClipperPolyList );
#if 0 //does not exist in rev 5741.
/**
* Function CopyPolygonsFromFilledPolysListToKiPolygonList
* Copy polygons from m_FilledPolysList to aKiPolyList
* @param aKiPolyList = a KI_POLYGON_SET to fill by polygons.
*/
void CopyPolygonsFromFilledPolysListToKiPolygonList( KI_POLYGON_SET& aKiPolyList );
#endif
bool BuildFilledSolidAreasPolygons( BOARD* aPcb, SHAPE_POLY_SET* aOutlineBuffer = NULL );
/**
* Function AddClearanceAreasPolygonsToPolysList
@ -352,7 +315,7 @@ public:
* false to use aMinClearanceValue only
* if both aMinClearanceValue = 0 and aUseNetClearance = false: create the zone outline polygon.
*/
void TransformOutlinesShapeWithClearanceToPolygon( CPOLYGONS_LIST& aCornerBuffer,
void TransformOutlinesShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
int aMinClearanceValue,
bool aUseNetClearance );
/**
@ -510,7 +473,7 @@ public:
* returns a reference to the list of filled polygons.
* @return Reference to the list of filled polygons.
*/
const CPOLYGONS_LIST& GetFilledPolysList() const
const SHAPE_POLY_SET& GetFilledPolysList() const
{
return m_FilledPolysList;
}
@ -519,7 +482,7 @@ public:
* Function AddFilledPolysList
* sets the list of filled polygons.
*/
void AddFilledPolysList( CPOLYGONS_LIST& aPolysList )
void AddFilledPolysList( SHAPE_POLY_SET& aPolysList )
{
m_FilledPolysList = aPolysList;
}
@ -548,7 +511,7 @@ public:
void AddPolygon( std::vector< wxPoint >& aPolygon );
void AddFilledPolygon( CPOLYGONS_LIST& aPolygon )
void AddFilledPolygon( SHAPE_POLY_SET& aPolygon )
{
m_FilledPolysList.Append( aPolygon );
}
@ -584,7 +547,7 @@ public:
private:
void buildFeatureHoleList( BOARD* aPcb, CPOLYGONS_LIST& aFeatures );
void buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeatures );
CPolyLine* m_Poly; ///< Outline of the zone.
CPolyLine* m_smoothedPoly; // Corner-smoothed version of m_Poly
@ -652,7 +615,7 @@ private:
* connecting "holes" with external main outline. In complex cases an outline
* described by m_Poly can have many filled areas
*/
CPOLYGONS_LIST m_FilledPolysList;
SHAPE_POLY_SET m_FilledPolysList;
};

View File

@ -698,11 +698,8 @@ static void export_vrml_drawings( MODEL_VRML& aModel, BOARD* pcb )
// board edges and cutouts
static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
{
CPOLYGONS_LIST bufferPcbOutlines; // stores the board main outlines
CPOLYGONS_LIST allLayerHoles; // Contains through holes, calculated only once
allLayerHoles.reserve( 20000 );
SHAPE_POLY_SET bufferPcbOutlines; // stores the board main outlines
SHAPE_POLY_SET allLayerHoles; // Contains through holes, calculated only once
// Build a polygon from edge cut items
wxString msg;
@ -715,47 +712,28 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
}
double scale = aModel.scale;
int i = 0;
int seg;
// deal with the solid outlines
int nvert = bufferPcbOutlines.GetCornersCount();
while( i < nvert )
for( int i = 0; i < bufferPcbOutlines.OutlineCount(); i++ )
{
const SHAPE_LINE_CHAIN& outline = bufferPcbOutlines.COutline( i );
seg = aModel.board.NewContour();
if( seg < 0 )
for( int j = 0; j < outline.PointCount(); j++ )
{
msg << wxT( "\n\n" ) <<
_( "VRML Export Failed:\nCould not add outline to contours." );
wxMessageBox( msg );
aModel.board.AddVertex( seg, (double)outline.CPoint(j).x * scale,
-((double)outline.CPoint(j).y * scale ) );
return;
}
while( i < nvert )
{
if( bufferPcbOutlines[i].end_contour )
break;
aModel.board.AddVertex( seg, bufferPcbOutlines[i].x * scale,
-(bufferPcbOutlines[i].y * scale ) );
++i;
}
aModel.board.EnsureWinding( seg, false );
++i;
}
// deal with the holes
nvert = allLayerHoles.GetCornersCount();
i = 0;
while( i < nvert )
for( int i = 0; i < allLayerHoles.OutlineCount(); i++ )
{
const SHAPE_LINE_CHAIN& outline = allLayerHoles.COutline( i );
seg = aModel.holes.NewContour();
if( seg < 0 )
@ -767,19 +745,14 @@ static void export_vrml_board( MODEL_VRML& aModel, BOARD* pcb )
return;
}
while( i < nvert )
for( int j = 0; j < outline.PointCount(); j++ )
{
if( allLayerHoles[i].end_contour )
break;
aModel.holes.AddVertex( seg, (double)outline.CPoint(j).x * scale,
-((double)outline.CPoint(j).y * scale ) );
aModel.holes.AddVertex( seg, allLayerHoles[i].x * scale,
-( allLayerHoles[i].y * scale ) );
++i;
}
aModel.holes.EnsureWinding( seg, true );
++i;
}
}
@ -871,9 +844,7 @@ static void export_vrml_tracks( MODEL_VRML& aModel, BOARD* pcb )
static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
{
double scale = aModel.scale;
double x, y;
for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
{
@ -890,33 +861,23 @@ static void export_vrml_zones( MODEL_VRML& aModel, BOARD* aPcb )
zone->BuildFilledSolidAreasPolygons( aPcb );
}
const CPOLYGONS_LIST& poly = zone->GetFilledPolysList();
int nvert = poly.GetCornersCount();
int i = 0;
const SHAPE_POLY_SET& poly = zone->GetFilledPolysList();
while( i < nvert )
for( int i = 0; i < poly.OutlineCount(); i++ )
{
const SHAPE_LINE_CHAIN& outline = poly.COutline( i );
int seg = vl->NewContour();
if( seg < 0 )
break;
while( i < nvert )
for( int j = 0; j < outline.PointCount(); j++ )
{
x = poly.GetX(i) * scale;
y = -(poly.GetY(i) * scale);
if( poly.IsEndContour(i) )
break;
if( !vl->AddVertex( seg, x, y ) )
if( !vl->AddVertex( seg, (double)outline.CPoint( j ).x * scale,
-((double)outline.CPoint( j ).y * scale ) ) )
throw( std::runtime_error( vl->GetError() ) );
++i;
}
vl->EnsureWinding( seg, false );
++i;
vl->EnsureWinding( seg, false );
}
}
}

View File

@ -1617,22 +1617,22 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
}
// Save the PolysList
const CPOLYGONS_LIST& fv = aZone->GetFilledPolysList();
const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList();
newLine = 0;
if( fv.GetCornersCount() )
if( !fv.IsEmpty() )
{
m_out->Print( aNestLevel+1, "(filled_polygon\n" );
m_out->Print( aNestLevel+2, "(pts\n" );
for( unsigned it = 0; it < fv.GetCornersCount(); ++it )
for( SHAPE_POLY_SET::CONST_ITERATOR it = fv.CIterate(); it; ++it )
{
if( newLine == 0 )
m_out->Print( aNestLevel+3, "(xy %s %s)",
FMT_IU( fv.GetX( it ) ).c_str(), FMT_IU( fv.GetY( it ) ).c_str() );
FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() );
else
m_out->Print( 0, " (xy %s %s)",
FMT_IU( fv.GetX( it ) ).c_str(), FMT_IU( fv.GetY( it ) ).c_str() );
FMT_IU( it->x ) .c_str(), FMT_IU( it->y ).c_str() );
if( newLine < 4 )
{
@ -1644,14 +1644,14 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
m_out->Print( 0, "\n" );
}
if( fv.IsEndContour( it ) )
if( it.IsEndContour() )
{
if( newLine != 0 )
m_out->Print( 0, "\n" );
m_out->Print( aNestLevel+2, ")\n" );
if( it+1 != fv.GetCornersCount() )
if( !it.IsLastContour() )
{
newLine = 0;
m_out->Print( aNestLevel+1, ")\n" );

View File

@ -2692,7 +2692,9 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
else if( TESTLINE( "$POLYSCORNERS" ) )
{
// Read the PolysList (polygons used for fill areas in the zone)
CPOLYGONS_LIST polysList;
SHAPE_POLY_SET polysList;
bool makeNewOutline = true;
while( ( line = READLINE( m_reader ) ) != NULL )
{
@ -2703,11 +2705,17 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER()
BIU x = biuParse( line, &data );
BIU y = biuParse( data, &data );
bool end_contour = intParse( data, &data ); // end_countour was a bool when file saved, so '0' or '1' here
int cornerUtilityFlg = intParse( data );
if( makeNewOutline )
polysList.NewOutline();
polysList.Append( CPolyPt( x, y, end_contour, cornerUtilityFlg ) );
polysList.Append( x, y );
bool end_contour = intParse( data, &data ); // end_countour was a bool when file saved, so '0' or '1' here
intParse( data ); // skip corner utility flag
makeNewOutline = end_contour;
}
zc->AddFilledPolysList( polysList );
}

View File

@ -757,7 +757,7 @@ void PCB_EDIT_FRAME::createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu*
AddMenuItem( zones_menu, ID_POPUP_PCB_FILL_ZONE, _( "Fill Zone" ),
KiBitmap( fill_zone_xpm ) );
if( edge_zone->GetFilledPolysList().GetCornersCount() > 0 )
if( !edge_zone->GetFilledPolysList().IsEmpty() )
{
AddMenuItem( zones_menu, ID_POPUP_PCB_REMOVE_FILLED_AREAS_IN_CURRENT_ZONE,
_( "Remove Filled Areas in Zone" ), KiBitmap( zone_unfill_xpm ) );

View File

@ -885,8 +885,9 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone )
// Draw the filling
if( displayMode != PCB_RENDER_SETTINGS::DZ_HIDE_FILLED )
{
const std::vector<CPolyPt> polyPoints = aZone->GetFilledPolysList().GetList();
if( polyPoints.size() == 0 ) // Nothing to draw
const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList();
if( polySet.OutlineCount() == 0 ) // Nothing to draw
return;
// Set up drawing options
@ -904,26 +905,28 @@ void PCB_PAINTER::draw( const ZONE_CONTAINER* aZone )
m_gal->SetIsStroke( true );
}
std::vector<CPolyPt>::const_iterator polyIterator;
for( polyIterator = polyPoints.begin(); polyIterator != polyPoints.end(); ++polyIterator )
for( int i = 0; i < polySet.OutlineCount(); i++ )
{
// Find out all of polygons and then draw them
corners.push_back( VECTOR2D( *polyIterator ) );
const SHAPE_LINE_CHAIN& outline = polySet.COutline( i );
// fixme: GAL drawing API that accepts SHAPEs directly (this fiddling with double<>int conversion
// is just a performance hog)
if( polyIterator->end_contour )
for( int j = 0; j < outline.PointCount(); j++ )
corners.push_back ( (VECTOR2D) outline.CPoint( j ) );
corners.push_back( (VECTOR2D) outline.CPoint( 0 ) );
if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_FILLED )
{
if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_FILLED )
{
m_gal->DrawPolygon( corners );
m_gal->DrawPolyline( corners );
}
else if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_OUTLINED )
{
m_gal->DrawPolyline( corners );
}
corners.clear();
m_gal->DrawPolygon( corners );
m_gal->DrawPolyline( corners );
}
else if( displayMode == PCB_RENDER_SETTINGS::DZ_SHOW_OUTLINED )
{
m_gal->DrawPolyline( corners );
}
corners.clear();
}
}
}

View File

@ -2540,7 +2540,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR )
wxString netnameFromfile; // the zone net name find in file
// bigger scope since each filled_polygon is concatenated in here
CPOLYGONS_LIST pts;
SHAPE_POLY_SET pts;
std::auto_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) );
@ -2790,13 +2790,14 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR )
if( token != T_pts )
Expecting( T_pts );
pts.NewOutline();
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
pts.Append( CPolyPt( parseXY() ) );
pts.Append( parseXY() );
}
NeedRIGHT();
pts.CloseLastContour();
}
break;
@ -2841,7 +2842,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR )
zone->Outline()->SetHatch( hatchStyle, hatchPitch, true );
}
if( pts.GetCornersCount() )
if( !pts.IsEmpty() )
zone->AddFilledPolysList( pts );
// Ensure keepout and non copper zones do not have a net

View File

@ -542,15 +542,14 @@ static const LAYER_ID plot_seq[] = {
/* Plot outlines of copper, for copper layer
*/
#include "clipper.hpp"
void PlotLayerOutlines( BOARD *aBoard, PLOTTER* aPlotter,
void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter,
LSET aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt )
{
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
itemplotter.SetLayerSet( aLayerMask );
CPOLYGONS_LIST outlines;
SHAPE_POLY_SET outlines;
for( LSEQ seq = aLayerMask.Seq( plot_seq, DIM( plot_seq ) ); seq; ++seq )
{
@ -559,51 +558,25 @@ void PlotLayerOutlines( BOARD *aBoard, PLOTTER* aPlotter,
outlines.RemoveAllContours();
aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
// Merge all overlapping polygons.
KI_POLYGON_SET kpolygons;
KI_POLYGON_SET ktmp;
outlines.ExportTo( ktmp );
kpolygons += ktmp;
outlines.Simplify();
// Plot outlines
std::vector< wxPoint > cornerList;
for( unsigned ii = 0; ii < kpolygons.size(); ii++ )
// Now we have one or more basic polygons: plot each polygon
for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
{
KI_POLYGON polygon = kpolygons[ii];
cornerList.clear();
const SHAPE_LINE_CHAIN& path = outlines.COutline( ii );
// polygon contains only one polygon, but it can have holes linked by
// overlapping segments.
// To plot clean outlines, we have to break this polygon into more polygons with
// no overlapping segments, using Clipper, because boost::polygon
// does not allow that
ClipperLib::Path raw_polygon;
ClipperLib::Paths normalized_polygons;
for( int jj = 0; jj < path.PointCount(); jj++ )
cornerList.push_back( wxPoint( path.CPoint( jj ).x , path.CPoint( jj ).x ) );
for( unsigned ic = 0; ic < polygon.size(); ic++ )
{
KI_POLY_POINT corner = *(polygon.begin() + ic);
raw_polygon.push_back( ClipperLib::IntPoint( corner.x(), corner.y() ) );
}
// Ensure the polygon is closed
if( cornerList[0] != cornerList[cornerList.size() - 1] )
cornerList.push_back( cornerList[0] );
ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons );
// Now we have one or more basic polygons: plot each polygon
for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ )
{
ClipperLib::Path& polygon = normalized_polygons[ii];
cornerList.clear();
for( unsigned jj = 0; jj < polygon.size(); jj++ )
cornerList.push_back( wxPoint( polygon[jj].X , polygon[jj].Y ) );
// Ensure the polygon is closed
if( cornerList[0] != cornerList[cornerList.size()-1] )
cornerList.push_back( cornerList[0] );
aPlotter->PlotPoly( cornerList, NO_FILL );
}
aPlotter->PlotPoly( cornerList, NO_FILL );
}
// Plot pad holes
@ -704,8 +677,8 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
// This extra margin is used to merge too close shapes
// (distance < aMinThickness), and will be removed when creating
// the actual shapes
CPOLYGONS_LIST bufferPolys; // Contains shapes to plot
CPOLYGONS_LIST initialPolys; // Contains exact shapes to plot
SHAPE_POLY_SET areas; // Contains shapes to plot
SHAPE_POLY_SET initialPolys; // Contains exact shapes to plot
/* calculates the coeff to compensate radius reduction of holes clearance
* due to the segment approx ( 1 /cos( PI/circleToSegmentsCount )
@ -722,7 +695,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
circleToSegmentsCount, correction );
// add shapes inflated by aMinThickness/2
module->TransformPadsShapesWithClearanceToPolygon( layer,
bufferPolys, inflate,
areas, inflate,
circleToSegmentsCount, correction );
}
@ -754,7 +727,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( !( via_set & aLayerMask ).any() )
continue;
via->TransformShapeWithClearanceToPolygon( bufferPolys, via_margin,
via->TransformShapeWithClearanceToPolygon( areas, via_margin,
circleToSegmentsCount,
correction );
via->TransformShapeWithClearanceToPolygon( initialPolys, via_clearance,
@ -771,7 +744,7 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
if( zone->GetLayer() != layer )
continue;
zone->TransformOutlinesShapeWithClearanceToPolygon( bufferPolys,
zone->TransformOutlinesShapeWithClearanceToPolygon( areas,
inflate, true );
zone->TransformOutlinesShapeWithClearanceToPolygon( initialPolys,
0, true );
@ -788,56 +761,15 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter,
zone.SetMinThickness( 0 ); // trace polygons only
zone.SetLayer ( layer );
// Now:
// 1 - merge polygons which are intersecting, i.e. remove gaps
// having a thickness < aMinThickness
// 2 - deflate resulting polygons by aMinThickness/2
KI_POLYGON_SET areasToMerge;
bufferPolys.ExportTo( areasToMerge );
KI_POLYGON_SET initialAreas;
initialPolys.ExportTo( initialAreas );
// Merge polygons: because each shape was created with an extra margin
// = aMinThickness/2, shapes too close ( dist < aMinThickness )
// will be merged, because they are overlapping
KI_POLYGON_SET areas;
areas |= areasToMerge; // Populates with merged polygons
// Deflate: remove the extra margin, to create the actual shapes
// Here I am using polygon:resize, because this function creates better shapes
// than deflate algo.
// Use here deflate made by Clipper, because:
// Clipper is (by far) faster and better, event using arcs to deflate shapes
// boost::polygon < 1.56 polygon resize function sometimes crashes when deflating using arcs
// boost::polygon >=1.56 polygon resize function just does not work
// Note also we combine polygons using boost::polygon, which works better than Clipper,
// especially with zones using holes linked to main outlines by overlapping segments
CPOLYGONS_LIST tmp;
tmp.ImportFrom( areas );
// Deflate area using Clipper, better than boost::polygon
ClipperLib::Paths areasDeflate;
tmp.ExportTo( areasDeflate );
// Deflate areas: they will have the right size after deflate
ClipperLib::ClipperOffset offset_engine;
circleToSegmentsCount = 16;
offset_engine.ArcTolerance = (double)inflate / 3.14 / circleToSegmentsCount;
offset_engine.AddPaths( areasDeflate, ClipperLib::jtRound, ClipperLib::etClosedPolygon );
offset_engine.Execute( areasDeflate, -inflate );
areas.BooleanAdd( initialPolys );
areas.Inflate( -inflate, circleToSegmentsCount );
// Combine the current areas to initial areas. This is mandatory because
// inflate/deflate transform is not perfect, and we want the initial areas perfectly kept
tmp.RemoveAllContours();
tmp.ImportFrom( areasDeflate );
areas.clear();
tmp.ExportTo( areas );
areas.BooleanAdd( initialPolys );
areas.Fracture();
// Resize slightly changes shapes (the transform is not perfect).
// So *ensure* initial shapes are kept
areas |= initialAreas;
zone.CopyPolygonsFromKiPolygonListToFilledPolysList( areas );
zone.AddFilledPolysList( areas );
itemplotter.PlotFilledAreas( &zone );
}

View File

@ -493,10 +493,9 @@ void BRDITEMS_PLOTTER::PlotTextePcb( TEXTE_PCB* pt_texte )
*/
void BRDITEMS_PLOTTER::PlotFilledAreas( ZONE_CONTAINER* aZone )
{
const CPOLYGONS_LIST& polysList = aZone->GetFilledPolysList();
unsigned imax = polysList.GetCornersCount();
const SHAPE_POLY_SET& polysList = aZone->GetFilledPolysList();
if( imax == 0 ) // Nothing to draw
if( polysList.IsEmpty() )
return;
// We need a buffer to store corners coordinates:
@ -511,12 +510,12 @@ void BRDITEMS_PLOTTER::PlotFilledAreas( ZONE_CONTAINER* aZone )
*
* in non filled mode the outline is plotted, but not the filling items
*/
for( unsigned ic = 0; ic < imax; ic++ )
for( SHAPE_POLY_SET::CONST_ITERATOR ic = polysList.CIterate(); ic; ++ic )
{
wxPoint pos = polysList.GetPos( ic );
wxPoint pos( ic->x, ic->y );
cornerList.push_back( pos );
if( polysList.IsEndContour( ic ) ) // Plot the current filled area outline
if( ic.IsEndContour() ) // Plot the current filled area outline
{
// First, close the outline
if( cornerList[0] != cornerList[cornerList.size() - 1] )

View File

@ -44,6 +44,8 @@
#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
#include <geometry/shape_poly_set.h>
#include <cassert>
#include <algorithm>
#include <limits>
@ -342,11 +344,16 @@ void RN_NET::clearNode( const RN_NODE_PTR& aNode )
}
RN_POLY::RN_POLY( const CPolyPt* aBegin, const CPolyPt* aEnd,
RN_POLY::RN_POLY( const SHAPE_POLY_SET* aParent,
int aSubpolygonIndex,
RN_LINKS& aConnections, const BOX2I& aBBox ) :
m_begin( aBegin ), m_end( aEnd ), m_bbox( aBBox )
m_subpolygonIndex( aSubpolygonIndex ),
m_bbox( aBBox ),
m_parentPolyset( aParent )
{
m_node = aConnections.AddNode( m_begin->x, m_begin->y );
const VECTOR2I& p = aParent->CVertex( aSubpolygonIndex, 0 );
m_node = aConnections.AddNode( p.x, p.y );
// Mark it as not appropriate as a destination of ratsnest edges
// (edges coming out from a polygon vertex look weird)
@ -356,48 +363,9 @@ RN_POLY::RN_POLY( const CPolyPt* aBegin, const CPolyPt* aEnd,
bool RN_POLY::HitTest( const RN_NODE_PTR& aNode ) const
{
long xt = aNode->GetX();
long yt = aNode->GetY();
VECTOR2I p( aNode->GetX(), aNode->GetY() );
// If the point lies outside the bounding box, there is no point to check it further
if( !m_bbox.Contains( xt, yt ) )
return false;
long xNew, yNew, xOld, yOld, x1, y1, x2, y2;
bool inside = false;
// For the first loop we have to use the last point as the previous point
xOld = m_end->x;
yOld = m_end->y;
for( const CPolyPt* point = m_begin; point <= m_end; ++point )
{
xNew = point->x;
yNew = point->y;
// Swap points if needed, so always x2 >= x1
if( xNew > xOld )
{
x1 = xOld; y1 = yOld;
x2 = xNew; y2 = yNew;
}
else
{
x1 = xNew; y1 = yNew;
x2 = xOld; y2 = yOld;
}
if( ( xNew < xt ) == ( xt <= xOld ) && /* edge "open" at left end */
(double)( yt - y1 ) * (double)( x2 - x1 ) < (double)( y2 - y1 ) * (double)( xt - x1 ) )
{
inside = !inside;
}
xOld = xNew;
yOld = yNew;
}
return inside;
return m_parentPolyset->Contains( p, m_subpolygonIndex );
}
@ -454,51 +422,14 @@ void RN_NET::AddItem( const TRACK* aTrack )
void RN_NET::AddItem( const ZONE_CONTAINER* aZone )
{
// Prepare a list of polygons (every zone can contain one or more polygons)
const std::vector<CPolyPt>& polyPoints = aZone->GetFilledPolysList().GetList();
const SHAPE_POLY_SET& polySet = aZone->GetFilledPolysList();
if( polyPoints.size() == 0 )
return;
// Origin and end of bounding box for a polygon
VECTOR2I origin( polyPoints[0].x, polyPoints[0].y );
VECTOR2I end( polyPoints[0].x, polyPoints[0].y );
unsigned int idxStart = 0;
// Extract polygons from zones
for( unsigned int i = 0; i < polyPoints.size(); ++i )
for( int i = 0; i < polySet.OutlineCount(); ++i )
{
const CPolyPt& point = polyPoints[i];
const SHAPE_LINE_CHAIN& path = polySet.COutline( i );
if( point.end_contour )
{
RN_POLY poly = RN_POLY( &polyPoints[idxStart], &point,
m_links, BOX2I( origin, end - origin ) );
poly.GetNode()->AddParent( aZone );
m_zones[aZone].m_Polygons.push_back( poly );
idxStart = i + 1;
if( idxStart < polyPoints.size() )
{
origin.x = polyPoints[idxStart].x;
origin.y = polyPoints[idxStart].y;
end.x = polyPoints[idxStart].x;
end.y = polyPoints[idxStart].y;
}
}
else
{
// Determine bounding box
if( point.x < origin.x )
origin.x = point.x;
else if( point.x > end.x )
end.x = point.x;
if( point.y < origin.y )
origin.y = point.y;
else if( point.y > end.y )
end.y = point.y;
}
RN_POLY poly = RN_POLY( &polySet, i, m_links, path.BBox() );
m_zones[aZone].m_Polygons.push_back( poly );
}
m_dirty = true;

View File

@ -47,7 +47,7 @@ class D_PAD;
class VIA;
class TRACK;
class ZONE_CONTAINER;
class CPolyPt;
class SHAPE_POLY_SET;
///> Types of items that are handled by the class
enum RN_ITEM_TYPE
@ -265,7 +265,8 @@ protected:
class RN_POLY
{
public:
RN_POLY( const CPolyPt* aBegin, const CPolyPt* aEnd,
RN_POLY( const SHAPE_POLY_SET* aParent,
int aSubpolygonIndex,
RN_LINKS& aConnections, const BOX2I& aBBox );
/**
@ -287,15 +288,16 @@ public:
bool HitTest( const RN_NODE_PTR& aNode ) const;
private:
///> Pointer to the first point of polyline bounding the polygon.
const CPolyPt* m_begin;
///> Pointer to the last point of polyline bounding the polygon.
const CPolyPt* m_end;
///> Index of the outline in the parent polygon set
int m_subpolygonIndex;
///> Bounding box of the polygon.
BOX2I m_bbox;
///> Polygon set containing the geometry
const SHAPE_POLY_SET* m_parentPolyset;
///> Node representing a polygon (it has the same coordinates as the first point of its
///> bounding polyline.
RN_NODE_PTR m_node;

View File

@ -43,6 +43,7 @@ class TRACK;
class VIA;
class NETCLASS;
class MODULE;
class SHAPE_POLY_SET;
typedef DSN::T DSN_T;
@ -3982,16 +3983,16 @@ public:
* any closed outline inside the main outline is a hole
* All contours should be closed, i.e. have valid vertices to build a closed polygon
* @param aBoard The BOARD to get information from in order to make the outlines.
* @param aOutlines The CPOLYGONS_LIST to fill in with main outlines.
* @param aHoles The empty CPOLYGONS_LIST to fill in with holes, if any.
* @param aOutlines The SHAPE_POLY_SET to fill in with main outlines.
* @param aHoles The empty SHAPE_POLY_SET to fill in with holes, if any.
* @param aErrorText = a wxString reference to display an error message
* with the coordinate of the point which creates the error
* (default = NULL , no message returned on error)
* @return true if success, false if a contour is not valid
*/
bool GetBoardPolygonOutlines( BOARD* aBoard,
CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
SHAPE_POLY_SET& aOutlines,
SHAPE_POLY_SET& aHoles,
wxString* aErrorText = NULL );
};

View File

@ -53,6 +53,8 @@
#include <collectors.h>
#include <geometry/shape_poly_set.h>
#include <specctra.h>
using namespace DSN;
@ -1330,8 +1332,8 @@ void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
* All contours should be closed, i.e. valid closed polygon vertices
*/
bool SPECCTRA_DB::GetBoardPolygonOutlines( BOARD* aBoard,
CPOLYGONS_LIST& aOutlines,
CPOLYGONS_LIST& aHoles,
SHAPE_POLY_SET& aOutlines,
SHAPE_POLY_SET& aHoles,
wxString* aErrorText )
{
bool success = true;
@ -1347,6 +1349,8 @@ bool SPECCTRA_DB::GetBoardPolygonOutlines( BOARD* aBoard,
BOUNDARY* boundary = new BOUNDARY( 0 );
pcb->structure->SetBOUNDARY( boundary );
aOutlines.NewOutline();
try
{
fillBOUNDARY( aBoard, boundary );
@ -1357,11 +1361,9 @@ bool SPECCTRA_DB::GetBoardPolygonOutlines( BOARD* aBoard,
{
corner.x = buffer[ii] * specctra2UIfactor;
corner.y = - buffer[ii+1] * specctra2UIfactor;
aOutlines.Append( corner );
aOutlines.Append( corner.x, corner.y );
}
aOutlines.CloseLastContour();
// Export holes, stored as keepouts polygonal shapes.
// by fillBOUNDARY()
KEEPOUTS& holes = pcb->structure->keepouts;
@ -1371,13 +1373,15 @@ bool SPECCTRA_DB::GetBoardPolygonOutlines( BOARD* aBoard,
KEEPOUT& keepout = *i;
PATH* poly_hole = (PATH*)keepout.shape;
POINTS& plist = poly_hole->GetPoints();
aHoles.NewOutline();
for( unsigned ii = 0; ii < plist.size(); ii++ )
{
corner.x = plist[ii].x * specctra2UIfactor;
corner.y = - plist[ii].y * specctra2UIfactor;
aHoles.Append( corner );
aHoles.Append( corner.x, corner.y );
}
aHoles.CloseLastContour();
}
}
catch( const IO_ERROR& ioe )
@ -1397,23 +1401,24 @@ bool SPECCTRA_DB::GetBoardPolygonOutlines( BOARD* aBoard,
if( ( bbbox.GetWidth() ) == 0 || ( bbbox.GetHeight() == 0 ) )
bbbox.Inflate( Millimeter2iu( 1.0 ) );
aOutlines.RemoveAllContours();
aOutlines.NewOutline();
corner.x = bbbox.GetOrigin().x;
corner.y = bbbox.GetOrigin().y;
aOutlines.Append( corner );
aOutlines.Append( corner.x, corner.y );
corner.x = bbbox.GetOrigin().x;
corner.y = bbbox.GetEnd().y;
aOutlines.Append( corner );
aOutlines.Append( corner.x, corner.y );
corner.x = bbbox.GetEnd().x;
corner.y = bbbox.GetEnd().y;
aOutlines.Append( corner );
aOutlines.Append( corner.x, corner.y );
corner.x = bbbox.GetEnd().x;
corner.y = bbbox.GetOrigin().y;
aOutlines.Append( corner );
aOutlines.CloseLastContour();
aOutlines.Append( corner.x, corner.y );
}
return success;

View File

@ -54,7 +54,7 @@
* to add holes for pads and tracks and other items not in net.
*/
bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST* aOutlineBuffer )
bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, SHAPE_POLY_SET* aOutlineBuffer )
{
/* 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
@ -92,7 +92,7 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST*
}
if( aOutlineBuffer )
aOutlineBuffer->Append( m_smoothedPoly->m_CornersList );
aOutlineBuffer->Append( ConvertPolyListToPolySet( 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
@ -105,15 +105,14 @@ bool ZONE_CONTAINER::BuildFilledSolidAreasPolygons( BOARD* aPcb, CPOLYGONS_LIST*
if( IsOnCopperLayer() )
{
if(g_UseOldZoneFillingAlgo)
AddClearanceAreasPolygonsToPolysList( aPcb );
else
AddClearanceAreasPolygonsToPolysList_NG( aPcb );
AddClearanceAreasPolygonsToPolysList_NG( aPcb );
}
else
{
int margin = m_ZoneMinThickness / 2;
m_smoothedPoly->m_CornersList.InflateOutline(m_FilledPolysList, -margin, true );
m_FilledPolysList = ConvertPolyListToPolySet( m_smoothedPoly->m_CornersList );
m_FilledPolysList.Inflate( -margin );
m_FilledPolysList.Fracture();
}
if( m_FillMode ) // if fill mode uses segments, create them:
@ -135,11 +134,9 @@ static bool SortByXValues( const int& a, const int &b )
int ZONE_CONTAINER::FillZoneAreasWithSegments()
{
int ics, ice;
int count = 0;
std::vector <int> x_coordinates;
bool error = false;
int istart, iend; // index of the starting and the endif corner of one filled area in m_FilledPolysList
int margin = m_ZoneMinThickness * 2 / 10;
int minwidth = Mils2iu( 2 );
margin = std::max ( minwidth, margin );
@ -148,113 +145,100 @@ int ZONE_CONTAINER::FillZoneAreasWithSegments()
// Read all filled areas in m_FilledPolysList
m_FillSegmList.clear();
istart = 0;
int end_list = m_FilledPolysList.GetCornersCount() - 1;
for( int ic = 0; ic <= end_list; ic++ )
for ( int index = 0; index < m_FilledPolysList.OutlineCount(); index++ )
{
CPolyPt* corner = &m_FilledPolysList[ic];
if ( corner->end_contour || ( ic == end_list ) )
const SHAPE_LINE_CHAIN& outline = m_FilledPolysList.COutline( index );
const BOX2I& rect = outline.BBox();
// Calculate the y limits of the zone
for( int refy = rect.GetY(), endy = rect.GetBottom(); refy < endy; refy += step )
{
iend = ic;
EDA_RECT rect = CalculateSubAreaBoundaryBox( istart, iend );
// find all intersection points of an infinite line with polyline sides
x_coordinates.clear();
// Calculate the y limits of the zone
for( int refy = rect.GetY(), endy = rect.GetBottom(); refy < endy; refy += step )
for( int v = 0; v < outline.PointCount(); v++ )
{
// find all intersection points of an infinite line with polyline sides
x_coordinates.clear();
for( ics = istart, ice = iend; ics <= iend; ice = ics, ics++ )
{
if( m_FilledPolysList[ice].m_flags )
continue;
int seg_startX = outline.CPoint( v ).x;
int seg_startY = outline.CPoint( v ).y;
int seg_endX = outline.CPoint( v + 1 ).x;
int seg_endY = outline.CPoint( v + 1 ).y;
int seg_startX = m_FilledPolysList[ics].x;
int seg_startY = m_FilledPolysList[ics].y;
int seg_endX = m_FilledPolysList[ice].x;
int seg_endY = m_FilledPolysList[ice].y;
/* Trivial cases: skip if ref above or below the segment to test */
if( ( seg_startY > refy ) && ( seg_endY > refy ) )
continue;
// segment below ref point, or its Y end pos on Y coordinate ref point: skip
if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
continue;
/* Trivial cases: skip if ref above or below the segment to test */
if( ( seg_startY > refy ) && (seg_endY > refy ) )
continue;
/* at this point refy is between seg_startY and seg_endY
* see if an horizontal line at Y = refy is intersecting this segment
*/
// calculate the x position of the intersection of this segment and the
// infinite line this is more easier if we move the X,Y axis origin to
// the segment start point:
// segment below ref point, or its Y end pos on Y coordinate ref point: skip
if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
continue;
seg_endX -= seg_startX;
seg_endY -= seg_startY;
double newrefy = (double) ( refy - seg_startY );
double intersec_x;
/* at this point refy is between seg_startY and seg_endY
* see if an horizontal line at Y = refy is intersecting this segment
*/
// calculate the x position of the intersection of this segment and the
// infinite line this is more easier if we move the X,Y axis origin to
// the segment start point:
seg_endX -= seg_startX;
seg_endY -= seg_startY;
double newrefy = (double) ( refy - seg_startY );
double intersec_x;
if ( seg_endY == 0 ) // horizontal segment on the same line: skip
continue;
if ( seg_endY == 0 ) // horizontal segment on the same line: skip
continue;
// Now calculate the x intersection coordinate of the horizontal line at
// y = newrefy and the segment from (0,0) to (seg_endX,seg_endY) with the
// horizontal line at the new refy position the line slope is:
// slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY
// and the x pos relative to the new origin is:
// intersec_x = refy/slope = refy * inv_slope
// Note: because horizontal segments are already tested and skipped, slope
// exists (seg_end_y not O)
double inv_slope = (double) seg_endX / seg_endY;
intersec_x = newrefy * inv_slope;
x_coordinates.push_back( (int) intersec_x + seg_startX );
}
// Now calculate the x intersection coordinate of the horizontal line at
// y = newrefy and the segment from (0,0) to (seg_endX,seg_endY) with the
// horizontal line at the new refy position the line slope is:
// slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY
// and the x pos relative to the new origin is:
// intersec_x = refy/slope = refy * inv_slope
// Note: because horizontal segments are already tested and skipped, slope
// exists (seg_end_y not O)
double inv_slope = (double) seg_endX / seg_endY;
intersec_x = newrefy * inv_slope;
x_coordinates.push_back( (int) intersec_x + seg_startX );
}
// A line scan is finished: build list of segments
// A line scan is finished: build list of segments
// Sort intersection points by increasing x value:
// So 2 consecutive points are the ends of a segment
sort( x_coordinates.begin(), x_coordinates.end(), SortByXValues );
// Sort intersection points by increasing x value:
// So 2 consecutive points are the ends of a segment
sort( x_coordinates.begin(), x_coordinates.end(), SortByXValues );
// Create segments
// Create segments
if ( !error && ( x_coordinates.size() & 1 ) != 0 )
{ // An even number of coordinates is expected, because a segment has 2 ends.
// An if this algorithm always works, it must always find an even count.
wxString msg = wxT("Fill Zone: odd number of points at y = ");
msg << refy;
wxMessageBox(msg );
error = true;
}
if( error )
break;
int iimax = x_coordinates.size() - 1;
for( int ii = 0; ii < iimax; ii +=2 )
{
wxPoint seg_start, seg_end;
count++;
seg_start.x = x_coordinates[ii];
seg_start.y = refy;
seg_end.x = x_coordinates[ii+1];
seg_end.y = refy;
SEGMENT segment( seg_start, seg_end );
m_FillSegmList.push_back( segment );
}
} //End examine segments in one area
if( !error && ( x_coordinates.size() & 1 ) != 0 )
{ // An even number of coordinates is expected, because a segment has 2 ends.
// An if this algorithm always works, it must always find an even count.
wxString msg = wxT( "Fill Zone: odd number of points at y = " );
msg << refy;
wxMessageBox( msg );
error = true;
}
if( error )
break;
istart = iend + 1; // istart points the first corner of the next area
} // End find one end of outline
int iimax = x_coordinates.size() - 1;
for( int ii = 0; ii < iimax; ii += 2 )
{
wxPoint seg_start, seg_end;
count++;
seg_start.x = x_coordinates[ii];
seg_start.y = refy;
seg_end.x = x_coordinates[ii + 1];
seg_end.y = refy;
SEGMENT segment( seg_start, seg_end );
m_FillSegmList.push_back( segment );
}
} //End examine segments in one area
if( error )
break;
} // End examine all areas
}
if( !error )
m_IsFilled = true;

View File

@ -48,7 +48,6 @@
#include <sstream>
#include <fctsys.h>
#include <polygons_defs.h>
#include <wxPcbStruct.h>
#include <trigo.h>
@ -70,7 +69,7 @@
#include <boost/foreach.hpp>
extern void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer,
extern void BuildUnconnectedThermalStubsPolygonList( SHAPE_POLY_SET& aCornerBuffer,
BOARD* aPcb, ZONE_CONTAINER* aZone,
double aArcCorrection,
double aRoundPadThermalRotation);
@ -78,7 +77,7 @@ extern void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuff
extern void Test_For_Copper_Island_And_Remove( BOARD* aPcb,
ZONE_CONTAINER* aZone_container );
extern void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
extern void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
D_PAD& aPad,
int aThermalGap,
int aCopperThickness,
@ -90,7 +89,7 @@ extern void CreateThermalReliefPadPolygon( CPOLYGONS_LIST& aCornerBuffer,
// Local Variables:
static double s_thermalRot = 450; // angle of stubs in thermal reliefs for round pads
void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, CPOLYGONS_LIST& aFeatures )
void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, SHAPE_POLY_SET& aFeatures )
{
int segsPerCircle;
double correctionFactor;
@ -368,83 +367,6 @@ void ZONE_CONTAINER::buildFeatureHoleList( BOARD* aPcb, CPOLYGONS_LIST& aFeature
}
static const SHAPE_POLY_SET convertPolyListToPolySet(const CPOLYGONS_LIST& aList)
{
SHAPE_POLY_SET rv;
unsigned corners_count = aList.GetCornersCount();
// Enter main outline: this is the first contour
unsigned ic = 0;
if(!corners_count)
return rv;
while( ic < corners_count )
{
rv.NewOutline( );
while( ic < corners_count )
{
rv.AppendVertex( aList.GetX(ic), aList.GetY(ic) );
if( aList.IsEndContour( ic ) )
break;
ic++;
}
ic++;
}
return rv;
}
static const CPOLYGONS_LIST convertPolySetToPolyList(const SHAPE_POLY_SET& aPolyset)
{
CPOLYGONS_LIST list;
CPolyPt corner, firstCorner;
for( int ii = 0; ii < aPolyset.OutlineCount(); ii++ )
{
for( int jj = 0; jj < aPolyset.VertexCount(ii); jj++ )
{
VECTOR2I v = aPolyset.GetVertex( jj, ii );
corner.x = v.x;
corner.y = v.y;
corner.end_contour = false;
if(!jj)
firstCorner = corner;
list.AddCorner( corner );
}
firstCorner.end_contour = true;
list.AddCorner( firstCorner );
}
return list;
}
static const SHAPE_POLY_SET convertBoostToPolySet ( const KI_POLYGON_SET& aSet )
{
SHAPE_POLY_SET rv;
BOOST_FOREACH ( const KI_POLYGON &poly, aSet )
{
rv.NewOutline();
for ( KI_POLYGON::iterator_type corner = poly.begin(); corner != poly.end(); ++ corner )
{
rv.AppendVertex ( corner->x(), corner->y() );
}
}
return rv;
}
/**
* Function AddClearanceAreasPolygonsToPolysList
@ -502,16 +424,18 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
if(g_DumpZonesWhenFilling)
dumper->BeginGroup("clipper-zone");
m_smoothedPoly->m_CornersList.InflateOutline( tmp, -outline_half_thickness, true );
SHAPE_POLY_SET solidAreas = convertPolyListToPolySet( tmp );
SHAPE_POLY_SET solidAreas = ConvertPolyListToPolySet( m_smoothedPoly->m_CornersList );
solidAreas.Inflate( -outline_half_thickness );
solidAreas.Simplify();
SHAPE_POLY_SET holes;
if(g_DumpZonesWhenFilling)
dumper->Write( &solidAreas, "solid-areas" );
tmp.RemoveAllContours();
buildFeatureHoleList( aPcb, tmp );
SHAPE_POLY_SET holes = convertPolyListToPolySet( tmp );
buildFeatureHoleList( aPcb, holes );
if(g_DumpZonesWhenFilling)
dumper->Write( &holes, "feature-holes" );
@ -521,61 +445,49 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
if (g_DumpZonesWhenFilling)
dumper->Write( &holes, "feature-holes-postsimplify" );
solidAreas.Subtract( holes );
solidAreas.BooleanSubtract( holes );
if (g_DumpZonesWhenFilling)
dumper->Write( &solidAreas, "solid-areas-minus-holes" );
m_FilledPolysList.RemoveAllContours();
SHAPE_POLY_SET fractured = solidAreas;
fractured.Fracture();
if (g_DumpZonesWhenFilling)
dumper->Write( &fractured, "fractured" );
m_FilledPolysList = convertPolySetToPolyList( fractured );
if (g_DumpZonesWhenFilling)
{
SHAPE_POLY_SET dupa = convertPolyListToPolySet ( m_FilledPolysList );
dumper->Write( &dupa, "verify-conv" );
}
m_FilledPolysList = fractured;
// Remove insulated islands:
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
tmp.RemoveAllContours();
SHAPE_POLY_SET thermalHoles;
// Test thermal stubs connections and add polygons to remove unconnected stubs.
// (this is a refinement for thermal relief shapes)
if( GetNetCode() > 0 )
BuildUnconnectedThermalStubsPolygonList( tmp, aPcb, this,
BuildUnconnectedThermalStubsPolygonList( thermalHoles, aPcb, this,
correctionFactor, s_thermalRot );
// remove copper areas corresponding to not connected stubs
if( tmp.GetCornersCount() )
if( !thermalHoles.IsEmpty() )
{
SHAPE_POLY_SET thermalHoles = convertPolyListToPolySet ( tmp );
thermalHoles.Simplify();
// Remove unconnected stubs
solidAreas.Subtract ( thermalHoles );
if (g_DumpZonesWhenFilling)
dumper->Write ( &thermalHoles, "thermal-holes" );
solidAreas.BooleanSubtract( thermalHoles );
if( g_DumpZonesWhenFilling )
dumper->Write( &thermalHoles, "thermal-holes" );
// put these areas in m_FilledPolysList
m_FilledPolysList.RemoveAllContours();
SHAPE_POLY_SET fractured = solidAreas;
fractured.Fracture();
if (g_DumpZonesWhenFilling)
if( g_DumpZonesWhenFilling )
dumper->Write ( &fractured, "fractured" );
m_FilledPolysList = convertPolySetToPolyList( fractured );
m_FilledPolysList = fractured;
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
@ -587,121 +499,4 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG( BOARD* aPcb )
void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb )
{
int segsPerCircle;
double correctionFactor;
std::auto_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO( "zones_dump.txt", true ) );
if(g_DumpZonesWhenFilling)
dumper->BeginGroup("boost-zone");
// Set the number of segments in arc approximations
if( m_ArcToSegmentsCount == ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF )
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF;
else
segsPerCircle = ARC_APPROX_SEGMENTS_COUNT_LOW_DEF;
/* calculates the coeff to compensate radius reduction of holes clearance
* due to the segment approx.
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
* s_Correction is 1 /cos( PI/s_CircleToSegmentsCount )
*/
correctionFactor = 1.0 / cos( M_PI / (double) segsPerCircle );
// 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.
CPOLYGONS_LIST cornerBufferPolysToSubstract;
// This KI_POLYGON_SET is the area(s) to fill, with m_ZoneMinThickness/2
KI_POLYGON_SET polyset_zone_solid_areas;
int outline_half_thickness = 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 main polygon is stored in polyset_zone_solid_areas
*/
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;
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "solid-areas" );
buildFeatureHoleList( aPcb, cornerBufferPolysToSubstract );
// cornerBufferPolysToSubstract contains polygons to substract.
// polyset_zone_solid_areas contains the main filled area
// Calculate now actual solid areas
if( cornerBufferPolysToSubstract.GetCornersCount() > 0 )
{
KI_POLYGON_SET polyset_holes;
cornerBufferPolysToSubstract.ExportTo( polyset_holes );
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_holes ), "feature-holes" );
// Remove holes from initial area.:
polyset_zone_solid_areas -= polyset_holes;
}
// put solid areas in m_FilledPolysList:
m_FilledPolysList.RemoveAllContours();
CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas );
// Remove insulated islands:
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
// Now we remove all unused thermal stubs.
cornerBufferPolysToSubstract.RemoveAllContours();
// Test thermal stubs connections and add polygons to remove unconnected stubs.
// (this is a refinement for thermal relief shapes)
if( GetNetCode() > 0 )
BuildUnconnectedThermalStubsPolygonList( cornerBufferPolysToSubstract, aPcb, this,
correctionFactor, s_thermalRot );
// remove copper areas corresponding to not connected stubs
if( cornerBufferPolysToSubstract.GetCornersCount() )
{
KI_POLYGON_SET polyset_holes;
cornerBufferPolysToSubstract.ExportTo( polyset_holes );
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_holes ), "thermal-holes" );
// Remove unconnected stubs
polyset_zone_solid_areas -= polyset_holes;
// put these areas in m_FilledPolysList
m_FilledPolysList.RemoveAllContours();
CopyPolygonsFromKiPolygonListToFilledPolysList( polyset_zone_solid_areas );
if( GetNetCode() > 0 )
TestForCopperIslandAndRemoveInsulatedIslands( aPcb );
}
if (g_DumpZonesWhenFilling)
dumper->Write ( convertBoostToPolySet( polyset_zone_solid_areas ), "complete" );
cornerBufferPolysToSubstract.RemoveAllContours();
}
void ZONE_CONTAINER::CopyPolygonsFromKiPolygonListToFilledPolysList( KI_POLYGON_SET& aKiPolyList )
{
m_FilledPolysList.RemoveAllContours();
m_FilledPolysList.ImportFrom( aKiPolyList );
}

View File

@ -27,7 +27,6 @@
*/
#include <fctsys.h>
#include <polygons_defs.h>
#include <PolyLine.h>
#include <wxPcbStruct.h>
#include <trigo.h>
@ -48,11 +47,10 @@
* false to create the outline polygon.
*/
void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
CPOLYGONS_LIST& aCornerBuffer, int aMinClearanceValue, bool aUseNetClearance )
SHAPE_POLY_SET& aCornerBuffer, int aMinClearanceValue, bool aUseNetClearance )
{
// Creates the zone outline polygon (with linked holes if any)
CPOLYGONS_LIST zoneOutline;
BuildFilledSolidAreasPolygons( NULL, &zoneOutline );
BuildFilledSolidAreasPolygons( NULL, &aCornerBuffer );
// add clearance to outline
int clearance = aMinClearanceValue;
@ -67,9 +65,9 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
// Calculate the polygon with clearance
// holes are linked to the main outline, so only one polygon is created.
if( clearance )
zoneOutline.InflateOutline( aCornerBuffer, clearance, true );
else
ConvertPolysListWithHolesToOnePolygon( zoneOutline, aCornerBuffer );
aCornerBuffer.Inflate( clearance );
aCornerBuffer.Fracture( );
}
@ -78,14 +76,14 @@ void ZONE_CONTAINER::TransformOutlinesShapeWithClearanceToPolygon(
* Function BuildUnconnectedThermalStubsPolygonList
* Creates a set of polygons corresponding to stubs created by thermal shapes on pads
* which are not connected to a zone (dangling bridges)
* @param aCornerBuffer = a CPOLYGONS_LIST where to store polygons
* @param aCornerBuffer = a SHAPE_POLY_SET where to store polygons
* @param aPcb = the board.
* @param aZone = a pointer to the ZONE_CONTAINER to examine.
* @param aArcCorrection = a pointer to the ZONE_CONTAINER to examine.
* @param aRoundPadThermalRotation = the rotation in 1.0 degree for thermal stubs in round pads
*/
void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer,
void BuildUnconnectedThermalStubsPolygonList( SHAPE_POLY_SET& aCornerBuffer,
BOARD* aPcb,
ZONE_CONTAINER* aZone,
double aArcCorrection,
@ -235,6 +233,7 @@ void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer,
break;
}
aCornerBuffer.NewOutline();
// add computed polygon to list
for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
@ -242,11 +241,7 @@ void BuildUnconnectedThermalStubsPolygonList( CPOLYGONS_LIST& aCornerBuffer,
wxPoint cpos = corners_buffer[ic];
RotatePoint( &cpos, fAngle ); // Rotate according to module orientation
cpos += pad->ShapePos(); // Shift origin to position
CPolyPt corner;
corner.x = cpos.x;
corner.y = cpos.y;
corner.end_contour = ( ic < (corners_buffer.size() - 1) ) ? false : true;
aCornerBuffer.Append( corner );
aCornerBuffer.Append( cpos.x, cpos.y );
}
}
}

View File

@ -40,7 +40,7 @@
void ZONE_CONTAINER::TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb )
{
if( m_FilledPolysList.GetCornersCount() == 0 )
if( m_FilledPolysList.IsEmpty() )
return;
// Build a list of points connected to the net:
@ -76,74 +76,27 @@ void ZONE_CONTAINER::TestForCopperIslandAndRemoveInsulatedIslands( BOARD* aPcb )
}
// test if a point is inside
unsigned indexstart = 0, indexend;
bool connected = false;
for( indexend = 0; indexend < m_FilledPolysList.GetCornersCount(); indexend++ )
for( int outline = 0; outline < m_FilledPolysList.OutlineCount(); outline++ )
{
if( m_FilledPolysList[indexend].end_contour ) // end of a filled sub-area found
bool connected = false;
for( unsigned ic = 0; ic < listPointsCandidates.size(); ic++ )
{
EDA_RECT bbox = CalculateSubAreaBoundaryBox( indexstart, indexend );
// test if this area is connected to a board item:
wxPoint pos = listPointsCandidates[ic];
for( unsigned ic = 0; ic < listPointsCandidates.size(); ic++ )
if( m_FilledPolysList.Contains( VECTOR2I( pos.x, pos.y ), outline ) )
{
// test if this area is connected to a board item:
wxPoint pos = listPointsCandidates[ic];
if( !bbox.Contains( pos ) )
continue;
if( TestPointInsidePolygon( m_FilledPolysList, indexstart, indexend,
pos.x, pos.y ) )
{
connected = true;
break;
}
connected = true;
break;
}
}
if( connected ) // this polygon is connected: analyse next polygon
{
indexstart = indexend + 1; // indexstart points the first point of the next polygon
connected = false;
}
else // Not connected: remove this polygon
{
m_FilledPolysList.DeleteCorners( indexstart, indexend );
indexend = indexstart; /* indexstart points the first point of the next polygon
* because the current poly is removed */
}
if( !connected ) // this polygon is connected: analyse next polygon
{
m_FilledPolysList.DeletePolygon( outline );
outline--;
}
}
}
EDA_RECT ZONE_CONTAINER::CalculateSubAreaBoundaryBox( int aIndexStart, int aIndexEnd )
{
CPolyPt start_point, end_point;
EDA_RECT bbox;
start_point = m_FilledPolysList[aIndexStart];
end_point = start_point;
for( int ii = aIndexStart; ii <= aIndexEnd; ii++ )
{
CPolyPt ptst = m_FilledPolysList[ii];
if( start_point.x > ptst.x )
start_point.x = ptst.x;
if( start_point.y > ptst.y )
start_point.y = ptst.y;
if( end_point.x < ptst.x )
end_point.x = ptst.x;
if( end_point.y < ptst.y )
end_point.y = ptst.y;
}
bbox.SetOrigin( start_point.x, start_point.y );
bbox.SetEnd( wxPoint( end_point.x, end_point.y ) );
return bbox;
}

View File

@ -51,8 +51,8 @@ void Merge_SubNets_Connected_By_CopperAreas( BOARD* aPcb, int aNetcode );
bool sort_areas( const ZONE_CONTAINER* ref, const ZONE_CONTAINER* tst )
{
if( ref->GetNetCode() == tst->GetNetCode() )
return ref->GetFilledPolysList().GetCornersCount() <
tst->GetFilledPolysList().GetCornersCount();
return ref->GetFilledPolysList().TotalVertices() <
tst->GetFilledPolysList().TotalVertices();
else
return ref->GetNetCode() < tst->GetNetCode();
}
@ -101,7 +101,7 @@ void BOARD::Test_Connections_To_Copper_Areas( int aNetcode )
if( aNetcode >= 0 && aNetcode != zone->GetNetCode() )
continue;
if( zone->GetFilledPolysList().GetCornersCount() == 0 )
if( zone->GetFilledPolysList().IsEmpty() )
continue;
zones_candidates.push_back( zone );
@ -156,16 +156,11 @@ void BOARD::Test_Connections_To_Copper_Areas( int aNetcode )
}
// test if a candidate is inside a filled area of this zone
unsigned indexstart = 0, indexend;
const CPOLYGONS_LIST& polysList = zone->GetFilledPolysList();
const SHAPE_POLY_SET& polysList = zone->GetFilledPolysList();
for( indexend = 0; indexend < polysList.GetCornersCount(); indexend++ )
for( int outline = 0; outline < polysList.OutlineCount(); outline++ )
{
// end of a filled sub-area found
if( polysList.IsEndContour( indexend ) )
{
subnet++;
EDA_RECT bbox = zone->CalculateSubAreaBoundaryBox( indexstart, indexend );
for( unsigned ic = 0; ic < candidates.size(); ic++ )
{
@ -207,22 +202,14 @@ void BOARD::Test_Connections_To_Copper_Areas( int aNetcode )
bool connected = false;
if( bbox.Contains( pos1 ) )
if( polysList.Contains( VECTOR2I( pos1.x, pos1.y ), outline ) )
connected = true;
if( !connected && ( pos1 != pos2 ) )
{
if( TestPointInsidePolygon( polysList, indexstart,
indexend, pos1.x, pos1.y ) )
if( polysList.Contains( VECTOR2I( pos2.x, pos2.y ), outline ) )
connected = true;
}
if( !connected && (pos1 != pos2 ) )
{
if( bbox.Contains( pos2 ) )
{
if( TestPointInsidePolygon( polysList,
indexstart, indexend,
pos2.x, pos2.y ) )
connected = true;
}
}
if( connected )
{
@ -247,13 +234,7 @@ void BOARD::Test_Connections_To_Copper_Areas( int aNetcode )
} // End if ( old_subnet > 0 )
} // End if( connected )
}
// End test candidates for the current filled area
indexstart = indexend + 1; // prepare test next area, starting at indexend+1
// (if exists). End read one area in
// zone->m_FilledPolysList
}
} // End read all segments in zone
}
} // End read all zones candidates
}

View File

@ -290,62 +290,26 @@ bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_
return false;
}
// polygons intersect, combine them
KI_POLYGON_WITH_HOLES areaRefPoly;
KI_POLYGON_WITH_HOLES areaToMergePoly;
area_ref->Outline()->m_CornersList.ExportTo( areaRefPoly );
area_to_combine->Outline()->m_CornersList.ExportTo( areaToMergePoly );
SHAPE_POLY_SET mergedOutlines = ConvertPolyListToPolySet( area_ref->Outline()->m_CornersList );
SHAPE_POLY_SET areaToMergePoly = ConvertPolyListToPolySet( area_to_combine->Outline()->m_CornersList );
KI_POLYGON_WITH_HOLES_SET mergedOutlines;
mergedOutlines.push_back( areaRefPoly );
mergedOutlines |= areaToMergePoly;
mergedOutlines.BooleanAdd( areaToMergePoly );
mergedOutlines.Simplify();
// We should have one polygon with hole
// We can have 2 polygons with hole, if the 2 initial polygons have only one common corner
// and therefore cannot be merged (they are dectected as intersecting)
// but we should never have more than 2 polys
if( mergedOutlines.size() > 2 )
if( mergedOutlines.OutlineCount() > 2 )
{
wxLogMessage(wxT("BOARD::CombineAreas error: more than 2 polys after merging") );
return false;
}
if( mergedOutlines.size() > 1 )
if( mergedOutlines.OutlineCount() > 1 )
return false;
areaRefPoly = mergedOutlines[0];
area_ref->Outline()->RemoveAllContours();
KI_POLYGON_WITH_HOLES::iterator_type corner = areaRefPoly.begin();
// create area with external contour: Recreate only area edges, NOT holes
area_ref->Outline()->Start( area_ref->GetLayer(), corner->x(), corner->y(),
area_ref->Outline()->GetHatchStyle() );
while( ++corner != areaRefPoly.end() )
{
area_ref->Outline()->AppendCorner( corner->x(), corner->y() );
}
area_ref->Outline()->CloseLastContour();
// add holes (set of polygons)
KI_POLYGON_WITH_HOLES::iterator_holes_type hole = areaRefPoly.begin_holes();
while( hole != areaRefPoly.end_holes() )
{
KI_POLYGON::iterator_type hole_corner = hole->begin();
// create area with external contour: Recreate only area edges, NOT holes
while( hole_corner != hole->end() )
{
area_ref->Outline()->AppendCorner( hole_corner->x(), hole_corner->y() );
hole_corner++;
}
area_ref->Outline()->CloseLastContour();
hole++;
}
area_ref->Outline()->m_CornersList = ConvertPolySetToPolyList( mergedOutlines );
RemoveArea( aDeletedList, area_to_combine );

View File

@ -9,12 +9,6 @@ set(POLYGON_SRCS
PolyLine.cpp
polygon_test_point_inside.cpp
clipper.cpp
poly2tri/common/shapes.cc
poly2tri/sweep/sweep.cc
poly2tri/sweep/cdt.cc
poly2tri/sweep/advancing_front.cc
poly2tri/sweep/sweep_context.cc
)
add_library(polygon STATIC ${POLYGON_SRCS})

View File

@ -115,85 +115,19 @@ CPolyLine::~CPolyLine()
* @return the polygon count (always >= 1, because there is at least one polygon)
* There are new polygons only if the polygon count is > 1
*/
#include "clipper.hpp"
int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
{
ClipperLib::Path raw_polygon;
ClipperLib::Paths normalized_polygons;
unsigned corners_count = m_CornersList.GetCornersCount();
SHAPE_POLY_SET polySet = ConvertPolyListToPolySet( m_CornersList );
KI_POLYGON_SET polysholes;
KI_POLYGON_WITH_HOLES mainpoly;
std::vector<KI_POLY_POINT> cornerslist;
KI_POLYGON_WITH_HOLES_SET all_contours;
KI_POLYGON poly_tmp;
polySet.Simplify();
// Normalize first contour
unsigned ic = 0;
while( ic < corners_count )
{
const CPolyPt& corner = m_CornersList[ic++];
raw_polygon.push_back( ClipperLib::IntPoint( corner.x, corner.y ) );
if( corner.end_contour )
break;
}
ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons );
// enter main outline
for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ )
{
ClipperLib::Path& polygon = normalized_polygons[ii];
cornerslist.clear();
for( unsigned jj = 0; jj < polygon.size(); jj++ )
cornerslist.push_back( KI_POLY_POINT( KiROUND( polygon[jj].X ),
KiROUND( polygon[jj].Y ) ) );
mainpoly.set( cornerslist.begin(), cornerslist.end() );
all_contours.push_back( mainpoly );
}
// Enter holes
while( ic < corners_count )
{
cornerslist.clear();
raw_polygon.clear();
normalized_polygons.clear();
// Normalize current hole and add it to hole list
while( ic < corners_count )
{
const CPolyPt& corner = m_CornersList[ic++];
raw_polygon.push_back( ClipperLib::IntPoint( corner.x, corner.y ) );
if( corner.end_contour )
{
ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons );
for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ )
{
ClipperLib::Path& polygon = normalized_polygons[ii];
cornerslist.clear();
for( unsigned jj = 0; jj < polygon.size(); jj++ )
cornerslist.push_back( KI_POLY_POINT( KiROUND( polygon[jj].X ),
KiROUND( polygon[jj].Y ) ) );
bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() );
polysholes.push_back( poly_tmp );
}
break;
}
}
}
all_contours -= polysholes;
// copy polygon with holes to destination
RemoveAllContours();
#define outlines all_contours
for( unsigned ii = 0; ii < outlines.size(); ii++ )
for( int ii = 0; ii < polySet.OutlineCount(); ii++ )
{
CPolyLine* polyline = this;
if( ii > 0 )
{
polyline = new CPolyLine;
@ -201,35 +135,14 @@ int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*>* aNewPolygonList )
aNewPolygonList->push_back( polyline );
}
KI_POLYGON_WITH_HOLES& curr_poly = outlines[ii];
KI_POLYGON_WITH_HOLES::iterator_type corner = curr_poly.begin();
// enter main contour
while( corner != curr_poly.end() )
{
polyline->AppendCorner( corner->x(), corner->y() );
corner++;
}
polyline->CloseLastContour();
SHAPE_POLY_SET pnew;
pnew.NewOutline();
pnew.Polygon( 0 ) = polySet.CPolygon( ii );
// add holes (set of polygons)
KI_POLYGON_WITH_HOLES::iterator_holes_type hole = curr_poly.begin_holes();
while( hole != curr_poly.end_holes() )
{
KI_POLYGON::iterator_type hole_corner = hole->begin();
// create area with external contour: Recreate only area edges, NOT holes
while( hole_corner != hole->end() )
{
polyline->AppendCorner( hole_corner->x(), hole_corner->y() );
hole_corner++;
}
polyline->CloseLastContour();
hole++;
}
polyline->RemoveNullSegments();
polyline->m_CornersList = ConvertPolySetToPolyList( pnew );
}
return outlines.size();
return polySet.OutlineCount();
}
/**
@ -1260,375 +1173,6 @@ int CPolyLine::HitTestForCorner( const wxPoint& aPos, int aDistMax ) const
return corner;
}
/*
* Copy the contours to a KI_POLYGON_WITH_HOLES
* The first contour is the main outline, others are holes
*/
void CPOLYGONS_LIST::ExportTo( KI_POLYGON_WITH_HOLES& aPolygoneWithHole ) const
{
unsigned corners_count = m_cornersList.size();
std::vector<KI_POLY_POINT> cornerslist;
KI_POLYGON poly;
// Enter main outline: this is the first contour
unsigned ic = 0;
while( ic < corners_count )
{
const CPolyPt& corner = GetCorner( ic++ );
cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
if( corner.end_contour )
break;
}
aPolygoneWithHole.set( cornerslist.begin(), cornerslist.end() );
// Enter holes: they are next contours (when exist)
if( ic < corners_count )
{
KI_POLYGON_SET holePolyList;
while( ic < corners_count )
{
cornerslist.clear();
while( ic < corners_count )
{
cornerslist.push_back( KI_POLY_POINT( GetX( ic ), GetY( ic ) ) );
if( IsEndContour( ic++ ) )
break;
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
holePolyList.push_back( poly );
}
aPolygoneWithHole.set_holes( holePolyList.begin(), holePolyList.end() );
}
}
/**
* Copy all contours to a KI_POLYGON_SET aPolygons
* Each contour is copied into a KI_POLYGON, and each KI_POLYGON
* is append to aPolygons
*/
void CPOLYGONS_LIST::ExportTo( KI_POLYGON_SET& aPolygons ) const
{
std::vector<KI_POLY_POINT> cornerslist;
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; )
{
KI_POLYGON poly;
cornerslist.clear();
unsigned ii;
for( ii = icnt; ii < corners_count; ii++ )
{
cornerslist.push_back( KI_POLY_POINT( GetX( ii ), GetY( ii ) ) );
if( IsEndContour( ii ) )
break;
}
bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
aPolygons.push_back( poly );
icnt = ii + 1;
}
}
/*
* 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
*/
void CPOLYGONS_LIST::ImportFrom( KI_POLYGON_SET& aPolygons )
{
CPolyPt corner;
for( unsigned ii = 0; ii < aPolygons.size(); ii++ )
{
KI_POLYGON& poly = aPolygons[ii];
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;
AddCorner( corner );
}
CloseLastContour();
}
}
/* 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
*
* 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 )
{
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
unsigned icnt = 0;
int width = std::abs( aInflateValue * 2 );
if( polyset_outline.size() )
{
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() )
{
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 )
{
aResult.ImportFrom( polyset_outline );
if( outlineHoles.size() )
aResult.ImportFrom( outlineHoles );
}
else
{
polyset_outline -= outlineHoles;
aResult.ImportFrom( polyset_outline );
}
}
/**
* Function ConvertPolysListWithHolesToOnePolygon
* converts the outline contours aPolysListWithHoles with holes to one polygon
* with no holes (only one contour)
* holes are linked to main outlines by overlap segments, to give only one polygon
*
* @param aPolysListWithHoles = the list of corners of contours (haing holes
* @param aOnePolyList = a polygon with no holes
*/
void ConvertPolysListWithHolesToOnePolygon( const CPOLYGONS_LIST& aPolysListWithHoles,
CPOLYGONS_LIST& aOnePolyList )
{
unsigned corners_count = aPolysListWithHoles.GetCornersCount();
int polycount = 0;
for( unsigned ii = 0; ii < corners_count; ii++ )
{
if( aPolysListWithHoles.IsEndContour( ii ) )
polycount++;
}
// If polycount<= 1, there is no holes found, and therefore just copy the polygon.
if( polycount <= 1 )
{
aOnePolyList.Append( aPolysListWithHoles );
return;
}
// Holes are found: convert them to only one polygon with overlap segments
KI_POLYGON_SET polysholes;
KI_POLYGON_SET mainpoly;
KI_POLYGON poly_tmp;
std::vector<KI_POLY_POINT> cornerslist;
corners_count = aPolysListWithHoles.GetCornersCount();
unsigned ic = 0;
// enter main outline
while( ic < corners_count )
{
const CPolyPt& corner = aPolysListWithHoles.GetCorner( ic++ );
cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
if( corner.end_contour )
break;
}
bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() );
mainpoly.push_back( poly_tmp );
while( ic < corners_count )
{
cornerslist.clear();
{
while( ic < corners_count )
{
const CPolyPt& corner = aPolysListWithHoles.GetCorner( ic++ );
cornerslist.push_back( KI_POLY_POINT( corner.x, corner.y ) );
if( corner.end_contour )
break;
}
bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() );
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 );
aOnePolyList.ImportFrom( mainpoly );
}
/**
* Function IsPolygonSelfIntersecting
@ -1724,21 +1268,80 @@ 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 )
const SHAPE_POLY_SET ConvertPolyListToPolySet( const CPOLYGONS_LIST& aList )
{
ClipperLib::Paths initialPoly;
ClipperLib::Paths modifiedPoly;
SHAPE_POLY_SET rv;
aOnePolyList.ExportTo( initialPoly );
SimplifyPolygon(initialPoly[0], modifiedPoly );
aPolysListWithHoles.ImportFrom( modifiedPoly );
unsigned corners_count = aList.GetCornersCount();
// Enter main outline: this is the first contour
unsigned ic = 0;
if( !corners_count )
return rv;
int index = 0;
while( ic < corners_count )
{
int hole = -1;
if( index == 0 )
{
rv.NewOutline();
hole = -1;
}
else
{
hole = rv.NewHole();
}
while( ic < corners_count )
{
rv.Append( aList.GetX( ic ), aList.GetY( ic ), 0, hole );
if( aList.IsEndContour( ic ) )
break;
ic++;
}
ic++;
index++;
}
return rv;
}
const CPOLYGONS_LIST ConvertPolySetToPolyList(const SHAPE_POLY_SET& aPolyset)
{
CPOLYGONS_LIST list;
CPolyPt corner, firstCorner;
const SHAPE_POLY_SET::POLYGON& poly = aPolyset.CPolygon( 0 );
for( unsigned int jj = 0; jj < poly.size() ; jj++ )
{
const SHAPE_LINE_CHAIN& path = poly[jj];
for( int i = 0; i < path.PointCount(); i++ )
{
const VECTOR2I &v = path.CPoint( i );
corner.x = v.x;
corner.y = v.y;
corner.end_contour = false;
if( i == 0 )
firstCorner = corner;
list.AddCorner( corner );
}
firstCorner.end_contour = true;
list.AddCorner( firstCorner );
}
return list;
}

View File

@ -53,8 +53,8 @@
#include <wx/gdicmn.h> // for wxPoint definition
#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>
#include <geometry/shape_poly_set.h> // fixme
class CSegment
{
@ -116,30 +116,21 @@ private:
public:
CPOLYGONS_LIST() {};
CPolyPt& operator [](int aIdx) {return m_cornersList[aIdx]; }
CPolyPt& operator [](int aIdx) { return m_cornersList[aIdx]; }
// Accessor:
const std::vector <CPolyPt>& GetList() const {return m_cornersList;}
int GetX( int ic ) const { return m_cornersList[ic].x; }
void SetX( int ic, int aValue ) { m_cornersList[ic].x = aValue; }
int GetY( int ic ) const { return m_cornersList[ic].y; }
void SetY( int ic, int aValue ) { m_cornersList[ic].y = aValue; }
int GetUtility( int ic ) const { return m_cornersList[ic].m_flags; }
void SetFlag( int ic, int aFlag )
{
m_cornersList[ic].m_flags = aFlag;
}
bool IsEndContour( int ic ) const
{
return m_cornersList[ic].end_contour;
}
void SetEndContour( int ic, bool end_contour )
{
m_cornersList[ic].end_contour = end_contour;
}
const wxPoint& GetPos( int ic ) const { return m_cornersList[ic]; }
const CPolyPt& GetCorner( int ic ) const { return m_cornersList[ic]; }
@ -157,6 +148,7 @@ public:
m_cornersList.erase( m_cornersList.begin() + aIdx );
}
// used only to erase an entire polygon
void DeleteCorners( int aIdFirstCorner, int aIdLastCorner )
{
m_cornersList.erase( m_cornersList.begin() + aIdFirstCorner,
@ -212,56 +204,6 @@ public:
* (number of corners flagged "end_contour"
*/
int GetContoursCount() const;
/**
* 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
@ -447,9 +389,6 @@ public:
const wxPoint& GetPos( int ic ) const { return m_CornersList.GetPos( ic ); }
int GetUtility( int ic ) const { return m_CornersList.GetUtility( ic ); };
void SetUtility( int ic, int aFlag ) { m_CornersList.SetFlag( ic, aFlag ); };
int GetHatchPitch() const { return m_hatchPitch; }
static int GetDefaultHatchPitchMils() { return 20; } // default hatch pitch value in mils
@ -473,11 +412,6 @@ public:
m_CornersList.SetY( ic, y );
}
void SetEndContour( int ic, bool end_contour )
{
m_CornersList.SetEndContour( ic, end_contour );
}
void SetHatchStyle( enum HATCH_STYLE style )
{
m_hatchStyle = style;
@ -549,30 +483,7 @@ public:
std::vector <CSegment> m_HatchLines; // hatch lines showing the polygon area
};
/**
* Function ConvertPolysListWithHolesToOnePolygon
* converts the outline contours aPolysListWithHoles with holes to one polygon
* with no holes (only one contour)
* holes are linked to main outlines by overlap segments, to give only one polygon
*
* @param aPolysListWithHoles = the list of corners of contours
* (main outline and holes)
* @param aOnePolyList = a polygon with no holes
*/
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 );
const SHAPE_POLY_SET ConvertPolyListToPolySet( const CPOLYGONS_LIST& aList );
const CPOLYGONS_LIST ConvertPolySetToPolyList( const SHAPE_POLY_SET& aPolyset );
#endif // #ifndef POLYLINE_H