Polygon boolean operations on SHAPE_POLY_SET: Add a parameter (aFastMode) to speed up calculations. By default, the transforms use an option to create stricly simple polygons.

In 3D viewer, this option can take a *very long* calculation time (minutes instead of seconds, or hangs) and they are now using aFastMode = true to do polygon calculations, especially for zones inside zones belong to the same net but having different priority (which creates weak polygons).
aFastMode = false is the default for other calculations (zone filling) as before.
This commit is contained in:
jean-pierre charras 2015-08-16 14:07:58 +02:00
parent cc2fe47c95
commit c63f6aa3c5
4 changed files with 108 additions and 77 deletions

View File

@ -61,6 +61,7 @@
#include <reporter.h> #include <reporter.h>
extern bool useFastModeForPolygons;
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer /* returns the Z orientation parameter 1.0 or -1.0 for aLayer
* Z orientation is 1.0 for all layers but "back" layers: * Z orientation is 1.0 for all layers but "back" layers:
@ -702,7 +703,7 @@ void EDA_3D_CANVAS::buildBoard3DAuxLayers( REPORTER* aErrorMessages, REPORTER* a
if( bufferPolys.IsEmpty() ) if( bufferPolys.IsEmpty() )
continue; continue;
bufferPolys.Fracture(); bufferPolys.Simplify( useFastModeForPolygons );
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer ); int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer ); int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );

View File

@ -63,6 +63,15 @@
#include <CImage.h> #include <CImage.h>
#include <reporter.h> #include <reporter.h>
// An option for all operations on polygons:
// when useFastModeForPolygons = true, calculations can be *a lot* faster.
// but created polygons can be not stricty simple (can share edges)
// Although stricty simple are better for glu tesselation functions, I do not see
// any issue when allowing not stricty simple polygons.
// But I see *very* long calculations when setting useFastMode to false.
// So, be careful if changing thie option
bool useFastModeForPolygons = true;
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer /* returns the Z orientation parameter 1.0 or -1.0 for aLayer
* Z orientation is 1.0 for all layers but "back" layers: * Z orientation is 1.0 for all layers but "back" layers:
* B_Cu , B_Adhes, B_Paste ), B_SilkS * B_Cu , B_Adhes, B_Paste ), B_SilkS
@ -139,7 +148,7 @@ void EDA_3D_CANVAS::buildBoardThroughHolesPolygonList( SHAPE_POLY_SET& allBoardH
} }
} }
allBoardHoles.Simplify(); allBoardHoles.Simplify( useFastModeForPolygons );
} }
@ -314,11 +323,11 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
if( currLayerHoles.OutlineCount() ) if( currLayerHoles.OutlineCount() )
{ {
currLayerHoles.Append(allLayerHoles); currLayerHoles.Append(allLayerHoles);
currLayerHoles.Simplify(); currLayerHoles.Simplify( useFastModeForPolygons );
bufferPolys.BooleanSubtract( currLayerHoles ); bufferPolys.BooleanSubtract( currLayerHoles, useFastModeForPolygons );
} }
else else
bufferPolys.BooleanSubtract( allLayerHoles ); bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer ); int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer ); int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );
@ -414,7 +423,7 @@ void EDA_3D_CANVAS::buildBoard3DView( GLuint aBoardList, GLuint aBodyOnlyList,
zpos += (copper_thickness + epsilon) / 2.0f; zpos += (copper_thickness + epsilon) / 2.0f;
board_thickness -= copper_thickness + epsilon; board_thickness -= copper_thickness + epsilon;
bufferPcbOutlines.BooleanSubtract( allLayerHoles ); bufferPcbOutlines.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
if( !bufferPcbOutlines.IsEmpty() ) if( !bufferPcbOutlines.IsEmpty() )
{ {
@ -574,15 +583,15 @@ void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* a
bufferPolys = bufferPcbOutlines; bufferPolys = bufferPcbOutlines;
cuts.Append(allLayerHoles); cuts.Append(allLayerHoles);
cuts.Simplify(); cuts.Simplify( useFastModeForPolygons );
bufferPolys.BooleanSubtract( cuts ); bufferPolys.BooleanSubtract( cuts, useFastModeForPolygons );
} }
// Remove holes from Solder paste layers and silkscreen // Remove holes from Solder paste layers and silkscreen
else if( layer == B_Paste || layer == F_Paste else if( layer == B_Paste || layer == F_Paste
|| layer == B_SilkS || layer == F_SilkS ) || layer == B_SilkS || layer == F_SilkS )
{ {
bufferPolys.BooleanSubtract( allLayerHoles ); bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
} }
int thickness = 0; int thickness = 0;

View File

@ -208,10 +208,12 @@ const SHAPE_LINE_CHAIN SHAPE_POLY_SET::convertFromClipper( const Path& aPath )
#include <common.h> #include <common.h>
#include <wx/wx.h> #include <wx/wx.h>
void SHAPE_POLY_SET::booleanOp( ClipType type, const SHAPE_POLY_SET& b ) void SHAPE_POLY_SET::booleanOp( ClipType aType, const SHAPE_POLY_SET& aOtherShape,
bool aFastMode )
{ {
Clipper c; Clipper c;
if( !aFastMode )
c.StrictlySimple( true ); c.StrictlySimple( true );
BOOST_FOREACH( const POLYGON& poly, m_polys ) BOOST_FOREACH( const POLYGON& poly, m_polys )
@ -220,7 +222,7 @@ void SHAPE_POLY_SET::booleanOp( ClipType type, const SHAPE_POLY_SET& b )
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true ); c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true );
} }
BOOST_FOREACH( const POLYGON& poly, b.m_polys ) BOOST_FOREACH( const POLYGON& poly, aOtherShape.m_polys )
{ {
for( unsigned int i = 0; i < poly.size(); i++ ) for( unsigned int i = 0; i < poly.size(); i++ )
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true ); c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true );
@ -228,21 +230,21 @@ void SHAPE_POLY_SET::booleanOp( ClipType type, const SHAPE_POLY_SET& b )
PolyTree solution; PolyTree solution;
c.Execute( type, solution, pftNonZero, pftNonZero ); c.Execute( aType, solution, pftNonZero, pftNonZero );
importTree( &solution ); importTree( &solution );
} }
void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& b ) void SHAPE_POLY_SET::BooleanAdd( const SHAPE_POLY_SET& b, bool aFastMode )
{ {
booleanOp( ctUnion, b ); booleanOp( ctUnion, b, aFastMode );
} }
void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& b ) void SHAPE_POLY_SET::BooleanSubtract( const SHAPE_POLY_SET& b, bool aFastMode )
{ {
booleanOp( ctDifference, b ); booleanOp( ctDifference, b, aFastMode );
} }
@ -496,9 +498,9 @@ void SHAPE_POLY_SET::fractureSingle( POLYGON& paths )
} }
void SHAPE_POLY_SET::Fracture() void SHAPE_POLY_SET::Fracture( bool aFastMode )
{ {
Simplify(); // remove overlapping holes/degeneracy Simplify( aFastMode ); // remove overlapping holes/degeneracy
BOOST_FOREACH( POLYGON& paths, m_polys ) BOOST_FOREACH( POLYGON& paths, m_polys )
{ {
@ -507,11 +509,11 @@ void SHAPE_POLY_SET::Fracture()
} }
void SHAPE_POLY_SET::Simplify() void SHAPE_POLY_SET::Simplify( bool aFastMode )
{ {
SHAPE_POLY_SET empty; SHAPE_POLY_SET empty;
booleanOp( ctUnion, empty ); booleanOp( ctUnion, empty, aFastMode );
} }

View File

@ -54,7 +54,8 @@ class SHAPE_POLY_SET : public SHAPE
* Base class for iterating over all vertices in a given SHAPE_POLY_SET * Base class for iterating over all vertices in a given SHAPE_POLY_SET
*/ */
template <class T> template <class T>
class ITERATOR_TEMPLATE { class ITERATOR_TEMPLATE
{
public: public:
bool IsEndContour() const bool IsEndContour() const
@ -245,17 +246,21 @@ class SHAPE_POLY_SET : public SHAPE
///> Performs boolean polyset union ///> Performs boolean polyset union
void BooleanAdd( const SHAPE_POLY_SET& b ); ///> For aFastMode meaning, see function booleanOp
void BooleanAdd( const SHAPE_POLY_SET& b, bool aFastMode = false );
///> Performs boolean polyset difference ///> Performs boolean polyset difference
void BooleanSubtract( const SHAPE_POLY_SET& b ); ///> For aFastMode meaning, see function booleanOp
void BooleanSubtract( const SHAPE_POLY_SET& b, bool aFastMode = false );
///> Performs outline inflation/deflation, using round corners. ///> Performs outline inflation/deflation, using round corners.
void Inflate( int aFactor, int aCircleSegmentsCount ); void Inflate( int aFactor, int aCircleSegmentsCount );
///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the outer ring ///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the outer ring
///> to the inner holes ///> to the inner holes
void Fracture(); ///> For aFastMode meaning, see function booleanOp
void Fracture( bool aFastMode = false);
///> Converts a set of slitted polygons to a set of polygons with holes ///> Converts a set of slitted polygons to a set of polygons with holes
void Unfracture(); void Unfracture();
@ -264,7 +269,8 @@ class SHAPE_POLY_SET : public SHAPE
bool HasHoles() const; bool HasHoles() const;
///> Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) ///> Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
void Simplify(); ///> For aFastMode meaning, see function booleanOp
void Simplify( bool aFastMode = false);
/// @copydoc SHAPE::Format() /// @copydoc SHAPE::Format()
const std::string Format() const; const std::string Format() const;
@ -316,7 +322,20 @@ class SHAPE_POLY_SET : public SHAPE
void fractureSingle( POLYGON& paths ); void fractureSingle( POLYGON& paths );
void importTree( ClipperLib::PolyTree* tree ); void importTree( ClipperLib::PolyTree* tree );
void booleanOp( ClipperLib::ClipType type, const SHAPE_POLY_SET& b );
/** Function booleanOp
* this is the engine to execute all polygon boolean transforms
* (AND, OR, ... and polygon simplification (merging overlaping polygons)
* @param aType is the transform type ( see ClipperLib::ClipType )
* @param aOtherShape is the SHAPE_LINE_CHAIN to combine with me.
* @param aFastMode is an option to choos if the result is a weak polygon
* or a stricty simple polygon.
* if aFastMode is true (default) the result can be a weak polygon
* if aFastMode is true (default) the result is (theorically) a strictly
* simple polygon, but calculations can be really significantly time consuming
*/
void booleanOp( ClipperLib::ClipType aType,
const SHAPE_POLY_SET& aOtherShape, bool aFastMode = false );
bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath ) const; bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath ) const;