42#ifndef __POLYGON_TRIANGULATION_H
43#define __POLYGON_TRIANGULATION_H
63#if defined( __MINGW32__ )
64 #define TRIANGULATESIMPLIFICATIONLEVEL 50
65 #define TRIANGULATEMINIMUMAREA 1000
66 #define TRIANGULATEDELAUNAYREFINE true
68 #define TRIANGULATESIMPLIFICATIONLEVEL ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel
69 #define TRIANGULATEMINIMUMAREA ADVANCED_CFG::GetCfg().m_TriangulateMinimumArea
70 #define TRIANGULATEDELAUNAYREFINE ADVANCED_CFG::GetCfg().m_TriangulateDelaunayRefine
73#define TRIANGULATE_TRACE "triangulate"
98 if( aPolygon.empty() )
101 if( aPolygon.size() == 1 )
108 for(
size_t i = 1; i < aPolygon.size(); i++ )
109 m_bbox.Merge( aPolygon[i].BBox() );
126 if( !outerRing || outerRing->
prev == outerRing->
next )
129 std::vector<VERTEX*> holeRings;
131 for(
size_t i = 1; i < aPolygon.size(); i++ )
134 baseIndex += aPolygon[i].PointCount();
139 if( holeRing && holeRing->
prev != holeRing->
next )
140 holeRings.push_back( holeRing );
145 if( !holeRings.empty() )
157 outerRing = simplified;
162 outerRing = decimated;
168 wxLogTrace(
TRIANGULATE_TRACE,
"Tesselation with holes failed, logging remaining vertices" );
197 if( !firstVertex || firstVertex->
prev == firstVertex->
next )
205 firstVertex = simplified;
215 if( aHintData && aHintData->
Vertices().size() ==
m_result.GetVertexCount() )
223 firstVertex = decimated;
229 wxLogTrace(
TRIANGULATE_TRACE,
"Tesselation failed, logging remaining vertices" );
243 size_t aTargetLeaves )
const
246 std::vector<double> fractions;
252 fractions.reserve( partitions.size() );
270 std::array<SCANLINE_HIT, 2>& aHits )
const
274 for(
int ii = 0; ii < aPoly.
PointCount(); ++ii )
281 if( a.
x == b.
x || aCut <= std::min( a.
x, b.
x ) || aCut >= std::max( a.
x, b.
x ) )
287 double t =
static_cast<double>( aCut - a.
x ) /
static_cast<double>( b.
x - a.
x );
288 int y =
static_cast<int>( std::lround( a.
y + t * ( b.
y - a.
y ) ) );
289 aHits[count++] = { ii,
VECTOR2I( aCut, y ) };
293 if( a.
y == b.
y || aCut <= std::min( a.
y, b.
y ) || aCut >= std::max( a.
y, b.
y ) )
299 double t =
static_cast<double>( aCut - a.
y ) /
static_cast<double>( b.
y - a.
y );
300 int x =
static_cast<int>( std::lround( a.
x + t * ( b.
x - a.
x ) ) );
301 aHits[count++] = { ii,
VECTOR2I( x, aCut ) };
318 idx = ( idx + 1 ) % count;
320 }
while( idx != ( aEnd + 1 ) % count && guard <= count + 2 );
328 std::array<SHAPE_LINE_CHAIN, 2>& aChildren,
double& aAreaA,
329 double& aAreaB )
const
331 std::array<SCANLINE_HIT, 2> hits;
337 augmented.
Split( hits[0].point,
true );
338 augmented.
Split( hits[1].point,
true );
340 int idxA = augmented.
Find( hits[0].point );
341 int idxB = augmented.
Find( hits[1].point );
343 if( idxA < 0 || idxB < 0 || idxA == idxB )
349 if( aChildren[0].PointCount() < 3 || aChildren[1].PointCount() < 3 )
352 aAreaA =
std::abs( aChildren[0].Area() );
353 aAreaB =
std::abs( aChildren[1].Area() );
354 return aAreaA > 0.0 && aAreaB > 0.0;
358 std::array<SHAPE_LINE_CHAIN, 2>& aChildren )
const
368 [&](
bool aVertical ) ->
bool
370 const int low = ( aVertical ? bbox.
GetX() : bbox.
GetY() ) + 1;
376 double bestImbalance = std::numeric_limits<double>::infinity();
377 std::array<SHAPE_LINE_CHAIN, 2> bestChildren;
379 constexpr int kSamples = 15;
381 for(
int ii = 1; ii <= kSamples; ++ii )
383 int cut = low + ( ( high - low ) * ii ) / ( kSamples + 1 );
384 std::array<SHAPE_LINE_CHAIN, 2> candidate;
393 if( imbalance < bestImbalance )
395 bestImbalance = imbalance;
396 bestChildren = std::move( candidate );
400 if( !std::isfinite( bestImbalance ) || bestImbalance > 0.35 )
403 aChildren = std::move( bestChildren );
407 return tryAxis( verticalFirst ) || tryAxis( !verticalFirst );
411 size_t aTargetLeaves )
const
413 std::vector<SHAPE_LINE_CHAIN> leaves = { aPoly };
415 if( aTargetLeaves < 2 )
418 while( leaves.size() < aTargetLeaves )
421 double bestArea = 0.0;
423 for(
size_t ii = 0; ii < leaves.size(); ++ii )
427 if(
area > bestArea )
430 bestLeaf =
static_cast<int>( ii );
437 std::array<SHAPE_LINE_CHAIN, 2> children;
442 leaves[bestLeaf] = std::move( children[0] );
443 leaves.push_back( std::move( children[1] ) );
451 constexpr size_t kVerticesPerLeaf = 50000;
452 constexpr size_t kMaxLeaves = 8;
455 while( leaves < kMaxLeaves
456 &&
static_cast<size_t>( aPoly.
PointCount() ) / leaves > kVerticesPerLeaf )
469 std::set<VERTEX*> seen;
470 wxLog::EnableLogging();
473 if( !p.next || p.next == &p || seen.find( &p ) != seen.end() )
482 if( aSeen && aSeen->count( aStart ) )
486 aSeen->insert( aStart );
490 wxString msg = wxString::Format(
"Vertices: %d,%d,",
static_cast<int>( aStart->
x ),
491 static_cast<int>( aStart->
y ) );
495 msg += wxString::Format(
"%d,%d,",
static_cast<int>( p->
x ),
static_cast<int>( p->
y ) );
502 }
while( p != aStart );
517 if( !aStart || aStart->
next == aStart->
prev )
552 }
while( p != aStart &&
next && p );
574 if( !aStart || aStart->
next == aStart->
prev )
578 const double epsSq = eps * eps;
581 constexpr size_t kMaxRun = 256;
592 if( v->x > aStart->
x || ( v->x == aStart->
x && v->y > aStart->
y ) )
602 const double areaBudget = std::min(
std::abs( aStart->
area() ) * 2e-4, 2.5e8 );
603 double areaUsed = 0.0;
608 double dx = b->x - a->x;
609 double dy = b->y - a->y;
610 double vx = p->
x - a->x;
611 double vy = p->
y - a->y;
612 double lenSq = dx * dx + dy * dy;
613 double dot = dx * vx + dy * vy;
616 return vx * vx + vy * vy <= aEpsSq;
618 if( dot < 0.0 || dot > lenSq )
621 double cross = dx * vy - dy * vx;
623 return cross * cross <= aEpsSq * lenSq;
628 auto triangleIsEmpty =
635 if(
area( aA, aB, aC ) > 0 )
638 const double minTX = std::min( a->
x, std::min( aB->x, c->
x ) );
639 const double minTY = std::min( a->
y, std::min( aB->y, c->
y ) );
640 const double maxTX = std::max( a->
x, std::max( aB->x, c->
x ) );
641 const double maxTY = std::max( a->
y, std::max( aB->y, c->
y ) );
643 const uint32_t minZ =
zOrder( minTX, minTY );
644 const uint32_t maxZ =
zOrder( maxTX, maxTY );
648 if( p != aA && p != aC && p->
inTriangle( *a, *aB, *c ) )
654 if( p != aA && p != aC && p->
inTriangle( *a, *aB, *c ) )
661 std::vector<const VERTEX*> absorbed;
662 absorbed.reserve( kMaxRun );
672 while(
end != aStart && absorbed.size() < kMaxRun && ringSize - removed >= 4 )
680 if( !triangleIsEmpty(
anchor,
end, tryEnd ) )
690 bool ok = inBand(
end,
anchor, tryEnd, epsSq );
692 for(
const VERTEX* v : absorbed )
697 ok = inBand( v,
anchor, tryEnd, epsSq );
704 absorbed.push_back(
end );
711 }
while(
anchor != aStart );
736 wxASSERT( aStart->
next && aStart->
prev );
740 while( p != aStart && p->
next && p->
prev )
810 constexpr int kMaxRecursion = 64;
812 if( pass >= kMaxRecursion )
814 wxLogTrace(
TRIANGULATE_TRACE,
"earcutList recursion limit reached; aborting triangulation", pass );
818 wxLogTrace(
TRIANGULATE_TRACE,
"earcutList starting at %p for pass %d", aPoint, pass );
826 int internal_pass = 1;
827 constexpr int kEarLookahead = 2;
829 while( aPoint->
prev != aPoint->
next )
834 VERTEX* bestEar =
nullptr;
835 double bestScore = -1.0;
838 for(
VERTEX* candidate = aPoint; candidate && lookahead < kEarLookahead;
839 candidate = candidate->
next, ++lookahead )
841 if( !candidate->isEar() ||
isTooSmall( candidate ) )
844 const double score =
earScore( candidate->prev, candidate, candidate->next );
846 if( !bestEar || score > bestScore )
855 prev = bestEar->
prev;
868 if( *prev != *nextNext &&
intersects( prev, aPoint,
next, nextNext ) &&
873 "Local intersection detected. Merging minor triangle with area %f",
874 area( prev, aPoint, nextNext ) );
875 m_result.AddTriangle( prev->
i, aPoint->
i, nextNext->
i );
893 if( aPoint == stop && aPoint->
prev != aPoint->
next )
904 if( newPoint->
next == newPoint->
prev )
918 if( internal_pass < 4 )
961 double prev_sq_len = ( aPoint->
prev->
x - aPoint->
x ) * ( aPoint->
prev->
x - aPoint->
x ) +
962 ( aPoint->
prev->
y - aPoint->
y ) * ( aPoint->
prev->
y - aPoint->
y );
963 double next_sq_len = ( aPoint->
next->
x - aPoint->
x ) * ( aPoint->
next->
x - aPoint->
x ) +
964 ( aPoint->
next->
y - aPoint->
y ) * ( aPoint->
next->
y - aPoint->
y );
965 double opp_sq_len = ( aPoint->
next->
x - aPoint->
prev->
x ) * ( aPoint->
next->
x - aPoint->
prev->
x ) +
968 return ( prev_sq_len < min_area || next_sq_len < min_area || opp_sq_len < min_area );
973 const double ab_sq = ( a->
x - b->
x ) * ( a->
x - b->
x ) + ( a->
y - b->
y ) * ( a->
y - b->
y );
974 const double bc_sq = ( b->
x - c->
x ) * ( b->
x - c->
x ) + ( b->
y - c->
y ) * ( b->
y - c->
y );
975 const double ca_sq = ( c->
x - a->
x ) * ( c->
x - a->
x ) + ( c->
y - a->
y ) * ( c->
y - a->
y );
976 const double norm = ab_sq + bc_sq + ca_sq;
995 for(
int i = 0; i < aPoints.
PointCount(); i++ )
999 sum += ( ( p2.
x - p1.
x ) * ( p2.
y + p1.
y ) );
1002 bool isCW = sum > 0.0;
1003 bool needReverse = ( aWantCCW == isCW );
1005 auto addVertex = [&](
int i )
1019 for(
int i = aPoints.
PointCount() - 1; i >= 0; i-- )
1024 for(
int i = 0; i < aPoints.
PointCount(); i++ )
1031 if( tail && tail->
next != tail && ( *tail == *tail->
next ) )
1050 std::vector<HoleInfo> holes;
1051 holes.reserve( aHoleRings.size() );
1053 for(
VERTEX* hole : aHoleRings )
1060 if( p->
x < leftmost->
x || ( p->
x == leftmost->
x && p->
y < leftmost->
y ) )
1066 holes.push_back( { leftmost, leftmost->
x } );
1069 std::sort( holes.begin(), holes.end(),
1070 [](
const HoleInfo& a,
const HoleInfo& b ) { return a.leftX < b.leftX; } );
1072 for(
const HoleInfo& hi : holes )
1078 VERTEX* bridgeReverse = bridge->
split( hi.leftmost );
1085 hi.leftmost->x, hi.leftmost->y );
1110 if( *p == *p->
next )
1114 if( toRemove == aEnd )
1129 }
while( again || p != aEnd );
1142 double hx = aHole->
x;
1143 double hy = aHole->
y;
1144 double qx = -std::numeric_limits<double>::infinity();
1149 if( hy <= p->y && hy >= p->
next->
y && p->
next->
y != p->
y )
1151 double x = p->
x + ( hy - p->
y ) * ( p->
next->
x - p->
x )
1154 if( x <= hx && x > qx )
1163 if( hy == p->
next->
y )
1172 }
while( p != aOuterStart );
1184 double tanMin = std::numeric_limits<double>::infinity();
1190 if( hx >= p->
x && p->
x >= mx && hx != p->
x )
1195 inside =
triArea( hx, hy, mx, my, p->
x, p->
y ) >= 0
1196 &&
triArea( mx, my, qx, hy, p->
x, p->
y ) >= 0
1197 &&
triArea( qx, hy, hx, hy, p->
x, p->
y ) >= 0;
1199 inside =
triArea( qx, hy, mx, my, p->
x, p->
y ) >= 0
1200 &&
triArea( mx, my, hx, hy, p->
x, p->
y ) >= 0
1201 &&
triArea( hx, hy, qx, hy, p->
x, p->
y ) >= 0;
1205 double t =
std::abs( hy - p->
y ) / ( hx - p->
x );
1221 }
while( p != stop );
1229 static double triArea(
double ax,
double ay,
double bx,
double by,
1230 double cx,
double cy )
1232 return ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax );
1251 struct VertexComparator {
1252 bool operator()(
const std::pair<VERTEX*,double>& a,
const std::pair<VERTEX*,double>& b)
const {
1253 return a.second > b.second;
1257 std::set<std::pair<VERTEX*,double>, VertexComparator> longest;
1262 double len = ( p->
x - p->
next->
x ) * ( p->
x - p->
next->
x ) +
1264 longest.emplace( p, len );
1268 }
while (p != aStart);
1270 avg /= longest.size();
1273 constexpr double kSubdivideThresholdFactor = 1.1;
1274 const double subdivideThreshold = avg * kSubdivideThresholdFactor;
1276 for(
auto it = longest.begin(); it != longest.end() && it->second > subdivideThreshold;
1286 int divisions = avg / it->second + 2 + pass;
1287 double step = 1.0 / divisions;
1289 for(
int i = 1; i < divisions; i++ )
1291 double x = a->
x * ( 1.0 - step * i ) + b->
x * ( step * i );
1292 double y = a->
y * ( 1.0 - step * i ) + b->
y * ( step * i );
1309 VERTEX* origPoly = start;
1312 if( !start || !start->
next || start->
next == start->
prev
1324 std::vector<VERTEX*> overlapPoints;
1327 while ( z_pt->
prevZ && *z_pt->
prevZ == *origPoly )
1330 overlapPoints.push_back( z_pt );
1332 while( z_pt->
nextZ && *z_pt->
nextZ == *origPoly )
1335 overlapPoints.push_back( z_pt );
1338 if( overlapPoints.size() != 2 || overlapPoints[0]->next == overlapPoints[1]
1339 || overlapPoints[0]->prev == overlapPoints[1] )
1341 origPoly = origPoly->
next;
1345 if( overlapPoints[0]->
area( overlapPoints[1] ) < 0 || overlapPoints[1]->
area( overlapPoints[0] ) < 0 )
1348 origPoly = origPoly->
next;
1352 wxLogTrace(
TRIANGULATE_TRACE,
"Splitting at overlap point %f, %f", overlapPoints[0]->x, overlapPoints[0]->y );
1353 std::swap( overlapPoints[0]->
next, overlapPoints[1]->
next );
1354 overlapPoints[0]->next->prev = overlapPoints[0];
1355 overlapPoints[1]->next->prev = overlapPoints[1];
1357 overlapPoints[0]->updateList();
1358 overlapPoints[1]->updateList();
1361 bool retval =
earcutList( overlapPoints[0], aPass )
1364 wxLogTrace(
TRIANGULATE_TRACE,
"%s at first overlap split", retval ?
"Success" :
"Failed" );
1368 }
while ( origPoly != start );
1378 while( marker != origPoly->
prev )
1381 if( origPoly->
next && origPoly->
i != marker->
i &&
goodSplit( origPoly, marker ) )
1394 marker = marker->
next;
1397 origPoly = origPoly->
next;
1398 }
while( origPoly != start );
1421 bool pos_area = a->
area( b ) > 0 && b->
area( a ) > 0;
1423 return no_intersect && local_split && ( same_dir || has_len ) && !a_on_edge && !b_on_edge && pos_area;
1428 constexpr int sign(
double aVal )
const
1430 return ( aVal > 0 ) - ( aVal < 0 );
1438 return q->
x <= std::max( p->
x, r->
x ) &&
1439 q->
x >= std::min( p->
x, r->
x ) &&
1440 q->
y <= std::max( p->
y, r->
y ) &&
1441 q->
y >= std::min( p->
y, r->
y );
1451 int sign1 =
sign(
area( p1, q1, p2 ) );
1452 int sign2 =
sign(
area( p1, q1, q2 ) );
1453 int sign3 =
sign(
area( p2, q2, p1 ) );
1454 int sign4 =
sign(
area( p2, q2, q1 ) );
1456 if( sign1 != sign2 && sign3 != sign4 )
1488 if( p->
i == a->
i || p->
i == b->
i || q->
i == a->
i || q->
i == b->
i )
constexpr coord_type GetY() const
constexpr size_type GetWidth() const
constexpr coord_type GetX() const
constexpr size_type GetHeight() const
constexpr coord_type GetRight() const
constexpr coord_type GetBottom() const
SHAPE_POLY_SET::TRIANGULATED_POLYGON & m_result
VERTEX * createRing(const SHAPE_LINE_CHAIN &aPoints, int aBaseIndex, bool aWantCCW)
Create a VERTEX linked list from a SHAPE_LINE_CHAIN with a global index offset.
bool intersects(const VERTEX *p1, const VERTEX *q1, const VERTEX *p2, const VERTEX *q2) const
Check for intersection between two segments, end points included.
VERTEX * eliminateHoles(VERTEX *aOuterRing, std::vector< VERTEX * > &aHoleRings)
Bridge all hole rings into the outer ring by sorting holes left-to-right and connecting each hole's l...
friend struct POLYGON_TRIANGULATION_TEST_ACCESS
constexpr int sign(double aVal) const
static double triArea(double ax, double ay, double bx, double by, double cx, double cy)
Signed area of triangle (ax,ay), (bx,by), (cx,cy).
VERTEX * decimateList(VERTEX *aStart)
Replace near-collinear runs with a single chord.
bool splitPolygon(VERTEX *start, int aPass)
If we cannot find an ear to slice in the current polygon list, we use this to split the polygon into ...
void logVertices(VERTEX *aStart, std::set< VERTEX * > *aSeen)
bool TesselatePolygon(const SHAPE_POLY_SET::POLYGON &aPolygon, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
Triangulate a polygon with holes by bridging holes directly into the outer ring's VERTEX linked list,...
friend class SHAPE_POLY_SET
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.
double earScore(const VERTEX *a, const VERTEX *b, const VERTEX *c) const
std::vector< SHAPE_LINE_CHAIN > partitionPolygonBalanced(const SHAPE_LINE_CHAIN &aPoly, size_t aTargetLeaves) const
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)
bool collectScanlineHits(const SHAPE_LINE_CHAIN &aPoly, bool aVertical, int aCut, std::array< SCANLINE_HIT, 2 > &aHits) const
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.
bool splitPolygonBalanced(const SHAPE_LINE_CHAIN &aPoly, std::array< SHAPE_LINE_CHAIN, 2 > &aChildren) const
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.
bool splitPolygonAtCoordinate(const SHAPE_LINE_CHAIN &aPoly, bool aVertical, int aCut, std::array< SHAPE_LINE_CHAIN, 2 > &aChildren, double &aAreaA, double &aAreaB) const
size_t suggestedPartitionLeafCount(const SHAPE_LINE_CHAIN &aPoly) const
std::vector< double > PartitionAreaFractionsForTesting(const SHAPE_LINE_CHAIN &aPoly, size_t aTargetLeaves) const
size_t m_vertices_original_size
bool sectorContainsSector(const VERTEX *m, const VERTEX *p) const
Whether sector in vertex m contains sector in vertex p in the same coordinate frame.
SHAPE_LINE_CHAIN createSplitChild(const SHAPE_LINE_CHAIN &aPoly, int aStart, int aEnd) const
void subdividePolygon(VERTEX *aStart, int pass=0)
Inserts a new vertex halfway between each existing pair of vertices.
VERTEX * filterPoints(VERTEX *aStart, VERTEX *aEnd=nullptr)
Remove consecutive duplicate vertices from the linked list.
bool TesselatePolygon(const SHAPE_LINE_CHAIN &aPoly, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
VERTEX * findHoleBridge(VERTEX *aHole, VERTEX *aOuterStart)
Find a vertex on the outer ring visible from the hole's leftmost vertex by casting a horizontal ray t...
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Split(const VECTOR2I &aP, bool aExact=false)
Insert the point aP belonging to one of the our segments, splitting the adjacent segment in two.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
SHAPE_LINE_CHAIN & Simplify2(bool aRemoveColinear=true)
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int Find(const VECTOR2I &aP, int aThreshold=0) const
Search for point aP.
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.
const std::deque< VECTOR2I > & Vertices() const
const std::deque< TRI > & Triangles() const
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
constexpr extended_type SquaredEuclideanNorm() const
Compute the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
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_SET(int aSimplificationLevel)
VECTOR2I::extended_type m_simplificationLevel
uint32_t zOrder(const double aX, const double aY) const
Note that while the inputs are doubles, these are scaled by the size of the bounding box to fit into ...
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...
bool inTriangle(const VERTEX &a, const VERTEX &b, const VERTEX &c)
Check to see if triangle surrounds our current vertex.
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...
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
#define TRIANGULATE_TRACE
#define TRIANGULATEMINIMUMAREA
#define TRIANGULATEDELAUNAYREFINE
#define TRIANGULATESIMPLIFICATIONLEVEL
static bool triangulationRefineEnabled()
Whether the sliver-minimizing flip post-pass runs, from the TriangulateDelaunayRefine setting.
const SHAPE_LINE_CHAIN chain
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR2< int64_t > VECTOR2L