pcbnew: Limit zone simplification
Commit73c229714
was a bit of a sledgehammer for the associated problem of degenerate points. This commit replaces that one by only performing additional simplification of the zone polygons on those polygons that fail our initial triangulation attempt. (cherry picked from commit3ebba6cbe1
)
This commit is contained in:
parent
4c409fbac9
commit
48b4a897af
|
@ -27,6 +27,25 @@
|
|||
#include <common.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <geometry/shape_circle.h>
|
||||
#include "clipper.hpp"
|
||||
|
||||
|
||||
ClipperLib::Path SHAPE_LINE_CHAIN::convertToClipper( bool aRequiredOrientation ) const
|
||||
{
|
||||
ClipperLib::Path c_path;
|
||||
|
||||
for( int i = 0; i < PointCount(); i++ )
|
||||
{
|
||||
const VECTOR2I& vertex = CPoint( i );
|
||||
c_path.push_back( ClipperLib::IntPoint( vertex.x, vertex.y ) );
|
||||
}
|
||||
|
||||
if( Orientation( c_path ) != aRequiredOrientation )
|
||||
ReversePath( c_path );
|
||||
|
||||
return c_path;
|
||||
}
|
||||
|
||||
|
||||
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
|
||||
{
|
||||
|
|
|
@ -455,62 +455,10 @@ int SHAPE_POLY_SET::AddHole( const SHAPE_LINE_CHAIN& aHole, int aOutline )
|
|||
}
|
||||
|
||||
|
||||
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( IntPoint( vertex.x, vertex.y ) );
|
||||
}
|
||||
|
||||
if( Orientation( c_path ) != aRequiredOrientation )
|
||||
ReversePath( c_path );
|
||||
|
||||
return c_path;
|
||||
}
|
||||
|
||||
|
||||
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 );
|
||||
|
||||
lc.SetClosed( true );
|
||||
|
||||
return lc;
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aOtherShape,
|
||||
POLYGON_MODE aFastMode )
|
||||
{
|
||||
Clipper c;
|
||||
|
||||
if( aFastMode == PM_STRICTLY_SIMPLE )
|
||||
c.StrictlySimple( true );
|
||||
|
||||
for( const POLYGON& poly : m_polys )
|
||||
{
|
||||
for( unsigned int i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true );
|
||||
}
|
||||
|
||||
for( 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 );
|
||||
}
|
||||
|
||||
PolyTree solution;
|
||||
|
||||
c.Execute( aType, solution, pftNonZero, pftNonZero );
|
||||
|
||||
importTree( &solution );
|
||||
booleanOp( aType, *this, aOtherShape, aFastMode );
|
||||
}
|
||||
|
||||
|
||||
|
@ -521,19 +469,18 @@ void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType,
|
|||
{
|
||||
Clipper c;
|
||||
|
||||
if( aFastMode == PM_STRICTLY_SIMPLE )
|
||||
c.StrictlySimple( true );
|
||||
c.StrictlySimple( aFastMode == PM_STRICTLY_SIMPLE );
|
||||
|
||||
for( const POLYGON& poly : aShape.m_polys )
|
||||
for( auto poly : aShape.m_polys )
|
||||
{
|
||||
for( unsigned int i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true );
|
||||
for( size_t i = 0 ; i < poly.size(); i++ )
|
||||
c.AddPath( poly[i].convertToClipper( i == 0 ), ptSubject, true );
|
||||
}
|
||||
|
||||
for( const POLYGON& poly : aOtherShape.m_polys )
|
||||
for( auto poly : aOtherShape.m_polys )
|
||||
{
|
||||
for( unsigned int i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true );
|
||||
for( size_t i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( poly[i].convertToClipper( i == 0 ), ptClip, true );
|
||||
}
|
||||
|
||||
PolyTree solution;
|
||||
|
@ -598,9 +545,8 @@ void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
|
|||
|
||||
for( 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 );
|
||||
for( size_t i = 0; i < poly.size(); i++ )
|
||||
c.AddPath( poly[i].convertToClipper( i == 0 ), jtRound, etClosedPolygon );
|
||||
}
|
||||
|
||||
PolyTree solution;
|
||||
|
@ -643,10 +589,10 @@ void SHAPE_POLY_SET::importTree( PolyTree* tree )
|
|||
{
|
||||
POLYGON paths;
|
||||
paths.reserve( n->Childs.size() + 1 );
|
||||
paths.push_back( convertFromClipper( n->Contour ) );
|
||||
paths.push_back( n->Contour );
|
||||
|
||||
for( unsigned int i = 0; i < n->Childs.size(); i++ )
|
||||
paths.push_back( convertFromClipper( n->Childs[i]->Contour ) );
|
||||
paths.push_back( n->Childs[i]->Contour );
|
||||
|
||||
m_polys.push_back( paths );
|
||||
}
|
||||
|
@ -1908,6 +1854,7 @@ void SHAPE_POLY_SET::CacheTriangulation()
|
|||
|
||||
SHAPE_POLY_SET tmpSet = *this;
|
||||
|
||||
if( tmpSet.HasHoles() )
|
||||
tmpSet.Fracture( PM_FAST );
|
||||
|
||||
m_triangulatedPolys.clear();
|
||||
|
|
|
@ -138,6 +138,7 @@ typedef long time_t;
|
|||
// Contains VECTOR2I
|
||||
%include math.i
|
||||
|
||||
%ignore SHAPE_LINE_CHAIN::convertFromClipper;
|
||||
#include <geometry/shape_line_chain.h>
|
||||
%include <geometry/shape_line_chain.h>
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include <vector>
|
||||
#include <math/box2.h>
|
||||
|
||||
#include "clipper.hpp"
|
||||
|
||||
class PolygonTriangulation
|
||||
{
|
||||
|
||||
|
@ -291,6 +293,27 @@ private:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function createList
|
||||
* Takes a Clipper path and converts it into a circular, doubly-linked
|
||||
* list for triangulation
|
||||
*/
|
||||
Vertex* createList( const ClipperLib::Path& aPath )
|
||||
{
|
||||
Vertex* tail = nullptr;
|
||||
|
||||
for( auto point : aPath )
|
||||
tail = insertVertex( VECTOR2I( point.X, point.Y ), tail );
|
||||
|
||||
if( tail && ( *tail == *tail->next ) )
|
||||
{
|
||||
tail->next->remove();
|
||||
}
|
||||
|
||||
return tail;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function createList
|
||||
* Takes the SHAPE_LINE_CHAIN and links each point into a
|
||||
|
@ -322,10 +345,10 @@ private:
|
|||
* there is an intersection (not technically allowed by KiCad, but could exist in an edited file),
|
||||
* we create a single triangle and remove both vertices before attempting to
|
||||
*/
|
||||
void earcutList( Vertex* aPoint, int pass = 0 )
|
||||
bool earcutList( Vertex* aPoint, int pass = 0 )
|
||||
{
|
||||
if( !aPoint )
|
||||
return;
|
||||
return true;
|
||||
|
||||
Vertex* stop = aPoint;
|
||||
Vertex* prev;
|
||||
|
@ -386,7 +409,7 @@ private:
|
|||
/**
|
||||
* At this point, our polygon should be fully tesselated.
|
||||
*/
|
||||
assert( aPoint->prev == aPoint->next );
|
||||
return( aPoint->prev == aPoint->next );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -585,10 +608,12 @@ private:
|
|||
return p;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
void TesselatePolygon( const SHAPE_LINE_CHAIN& aPoly )
|
||||
{
|
||||
ClipperLib::Clipper c;
|
||||
m_bbox = aPoly.BBox();
|
||||
|
||||
if( !m_bbox.GetWidth() || !m_bbox.GetHeight() )
|
||||
|
@ -599,7 +624,23 @@ public:
|
|||
return;
|
||||
|
||||
outerNode->updateList();
|
||||
if( !earcutList( outerNode ) )
|
||||
{
|
||||
m_vertices.clear();
|
||||
m_result.Clear();
|
||||
|
||||
ClipperLib::Paths simplified;
|
||||
ClipperLib::SimplifyPolygon( aPoly.convertToClipper( true ), simplified );
|
||||
|
||||
for( auto path : simplified )
|
||||
{
|
||||
outerNode = createList( path );
|
||||
if( !outerNode )
|
||||
return;
|
||||
|
||||
earcutList( outerNode );
|
||||
}
|
||||
}
|
||||
|
||||
m_vertices.clear();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <math/vector2d.h>
|
||||
#include <geometry/shape.h>
|
||||
#include <geometry/seg.h>
|
||||
#include "clipper.hpp"
|
||||
|
||||
/**
|
||||
* Class SHAPE_LINE_CHAIN
|
||||
|
@ -125,6 +126,16 @@ public:
|
|||
m_points[i] = *aV++;
|
||||
}
|
||||
|
||||
SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath ) :
|
||||
SHAPE( SH_LINE_CHAIN ),
|
||||
m_closed( true )
|
||||
{
|
||||
m_points.reserve( aPath.size() );
|
||||
|
||||
for( auto point : aPath )
|
||||
m_points.emplace_back( point.X, point.Y );
|
||||
}
|
||||
|
||||
~SHAPE_LINE_CHAIN()
|
||||
{}
|
||||
|
||||
|
@ -579,6 +590,19 @@ public:
|
|||
*/
|
||||
SHAPE_LINE_CHAIN& Simplify();
|
||||
|
||||
/**
|
||||
* Function convertFromClipper()
|
||||
* Appends the Clipper path to the current SHAPE_LINE_CHAIN
|
||||
*
|
||||
*/
|
||||
void convertFromClipper( const ClipperLib::Path& aPath );
|
||||
|
||||
/**
|
||||
* Creates a new Clipper path from the SHAPE_LINE_CHAIN in a given orientation
|
||||
*
|
||||
*/
|
||||
ClipperLib::Path convertToClipper( bool aRequiredOrientation ) const;
|
||||
|
||||
/**
|
||||
* Function NearestPoint()
|
||||
*
|
||||
|
|
|
@ -73,7 +73,11 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
int a, b, c;
|
||||
};
|
||||
|
||||
void Clear();
|
||||
void Clear()
|
||||
{
|
||||
m_vertices.clear();
|
||||
m_triangles.clear();
|
||||
}
|
||||
|
||||
void GetTriangle( int index, VECTOR2I& a, VECTOR2I& b, VECTOR2I& c ) const
|
||||
{
|
||||
|
@ -1116,9 +1120,6 @@ class SHAPE_POLY_SET : public SHAPE
|
|||
|
||||
bool pointInPolygon( const VECTOR2I& aP, const SHAPE_LINE_CHAIN& aPath ) const;
|
||||
|
||||
const ClipperLib::Path convertToClipper( const SHAPE_LINE_CHAIN& aPath, bool aRequiredOrientation );
|
||||
const SHAPE_LINE_CHAIN convertFromClipper( const ClipperLib::Path& aPath );
|
||||
|
||||
/**
|
||||
* containsSingle function
|
||||
* Checks whether the point aP is inside the aSubpolyIndex-th polygon of the polyset. If
|
||||
|
|
Loading…
Reference in New Issue