46#ifndef __POLYGON_TRIANGULATION_H
47#define __POLYGON_TRIANGULATION_H
63#define TRIANGULATE_TRACE "triangulate"
89 if( !firstVertex || firstVertex->
prev == firstVertex->
next )
112 wxLogTrace(
TRIANGULATE_TRACE,
"Tesselation failed, logging remaining vertices" );
128 std::set<VERTEX*> seen;
129 wxLog::EnableLogging();
132 if( !p.next || p.next == &p || seen.find( &p ) != seen.end() )
141 if( aSeen && aSeen->count( aStart ) )
145 aSeen->insert( aStart );
149 wxString msg = wxString::Format(
"Vertices: %d,%d,",
static_cast<int>( aStart->
x ),
150 static_cast<int>( aStart->
y ) );
154 msg += wxString::Format(
"%d,%d,",
static_cast<int>( p->
x ),
static_cast<int>( p->
y ) );
161 }
while( p != aStart );
176 if( !aStart || aStart->
next == aStart->
prev )
211 }
while( p != aStart &&
next && p );
237 wxASSERT( aStart->
next && aStart->
prev );
241 while( p != aStart && p->
next && p->
prev )
311 wxLogTrace(
TRIANGULATE_TRACE,
"earcutList starting at %p for pass %d", aPoint, pass );
319 int internal_pass = 1;
321 while( aPoint->
prev != aPoint->
next )
326 if( aPoint->
isEar() )
350 if( *prev != *nextNext &&
intersects( prev, aPoint,
next, nextNext ) &&
355 "Local intersection detected. Merging minor triangle with area %f",
356 area( prev, aPoint, nextNext ) );
375 if( aPoint == stop && aPoint->
prev != aPoint->
next )
386 if( newPoint->
next == newPoint->
prev )
400 if( internal_pass < 4 )
443 double prev_sq_len = ( aPoint->
prev->
x - aPoint->
x ) * ( aPoint->
prev->
x - aPoint->
x ) +
444 ( aPoint->
prev->
y - aPoint->
y ) * ( aPoint->
prev->
y - aPoint->
y );
445 double next_sq_len = ( aPoint->
next->
x - aPoint->
x ) * ( aPoint->
next->
x - aPoint->
x ) +
446 ( aPoint->
next->
y - aPoint->
y ) * ( aPoint->
next->
y - aPoint->
y );
447 double opp_sq_len = ( aPoint->
next->
x - aPoint->
prev->
x ) * ( aPoint->
next->
x - aPoint->
prev->
x ) +
450 return ( prev_sq_len < min_area || next_sq_len < min_area || opp_sq_len < min_area );
460 struct VertexComparator {
461 bool operator()(
const std::pair<VERTEX*,double>& a,
const std::pair<VERTEX*,double>& b)
const {
462 return a.second > b.second;
466 std::set<std::pair<VERTEX*,double>, VertexComparator> longest;
471 double len = ( p->
x - p->
next->
x ) * ( p->
x - p->
next->
x ) +
473 longest.emplace( p, len );
477 }
while (p != aStart);
479 avg /= longest.size();
482 for(
auto it = longest.begin(); it != longest.end() && it->second > avg; ++it )
491 int divisions = avg / it->second + 2 + pass;
492 double step = 1.0 / divisions;
494 for(
int i = 1; i < divisions; i++ )
496 double x = a->
x * ( 1.0 - step * i ) + b->
x * ( step * i );
497 double y = a->
y * ( 1.0 - step * i ) + b->
y * ( step * i );
517 if( !start || !start->
next || start->
next == start->
prev
529 std::vector<VERTEX*> overlapPoints;
532 while ( z_pt->
prevZ && *z_pt->
prevZ == *origPoly )
535 overlapPoints.push_back( z_pt );
537 while( z_pt->
nextZ && *z_pt->
nextZ == *origPoly )
540 overlapPoints.push_back( z_pt );
543 if( overlapPoints.size() != 2 || overlapPoints[0]->next == overlapPoints[1]
544 || overlapPoints[0]->prev == overlapPoints[1] )
546 origPoly = origPoly->
next;
550 if( overlapPoints[0]->
area( overlapPoints[1] ) < 0 || overlapPoints[1]->
area( overlapPoints[0] ) < 0 )
553 origPoly = origPoly->
next;
557 wxLogTrace(
TRIANGULATE_TRACE,
"Splitting at overlap point %f, %f", overlapPoints[0]->x, overlapPoints[0]->y );
558 std::swap( overlapPoints[0]->
next, overlapPoints[1]->
next );
559 overlapPoints[0]->next->prev = overlapPoints[0];
560 overlapPoints[1]->next->prev = overlapPoints[1];
562 overlapPoints[0]->updateList();
563 overlapPoints[1]->updateList();
568 wxLogTrace(
TRIANGULATE_TRACE,
"%s at first overlap split", retval ?
"Success" :
"Failed" );
572 }
while ( origPoly != start );
582 while( marker != origPoly->
prev )
585 if( origPoly->
next && origPoly->
i != marker->
i &&
goodSplit( origPoly, marker ) )
598 marker = marker->
next;
601 origPoly = origPoly->
next;
602 }
while( origPoly != start );
625 bool pos_area = a->
area( b ) > 0 && b->
area( a ) > 0;
627 return no_intersect && local_split && ( same_dir || has_len ) && !a_on_edge && !b_on_edge && pos_area;
632 constexpr int sign(
double aVal )
const
634 return ( aVal > 0 ) - ( aVal < 0 );
642 return q->
x <= std::max( p->
x, r->
x ) &&
643 q->
x >= std::min( p->
x, r->
x ) &&
644 q->
y <= std::max( p->
y, r->
y ) &&
645 q->
y >= std::min( p->
y, r->
y );
655 int sign1 =
sign(
area( p1, q1, p2 ) );
656 int sign2 =
sign(
area( p1, q1, q2 ) );
657 int sign3 =
sign(
area( p2, q2, p1 ) );
658 int sign4 =
sign(
area( p2, q2, q1 ) );
660 if( sign1 != sign2 && sign3 != sign4 )
692 if( p->
i == a->
i || p->
i == b->
i || q->
i == a->
i || q->
i == b->
i )
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
SHAPE_POLY_SET::TRIANGULATED_POLYGON & m_result
bool intersects(const VERTEX *p1, const VERTEX *q1, const VERTEX *p2, const VERTEX *q2) const
Check for intersection between two segments, end points included.
bool splitPolygon(VERTEX *start)
If we cannot find an ear to slice in the current polygon list, we use this to split the polygon into ...
constexpr int sign(double aVal) const
void logVertices(VERTEX *aStart, std::set< VERTEX * > *aSeen)
VERTEX * insertTriVertex(const VECTOR2I &pt, VERTEX *last)
Create an entry in the vertices lookup and optionally inserts the newly created vertex into an existi...
bool goodSplit(const VERTEX *a, const VERTEX *b) const
Check if a segment joining two vertices lies fully inside the polygon.
VERTEX * simplifyList(VERTEX *aStart)
Simplify the line chain by removing points that are too close to each other.
POLYGON_TRIANGULATION(SHAPE_POLY_SET::TRIANGULATED_POLYGON &aResult)
constexpr bool overlapping(const VERTEX *p, const VERTEX *q, const VERTEX *r) const
If p, q, and r are collinear and r lies between p and q, then return true.
void logRemaining()
Outputs a list of vertices that have not yet been triangulated.
VERTEX * removeNullTriangles(VERTEX *aStart)
Iterate through the list to remove NULL triangles if they exist.
bool intersectsPolygon(const VERTEX *a, const VERTEX *b) const
Check whether the segment from vertex a -> vertex b crosses any of the segments of the polygon of whi...
bool isTooSmall(const VERTEX *aPoint) const
Check whether a given vertex is too small to matter.
bool earcutList(VERTEX *aPoint, int pass=0)
Walk through a circular linked list starting at aPoint.
size_t m_vertices_original_size
void subdividePolygon(VERTEX *aStart, int pass=0)
Inserts a new vertex halfway between each existing pair of vertices.
bool TesselatePolygon(const SHAPE_LINE_CHAIN &aPoly, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const std::vector< VECTOR2I > & CPoints() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void AddVertex(const VECTOR2I &aP)
const std::deque< VECTOR2I > & Vertices() const
const std::deque< TRI > & Triangles() const
size_t GetVertexCount() const
void AddTriangle(int a, int b, int c)
void SetTriangles(const std::deque< TRI > &aTriangles)
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
std::deque< VERTEX > m_vertices
bool middleInside(const VERTEX *a, const VERTEX *b) const
Check if the middle of the segment from a to b is inside the polygon.
VERTEX * createList(const SHAPE_LINE_CHAIN &points, VERTEX *aTail=nullptr, void *aUserData=nullptr)
Create a list of vertices from a line chain.
bool locallyInside(const VERTEX *a, const VERTEX *b) const
Check whether the segment from vertex a -> vertex b is inside the polygon around the immediate area o...
double area(const VERTEX *p, const VERTEX *q, const VERTEX *r) const
Return the twice the signed area of the triangle formed by vertices p, q, and r.
VERTEX * insertVertex(int aIndex, const VECTOR2I &pt, VERTEX *last, void *aUserData=nullptr)
Insert a vertex into the vertex set.
VERTEX * split(VERTEX *b)
Split the referenced polygon between the reference point and vertex b, assuming they are in the same ...
void updateList()
After inserting or changing nodes, this function should be called to remove duplicate vertices and en...
void remove()
Remove the node from the linked list and z-ordered linked list.
double area(const VERTEX *aEnd=nullptr) const
Returns the signed area of the polygon connected to the current vertex, optionally ending at a specif...
bool isEar(bool aMatchUserData=false) const
Check whether the given vertex is in the middle of an ear.
int m_TriangulateSimplificationLevel
The number of internal units that will be allowed to deflect from the base segment when creating a ne...
int m_TriangulateMinimumArea
The minimum area of a polygon that can be left over after triangulation and still consider the triang...
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
#define TRIANGULATE_TRACE
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D