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>
extern bool useFastModeForPolygons;
/* returns the Z orientation parameter 1.0 or -1.0 for aLayer
* 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() )
continue;
bufferPolys.Fracture();
bufferPolys.Simplify( useFastModeForPolygons );
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( layer );
int zpos = GetPrm3DVisu().GetLayerZcoordBIU( layer );

View File

@ -63,6 +63,15 @@
#include <CImage.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
* Z orientation is 1.0 for all layers but "back" layers:
* 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() )
{
currLayerHoles.Append(allLayerHoles);
currLayerHoles.Simplify();
bufferPolys.BooleanSubtract( currLayerHoles );
currLayerHoles.Simplify( useFastModeForPolygons );
bufferPolys.BooleanSubtract( currLayerHoles, useFastModeForPolygons );
}
else
bufferPolys.BooleanSubtract( allLayerHoles );
bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
int thickness = GetPrm3DVisu().GetLayerObjectThicknessBIU( 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;
board_thickness -= copper_thickness + epsilon;
bufferPcbOutlines.BooleanSubtract( allLayerHoles );
bufferPcbOutlines.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
if( !bufferPcbOutlines.IsEmpty() )
{
@ -574,15 +583,15 @@ void EDA_3D_CANVAS::buildTechLayers3DView( REPORTER* aErrorMessages, REPORTER* a
bufferPolys = bufferPcbOutlines;
cuts.Append(allLayerHoles);
cuts.Simplify();
cuts.Simplify( useFastModeForPolygons );
bufferPolys.BooleanSubtract( cuts );
bufferPolys.BooleanSubtract( cuts, useFastModeForPolygons );
}
// Remove holes from Solder paste layers and silkscreen
else if( layer == B_Paste || layer == F_Paste
|| layer == B_SilkS || layer == F_SilkS )
{
bufferPolys.BooleanSubtract( allLayerHoles );
bufferPolys.BooleanSubtract( allLayerHoles, useFastModeForPolygons );
}
int thickness = 0;

View File

@ -208,11 +208,13 @@ const SHAPE_LINE_CHAIN SHAPE_POLY_SET::convertFromClipper( const Path& aPath )
#include <common.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;
c.StrictlySimple( true );
if( !aFastMode )
c.StrictlySimple( true );
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 );
}
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++ )
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;
c.Execute( type, solution, pftNonZero, pftNonZero );
c.Execute( aType, solution, pftNonZero, pftNonZero );
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 )
{
@ -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;
booleanOp( ctUnion, empty );
booleanOp( ctUnion, empty, aFastMode );
}

View File

@ -54,68 +54,69 @@ class SHAPE_POLY_SET : public SHAPE
* Base class for iterating over all vertices in a given SHAPE_POLY_SET
*/
template <class T>
class ITERATOR_TEMPLATE {
public:
class ITERATOR_TEMPLATE
{
public:
bool IsEndContour() const
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() )
{
return m_currentVertex + 1 == m_poly->CPolygon( m_currentOutline )[0].PointCount();
m_currentVertex = 0;
m_currentOutline++;
}
}
bool IsLastContour() const
{
return m_currentOutline == m_lastOutline;
}
void operator++( int dummy )
{
Advance();
}
operator bool() const
{
return m_currentOutline <= m_lastOutline;
}
void operator++()
{
Advance();
}
void Advance()
{
m_currentVertex ++;
T& Get()
{
return m_poly->Polygon( m_currentOutline )[0].Point( m_currentVertex );
}
if( m_currentVertex >= m_poly->CPolygon( m_currentOutline )[0].PointCount() )
{
m_currentVertex = 0;
m_currentOutline++;
}
}
T& operator*()
{
return Get();
}
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();
}
T* operator->()
{
return &Get();
}
private:
friend class SHAPE_POLY_SET;
private:
friend class SHAPE_POLY_SET;
SHAPE_POLY_SET* m_poly;
int m_currentOutline;
int m_lastOutline;
int m_currentVertex;
SHAPE_POLY_SET* m_poly;
int m_currentOutline;
int m_lastOutline;
int m_currentVertex;
};
typedef ITERATOR_TEMPLATE<VECTOR2I> ITERATOR;
@ -245,17 +246,21 @@ class SHAPE_POLY_SET : public SHAPE
///> 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
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.
void Inflate( int aFactor, int aCircleSegmentsCount );
///> Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the outer ring
///> 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
void Unfracture();
@ -264,7 +269,8 @@ class SHAPE_POLY_SET : public SHAPE
bool HasHoles() const;
///> 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()
const std::string Format() const;
@ -316,7 +322,20 @@ class SHAPE_POLY_SET : public SHAPE
void fractureSingle( POLYGON& paths );
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;