|
|
@ -56,10 +56,10 @@ |
|
|
|
#include <math/box2.h> |
|
|
|
#include <math/vector2d.h> |
|
|
|
|
|
|
|
class PolygonTriangulation |
|
|
|
class POLYGON_TRIANGULATION |
|
|
|
{ |
|
|
|
public: |
|
|
|
PolygonTriangulation( SHAPE_POLY_SET::TRIANGULATED_POLYGON& aResult ) : |
|
|
|
POLYGON_TRIANGULATION( SHAPE_POLY_SET::TRIANGULATED_POLYGON& aResult ) : |
|
|
|
m_result( aResult ) |
|
|
|
{}; |
|
|
|
|
|
|
@ -74,7 +74,8 @@ public: |
|
|
|
/// Place the polygon Vertices into a circular linked list |
|
|
|
/// and check for lists that have only 0, 1 or 2 elements and |
|
|
|
/// therefore cannot be polygons |
|
|
|
Vertex* firstVertex = createList( aPoly ); |
|
|
|
VERTEX* firstVertex = createList( aPoly ); |
|
|
|
|
|
|
|
if( !firstVertex || firstVertex->prev == firstVertex->next ) |
|
|
|
return false; |
|
|
|
|
|
|
@ -86,9 +87,9 @@ public: |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
struct Vertex |
|
|
|
struct VERTEX |
|
|
|
{ |
|
|
|
Vertex( size_t aIndex, double aX, double aY, PolygonTriangulation* aParent ) : |
|
|
|
VERTEX( size_t aIndex, double aX, double aY, POLYGON_TRIANGULATION* aParent ) : |
|
|
|
i( aIndex ), |
|
|
|
x( aX ), |
|
|
|
y( aY ), |
|
|
@ -96,14 +97,14 @@ private: |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
Vertex& operator=( const Vertex& ) = delete; |
|
|
|
Vertex& operator=( Vertex&& ) = delete; |
|
|
|
VERTEX& operator=( const VERTEX& ) = delete; |
|
|
|
VERTEX& operator=( VERTEX&& ) = delete; |
|
|
|
|
|
|
|
bool operator==( const Vertex& rhs ) const |
|
|
|
bool operator==( const VERTEX& rhs ) const |
|
|
|
{ |
|
|
|
return this->x == rhs.x && this->y == rhs.y; |
|
|
|
} |
|
|
|
bool operator!=( const Vertex& rhs ) const { return !( *this == rhs ); } |
|
|
|
bool operator!=( const VERTEX& rhs ) const { return !( *this == rhs ); } |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
@ -116,14 +117,14 @@ private: |
|
|
|
* @return the newly created vertex in the polygon that does not include the |
|
|
|
* reference vertex. |
|
|
|
*/ |
|
|
|
Vertex* split( Vertex* b ) |
|
|
|
VERTEX* split( VERTEX* b ) |
|
|
|
{ |
|
|
|
parent->m_vertices.emplace_back( i, x, y, parent ); |
|
|
|
Vertex* a2 = &parent->m_vertices.back(); |
|
|
|
VERTEX* a2 = &parent->m_vertices.back(); |
|
|
|
parent->m_vertices.emplace_back( b->i, b->x, b->y, parent ); |
|
|
|
Vertex* b2 = &parent->m_vertices.back(); |
|
|
|
Vertex* an = next; |
|
|
|
Vertex* bp = b->prev; |
|
|
|
VERTEX* b2 = &parent->m_vertices.back(); |
|
|
|
VERTEX* an = next; |
|
|
|
VERTEX* bp = b->prev; |
|
|
|
|
|
|
|
next = b; |
|
|
|
b->prev = this; |
|
|
@ -172,7 +173,7 @@ private: |
|
|
|
*/ |
|
|
|
void updateList() |
|
|
|
{ |
|
|
|
Vertex* p = next; |
|
|
|
VERTEX* p = next; |
|
|
|
|
|
|
|
while( p != this ) |
|
|
|
{ |
|
|
@ -201,14 +202,14 @@ private: |
|
|
|
*/ |
|
|
|
void zSort() |
|
|
|
{ |
|
|
|
std::deque<Vertex*> queue; |
|
|
|
std::deque<VERTEX*> queue; |
|
|
|
|
|
|
|
queue.push_back( this ); |
|
|
|
|
|
|
|
for( auto p = next; p && p != this; p = p->next ) |
|
|
|
queue.push_back( p ); |
|
|
|
|
|
|
|
std::sort( queue.begin(), queue.end(), []( const Vertex* a, const Vertex* b ) |
|
|
|
std::sort( queue.begin(), queue.end(), []( const VERTEX* a, const VERTEX* b ) |
|
|
|
{ |
|
|
|
if( a->z != b->z ) |
|
|
|
return a->z < b->z; |
|
|
@ -222,7 +223,7 @@ private: |
|
|
|
return a->i < b->i; |
|
|
|
} ); |
|
|
|
|
|
|
|
Vertex* prev_elem = nullptr; |
|
|
|
VERTEX* prev_elem = nullptr; |
|
|
|
|
|
|
|
for( auto elem : queue ) |
|
|
|
{ |
|
|
@ -240,7 +241,7 @@ private: |
|
|
|
/** |
|
|
|
* Check to see if triangle surrounds our current vertex |
|
|
|
*/ |
|
|
|
bool inTriangle( const Vertex& a, const Vertex& b, const Vertex& c ) |
|
|
|
bool inTriangle( const VERTEX& a, const VERTEX& b, const VERTEX& c ) |
|
|
|
{ |
|
|
|
return ( c.x - x ) * ( a.y - y ) - ( a.x - x ) * ( c.y - y ) >= 0 |
|
|
|
&& ( a.x - x ) * ( b.y - y ) - ( b.x - x ) * ( a.y - y ) >= 0 |
|
|
@ -250,18 +251,18 @@ private: |
|
|
|
const size_t i; |
|
|
|
const double x; |
|
|
|
const double y; |
|
|
|
PolygonTriangulation* parent; |
|
|
|
POLYGON_TRIANGULATION* parent; |
|
|
|
|
|
|
|
// previous and next vertices nodes in a polygon ring |
|
|
|
Vertex* prev = nullptr; |
|
|
|
Vertex* next = nullptr; |
|
|
|
VERTEX* prev = nullptr; |
|
|
|
VERTEX* next = nullptr; |
|
|
|
|
|
|
|
// z-order curve value |
|
|
|
int32_t z = 0; |
|
|
|
|
|
|
|
// previous and next nodes in z-order |
|
|
|
Vertex* prevZ = nullptr; |
|
|
|
Vertex* nextZ = nullptr; |
|
|
|
VERTEX* prevZ = nullptr; |
|
|
|
VERTEX* nextZ = nullptr; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
@ -294,10 +295,10 @@ private: |
|
|
|
* as the NULL triangles are inserted as Steiner points to improve the |
|
|
|
* triangulation regularity of polygons |
|
|
|
*/ |
|
|
|
Vertex* removeNullTriangles( Vertex* aStart ) |
|
|
|
VERTEX* removeNullTriangles( VERTEX* aStart ) |
|
|
|
{ |
|
|
|
Vertex* retval = nullptr; |
|
|
|
Vertex* p = aStart->next; |
|
|
|
VERTEX* retval = nullptr; |
|
|
|
VERTEX* p = aStart->next; |
|
|
|
|
|
|
|
while( p != aStart ) |
|
|
|
{ |
|
|
@ -328,9 +329,9 @@ private: |
|
|
|
/** |
|
|
|
* Take a Clipper path and converts it into a circular, doubly-linked list for triangulation. |
|
|
|
*/ |
|
|
|
Vertex* createList( const ClipperLib::Path& aPath ) |
|
|
|
VERTEX* createList( const ClipperLib::Path& aPath ) |
|
|
|
{ |
|
|
|
Vertex* tail = nullptr; |
|
|
|
VERTEX* tail = nullptr; |
|
|
|
double sum = 0.0; |
|
|
|
auto len = aPath.size(); |
|
|
|
|
|
|
@ -369,9 +370,9 @@ private: |
|
|
|
/** |
|
|
|
* Take a #SHAPE_LINE_CHAIN and links each point into a circular, doubly-linked list. |
|
|
|
*/ |
|
|
|
Vertex* createList( const SHAPE_LINE_CHAIN& points ) |
|
|
|
VERTEX* createList( const SHAPE_LINE_CHAIN& points ) |
|
|
|
{ |
|
|
|
Vertex* tail = nullptr; |
|
|
|
VERTEX* tail = nullptr; |
|
|
|
double sum = 0.0; |
|
|
|
|
|
|
|
// Check for winding order |
|
|
@ -411,14 +412,14 @@ private: |
|
|
|
* an edited file), we create a single triangle and remove both vertices before attempting |
|
|
|
* to. |
|
|
|
*/ |
|
|
|
bool earcutList( Vertex* aPoint, int pass = 0 ) |
|
|
|
bool earcutList( VERTEX* aPoint, int pass = 0 ) |
|
|
|
{ |
|
|
|
if( !aPoint ) |
|
|
|
return true; |
|
|
|
|
|
|
|
Vertex* stop = aPoint; |
|
|
|
Vertex* prev; |
|
|
|
Vertex* next; |
|
|
|
VERTEX* stop = aPoint; |
|
|
|
VERTEX* prev; |
|
|
|
VERTEX* next; |
|
|
|
|
|
|
|
while( aPoint->prev != aPoint->next ) |
|
|
|
{ |
|
|
@ -437,7 +438,7 @@ private: |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
Vertex* nextNext = next->next; |
|
|
|
VERTEX* nextNext = next->next; |
|
|
|
|
|
|
|
if( *prev != *nextNext && intersects( prev, aPoint, next, nextNext ) && |
|
|
|
locallyInside( prev, nextNext ) && |
|
|
@ -504,11 +505,11 @@ private: |
|
|
|
* |
|
|
|
* @return true if aEar is the apex point of a ear in the polygon. |
|
|
|
*/ |
|
|
|
bool isEar( Vertex* aEar ) const |
|
|
|
bool isEar( VERTEX* aEar ) const |
|
|
|
{ |
|
|
|
const Vertex* a = aEar->prev; |
|
|
|
const Vertex* b = aEar; |
|
|
|
const Vertex* c = aEar->next; |
|
|
|
const VERTEX* a = aEar->prev; |
|
|
|
const VERTEX* b = aEar; |
|
|
|
const VERTEX* c = aEar->next; |
|
|
|
|
|
|
|
// If the area >=0, then the three points for a concave sequence |
|
|
|
// with b as the reflex point |
|
|
@ -526,7 +527,7 @@ private: |
|
|
|
const int32_t maxZ = zOrder( maxTX, maxTY ); |
|
|
|
|
|
|
|
// first look for points inside the triangle in increasing z-order |
|
|
|
Vertex* p = aEar->nextZ; |
|
|
|
VERTEX* p = aEar->nextZ; |
|
|
|
|
|
|
|
while( p && p->z <= maxZ ) |
|
|
|
{ |
|
|
@ -560,20 +561,20 @@ private: |
|
|
|
* independently. This is assured to generate at least one new ear if the |
|
|
|
* split is successful |
|
|
|
*/ |
|
|
|
bool splitPolygon( Vertex* start ) |
|
|
|
bool splitPolygon( VERTEX* start ) |
|
|
|
{ |
|
|
|
Vertex* origPoly = start; |
|
|
|
VERTEX* origPoly = start; |
|
|
|
|
|
|
|
do |
|
|
|
{ |
|
|
|
Vertex* marker = origPoly->next->next; |
|
|
|
VERTEX* marker = origPoly->next->next; |
|
|
|
|
|
|
|
while( marker != origPoly->prev ) |
|
|
|
{ |
|
|
|
// Find a diagonal line that is wholly enclosed by the polygon interior |
|
|
|
if( origPoly->i != marker->i && goodSplit( origPoly, marker ) ) |
|
|
|
{ |
|
|
|
Vertex* newPoly = origPoly->split( marker ); |
|
|
|
VERTEX* newPoly = origPoly->split( marker ); |
|
|
|
|
|
|
|
origPoly->updateList(); |
|
|
|
newPoly->updateList(); |
|
|
@ -599,7 +600,7 @@ private: |
|
|
|
* and the midpoint. Finally, we check to split creates two new polygons, |
|
|
|
* each with positive area. |
|
|
|
*/ |
|
|
|
bool goodSplit( const Vertex* a, const Vertex* b ) const |
|
|
|
bool goodSplit( const VERTEX* a, const VERTEX* b ) const |
|
|
|
{ |
|
|
|
bool a_on_edge = ( a->nextZ && *a == *a->nextZ ) || ( a->prevZ && *a == *a->prevZ ); |
|
|
|
bool b_on_edge = ( b->nextZ && *b == *b->nextZ ) || ( b->prevZ && *b == *b->prevZ ); |
|
|
@ -616,7 +617,7 @@ private: |
|
|
|
/** |
|
|
|
* Return the twice the signed area of the triangle formed by vertices p, q, and r. |
|
|
|
*/ |
|
|
|
double area( const Vertex* p, const Vertex* q, const Vertex* r ) const |
|
|
|
double area( const VERTEX* p, const VERTEX* q, const VERTEX* r ) const |
|
|
|
{ |
|
|
|
return ( q->y - p->y ) * ( r->x - q->x ) - ( q->x - p->x ) * ( r->y - q->y ); |
|
|
|
} |
|
|
@ -630,7 +631,7 @@ private: |
|
|
|
/** |
|
|
|
* If p, q, and r are collinear and r lies between p and q, then return true. |
|
|
|
*/ |
|
|
|
constexpr bool overlapping( const Vertex* p, const Vertex* q, const Vertex* r ) const |
|
|
|
constexpr bool overlapping( const VERTEX* p, const VERTEX* q, const VERTEX* r ) const |
|
|
|
{ |
|
|
|
return q->x <= std::max( p->x, r->x ) && |
|
|
|
q->x >= std::min( p->x, r->x ) && |
|
|
@ -643,7 +644,7 @@ private: |
|
|
|
* |
|
|
|
* @return true if p1-p2 intersects q1-q2. |
|
|
|
*/ |
|
|
|
bool intersects( const Vertex* p1, const Vertex* q1, const Vertex* p2, const Vertex* q2 ) const |
|
|
|
bool intersects( const VERTEX* p1, const VERTEX* q1, const VERTEX* p2, const VERTEX* q2 ) const |
|
|
|
{ |
|
|
|
int sign1 = sign( area( p1, q1, p2 ) ); |
|
|
|
int sign2 = sign( area( p1, q1, q2 ) ); |
|
|
@ -675,9 +676,9 @@ private: |
|
|
|
* |
|
|
|
* @return true if the segment intersects the edge of the polygon. |
|
|
|
*/ |
|
|
|
bool intersectsPolygon( const Vertex* a, const Vertex* b ) const |
|
|
|
bool intersectsPolygon( const VERTEX* a, const VERTEX* b ) const |
|
|
|
{ |
|
|
|
const Vertex* p = a->next; |
|
|
|
const VERTEX* p = a->next; |
|
|
|
|
|
|
|
do |
|
|
|
{ |
|
|
@ -702,7 +703,7 @@ private: |
|
|
|
* |
|
|
|
* @return true if the segment from a->b is inside a's polygon next to vertex a. |
|
|
|
*/ |
|
|
|
bool locallyInside( const Vertex* a, const Vertex* b ) const |
|
|
|
bool locallyInside( const VERTEX* a, const VERTEX* b ) const |
|
|
|
{ |
|
|
|
if( area( a->prev, a, a->next ) < 0 ) |
|
|
|
return area( a, b, a->next ) >= 0 && area( a, a->prev, b ) >= 0; |
|
|
@ -713,9 +714,9 @@ private: |
|
|
|
/** |
|
|
|
* Check to see if the segment halfway point between a and b is inside the polygon |
|
|
|
*/ |
|
|
|
bool middleInside( const Vertex* a, const Vertex* b ) const |
|
|
|
bool middleInside( const VERTEX* a, const VERTEX* b ) const |
|
|
|
{ |
|
|
|
const Vertex* p = a; |
|
|
|
const VERTEX* p = a; |
|
|
|
bool inside = false; |
|
|
|
double px = ( a->x + b->x ) / 2; |
|
|
|
double py = ( a->y + b->y ) / 2; |
|
|
@ -738,12 +739,12 @@ private: |
|
|
|
* |
|
|
|
* @return a pointer to the newly created vertex. |
|
|
|
*/ |
|
|
|
Vertex* insertVertex( const VECTOR2I& pt, Vertex* last ) |
|
|
|
VERTEX* insertVertex( const VECTOR2I& pt, VERTEX* last ) |
|
|
|
{ |
|
|
|
m_result.AddVertex( pt ); |
|
|
|
m_vertices.emplace_back( m_result.GetVertexCount() - 1, pt.x, pt.y, this ); |
|
|
|
|
|
|
|
Vertex* p = &m_vertices.back(); |
|
|
|
VERTEX* p = &m_vertices.back(); |
|
|
|
|
|
|
|
if( !last ) |
|
|
|
{ |
|
|
@ -762,7 +763,7 @@ private: |
|
|
|
|
|
|
|
private: |
|
|
|
BOX2I m_bbox; |
|
|
|
std::deque<Vertex> m_vertices; |
|
|
|
std::deque<VERTEX> m_vertices; |
|
|
|
SHAPE_POLY_SET::TRIANGULATED_POLYGON& m_result; |
|
|
|
}; |
|
|
|
|
|
|
|