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 )
819 constexpr int kMaxRecursion = 64;
821 if( pass >= kMaxRecursion )
823 wxLogTrace(
TRIANGULATE_TRACE,
"earcutList recursion limit reached; aborting triangulation", pass );
827 wxLogTrace(
TRIANGULATE_TRACE,
"earcutList starting at %p for pass %d", aPoint, pass );
835 int internal_pass = 1;
836 constexpr int kEarLookahead = 2;
839 constexpr size_t kReflexIndexMinVertices = 8192;
841 const VERTEX* walk = aPoint;
847 }
while( walk != aPoint && ringSize < kReflexIndexMinVertices );
849 const bool useReflexIndex = ringSize >= kReflexIndexMinVertices;
851 while( aPoint->
prev != aPoint->
next )
859 VERTEX* bestEar =
nullptr;
860 double bestScore = -1.0;
863 for(
VERTEX* candidate = aPoint; candidate && lookahead < kEarLookahead;
864 candidate = candidate->
next, ++lookahead )
866 if( !candidate->isEar() ||
isTooSmall( candidate ) )
869 const double score =
earScore( candidate->prev, candidate, candidate->next );
871 if( !bestEar || score > bestScore )
880 prev = bestEar->
prev;
897 if( *prev != *nextNext &&
intersects( prev, aPoint,
next, nextNext ) &&
902 "Local intersection detected. Merging minor triangle with area %f",
903 area( prev, aPoint, nextNext ) );
904 m_result.AddTriangle( prev->
i, aPoint->
i, nextNext->
i );
923 if( aPoint == stop && aPoint->
prev != aPoint->
next )
937 if( newPoint->
next == newPoint->
prev )
951 if( internal_pass < 4 )
999 double prev_sq_len = ( aPoint->
prev->
x - aPoint->
x ) * ( aPoint->
prev->
x - aPoint->
x ) +
1000 ( aPoint->
prev->
y - aPoint->
y ) * ( aPoint->
prev->
y - aPoint->
y );
1001 double next_sq_len = ( aPoint->
next->
x - aPoint->
x ) * ( aPoint->
next->
x - aPoint->
x ) +
1002 ( aPoint->
next->
y - aPoint->
y ) * ( aPoint->
next->
y - aPoint->
y );
1003 double opp_sq_len = ( aPoint->
next->
x - aPoint->
prev->
x ) * ( aPoint->
next->
x - aPoint->
prev->
x ) +
1006 return ( prev_sq_len < min_area || next_sq_len < min_area || opp_sq_len < min_area );
1011 const double ab_sq = ( a->
x - b->
x ) * ( a->
x - b->
x ) + ( a->
y - b->
y ) * ( a->
y - b->
y );
1012 const double bc_sq = ( b->
x - c->
x ) * ( b->
x - c->
x ) + ( b->
y - c->
y ) * ( b->
y - c->
y );
1013 const double ca_sq = ( c->
x - a->
x ) * ( c->
x - a->
x ) + ( c->
y - a->
y ) * ( c->
y - a->
y );
1014 const double norm = ab_sq + bc_sq + ca_sq;
1033 for(
int i = 0; i < aPoints.
PointCount(); i++ )
1037 sum += ( ( p2.
x - p1.
x ) * ( p2.
y + p1.
y ) );
1040 bool isCW = sum > 0.0;
1041 bool needReverse = ( aWantCCW == isCW );
1043 auto addVertex = [&](
int i )
1057 for(
int i = aPoints.
PointCount() - 1; i >= 0; i-- )
1062 for(
int i = 0; i < aPoints.
PointCount(); i++ )
1069 if( tail && tail->
next != tail && ( *tail == *tail->
next ) )
1088 std::vector<HoleInfo> holes;
1089 holes.reserve( aHoleRings.size() );
1091 for(
VERTEX* hole : aHoleRings )
1104 if( p->
x < leftmost->
x || ( p->
x == leftmost->
x && p->
y < leftmost->
y ) )
1116 holes.push_back( { leftmost, leftmost->
x } );
1119 std::sort( holes.begin(), holes.end(),
1120 [](
const HoleInfo& a,
const HoleInfo& b ) { return a.leftX < b.leftX; } );
1122 for(
const HoleInfo& hi : holes )
1128 VERTEX* bridgeReverse = bridge->
split( hi.leftmost );
1135 hi.leftmost->x, hi.leftmost->y );
1160 if( *p == *p->
next )
1164 if( toRemove == aEnd )
1179 }
while( again || p != aEnd );
1192 double hx = aHole->
x;
1193 double hy = aHole->
y;
1194 double qx = -std::numeric_limits<double>::infinity();
1199 if( hy <= p->y && hy >= p->
next->
y && p->
next->
y != p->
y )
1201 double x = p->
x + ( hy - p->
y ) * ( p->
next->
x - p->
x )
1204 if( x <= hx && x > qx )
1213 if( hy == p->
next->
y )
1222 }
while( p != aOuterStart );
1234 double tanMin = std::numeric_limits<double>::infinity();
1240 if( hx >= p->
x && p->
x >= mx && hx != p->
x )
1245 inside =
triArea( hx, hy, mx, my, p->
x, p->
y ) >= 0
1246 &&
triArea( mx, my, qx, hy, p->
x, p->
y ) >= 0
1247 &&
triArea( qx, hy, hx, hy, p->
x, p->
y ) >= 0;
1249 inside =
triArea( qx, hy, mx, my, p->
x, p->
y ) >= 0
1250 &&
triArea( mx, my, hx, hy, p->
x, p->
y ) >= 0
1251 &&
triArea( hx, hy, qx, hy, p->
x, p->
y ) >= 0;
1255 double t =
std::abs( hy - p->
y ) / ( hx - p->
x );
1271 }
while( p != stop );
1279 static double triArea(
double ax,
double ay,
double bx,
double by,
1280 double cx,
double cy )
1282 return ( bx - ax ) * ( cy - ay ) - ( by - ay ) * ( cx - ax );
1301 struct VertexComparator {
1302 bool operator()(
const std::pair<VERTEX*,double>& a,
const std::pair<VERTEX*,double>& b)
const {
1303 return a.second > b.second;
1307 std::set<std::pair<VERTEX*,double>, VertexComparator> longest;
1312 double len = ( p->
x - p->
next->
x ) * ( p->
x - p->
next->
x ) +
1314 longest.emplace( p, len );
1318 }
while (p != aStart);
1320 avg /= longest.size();
1323 constexpr double kSubdivideThresholdFactor = 1.1;
1324 const double subdivideThreshold = avg * kSubdivideThresholdFactor;
1326 for(
auto it = longest.begin(); it != longest.end() && it->second > subdivideThreshold;
1336 int divisions = avg / it->second + 2 + pass;
1337 double step = 1.0 / divisions;
1339 for(
int i = 1; i < divisions; i++ )
1341 double x = a->
x * ( 1.0 - step * i ) + b->
x * ( step * i );
1342 double y = a->
y * ( 1.0 - step * i ) + b->
y * ( step * i );
1359 VERTEX* origPoly = start;
1362 if( !start || !start->
next || start->
next == start->
prev
1374 std::vector<VERTEX*> overlapPoints;
1377 while ( z_pt->
prevZ && *z_pt->
prevZ == *origPoly )
1380 overlapPoints.push_back( z_pt );
1382 while( z_pt->
nextZ && *z_pt->
nextZ == *origPoly )
1385 overlapPoints.push_back( z_pt );
1388 if( overlapPoints.size() != 2 || overlapPoints[0]->next == overlapPoints[1]
1389 || overlapPoints[0]->prev == overlapPoints[1] )
1391 origPoly = origPoly->
next;
1395 if( overlapPoints[0]->
area( overlapPoints[1] ) < 0 || overlapPoints[1]->
area( overlapPoints[0] ) < 0 )
1398 origPoly = origPoly->
next;
1402 wxLogTrace(
TRIANGULATE_TRACE,
"Splitting at overlap point %f, %f", overlapPoints[0]->x, overlapPoints[0]->y );
1403 std::swap( overlapPoints[0]->
next, overlapPoints[1]->
next );
1404 overlapPoints[0]->next->prev = overlapPoints[0];
1405 overlapPoints[1]->next->prev = overlapPoints[1];
1407 overlapPoints[0]->updateList();
1408 overlapPoints[1]->updateList();
1411 bool retval =
earcutList( overlapPoints[0], aPass )
1414 wxLogTrace(
TRIANGULATE_TRACE,
"%s at first overlap split", retval ?
"Success" :
"Failed" );
1418 }
while ( origPoly != start );
1428 while( marker != origPoly->
prev )
1431 if( origPoly->
next && origPoly->
i != marker->
i &&
goodSplit( origPoly, marker ) )
1444 marker = marker->
next;
1447 origPoly = origPoly->
next;
1448 }
while( origPoly != start );
1503 bool pos_area = a->
area( b ) > 0 && b->
area( a ) > 0;
1505 return no_intersect && local_split && ( same_dir || has_len ) && !a_on_edge && !b_on_edge && pos_area;
1510 constexpr int sign(
double aVal )
const
1512 return ( aVal > 0 ) - ( aVal < 0 );
1520 return q->
x <= std::max( p->
x, r->
x ) &&
1521 q->
x >= std::min( p->
x, r->
x ) &&
1522 q->
y <= std::max( p->
y, r->
y ) &&
1523 q->
y >= std::min( p->
y, r->
y );
1533 int sign1 =
sign(
area( p1, q1, p2 ) );
1534 int sign2 =
sign(
area( p1, q1, q2 ) );
1535 int sign3 =
sign(
area( p2, q2, p1 ) );
1536 int sign4 =
sign(
area( p2, q2, q1 ) );
1538 if( sign1 != sign2 && sign3 != sign4 )
1570 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
bool earcutRing(VERTEX *aPoint, int pass)
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 isUnindexedReflex(const VERTEX *aPoint) const
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...
bool clipRemainingEars(VERTEX *aStart)
Last resort for a ring that can be neither ear clipped nor split, typically a hatch sliver whose ears...
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...
void buildReflexIndex(VERTEX *aStart)
Index the reflex vertices of the ring containing aStart in z-order.
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...
bool isEar(bool aMatchUserData=false) const
Check whether the given vertex is in the middle of an ear.
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