diff --git a/3d-viewer/3d_canvas.h b/3d-viewer/3d_canvas.h index 2f59126ee6..c82f58a092 100644 --- a/3d-viewer/3d_canvas.h +++ b/3d-viewer/3d_canvas.h @@ -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 ); diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index 9fe8219876..390298e05e 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -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 diff --git a/3d-viewer/3d_draw_basic_functions.cpp b/3d-viewer/3d_draw_basic_functions.cpp index f17bfa2a83..216a61ac8a 100644 --- a/3d-viewer/3d_draw_basic_functions.cpp +++ b/3d-viewer/3d_draw_basic_functions.cpp @@ -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 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 ) { diff --git a/3d-viewer/3d_draw_basic_functions.h b/3d-viewer/3d_draw_basic_functions.h index 1a90c4d6b5..243de7db54 100644 --- a/3d-viewer/3d_draw_basic_functions.h +++ b/3d-viewer/3d_draw_basic_functions.h @@ -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 ); diff --git a/3d-viewer/3d_draw_board_body.cpp b/3d-viewer/3d_draw_board_body.cpp index c5511f11bd..d7419d098c 100644 --- a/3d-viewer/3d_draw_board_body.cpp +++ b/3d-viewer/3d_draw_board_body.cpp @@ -57,6 +57,8 @@ #include #include <3d_draw_basic_functions.h> #include +#include + #include #include @@ -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 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) diff --git a/3d-viewer/3d_draw_helper_functions.cpp b/3d-viewer/3d_draw_helper_functions.cpp index e9f79d7f6e..a726cc91c1 100644 --- a/3d-viewer/3d_draw_helper_functions.cpp +++ b/3d-viewer/3d_draw_helper_functions.cpp @@ -358,7 +358,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 ); @@ -436,7 +436,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 ) @@ -449,17 +449,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 ); } } diff --git a/common/common_plotDXF_functions.cpp b/common/common_plotDXF_functions.cpp index da5ef033ce..4567ee67ab 100644 --- a/common/common_plotDXF_functions.cpp +++ b/common/common_plotDXF_functions.cpp @@ -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& 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 ); diff --git a/common/convert_basic_shapes_to_polygon.cpp b/common/convert_basic_shapes_to_polygon.cpp index 38c5b79bf4..fbbd3c17a0 100644 --- a/common/convert_basic_shapes_to_polygon.cpp +++ b/common/convert_basic_shapes_to_polygon.cpp @@ -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 ); } diff --git a/common/geometry/shape_poly_set.cpp b/common/geometry/shape_poly_set.cpp index 6c223d7fb3..e3d6e2cb93 100644 --- a/common/geometry/shape_poly_set.cpp +++ b/common/geometry/shape_poly_set.cpp @@ -4,6 +4,9 @@ * Copyright (C) 2015 CERN * @author Tomasz Wlostowski * + * 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 #include -#include -#include #include #include #include #include -#include "geometry/shape_poly_set.h" +#include +#include +#include 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 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::max(); - int64_t x_nearest = 0; + int x = edge->m_p1.x; + int y = edge->m_p1.y; + int min_dist = std::numeric_limits::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::max(); + int x_min = std::numeric_limits::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::max(); + int x_min = std::numeric_limits::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; +} diff --git a/gerbview/class_gerber_draw_item.cpp b/gerbview/class_gerber_draw_item.cpp index 0e36b73250..b91539560c 100644 --- a/gerbview/class_gerber_draw_item.cpp +++ b/gerbview/class_gerber_draw_item.cpp @@ -27,7 +27,6 @@ */ #include -#include #include #include #include diff --git a/include/convert_basic_shapes_to_polygon.h b/include/convert_basic_shapes_to_polygon.h index 3e45baf6b6..23940ec42a 100644 --- a/include/convert_basic_shapes_to_polygon.h +++ b/include/convert_basic_shapes_to_polygon.h @@ -33,8 +33,8 @@ #include #include #include -#include +#include /** * 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 ); diff --git a/include/geometry/shape_line_chain.h b/include/geometry/shape_line_chain.h index 8bf0410806..16b80f32b5 100644 --- a/include/geometry/shape_line_chain.h +++ b/include/geometry/shape_line_chain.h @@ -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 m_points; diff --git a/include/geometry/shape_poly_set.h b/include/geometry/shape_poly_set.h index 63921493d6..7e378eeb70 100644 --- a/include/geometry/shape_poly_set.h +++ b/include/geometry/shape_poly_set.h @@ -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 POLYGON; + + /** + * Class ITERATOR_TEMPLATE + * + * Base class for iterating over all vertices in a given SHAPE_POLY_SET + */ + template + 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 ITERATOR; + typedef ITERATOR_TEMPLATE 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( 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 Polyset; + const ClipperLib::Path convertToClipper( const SHAPE_LINE_CHAIN& aPath, bool aRequiredOrientation ); + const SHAPE_LINE_CHAIN convertFromClipper( const ClipperLib::Path& aPath ); + + typedef std::vector Polyset; Polyset m_polys; }; diff --git a/pcbnew/board_items_to_polygon_shape_transform.cpp b/pcbnew/board_items_to_polygon_shape_transform.cpp index f4623c251c..e38ac4b0ec 100644 --- a/pcbnew/board_items_to_polygon_shape_transform.cpp +++ b/pcbnew/board_items_to_polygon_shape_transform.cpp @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -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 -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; } diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index f1058673b8..d4e8d39ea3 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2741,8 +2741,8 @@ wxString BOARD::GetNextModuleReferenceWithPrefix( const wxString& aPrefix, * return true if success, false if a contour is not valid */ #include -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: diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 3829f86a37..6510b89514 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -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 diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 23d8bcff8d..d294e22316 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -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; diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 17537c1ea2..a7aba66618 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -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 ); diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 1729049de7..c415baccae 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -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; /** diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index e1aeee7e4d..b1f1d31e7e 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -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; diff --git a/pcbnew/class_track.h b/pcbnew/class_track.h index f2e66ae67b..fd37d95675 100644 --- a/pcbnew/class_track.h +++ b/pcbnew/class_track.h @@ -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; diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index abec9aede3..e9b6c27977 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -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 ); -} +} \ No newline at end of file diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 8bed725beb..08d1259b5f 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -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; }; diff --git a/pcbnew/exporters/export_vrml.cpp b/pcbnew/exporters/export_vrml.cpp index 07c8b41be8..40dba6eaaa 100644 --- a/pcbnew/exporters/export_vrml.cpp +++ b/pcbnew/exporters/export_vrml.cpp @@ -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 ); } } } diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index fc46fc4599..d701b8366e 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -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" ); diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 94e4c74df7..2e5bf804de 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2678,7 +2678,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 ) { @@ -2689,11 +2691,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 ); } diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index e3571c36b3..52098031e5 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -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 ) ); diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index c23be9aa51..26e332ad6b 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -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 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::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(); } } } diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 898551ea8d..d92f06830a 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -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 diff --git a/pcbnew/plot_board_layers.cpp b/pcbnew/plot_board_layers.cpp index 64843da411..ec06a9ffcd 100644 --- a/pcbnew/plot_board_layers.cpp +++ b/pcbnew/plot_board_layers.cpp @@ -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 ); } diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 99b600aa77..bff7f5a5dd 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -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] ) diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index 74c9cc1d52..524c84529c 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -44,6 +44,8 @@ #include #include +#include + #include #include #include @@ -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& 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; diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index 4c8793f92b..b1bd137a12 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -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; diff --git a/pcbnew/specctra.h b/pcbnew/specctra.h index 06ab58753e..540fcf9b13 100644 --- a/pcbnew/specctra.h +++ b/pcbnew/specctra.h @@ -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 ); }; diff --git a/pcbnew/specctra_export.cpp b/pcbnew/specctra_export.cpp index e1c75b535b..51155ef6e5 100644 --- a/pcbnew/specctra_export.cpp +++ b/pcbnew/specctra_export.cpp @@ -53,6 +53,8 @@ #include +#include + #include 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; diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index 400d977a69..1b715cf4af 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -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 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; diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp index e779afb3be..d23562cef0 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Boost.cpp @@ -48,7 +48,6 @@ #include #include -#include #include #include @@ -70,7 +69,7 @@ #include -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 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 ); } diff --git a/pcbnew/zones_convert_to_polygons_aux_functions.cpp b/pcbnew/zones_convert_to_polygons_aux_functions.cpp index bdd789bf3a..8ac4e585c4 100644 --- a/pcbnew/zones_convert_to_polygons_aux_functions.cpp +++ b/pcbnew/zones_convert_to_polygons_aux_functions.cpp @@ -27,7 +27,6 @@ */ #include -#include #include #include #include @@ -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 ); } } } diff --git a/pcbnew/zones_polygons_insulated_copper_islands.cpp b/pcbnew/zones_polygons_insulated_copper_islands.cpp index 5e72a64497..bfb861e12e 100644 --- a/pcbnew/zones_polygons_insulated_copper_islands.cpp +++ b/pcbnew/zones_polygons_insulated_copper_islands.cpp @@ -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; -} diff --git a/pcbnew/zones_polygons_test_connections.cpp b/pcbnew/zones_polygons_test_connections.cpp index 3f45b0652c..6306260699 100644 --- a/pcbnew/zones_polygons_test_connections.cpp +++ b/pcbnew/zones_polygons_test_connections.cpp @@ -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 } diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index 4f2c61b7e4..4f8c080305 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -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 ); diff --git a/polygon/CMakeLists.txt b/polygon/CMakeLists.txt index 26eade92c7..2f09cbe9a9 100644 --- a/polygon/CMakeLists.txt +++ b/polygon/CMakeLists.txt @@ -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}) diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index cccd65ad18..3229d4b98a 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -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* 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 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* 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 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 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 - -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 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; +} \ No newline at end of file diff --git a/polygon/PolyLine.h b/polygon/PolyLine.h index 600bdf1e0e..5ac5afd3bf 100644 --- a/polygon/PolyLine.h +++ b/polygon/PolyLine.h @@ -53,8 +53,8 @@ #include // for wxPoint definition #include // for LAYER_NUM definition #include // for EDA_RECT definition -#include -#include + +#include // 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 & 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 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 diff --git a/polygon/poly2tri/common/shapes.cc b/polygon/poly2tri/common/shapes.cc deleted file mode 100644 index 06eb1f80c5..0000000000 --- a/polygon/poly2tri/common/shapes.cc +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "shapes.h" -#include - -namespace p2t { -Triangle::Triangle( Point& a, Point& b, Point& c ) -{ - points_[0] = &a; points_[1] = &b; points_[2] = &c; - neighbors_[0] = NULL; neighbors_[1] = NULL; neighbors_[2] = NULL; - constrained_edge[0] = constrained_edge[1] = constrained_edge[2] = false; - delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; - interior_ = false; -} - - -// Update neighbor pointers -void Triangle::MarkNeighbor( Point* p1, Point* p2, Triangle* t ) -{ - if( (p1 == points_[2] && p2 == points_[1]) || (p1 == points_[1] && p2 == points_[2]) ) - neighbors_[0] = t; - else if( (p1 == points_[0] && p2 == points_[2]) || (p1 == points_[2] && p2 == points_[0]) ) - neighbors_[1] = t; - else if( (p1 == points_[0] && p2 == points_[1]) || (p1 == points_[1] && p2 == points_[0]) ) - neighbors_[2] = t; - else - assert( 0 ); -} - - -// Exhaustive search to update neighbor pointers -void Triangle::MarkNeighbor( Triangle& t ) -{ - if( t.Contains( points_[1], points_[2] ) ) - { - neighbors_[0] = &t; - t.MarkNeighbor( points_[1], points_[2], this ); - } - else if( t.Contains( points_[0], points_[2] ) ) - { - neighbors_[1] = &t; - t.MarkNeighbor( points_[0], points_[2], this ); - } - else if( t.Contains( points_[0], points_[1] ) ) - { - neighbors_[2] = &t; - t.MarkNeighbor( points_[0], points_[1], this ); - } -} - - -/** - * Clears all references to all other triangles and points - */ -void Triangle::Clear() -{ - Triangle* t; - - for( int i = 0; i<3; i++ ) - { - t = neighbors_[i]; - - if( t != NULL ) - { - t->ClearNeighbor( this ); - } - } - - ClearNeighbors(); - points_[0] = points_[1] = points_[2] = NULL; -} - - -void Triangle::ClearNeighbor( Triangle* triangle ) -{ - if( neighbors_[0] == triangle ) - { - neighbors_[0] = NULL; - } - else if( neighbors_[1] == triangle ) - { - neighbors_[1] = NULL; - } - else - { - neighbors_[2] = NULL; - } -} - - -void Triangle::ClearNeighbors() -{ - neighbors_[0] = NULL; - neighbors_[1] = NULL; - neighbors_[2] = NULL; -} - - -void Triangle::ClearDelunayEdges() -{ - delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; -} - - -Point* Triangle::OppositePoint( Triangle& t, Point& p ) -{ - Point* cw = t.PointCW( p ); - - /* - double x = cw->x; - double y = cw->y; - - x = p.x; - y = p.y; - */ - - return PointCW( *cw ); -} - - -// Legalized triangle by rotating clockwise around point(0) -void Triangle::Legalize( Point& point ) -{ - points_[1] = points_[0]; - points_[0] = points_[2]; - points_[2] = &point; -} - - -// Legalize triagnle by rotating clockwise around oPoint -void Triangle::Legalize( Point& opoint, Point& npoint ) -{ - if( &opoint == points_[0] ) - { - points_[1] = points_[0]; - points_[0] = points_[2]; - points_[2] = &npoint; - } - else if( &opoint == points_[1] ) - { - points_[2] = points_[1]; - points_[1] = points_[0]; - points_[0] = &npoint; - } - else if( &opoint == points_[2] ) - { - points_[0] = points_[2]; - points_[2] = points_[1]; - points_[1] = &npoint; - } - else - { - assert( 0 ); - } -} - - -int Triangle::Index( const Point* p ) -{ - if( p == points_[0] ) - { - return 0; - } - else if( p == points_[1] ) - { - return 1; - } - else if( p == points_[2] ) - { - return 2; - } - - assert( 0 ); - return 0; // you better hope its a Debug build. -} - - -int Triangle::EdgeIndex( const Point* p1, const Point* p2 ) -{ - if( points_[0] == p1 ) - { - if( points_[1] == p2 ) - { - return 2; - } - else if( points_[2] == p2 ) - { - return 1; - } - } - else if( points_[1] == p1 ) - { - if( points_[2] == p2 ) - { - return 0; - } - else if( points_[0] == p2 ) - { - return 2; - } - } - else if( points_[2] == p1 ) - { - if( points_[0] == p2 ) - { - return 1; - } - else if( points_[1] == p2 ) - { - return 0; - } - } - - return -1; -} - - -void Triangle::MarkConstrainedEdge( const int index ) -{ - constrained_edge[index] = true; -} - - -void Triangle::MarkConstrainedEdge( Edge& edge ) -{ - MarkConstrainedEdge( edge.p, edge.q ); -} - - -// Mark edge as constrained -void Triangle::MarkConstrainedEdge( Point* p, Point* q ) -{ - if( (q == points_[0] && p == points_[1]) || (q == points_[1] && p == points_[0]) ) - { - constrained_edge[2] = true; - } - else if( (q == points_[0] && p == points_[2]) || (q == points_[2] && p == points_[0]) ) - { - constrained_edge[1] = true; - } - else if( (q == points_[1] && p == points_[2]) || (q == points_[2] && p == points_[1]) ) - { - constrained_edge[0] = true; - } -} - - -// The point counter-clockwise to given point -Point* Triangle::PointCW( Point& point ) -{ - if( &point == points_[0] ) - { - return points_[2]; - } - else if( &point == points_[1] ) - { - return points_[0]; - } - else if( &point == points_[2] ) - { - return points_[1]; - } - - assert( 0 ); - return NULL; // you better hope its a Debug build. -} - - -// The point counter-clockwise to given point -Point* Triangle::PointCCW( Point& point ) -{ - if( &point == points_[0] ) - { - return points_[1]; - } - else if( &point == points_[1] ) - { - return points_[2]; - } - else if( &point == points_[2] ) - { - return points_[0]; - } - - assert( 0 ); - return NULL; // you better hope its a Debug build. -} - - -// The neighbor clockwise to given point -Triangle* Triangle::NeighborCW( Point& point ) -{ - if( &point == points_[0] ) - { - return neighbors_[1]; - } - else if( &point == points_[1] ) - { - return neighbors_[2]; - } - - return neighbors_[0]; -} - - -// The neighbor counter-clockwise to given point -Triangle* Triangle::NeighborCCW( Point& point ) -{ - if( &point == points_[0] ) - { - return neighbors_[2]; - } - else if( &point == points_[1] ) - { - return neighbors_[0]; - } - - return neighbors_[1]; -} - - -bool Triangle::GetConstrainedEdgeCCW( Point& p ) -{ - if( &p == points_[0] ) - { - return constrained_edge[2]; - } - else if( &p == points_[1] ) - { - return constrained_edge[0]; - } - - return constrained_edge[1]; -} - - -bool Triangle::GetConstrainedEdgeCW( Point& p ) -{ - if( &p == points_[0] ) - { - return constrained_edge[1]; - } - else if( &p == points_[1] ) - { - return constrained_edge[2]; - } - - return constrained_edge[0]; -} - - -void Triangle::SetConstrainedEdgeCCW( Point& p, bool ce ) -{ - if( &p == points_[0] ) - { - constrained_edge[2] = ce; - } - else if( &p == points_[1] ) - { - constrained_edge[0] = ce; - } - else - { - constrained_edge[1] = ce; - } -} - - -void Triangle::SetConstrainedEdgeCW( Point& p, bool ce ) -{ - if( &p == points_[0] ) - { - constrained_edge[1] = ce; - } - else if( &p == points_[1] ) - { - constrained_edge[2] = ce; - } - else - { - constrained_edge[0] = ce; - } -} - - -bool Triangle::GetDelunayEdgeCCW( Point& p ) -{ - if( &p == points_[0] ) - { - return delaunay_edge[2]; - } - else if( &p == points_[1] ) - { - return delaunay_edge[0]; - } - - return delaunay_edge[1]; -} - - -bool Triangle::GetDelunayEdgeCW( Point& p ) -{ - if( &p == points_[0] ) - { - return delaunay_edge[1]; - } - else if( &p == points_[1] ) - { - return delaunay_edge[2]; - } - - return delaunay_edge[0]; -} - - -void Triangle::SetDelunayEdgeCCW( Point& p, bool e ) -{ - if( &p == points_[0] ) - { - delaunay_edge[2] = e; - } - else if( &p == points_[1] ) - { - delaunay_edge[0] = e; - } - else - { - delaunay_edge[1] = e; - } -} - - -void Triangle::SetDelunayEdgeCW( Point& p, bool e ) -{ - if( &p == points_[0] ) - { - delaunay_edge[1] = e; - } - else if( &p == points_[1] ) - { - delaunay_edge[2] = e; - } - else - { - delaunay_edge[0] = e; - } -} - - -// The neighbor across to given point -Triangle& Triangle::NeighborAcross( Point& opoint ) -{ - if( &opoint == points_[0] ) - { - return *neighbors_[0]; - } - else if( &opoint == points_[1] ) - { - return *neighbors_[1]; - } - - return *neighbors_[2]; -} - - -void Triangle::DebugPrint() -{ - std::cout << points_[0]->x << "," << points_[0]->y << " "; - std::cout << points_[1]->x << "," << points_[1]->y << " "; - std::cout << points_[2]->x << "," << points_[2]->y << "\n"; -} -} diff --git a/polygon/poly2tri/common/shapes.h b/polygon/poly2tri/common/shapes.h deleted file mode 100644 index c65f485eaf..0000000000 --- a/polygon/poly2tri/common/shapes.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Include guard -#ifndef SHAPES_H -#define SHAPES_H - -#include -#include -#include -#include - -namespace p2t { -struct Edge; - -struct Point -{ - double x, y; - - /// Default constructor does nothing (for performance). - Point() - { - x = 0.0; - y = 0.0; - } - - /// The edges this point constitutes an upper ending point - std::vector edge_list; - - /// Construct using coordinates. - Point( double x, double y ) : x( x ), y( y ) {} - - /// Set this point to all zeros. - void set_zero() - { - x = 0.0; - y = 0.0; - } - - /// Set this point to some specified coordinates. - void set( double x_, double y_ ) - { - x = x_; - y = y_; - } - - /// Negate this point. - Point operator -() const - { - Point v; - - v.set( -x, -y ); - return v; - } - - /// Add a point to this point. - void operator +=( const Point& v ) - { - x += v.x; - y += v.y; - } - - /// Subtract a point from this point. - void operator -=( const Point& v ) - { - x -= v.x; - y -= v.y; - } - - /// Multiply this point by a scalar. - void operator *=( double a ) - { - x *= a; - y *= a; - } - - /// Get the length of this point (the norm). - double Length() const - { - return sqrt( x * x + y * y ); - } - - /// Convert this point into a unit point. Returns the Length. - double Normalize() - { - double len = Length(); - - x /= len; - y /= len; - return len; - } -}; - -// Represents a simple polygon's edge -struct Edge -{ - Point* p, * q; - - /// Constructor - Edge( Point& p1, Point& p2 ) : p( &p1 ), q( &p2 ) - { - if( p1.y > p2.y ) - { - q = &p1; - p = &p2; - } - else if( p1.y == p2.y ) - { - if( p1.x > p2.x ) - { - q = &p1; - p = &p2; - } - else if( p1.x == p2.x ) - { - // Repeat points - assert( false ); - } - } - - q->edge_list.push_back( this ); - } -}; - -// Triangle-based data structures are know to have better performance than quad-edge structures -// See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator" -// "Triangulations in CGAL" -class Triangle -{ -public: - -/// Constructor - Triangle( Point& a, Point& b, Point& c ); - -/// Flags to determine if an edge is a Constrained edge - bool constrained_edge[3]; -/// Flags to determine if an edge is a Delauney edge - bool delaunay_edge[3]; - - Point* GetPoint( const int& index ); - Point* PointCW( Point& point ); - Point* PointCCW( Point& point ); - Point* OppositePoint( Triangle& t, Point& p ); - - Triangle* GetNeighbor( const int& index ); - void MarkNeighbor( Point* p1, Point* p2, Triangle* t ); - void MarkNeighbor( Triangle& t ); - - void MarkConstrainedEdge( const int index ); - void MarkConstrainedEdge( Edge& edge ); - void MarkConstrainedEdge( Point* p, Point* q ); - - int Index( const Point* p ); - int EdgeIndex( const Point* p1, const Point* p2 ); - - Triangle* NeighborCW( Point& point ); - Triangle* NeighborCCW( Point& point ); - bool GetConstrainedEdgeCCW( Point& p ); - bool GetConstrainedEdgeCW( Point& p ); - void SetConstrainedEdgeCCW( Point& p, bool ce ); - void SetConstrainedEdgeCW( Point& p, bool ce ); - bool GetDelunayEdgeCCW( Point& p ); - bool GetDelunayEdgeCW( Point& p ); - void SetDelunayEdgeCCW( Point& p, bool e ); - void SetDelunayEdgeCW( Point& p, bool e ); - - bool Contains( Point* p ); - bool Contains( const Edge& e ); - bool Contains( Point* p, Point* q ); - void Legalize( Point& point ); - void Legalize( Point& opoint, Point& npoint ); - -/** - * Clears all references to all other triangles and points - */ - void Clear(); - void ClearNeighbor( Triangle* triangle ); - void ClearNeighbors(); - void ClearDelunayEdges(); - - inline bool IsInterior(); - inline void IsInterior( bool b ); - - Triangle& NeighborAcross( Point& opoint ); - - void DebugPrint(); - -private: - -/// Triangle points - Point* points_[3]; -/// Neighbor list - Triangle* neighbors_[3]; - -/// Has this triangle been marked as an interior triangle? - bool interior_; -}; - -inline bool cmp( const Point* a, const Point* b ) -{ - if( a->y < b->y ) - { - return true; - } - else if( a->y == b->y ) - { - // Make sure q is point with greater x value - if( a->x < b->x ) - { - return true; - } - } - - return false; -} - - -/// Add two points_ component-wise. -inline Point operator +( const Point& a, const Point& b ) -{ - return Point( a.x + b.x, a.y + b.y ); -} - - -/// Subtract two points_ component-wise. -inline Point operator -( const Point& a, const Point& b ) -{ - return Point( a.x - b.x, a.y - b.y ); -} - - -/// Multiply point by scalar -inline Point operator *( double s, const Point& a ) -{ - return Point( s * a.x, s * a.y ); -} - - -inline bool operator ==( const Point& a, const Point& b ) -{ - return a.x == b.x && a.y == b.y; -} - - -inline bool operator !=( const Point& a, const Point& b ) -{ - return !(a.x == b.x) && !(a.y == b.y); -} - - -/// Peform the dot product on two vectors. -inline double Dot( const Point& a, const Point& b ) -{ - return a.x * b.x + a.y * b.y; -} - - -/// Perform the cross product on two vectors. In 2D this produces a scalar. -inline double Cross( const Point& a, const Point& b ) -{ - return a.x * b.y - a.y * b.x; -} - - -/// Perform the cross product on a point and a scalar. In 2D this produces -/// a point. -inline Point Cross( const Point& a, double s ) -{ - return Point( s * a.y, -s * a.x ); -} - - -/// Perform the cross product on a scalar and a point. In 2D this produces -/// a point. -inline Point Cross( const double s, const Point& a ) -{ - return Point( -s * a.y, s * a.x ); -} - - -inline Point* Triangle::GetPoint( const int& index ) -{ - return points_[index]; -} - - -inline Triangle* Triangle::GetNeighbor( const int& index ) -{ - return neighbors_[index]; -} - - -inline bool Triangle::Contains( Point* p ) -{ - return p == points_[0] || p == points_[1] || p == points_[2]; -} - - -inline bool Triangle::Contains( const Edge& e ) -{ - return Contains( e.p ) && Contains( e.q ); -} - - -inline bool Triangle::Contains( Point* p, Point* q ) -{ - return Contains( p ) && Contains( q ); -} - - -inline bool Triangle::IsInterior() -{ - return interior_; -} - - -inline void Triangle::IsInterior( bool b ) -{ - interior_ = b; -} -} - -#endif diff --git a/polygon/poly2tri/common/utils.h b/polygon/poly2tri/common/utils.h deleted file mode 100644 index 3de9fb11bf..0000000000 --- a/polygon/poly2tri/common/utils.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef UTILS_H -#define UTILS_H - -// Otherwise #defines like M_PI are undeclared under Visual Studio -#define _USE_MATH_DEFINES - -#include -#include - -namespace p2t { -const double PI_3div4 = 3 * M_PI / 4; -const double PI_div2 = 1.57079632679489661923; -const double EPSILON = 1e-12; - -enum Orientation { - CW, CCW, COLLINEAR -}; - -/** - * Forumla to calculate signed area
- * Positive if CCW
- * Negative if CW
- * 0 if collinear
- *
- * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
- *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
- * 
- */ -Orientation Orient2d( Point& pa, Point& pb, Point& pc ) -{ - double detleft = (pa.x - pc.x) * (pb.y - pc.y); - double detright = (pa.y - pc.y) * (pb.x - pc.x); - double val = detleft - detright; - - if( val > -EPSILON && val < EPSILON ) - { - return COLLINEAR; - } - else if( val > 0 ) - { - return CCW; - } - - return CW; -} - - -/* - * bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) - * { - * double pdx = pd.x; - * double pdy = pd.y; - * double adx = pa.x - pdx; - * double ady = pa.y - pdy; - * double bdx = pb.x - pdx; - * double bdy = pb.y - pdy; - * - * double adxbdy = adx * bdy; - * double bdxady = bdx * ady; - * double oabd = adxbdy - bdxady; - * - * if (oabd <= EPSILON) { - * return false; - * } - * - * double cdx = pc.x - pdx; - * double cdy = pc.y - pdy; - * - * double cdxady = cdx * ady; - * double adxcdy = adx * cdy; - * double ocad = cdxady - adxcdy; - * - * if (ocad <= EPSILON) { - * return false; - * } - * - * return true; - * } - * - */ - -bool InScanArea( Point& pa, Point& pb, Point& pc, Point& pd ) -{ - double oadb = (pa.x - pb.x) * (pd.y - pb.y) - (pd.x - pb.x) * (pa.y - pb.y); - - if( oadb >= -EPSILON ) - { - return false; - } - - double oadc = (pa.x - pc.x) * (pd.y - pc.y) - (pd.x - pc.x) * (pa.y - pc.y); - - if( oadc <= EPSILON ) - { - return false; - } - - return true; -} -} - -#endif diff --git a/polygon/poly2tri/poly2tri.h b/polygon/poly2tri/poly2tri.h deleted file mode 100644 index 487755e2e9..0000000000 --- a/polygon/poly2tri/poly2tri.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef POLY2TRI_H -#define POLY2TRI_H - -#include "common/shapes.h" -#include "sweep/cdt.h" - -#endif - diff --git a/polygon/poly2tri/sweep/advancing_front.cc b/polygon/poly2tri/sweep/advancing_front.cc deleted file mode 100644 index 019df4a6eb..0000000000 --- a/polygon/poly2tri/sweep/advancing_front.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "advancing_front.h" - -namespace p2t { - -AdvancingFront::AdvancingFront(Node& head, Node& tail) -{ - head_ = &head; - tail_ = &tail; - search_node_ = &head; -} - -Node* AdvancingFront::LocateNode(const double& x) -{ - Node* node = search_node_; - - if (x < node->value) { - while ((node = node->prev) != NULL) { - if (x >= node->value) { - search_node_ = node; - return node; - } - } - } else { - while ((node = node->next) != NULL) { - if (x < node->value) { - search_node_ = node->prev; - return node->prev; - } - } - } - return NULL; -} - -Node* AdvancingFront::FindSearchNode(const double& x) -{ - (void)x; // suppress compiler warnings "unused parameter 'x'" - // TODO: implement BST index - return search_node_; -} - -Node* AdvancingFront::LocatePoint(const Point* point) -{ - const double px = point->x; - Node* node = FindSearchNode(px); - const double nx = node->point->x; - - if (px == nx) { - if (point != node->point) { - // We might have two nodes with same x value for a short time - if (point == node->prev->point) { - node = node->prev; - } else if (point == node->next->point) { - node = node->next; - } else { - assert(0); - } - } - } else if (px < nx) { - while ((node = node->prev) != NULL) { - if (point == node->point) { - break; - } - } - } else { - while ((node = node->next) != NULL) { - if (point == node->point) - break; - } - } - if(node) search_node_ = node; - return node; -} - -AdvancingFront::~AdvancingFront() -{ -} - -} - diff --git a/polygon/poly2tri/sweep/advancing_front.h b/polygon/poly2tri/sweep/advancing_front.h deleted file mode 100644 index bab73d449c..0000000000 --- a/polygon/poly2tri/sweep/advancing_front.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ADVANCED_FRONT_H -#define ADVANCED_FRONT_H - -#include "../common/shapes.h" - -namespace p2t { - -struct Node; - -// Advancing front node -struct Node { - Point* point; - Triangle* triangle; - - Node* next; - Node* prev; - - double value; - - Node(Point& p) : point(&p), triangle(NULL), next(NULL), prev(NULL), value(p.x) - { - } - - Node(Point& p, Triangle& t) : point(&p), triangle(&t), next(NULL), prev(NULL), value(p.x) - { - } - -}; - -// Advancing front -class AdvancingFront { -public: - -AdvancingFront(Node& head, Node& tail); -// Destructor -~AdvancingFront(); - -Node* head(); -void set_head(Node* node); -Node* tail(); -void set_tail(Node* node); -Node* search(); -void set_search(Node* node); - -/// Locate insertion point along advancing front -Node* LocateNode(const double& x); - -Node* LocatePoint(const Point* point); - -private: - -Node* head_, *tail_, *search_node_; - -Node* FindSearchNode(const double& x); -}; - -inline Node* AdvancingFront::head() -{ - return head_; -} -inline void AdvancingFront::set_head(Node* node) -{ - head_ = node; -} - -inline Node* AdvancingFront::tail() -{ - return tail_; -} -inline void AdvancingFront::set_tail(Node* node) -{ - tail_ = node; -} - -inline Node* AdvancingFront::search() -{ - return search_node_; -} - -inline void AdvancingFront::set_search(Node* node) -{ - search_node_ = node; -} - -} - -#endif diff --git a/polygon/poly2tri/sweep/cdt.cc b/polygon/poly2tri/sweep/cdt.cc deleted file mode 100644 index d7838257c7..0000000000 --- a/polygon/poly2tri/sweep/cdt.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "cdt.h" - -namespace p2t { - -CDT::CDT(std::vector polyline) -{ - sweep_context_ = new SweepContext(polyline); - sweep_ = new Sweep; -} - -void CDT::AddHole(std::vector polyline) -{ - sweep_context_->AddHole(polyline); -} - -void CDT::AddPoint(Point* point) { - sweep_context_->AddPoint(point); -} - -void CDT::Triangulate() -{ - sweep_->Triangulate(*sweep_context_); -} - -std::vector CDT::GetTriangles() -{ - return sweep_context_->GetTriangles(); -} - -std::list CDT::GetMap() -{ - return sweep_context_->GetMap(); -} - -CDT::~CDT() -{ - delete sweep_context_; - delete sweep_; -} - -} - diff --git a/polygon/poly2tri/sweep/cdt.h b/polygon/poly2tri/sweep/cdt.h deleted file mode 100644 index 3e6f024086..0000000000 --- a/polygon/poly2tri/sweep/cdt.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CDT_H -#define CDT_H - -#include "advancing_front.h" -#include "sweep_context.h" -#include "sweep.h" - -/** - * - * @author Mason Green - * - */ - -namespace p2t { - -class CDT -{ -public: - - /** - * Constructor - add polyline with non repeating points - * - * @param polyline - */ - CDT(std::vector polyline); - - /** - * Destructor - clean up memory - */ - ~CDT(); - - /** - * Add a hole - * - * @param polyline - */ - void AddHole(std::vector polyline); - - /** - * Add a steiner point - * - * @param point - */ - void AddPoint(Point* point); - - /** - * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points - */ - void Triangulate(); - - /** - * Get CDT triangles - */ - std::vector GetTriangles(); - - /** - * Get triangle map - */ - std::list GetMap(); - - private: - - /** - * Internals - */ - - SweepContext* sweep_context_; - Sweep* sweep_; - -}; - -} - -#endif diff --git a/polygon/poly2tri/sweep/sweep.cc b/polygon/poly2tri/sweep/sweep.cc deleted file mode 100644 index 75e7adf9ee..0000000000 --- a/polygon/poly2tri/sweep/sweep.cc +++ /dev/null @@ -1,817 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include "sweep.h" -#include "sweep_context.h" -#include "advancing_front.h" -#include "../common/utils.h" - -namespace p2t { - -// Triangulate simple polygon with holes -void Sweep::Triangulate(SweepContext& tcx) -{ - tcx.InitTriangulation(); - tcx.CreateAdvancingFront(nodes_); - // Sweep points; build mesh - SweepPoints(tcx); - // Clean up - FinalizationPolygon(tcx); -} - -void Sweep::SweepPoints(SweepContext& tcx) -{ - for (int i = 1; i < tcx.point_count(); i++) { - Point& point = *tcx.GetPoint(i); - Node* node = &PointEvent(tcx, point); - for (unsigned int i = 0; i < point.edge_list.size(); i++) { - EdgeEvent(tcx, point.edge_list[i], node); - } - } -} - -void Sweep::FinalizationPolygon(SweepContext& tcx) -{ - // Get an Internal triangle to start with - Triangle* t = tcx.front()->head()->next->triangle; - Point* p = tcx.front()->head()->next->point; - while (!t->GetConstrainedEdgeCW(*p)) { - t = t->NeighborCCW(*p); - } - - // Collect interior triangles constrained by edges - tcx.MeshClean(*t); -} - -Node& Sweep::PointEvent(SweepContext& tcx, Point& point) -{ - Node& node = tcx.LocateNode(point); - Node& new_node = NewFrontTriangle(tcx, point, node); - - // Only need to check +epsilon since point never have smaller - // x value than node due to how we fetch nodes from the front - if (point.x <= node.point->x + EPSILON) { - Fill(tcx, node); - } - - //tcx.AddNode(new_node); - - FillAdvancingFront(tcx, new_node); - return new_node; -} - -void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node) -{ - tcx.edge_event.constrained_edge = edge; - tcx.edge_event.right = (edge->p->x > edge->q->x); - - if (IsEdgeSideOfTriangle(*node->triangle, *edge->p, *edge->q)) { - return; - } - - // For now we will do all needed filling - // TODO: integrate with flip process might give some better performance - // but for now this avoid the issue with cases that needs both flips and fills - FillEdgeEvent(tcx, edge, node); - EdgeEvent(tcx, *edge->p, *edge->q, node->triangle, *edge->q); -} - -void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) -{ - if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { - return; - } - - Point* p1 = triangle->PointCCW(point); - Orientation o1 = Orient2d(eq, *p1, ep); - if (o1 == COLLINEAR) { - if( triangle->Contains(&eq, p1)) { - triangle->MarkConstrainedEdge(&eq, p1 ); - // We are modifying the constraint maybe it would be better to - // not change the given constraint and just keep a variable for the new constraint - tcx.edge_event.constrained_edge->q = p1; - triangle = &triangle->NeighborAcross(point); - EdgeEvent( tcx, ep, *p1, triangle, *p1 ); - } else { - std::runtime_error("EdgeEvent - collinear points not supported"); - assert(0); - } - return; - } - - Point* p2 = triangle->PointCW(point); - Orientation o2 = Orient2d(eq, *p2, ep); - if (o2 == COLLINEAR) { - if( triangle->Contains(&eq, p2)) { - triangle->MarkConstrainedEdge(&eq, p2 ); - // We are modifying the constraint maybe it would be better to - // not change the given constraint and just keep a variable for the new constraint - tcx.edge_event.constrained_edge->q = p2; - triangle = &triangle->NeighborAcross(point); - EdgeEvent( tcx, ep, *p2, triangle, *p2 ); - } else { - std::runtime_error("EdgeEvent - collinear points not supported"); - assert(0); - } - return; - } - - if (o1 == o2) { - // Need to decide if we are rotating CW or CCW to get to a triangle - // that will cross edge - if (o1 == CW) { - triangle = triangle->NeighborCCW(point); - } else{ - triangle = triangle->NeighborCW(point); - } - EdgeEvent(tcx, ep, eq, triangle, point); - } else { - // This triangle crosses constraint so lets flippin start! - FlipEdgeEvent(tcx, ep, eq, triangle, point); - } -} - -bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq) -{ - int index = triangle.EdgeIndex(&ep, &eq); - - if (index != -1) { - triangle.MarkConstrainedEdge(index); - Triangle* t = triangle.GetNeighbor(index); - if (t) { - t->MarkConstrainedEdge(&ep, &eq); - } - return true; - } - return false; -} - -Node& Sweep::NewFrontTriangle(SweepContext& tcx, Point& point, Node& node) -{ - Triangle* triangle = new Triangle(point, *node.point, *node.next->point); - - triangle->MarkNeighbor(*node.triangle); - tcx.AddToMap(triangle); - - Node* new_node = new Node(point); - nodes_.push_back(new_node); - - new_node->next = node.next; - new_node->prev = &node; - node.next->prev = new_node; - node.next = new_node; - - if (!Legalize(tcx, *triangle)) { - tcx.MapTriangleToNodes(*triangle); - } - - return *new_node; -} - -void Sweep::Fill(SweepContext& tcx, Node& node) -{ - Triangle* triangle = new Triangle(*node.prev->point, *node.point, *node.next->point); - - // TODO: should copy the constrained_edge value from neighbor triangles - // for now constrained_edge values are copied during the legalize - triangle->MarkNeighbor(*node.prev->triangle); - triangle->MarkNeighbor(*node.triangle); - - tcx.AddToMap(triangle); - - // Update the advancing front - node.prev->next = node.next; - node.next->prev = node.prev; - - // If it was legalized the triangle has already been mapped - if (!Legalize(tcx, *triangle)) { - tcx.MapTriangleToNodes(*triangle); - } - -} - -void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) -{ - - // Fill right holes - Node* node = n.next; - - while (node->next) { - // if HoleAngle exceeds 90 degrees then break. - if (LargeHole_DontFill(node)) break; - Fill(tcx, *node); - node = node->next; - } - - // Fill left holes - node = n.prev; - - while (node->prev) { - // if HoleAngle exceeds 90 degrees then break. - if (LargeHole_DontFill(node)) break; - Fill(tcx, *node); - node = node->prev; - } - - // Fill right basins - if (n.next && n.next->next) { - double angle = BasinAngle(n); - if (angle < PI_3div4) { - FillBasin(tcx, n); - } - } -} - -// True if HoleAngle exceeds 90 degrees. -bool Sweep::LargeHole_DontFill(Node* node) { - - Node* nextNode = node->next; - Node* prevNode = node->prev; - if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point)) - return false; - - // Check additional points on front. - Node* next2Node = nextNode->next; - // "..Plus.." because only want angles on same side as point being added. - if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) - return false; - - Node* prev2Node = prevNode->prev; - // "..Plus.." because only want angles on same side as point being added. - if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) - return false; - - return true; -} - -bool Sweep::AngleExceeds90Degrees(Point* origin, Point* pa, Point* pb) { - double angle = Angle(*origin, *pa, *pb); - bool exceeds90Degrees = ((angle > PI_div2) || (angle < -PI_div2)); - return exceeds90Degrees; -} - -bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(Point* origin, Point* pa, Point* pb) { - double angle = Angle(*origin, *pa, *pb); - bool exceedsPlus90DegreesOrIsNegative = (angle > PI_div2) || (angle < 0); - return exceedsPlus90DegreesOrIsNegative; -} - -double Sweep::Angle(Point& origin, Point& pa, Point& pb) { - /* Complex plane - * ab = cosA +i*sinA - * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) - * atan2(y,x) computes the principal value of the argument function - * applied to the complex number x+iy - * Where x = ax*bx + ay*by - * y = ax*by - ay*bx - */ - double px = origin.x; - double py = origin.y; - double ax = pa.x- px; - double ay = pa.y - py; - double bx = pb.x - px; - double by = pb.y - py; - double x = ax * by - ay * bx; - double y = ax * bx + ay * by; - double angle = atan2(x, y); - return angle; -} - -double Sweep::BasinAngle(Node& node) -{ - double ax = node.point->x - node.next->next->point->x; - double ay = node.point->y - node.next->next->point->y; - return atan2(ay, ax); -} - -double Sweep::HoleAngle(Node& node) -{ - /* Complex plane - * ab = cosA +i*sinA - * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) - * atan2(y,x) computes the principal value of the argument function - * applied to the complex number x+iy - * Where x = ax*bx + ay*by - * y = ax*by - ay*bx - */ - double ax = node.next->point->x - node.point->x; - double ay = node.next->point->y - node.point->y; - double bx = node.prev->point->x - node.point->x; - double by = node.prev->point->y - node.point->y; - return atan2(ax * by - ay * bx, ax * bx + ay * by); -} - -bool Sweep::Legalize(SweepContext& tcx, Triangle& t) -{ - // To legalize a triangle we start by finding if any of the three edges - // violate the Delaunay condition - for (int i = 0; i < 3; i++) { - if (t.delaunay_edge[i]) - continue; - - Triangle* ot = t.GetNeighbor(i); - - if (ot) { - Point* p = t.GetPoint(i); - Point* op = ot->OppositePoint(t, *p); - int oi = ot->Index(op); - - // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) - // then we should not try to legalize - if (ot->constrained_edge[oi] || ot->delaunay_edge[oi]) { - t.constrained_edge[i] = ot->constrained_edge[oi]; - continue; - } - - bool inside = Incircle(*p, *t.PointCCW(*p), *t.PointCW(*p), *op); - - if (inside) { - // Lets mark this shared edge as Delaunay - t.delaunay_edge[i] = true; - ot->delaunay_edge[oi] = true; - - // Lets rotate shared edge one vertex CW to legalize it - RotateTrianglePair(t, *p, *ot, *op); - - // We now got one valid Delaunay Edge shared by two triangles - // This gives us 4 new edges to check for Delaunay - - // Make sure that triangle to node mapping is done only one time for a specific triangle - bool not_legalized = !Legalize(tcx, t); - if (not_legalized) { - tcx.MapTriangleToNodes(t); - } - - not_legalized = !Legalize(tcx, *ot); - if (not_legalized) - tcx.MapTriangleToNodes(*ot); - - // Reset the Delaunay edges, since they only are valid Delaunay edges - // until we add a new triangle or point. - // XXX: need to think about this. Can these edges be tried after we - // return to previous recursive level? - t.delaunay_edge[i] = false; - ot->delaunay_edge[oi] = false; - - // If triangle have been legalized no need to check the other edges since - // the recursive legalization will handles those so we can end here. - return true; - } - } - } - return false; -} - -bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd) -{ - double adx = pa.x - pd.x; - double ady = pa.y - pd.y; - double bdx = pb.x - pd.x; - double bdy = pb.y - pd.y; - - double adxbdy = adx * bdy; - double bdxady = bdx * ady; - double oabd = adxbdy - bdxady; - - if (oabd <= 0) - return false; - - double cdx = pc.x - pd.x; - double cdy = pc.y - pd.y; - - double cdxady = cdx * ady; - double adxcdy = adx * cdy; - double ocad = cdxady - adxcdy; - - if (ocad <= 0) - return false; - - double bdxcdy = bdx * cdy; - double cdxbdy = cdx * bdy; - - double alift = adx * adx + ady * ady; - double blift = bdx * bdx + bdy * bdy; - double clift = cdx * cdx + cdy * cdy; - - double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; - - return det > 0; -} - -void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) -{ - Triangle* n1, *n2, *n3, *n4; - n1 = t.NeighborCCW(p); - n2 = t.NeighborCW(p); - n3 = ot.NeighborCCW(op); - n4 = ot.NeighborCW(op); - - bool ce1, ce2, ce3, ce4; - ce1 = t.GetConstrainedEdgeCCW(p); - ce2 = t.GetConstrainedEdgeCW(p); - ce3 = ot.GetConstrainedEdgeCCW(op); - ce4 = ot.GetConstrainedEdgeCW(op); - - bool de1, de2, de3, de4; - de1 = t.GetDelunayEdgeCCW(p); - de2 = t.GetDelunayEdgeCW(p); - de3 = ot.GetDelunayEdgeCCW(op); - de4 = ot.GetDelunayEdgeCW(op); - - t.Legalize(p, op); - ot.Legalize(op, p); - - // Remap delaunay_edge - ot.SetDelunayEdgeCCW(p, de1); - t.SetDelunayEdgeCW(p, de2); - t.SetDelunayEdgeCCW(op, de3); - ot.SetDelunayEdgeCW(op, de4); - - // Remap constrained_edge - ot.SetConstrainedEdgeCCW(p, ce1); - t.SetConstrainedEdgeCW(p, ce2); - t.SetConstrainedEdgeCCW(op, ce3); - ot.SetConstrainedEdgeCW(op, ce4); - - // Remap neighbors - // XXX: might optimize the markNeighbor by keeping track of - // what side should be assigned to what neighbor after the - // rotation. Now mark neighbor does lots of testing to find - // the right side. - t.ClearNeighbors(); - ot.ClearNeighbors(); - if (n1) ot.MarkNeighbor(*n1); - if (n2) t.MarkNeighbor(*n2); - if (n3) t.MarkNeighbor(*n3); - if (n4) ot.MarkNeighbor(*n4); - t.MarkNeighbor(ot); -} - -void Sweep::FillBasin(SweepContext& tcx, Node& node) -{ - if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { - tcx.basin.left_node = node.next->next; - } else { - tcx.basin.left_node = node.next; - } - - // Find the bottom and right node - tcx.basin.bottom_node = tcx.basin.left_node; - while (tcx.basin.bottom_node->next - && tcx.basin.bottom_node->point->y >= tcx.basin.bottom_node->next->point->y) { - tcx.basin.bottom_node = tcx.basin.bottom_node->next; - } - if (tcx.basin.bottom_node == tcx.basin.left_node) { - // No valid basin - return; - } - - tcx.basin.right_node = tcx.basin.bottom_node; - while (tcx.basin.right_node->next - && tcx.basin.right_node->point->y < tcx.basin.right_node->next->point->y) { - tcx.basin.right_node = tcx.basin.right_node->next; - } - if (tcx.basin.right_node == tcx.basin.bottom_node) { - // No valid basins - return; - } - - tcx.basin.width = tcx.basin.right_node->point->x - tcx.basin.left_node->point->x; - tcx.basin.left_highest = tcx.basin.left_node->point->y > tcx.basin.right_node->point->y; - - FillBasinReq(tcx, tcx.basin.bottom_node); -} - -void Sweep::FillBasinReq(SweepContext& tcx, Node* node) -{ - // if shallow stop filling - if (IsShallow(tcx, *node)) { - return; - } - - Fill(tcx, *node); - - if (node->prev == tcx.basin.left_node && node->next == tcx.basin.right_node) { - return; - } else if (node->prev == tcx.basin.left_node) { - Orientation o = Orient2d(*node->point, *node->next->point, *node->next->next->point); - if (o == CW) { - return; - } - node = node->next; - } else if (node->next == tcx.basin.right_node) { - Orientation o = Orient2d(*node->point, *node->prev->point, *node->prev->prev->point); - if (o == CCW) { - return; - } - node = node->prev; - } else { - // Continue with the neighbor node with lowest Y value - if (node->prev->point->y < node->next->point->y) { - node = node->prev; - } else { - node = node->next; - } - } - - FillBasinReq(tcx, node); -} - -bool Sweep::IsShallow(SweepContext& tcx, Node& node) -{ - double height; - - if (tcx.basin.left_highest) { - height = tcx.basin.left_node->point->y - node.point->y; - } else { - height = tcx.basin.right_node->point->y - node.point->y; - } - - // if shallow stop filling - if (tcx.basin.width > height) { - return true; - } - return false; -} - -void Sweep::FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) -{ - if (tcx.edge_event.right) { - FillRightAboveEdgeEvent(tcx, edge, node); - } else { - FillLeftAboveEdgeEvent(tcx, edge, node); - } -} - -void Sweep::FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) -{ - while (node->next->point->x < edge->p->x) { - // Check if next node is below the edge - if (Orient2d(*edge->q, *node->next->point, *edge->p) == CCW) { - FillRightBelowEdgeEvent(tcx, edge, *node); - } else { - node = node->next; - } - } -} - -void Sweep::FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) -{ - if (node.point->x < edge->p->x) { - if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { - // Concave - FillRightConcaveEdgeEvent(tcx, edge, node); - } else{ - // Convex - FillRightConvexEdgeEvent(tcx, edge, node); - // Retry this one - FillRightBelowEdgeEvent(tcx, edge, node); - } - } -} - -void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) -{ - Fill(tcx, *node.next); - if (node.next->point != edge->p) { - // Next above or below edge? - if (Orient2d(*edge->q, *node.next->point, *edge->p) == CCW) { - // Below - if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { - // Next is concave - FillRightConcaveEdgeEvent(tcx, edge, node); - } else { - // Next is convex - } - } - } - -} - -void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) -{ - // Next concave or convex? - if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) { - // Concave - FillRightConcaveEdgeEvent(tcx, edge, *node.next); - } else{ - // Convex - // Next above or below edge? - if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) { - // Below - FillRightConvexEdgeEvent(tcx, edge, *node.next); - } else{ - // Above - } - } -} - -void Sweep::FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) -{ - while (node->prev->point->x > edge->p->x) { - // Check if next node is below the edge - if (Orient2d(*edge->q, *node->prev->point, *edge->p) == CW) { - FillLeftBelowEdgeEvent(tcx, edge, *node); - } else { - node = node->prev; - } - } -} - -void Sweep::FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) -{ - if (node.point->x > edge->p->x) { - if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { - // Concave - FillLeftConcaveEdgeEvent(tcx, edge, node); - } else { - // Convex - FillLeftConvexEdgeEvent(tcx, edge, node); - // Retry this one - FillLeftBelowEdgeEvent(tcx, edge, node); - } - } -} - -void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) -{ - // Next concave or convex? - if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) { - // Concave - FillLeftConcaveEdgeEvent(tcx, edge, *node.prev); - } else{ - // Convex - // Next above or below edge? - if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) { - // Below - FillLeftConvexEdgeEvent(tcx, edge, *node.prev); - } else{ - // Above - } - } -} - -void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) -{ - Fill(tcx, *node.prev); - if (node.prev->point != edge->p) { - // Next above or below edge? - if (Orient2d(*edge->q, *node.prev->point, *edge->p) == CW) { - // Below - if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { - // Next is concave - FillLeftConcaveEdgeEvent(tcx, edge, node); - } else{ - // Next is convex - } - } - } - -} - -void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p) -{ - Triangle& ot = t->NeighborAcross(p); - Point& op = *ot.OppositePoint(*t, p); - - if (&ot == NULL) { - // If we want to integrate the fillEdgeEvent do it here - // With current implementation we should never get here - //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); - assert(0); - } - - if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { - // Lets rotate shared edge one vertex CW - RotateTrianglePair(*t, p, ot, op); - tcx.MapTriangleToNodes(*t); - tcx.MapTriangleToNodes(ot); - - if (p == eq && op == ep) { - if (eq == *tcx.edge_event.constrained_edge->q && ep == *tcx.edge_event.constrained_edge->p) { - t->MarkConstrainedEdge(&ep, &eq); - ot.MarkConstrainedEdge(&ep, &eq); - Legalize(tcx, *t); - Legalize(tcx, ot); - } else { - // XXX: I think one of the triangles should be legalized here? - } - } else { - Orientation o = Orient2d(eq, op, ep); - t = &NextFlipTriangle(tcx, (int)o, *t, ot, p, op); - FlipEdgeEvent(tcx, ep, eq, t, p); - } - } else { - Point& newP = NextFlipPoint(ep, eq, ot, op); - FlipScanEdgeEvent(tcx, ep, eq, *t, ot, newP); - EdgeEvent(tcx, ep, eq, t, p); - } -} - -Triangle& Sweep::NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op) -{ - if (o == CCW) { - // ot is not crossing edge after flip - int edge_index = ot.EdgeIndex(&p, &op); - ot.delaunay_edge[edge_index] = true; - Legalize(tcx, ot); - ot.ClearDelunayEdges(); - return t; - } - - // t is not crossing edge after flip - int edge_index = t.EdgeIndex(&p, &op); - - t.delaunay_edge[edge_index] = true; - Legalize(tcx, t); - t.ClearDelunayEdges(); - return ot; -} - -Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) -{ - Orientation o2d = Orient2d(eq, op, ep); - if (o2d == CW) { - // Right - return *ot.PointCCW(op); - } else if (o2d == CCW) { - // Left - return *ot.PointCW(op); - } - - //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); - assert(0); - - // Never executed, due tu assert( 0 ). Just to avoid compil warning - return ep; -} - -void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, - Triangle& t, Point& p) -{ - Triangle& ot = t.NeighborAcross(p); - Point& op = *ot.OppositePoint(t, p); - - if (&t.NeighborAcross(p) == NULL) { - // If we want to integrate the fillEdgeEvent do it here - // With current implementation we should never get here - //throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); - assert(0); - } - - if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) { - // flip with new edge op->eq - FlipEdgeEvent(tcx, eq, op, &ot, op); - // TODO: Actually I just figured out that it should be possible to - // improve this by getting the next ot and op before the the above - // flip and continue the flipScanEdgeEvent here - // set new ot and op here and loop back to inScanArea test - // also need to set a new flip_triangle first - // Turns out at first glance that this is somewhat complicated - // so it will have to wait. - } else{ - Point& newP = NextFlipPoint(ep, eq, ot, op); - FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP); - } -} - -Sweep::~Sweep() { - - // Clean up memory - for( unsigned i = 0; i < nodes_.size(); i++ ) - { - delete nodes_[i]; - } - -} - -} - diff --git a/polygon/poly2tri/sweep/sweep.h b/polygon/poly2tri/sweep/sweep.h deleted file mode 100644 index 07822d1f65..0000000000 --- a/polygon/poly2tri/sweep/sweep.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Sweep-line, Constrained Delauney Triangulation (CDT) See: Domiter, V. and - * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', - * International Journal of Geographical Information Science - * - * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, thahlen@gmail.com - */ - -#ifndef SWEEP_H -#define SWEEP_H - -#include - -namespace p2t { - -class SweepContext; -struct Node; -struct Point; -struct Edge; -class Triangle; - -class Sweep -{ -public: - - /** - * Triangulate - * - * @param tcx - */ - void Triangulate(SweepContext& tcx); - - /** - * Destructor - clean up memory - */ - ~Sweep(); - -private: - - /** - * Start sweeping the Y-sorted point set from bottom to top - * - * @param tcx - */ - void SweepPoints(SweepContext& tcx); - - /** - * Find closes node to the left of the new point and - * create a new triangle. If needed new holes and basins - * will be filled to. - * - * @param tcx - * @param point - * @return - */ - Node& PointEvent(SweepContext& tcx, Point& point); - - /** - * - * - * @param tcx - * @param edge - * @param node - */ - void EdgeEvent(SweepContext& tcx, Edge* edge, Node* node); - - void EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point); - - /** - * Creates a new front triangle and legalize it - * - * @param tcx - * @param point - * @param node - * @return - */ - Node& NewFrontTriangle(SweepContext& tcx, Point& point, Node& node); - - /** - * Adds a triangle to the advancing front to fill a hole. - * @param tcx - * @param node - middle node, that is the bottom of the hole - */ - void Fill(SweepContext& tcx, Node& node); - - /** - * Returns true if triangle was legalized - */ - bool Legalize(SweepContext& tcx, Triangle& t); - - /** - * Requirement:
- * 1. a,b and c form a triangle.
- * 2. a and d is know to be on opposite side of bc
- *
-   *                a
-   *                +
-   *               / \
-   *              /   \
-   *            b/     \c
-   *            +-------+
-   *           /    d    \
-   *          /           \
-   * 
- * Fact: d has to be in area B to have a chance to be inside the circle formed by - * a,b and c
- * d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW
- * This preknowledge gives us a way to optimize the incircle test - * @param pa - triangle point, opposite d - * @param pb - triangle point - * @param pc - triangle point - * @param pd - point opposite a - * @return true if d is inside circle, false if on circle edge - */ - bool Incircle(Point& pa, Point& pb, Point& pc, Point& pd); - - /** - * Rotates a triangle pair one vertex CW - *
-   *       n2                    n2
-   *  P +-----+             P +-----+
-   *    | t  /|               |\  t |
-   *    |   / |               | \   |
-   *  n1|  /  |n3           n1|  \  |n3
-   *    | /   |    after CW   |   \ |
-   *    |/ oT |               | oT \|
-   *    +-----+ oP            +-----+
-   *       n4                    n4
-   * 
- */ - void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op); - - /** - * Fills holes in the Advancing Front - * - * - * @param tcx - * @param n - */ - void FillAdvancingFront(SweepContext& tcx, Node& n); - - // Decision-making about when to Fill hole. - // Contributed by ToolmakerSteve2 - bool LargeHole_DontFill(Node* node); - bool AngleExceeds90Degrees(Point* origin, Point* pa, Point* pb); - bool AngleExceedsPlus90DegreesOrIsNegative(Point* origin, Point* pa, Point* pb); - double Angle(Point& origin, Point& pa, Point& pb); - - /** - * - * @param node - middle node - * @return the angle between 3 front nodes - */ - double HoleAngle(Node& node); - - /** - * The basin angle is decided against the horizontal line [1,0] - */ - double BasinAngle(Node& node); - - /** - * Fills a basin that has formed on the Advancing Front to the right - * of given node.
- * First we decide a left,bottom and right node that forms the - * boundaries of the basin. Then we do a reqursive fill. - * - * @param tcx - * @param node - starting node, this or next node will be left node - */ - void FillBasin(SweepContext& tcx, Node& node); - - /** - * Recursive algorithm to fill a Basin with triangles - * - * @param tcx - * @param node - bottom_node - */ - void FillBasinReq(SweepContext& tcx, Node* node); - - bool IsShallow(SweepContext& tcx, Node& node); - - bool IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq); - - void FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); - - void FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); - - void FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); - - void FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); - - void FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); - - void FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); - - void FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); - - void FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); - - void FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); - - void FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p); - - /** - * After a flip we have two triangles and know that only one will still be - * intersecting the edge. So decide which to contiune with and legalize the other - * - * @param tcx - * @param o - should be the result of an orient2d( eq, op, ep ) - * @param t - triangle 1 - * @param ot - triangle 2 - * @param p - a point shared by both triangles - * @param op - another point shared by both triangles - * @return returns the triangle still intersecting the edge - */ - Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op); - - /** - * When we need to traverse from one triangle to the next we need - * the point in current triangle that is the opposite point to the next - * triangle. - * - * @param ep - * @param eq - * @param ot - * @param op - * @return - */ - Point& NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op); - - /** - * Scan part of the FlipScan algorithm
- * When a triangle pair isn't flippable we will scan for the next - * point that is inside the flip triangle scan area. When found - * we generate a new flipEdgeEvent - * - * @param tcx - * @param ep - last point on the edge we are traversing - * @param eq - first point on the edge we are traversing - * @param flipTriangle - the current triangle sharing the point eq with edge - * @param t - * @param p - */ - void FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, Triangle& t, Point& p); - - void FinalizationPolygon(SweepContext& tcx); - - std::vector nodes_; - -}; - -} - -#endif diff --git a/polygon/poly2tri/sweep/sweep_context.cc b/polygon/poly2tri/sweep/sweep_context.cc deleted file mode 100644 index 6c0b0447dd..0000000000 --- a/polygon/poly2tri/sweep/sweep_context.cc +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "sweep_context.h" -#include -#include "advancing_front.h" - -namespace p2t { - -SweepContext::SweepContext(std::vector polyline) : - front_(0), - head_(0), - tail_(0), - af_head_(0), - af_middle_(0), - af_tail_(0) -{ - basin = Basin(); - edge_event = EdgeEvent(); - - points_ = polyline; - - InitEdges(points_); -} - -void SweepContext::AddHole(std::vector polyline) -{ - InitEdges(polyline); - for(unsigned int i = 0; i < polyline.size(); i++) { - points_.push_back(polyline[i]); - } -} - -void SweepContext::AddPoint(Point* point) { - points_.push_back(point); -} - -std::vector SweepContext::GetTriangles() -{ - return triangles_; -} - -std::list SweepContext::GetMap() -{ - return map_; -} - -void SweepContext::InitTriangulation() -{ - double xmax(points_[0]->x), xmin(points_[0]->x); - double ymax(points_[0]->y), ymin(points_[0]->y); - - // Calculate bounds. - for (unsigned int i = 0; i < points_.size(); i++) { - Point& p = *points_[i]; - if (p.x > xmax) - xmax = p.x; - if (p.x < xmin) - xmin = p.x; - if (p.y > ymax) - ymax = p.y; - if (p.y < ymin) - ymin = p.y; - } - - double dx = kAlpha * (xmax - xmin); - double dy = kAlpha * (ymax - ymin); - head_ = new Point(xmax + dx, ymin - dy); - tail_ = new Point(xmin - dx, ymin - dy); - - // Sort points along y-axis - std::sort(points_.begin(), points_.end(), cmp); - -} - -void SweepContext::InitEdges(std::vector polyline) -{ - int num_points = polyline.size(); - for (int i = 0; i < num_points; i++) { - int j = i < num_points - 1 ? i + 1 : 0; - edge_list.push_back(new Edge(*polyline[i], *polyline[j])); - } -} - -Point* SweepContext::GetPoint(const int& index) -{ - return points_[index]; -} - -void SweepContext::AddToMap(Triangle* triangle) -{ - map_.push_back(triangle); -} - -Node& SweepContext::LocateNode(Point& point) -{ - // TODO implement search tree - return *front_->LocateNode(point.x); -} - -void SweepContext::CreateAdvancingFront(std::vector nodes) -{ - - (void) nodes; - // Initial triangle - Triangle* triangle = new Triangle(*points_[0], *tail_, *head_); - - map_.push_back(triangle); - - af_head_ = new Node(*triangle->GetPoint(1), *triangle); - af_middle_ = new Node(*triangle->GetPoint(0), *triangle); - af_tail_ = new Node(*triangle->GetPoint(2)); - front_ = new AdvancingFront(*af_head_, *af_tail_); - - // TODO: More intuitive if head is middles next and not previous? - // so swap head and tail - af_head_->next = af_middle_; - af_middle_->next = af_tail_; - af_middle_->prev = af_head_; - af_tail_->prev = af_middle_; -} - -void SweepContext::RemoveNode(Node* node) -{ - delete node; -} - -void SweepContext::MapTriangleToNodes(Triangle& t) -{ - for (int i = 0; i < 3; i++) { - if (!t.GetNeighbor(i)) { - Node* n = front_->LocatePoint(t.PointCW(*t.GetPoint(i))); - if (n) - n->triangle = &t; - } - } -} - -void SweepContext::RemoveFromMap(Triangle* triangle) -{ - map_.remove(triangle); -} - -void SweepContext::MeshClean(Triangle& triangle) -{ - std::vector triangles; - triangles.push_back(&triangle); - - while(!triangles.empty()){ - Triangle *t = triangles.back(); - triangles.pop_back(); - - if (t != NULL && !t->IsInterior()) { - t->IsInterior(true); - triangles_.push_back(t); - for (int i = 0; i < 3; i++) { - if (!t->constrained_edge[i]) - triangles.push_back(t->GetNeighbor(i)); - } - } - } -} - -SweepContext::~SweepContext() -{ - - // Clean up memory - - delete head_; - delete tail_; - delete front_; - delete af_head_; - delete af_middle_; - delete af_tail_; - - typedef std::list type_list; - - for(type_list::iterator iter = map_.begin(); iter != map_.end(); ++iter) { - Triangle* ptr = *iter; - delete ptr; - } - - for(unsigned int i = 0; i < edge_list.size(); i++) { - delete edge_list[i]; - } - -} - -} diff --git a/polygon/poly2tri/sweep/sweep_context.h b/polygon/poly2tri/sweep/sweep_context.h deleted file mode 100644 index 1010c0e8a8..0000000000 --- a/polygon/poly2tri/sweep/sweep_context.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SWEEP_CONTEXT_H -#define SWEEP_CONTEXT_H - -#include -#include -#include - -namespace p2t { - -// Inital triangle factor, seed triangle will extend 30% of -// PointSet width to both left and right. -const double kAlpha = 0.3; - -struct Point; -class Triangle; -struct Node; -struct Edge; -class AdvancingFront; - -class SweepContext { -public: - -/// Constructor -SweepContext(std::vector polyline); -/// Destructor -~SweepContext(); - -void set_head(Point* p1); - -Point* head(); - -void set_tail(Point* p1); - -Point* tail(); - -int point_count(); - -Node& LocateNode(Point& point); - -void RemoveNode(Node* node); - -void CreateAdvancingFront(std::vector nodes); - -/// Try to map a node to all sides of this triangle that don't have a neighbor -void MapTriangleToNodes(Triangle& t); - -void AddToMap(Triangle* triangle); - -Point* GetPoint(const int& index); - -Point* GetPoints(); - -void RemoveFromMap(Triangle* triangle); - -void AddHole(std::vector polyline); - -void AddPoint(Point* point); - -AdvancingFront* front(); - -void MeshClean(Triangle& triangle); - -std::vector GetTriangles(); -std::list GetMap(); - -std::vector edge_list; - -struct Basin { - Node* left_node; - Node* bottom_node; - Node* right_node; - double width; - bool left_highest; - - Basin() : left_node(NULL), bottom_node(NULL), right_node(NULL), width(0.0), left_highest(false) - { - } - - void Clear() - { - left_node = NULL; - bottom_node = NULL; - right_node = NULL; - width = 0.0; - left_highest = false; - } -}; - -struct EdgeEvent { - Edge* constrained_edge; - bool right; - - EdgeEvent() : constrained_edge(NULL), right(false) - { - } -}; - -Basin basin; -EdgeEvent edge_event; - -private: - -friend class Sweep; - -std::vector triangles_; -std::list map_; -std::vector points_; - -// Advancing front -AdvancingFront* front_; -// head point used with advancing front -Point* head_; -// tail point used with advancing front -Point* tail_; - -Node *af_head_, *af_middle_, *af_tail_; - -void InitTriangulation(); -void InitEdges(std::vector polyline); - -}; - -inline AdvancingFront* SweepContext::front() -{ - return front_; -} - -inline int SweepContext::point_count() -{ - return points_.size(); -} - -inline void SweepContext::set_head(Point* p1) -{ - head_ = p1; -} - -inline Point* SweepContext::head() -{ - return head_; -} - -inline void SweepContext::set_tail(Point* p1) -{ - tail_ = p1; -} - -inline Point* SweepContext::tail() -{ - return tail_; -} - -} - -#endif diff --git a/polygon/polygons_defs.h b/polygon/polygons_defs.h deleted file mode 100644 index 82bccfab77..0000000000 --- a/polygon/polygons_defs.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2012-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2012-2014 KiCad Developers, see CHANGELOG.TXT for contributors. - * - * 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 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* - * file polygons_defs.h - * definitions to use boost::polygon in KiCad. - */ - -#ifndef _POLYGONS_DEFS_H_ -#define _POLYGONS_DEFS_H_ - -#include - -// Define some types used here from boost::polygon -namespace bpl = boost::polygon; // bpl = boost polygon library -using namespace bpl::operators; // +, -, =, ... - -// Definitions needed by boost::polygon -typedef int coordinate_type; - -/** - * KI_POLYGON defines a single polygon ( boost::polygon_data type. - * When holes are created in a KPolygon, they are - * linked to main outline by overlapping segments, - * so there is always one polygon and one list of corners - * coordinates are int - */ -typedef bpl::polygon_data KI_POLYGON; - -/** - * KI_POLYGON_SET defines a set of single KI_POLYGON. - * A KI_POLYGON_SET is used to store a set of polygons - * when performing operations between 2 polygons - * or 2 sets of polygons - * The result of operations like and, xor... between 2 polygons - * is always stored in a KI_POLYGON_SET, because these operations - * can create many polygons - */ -typedef std::vector KI_POLYGON_SET; - -/** - * KI_POLY_POINT defines a point for boost::polygon. - * KI_POLY_POINT store x and y coordinates (int) - */ -typedef bpl::point_data KI_POLY_POINT; - -/** - * KI_POLYGON_WITH_HOLES defines a single polygon with holes - * When holes are created in a KI_POLYGON_WITH_HOLES, they are - * stored as separate single polygons, - * KI_POLYGON_WITH_HOLES store always one polygon for the external outline - * and one list of polygons (holes) which can be empty - */ -typedef bpl::polygon_with_holes_data KI_POLYGON_WITH_HOLES; - -/** - * KI_POLYGON_WITH_HOLES_SET defines a set of KI_POLYGON_WITH_HOLES. - * A KI_POLYGON_WITH_HOLES_SET is used to store a set of polygons with holes - * when performing operations between 2 polygons - * or 2 sets of polygons with holes - * The result of operations like and, xor... between 2 polygons with holes - * is always stored in a KI_POLYGON_WITH_HOLES_SET, because these operations - * can create many separate polygons with holespolygons - */ -typedef std::vector KI_POLYGON_WITH_HOLES_SET; - - -#endif // #ifndef _POLYGONS_DEFS_H_