Lagrange
Loading...
Searching...
No Matches
earcut.h
1// Source: https://github.com/mapbox/earcut.hpp
2// SPDX-License-Identifier: ISC
3//
4// This file has been modified by Adobe.
5//
6// All modifications are Copyright 2022 Adobe.
7#pragma once
8
9#include <algorithm>
10#include <cassert>
11#include <cmath>
12#include <cstddef>
13#include <cstdint>
14#include <limits>
15#include <memory>
16#include <utility>
17#include <vector>
18
19namespace lagrange {
20namespace mapbox {
21
22namespace util {
23
24template <std::size_t I, typename T>
25struct nth
26{
27 inline static typename std::tuple_element<I, T>::type get(const T& t)
28 {
29 return std::get<I>(t);
30 };
31};
32
33} // namespace util
34
35namespace detail {
36
37template <typename N = uint32_t>
38class Earcut
39{
40public:
41 std::vector<N> indices;
42 std::size_t vertices = 0;
43
44 template <typename Polygon>
45 void operator()(const Polygon& points);
46
47private:
48 struct Node
49 {
50 Node(N index, double x_, double y_)
51 : x(x_)
52 , y(y_)
53 , i(index)
54 , steiner(0)
55 {}
56 Node(const Node&) = delete;
57 Node& operator=(const Node&) = delete;
58 Node(Node&&) = delete;
59 Node& operator=(Node&&) = delete;
60
61 const double x;
62 const double y;
63
64 // previous and next vertice nodes in a polygon ring
65 Node* prev = nullptr;
66 Node* next = nullptr;
67
68 // z-order curve value
69 int32_t z = 0;
70
71 // original index in polygon
72 const N i : (sizeof(N) * 8 - 1);
73
74 // indicates whether this is a steiner point
75 N steiner : 1;
76
77 // previous and next nodes in z-order
78 Node* prevZ = nullptr;
79 Node* nextZ = nullptr;
80 };
81
82 // Cache-optimized Triangle structure for repeated geometric tests
83 struct Triangle
84 {
85 const double ax, ay;
86 const double bx, by;
87 const double cx, cy;
88
89 Triangle(const Node* a, const Node* b, const Node* c)
90 : ax(a->x)
91 , ay(a->y)
92 , bx(b->x)
93 , by(b->y)
94 , cx(c->x)
95 , cy(c->y)
96 {}
97
98 inline double area() const { return (by - ay) * (cx - bx) - (bx - ax) * (cy - by); }
99
100 inline bool containsPoint(double px, double py) const
101 {
102 return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
103 (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
104 (bx - px) * (cy - py) >= (cx - px) * (by - py);
105 }
106 };
107
108 template <typename Ring>
109 Node* linkedList(const Ring& points, const bool clockwise);
110 Node* filterPoints(Node* start, Node* end = nullptr);
111 void earcutLinked(Node* ear, int pass = 0);
112 bool isEar(Node* ear);
113 bool isEarHashed(Node* ear);
114 Node* cureLocalIntersections(Node* start);
115 void splitEarcut(Node* start);
116 template <typename Polygon>
117 Node* eliminateHoles(const Polygon& points, Node* outerNode);
118 Node* eliminateHole(Node* hole, Node* outerNode);
119 Node* findHoleBridge(Node* hole, Node* outerNode);
120 bool sectorContainsSector(const Node* m, const Node* p);
121 void indexCurve(Node* start);
122 Node* sortLinked(Node* list);
123 int32_t zOrder(const double x_, const double y_);
124 Node* getLeftmost(Node* start);
125 bool pointInTriangle(
126 double ax,
127 double ay,
128 double bx,
129 double by,
130 double cx,
131 double cy,
132 double px,
133 double py) const;
134 bool isValidDiagonal(Node* a, Node* b);
135 double area(const Node* p, const Node* q, const Node* r) const;
136 bool equals(const Node* p1, const Node* p2);
137 bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2);
138 bool onSegment(const Node* p, const Node* q, const Node* r);
139 int sign(double val);
140 bool intersectsPolygon(const Node* a, const Node* b);
141 bool locallyInside(const Node* a, const Node* b);
142 bool middleInside(const Node* a, const Node* b);
143 Node* splitPolygon(Node* a, Node* b);
144 template <typename Point>
145 Node* insertNode(std::size_t i, const Point& p, Node* last);
146 void removeNode(Node* p);
147
148 bool hashing;
149 double minX, maxX;
150 double minY, maxY;
151 double inv_size = 0;
152
153 template <typename T, typename Alloc = std::allocator<T>>
154 class ObjectPool
155 {
156 public:
157 ObjectPool() { allocateNewBlock(256); }
158 ObjectPool(std::size_t blockSize_)
159 : baseBlockSize(blockSize_)
160 {
161 allocateNewBlock(std::max<std::size_t>(blockSize_, 256));
162 }
163 ~ObjectPool() { clear(); }
164 template <typename... Args>
165 T* construct(Args&&... args)
166 {
167 // If current block is full, move to next block or allocate new one
168 if (currentIndex >= baseBlockSize) {
169 currentBlockIndex++;
170 if (currentBlockIndex < memoryBlocks.size()) {
171 // Reuse existing block
172 currentIndex = 0;
173 } else {
174 // Allocate a new one
175 allocateNewBlock(baseBlockSize);
176 }
177 }
178
179 T* object = memoryBlocks[currentBlockIndex].get() + currentIndex;
180 alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
181 totalObjects++;
182 currentIndex++;
183 return object;
184 }
185 void reset() { clear(); }
186 void clear()
187 {
188 // Destroy all objects, but keep blocks allocated for reuse
189 std::size_t objectsDestroyed = 0;
190 for (std::size_t blockIdx = 0;
191 blockIdx < memoryBlocks.size() && objectsDestroyed < totalObjects;
192 ++blockIdx) {
193 // check if we are in the last block
194 std::size_t objectsInThisBlock =
195 std::min(baseBlockSize, totalObjects - objectsDestroyed);
196 for (std::size_t i = 0; i < objectsInThisBlock; ++i) {
197 T* object = memoryBlocks[blockIdx].get() + i;
198 alloc_traits::destroy(alloc, object);
199 }
200 objectsDestroyed += objectsInThisBlock;
201 }
202 // Reset to start from first block again
203 currentBlockIndex = 0;
204 currentIndex = 0;
205 totalObjects = 0;
206 }
207
208 private:
209 Alloc alloc;
210 typedef typename std::allocator_traits<Alloc> alloc_traits;
211
212 // Custom deleter that uses the allocator
213 struct AllocDeleter
214 {
215 Alloc alloc;
216 std::size_t capacity;
217 void operator()(T* ptr) { alloc_traits::deallocate(alloc, ptr, capacity); }
218 };
219
220 std::vector<std::unique_ptr<T[], AllocDeleter>> memoryBlocks;
221 std::vector<std::size_t> blockCapacities;
222 std::size_t currentBlockIndex = 0;
223 std::size_t currentIndex = 0;
224 std::size_t totalObjects = 0;
225 std::size_t baseBlockSize = 256;
226
227 void allocateNewBlock(std::size_t capacity)
228 {
229 T* rawMemory = alloc_traits::allocate(alloc, capacity);
230 auto newBlock =
231 std::unique_ptr<T[], AllocDeleter>(rawMemory, AllocDeleter{alloc, capacity});
232 memoryBlocks.push_back(std::move(newBlock));
233 blockCapacities.push_back(capacity);
234 currentBlockIndex = memoryBlocks.size() - 1;
235 currentIndex = 0;
236 }
237 };
238
239 std::unique_ptr<ObjectPool<Node>> nodes;
240 std::vector<Node*> holeQueue;
241};
242
243template <typename N>
244template <typename Polygon>
245void Earcut<N>::operator()(const Polygon& points)
246{
247 // reset
248 indices.clear();
249 vertices = 0;
250
251 if (points.empty()) return;
252
253 double x;
254 double y;
255 int threshold = 80;
256 std::size_t len = 0;
257
258 for (size_t i = 0; threshold >= 0 && i < points.size(); i++) {
259 threshold -= static_cast<int>(points[i].size());
260 len += points[i].size();
261 }
262
263 // estimate size of nodes and indices
264 if (!nodes) {
265 std::size_t estimatedNodes = len * 3 / 2;
266 nodes = std::make_unique<ObjectPool<Node>>(std::max<std::size_t>(estimatedNodes, 256));
267 }
268 indices.reserve(len + points[0].size());
269
270 Node* outerNode = linkedList(points[0], true);
271 if (!outerNode || outerNode->prev == outerNode->next) return;
272
273 if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
274
275 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
276 hashing = threshold < 0;
277 if (hashing) {
278 Node* p = outerNode->next;
279 minX = maxX = outerNode->x;
280 minY = maxY = outerNode->y;
281 do {
282 x = p->x;
283 y = p->y;
284 minX = std::min<double>(minX, x);
285 minY = std::min<double>(minY, y);
286 maxX = std::max<double>(maxX, x);
287 maxY = std::max<double>(maxY, y);
288 p = p->next;
289 } while (p != outerNode);
290
291 // minX, minY and inv_size are later used to transform coords into integers for z-order
292 // calculation
293 inv_size = std::max<double>(maxX - minX, maxY - minY);
294 inv_size = inv_size != .0 ? (32767. / inv_size) : .0;
295 }
296
297 earcutLinked(outerNode);
298
299 nodes->clear();
300 holeQueue.clear();
301}
302
303// create a circular doubly linked list from polygon points in the specified winding order
304template <typename N>
305template <typename Ring>
306typename Earcut<N>::Node* Earcut<N>::linkedList(const Ring& points, const bool clockwise)
307{
308 using Point = typename Ring::value_type;
309 double sum = 0;
310 const std::size_t len = points.size();
311 std::size_t i, j;
312 Node* last = nullptr;
313
314 // calculate original winding order of a polygon ring
315 for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
316 const auto& p1 = points[i];
317 const auto& p2 = points[j];
318 const double p20 = util::nth<0, Point>::get(p2);
319 const double p10 = util::nth<0, Point>::get(p1);
320 const double p11 = util::nth<1, Point>::get(p1);
321 const double p21 = util::nth<1, Point>::get(p2);
322 sum += (p20 - p10) * (p11 + p21);
323 }
324
325 // link points into circular doubly-linked list in the specified winding order
326 if (clockwise == (sum > 0)) {
327 for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
328 } else {
329 for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
330 }
331
332 if (last && equals(last, last->next)) {
333 removeNode(last);
334 last = last->next;
335 }
336
337 vertices += len;
338
339 return last;
340}
341
342// eliminate colinear or duplicate points
343template <typename N>
344typename Earcut<N>::Node* Earcut<N>::filterPoints(Node* start, Node* end)
345{
346 if (!end) end = start;
347
348 Node* p = start;
349 bool again;
350 do {
351 again = false;
352
353 if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
354 removeNode(p);
355 p = end = p->prev;
356
357 if (p == p->next) break;
358 again = true;
359
360 } else {
361 p = p->next;
362 }
363 } while (again || p != end);
364
365 return end;
366}
367
368// main ear slicing loop which triangulates a polygon (given as a linked list)
369template <typename N>
370void Earcut<N>::earcutLinked(Node* ear, int pass)
371{
372 if (!ear) return;
373
374 // interlink polygon nodes in z-order
375 if (!pass && hashing) indexCurve(ear);
376
377 Node* stop = ear;
378 Node* prev;
379 Node* next;
380
381 // iterate through ears, slicing them one by one
382 while (ear->prev != ear->next) {
383 prev = ear->prev;
384 next = ear->next;
385
386 if (hashing ? isEarHashed(ear) : isEar(ear)) {
387 // cut off the triangle
388 indices.emplace_back(prev->i);
389 indices.emplace_back(ear->i);
390 indices.emplace_back(next->i);
391
392 removeNode(ear);
393
394 // skipping the next vertice leads to less sliver triangles
395 ear = next->next;
396 stop = next->next;
397
398 continue;
399 }
400
401 ear = next;
402
403 // if we looped through the whole remaining polygon and can't find any more ears
404 if (ear == stop) {
405 // try filtering points and slicing again
406 if (!pass) earcutLinked(filterPoints(ear), 1);
407
408 // if this didn't work, try curing all small self-intersections locally
409 else if (pass == 1) {
410 ear = cureLocalIntersections(filterPoints(ear));
411 earcutLinked(ear, 2);
412
413 // as a last resort, try splitting the remaining polygon into two
414 } else if (pass == 2)
415 splitEarcut(ear);
416
417 break;
418 }
419 }
420}
421
422// check whether a polygon node forms a valid ear with adjacent nodes
423template <typename N>
424bool Earcut<N>::isEar(Node* ear)
425{
426 const Node* a = ear->prev;
427 const Node* b = ear;
428 const Node* c = ear->next;
429
430 // Create triangle with cached coordinates and bounding box
431 const Triangle tri(a, b, c);
432 if (tri.area() >= 0) return false; // reflex, can't be an ear
433
434 // now make sure we don't have other points inside the potential ear
435 Node* p = ear->next->next;
436
437 while (p != ear->prev) {
438 if (tri.containsPoint(p->x, p->y) && area(p->prev, p, p->next) >= 0) return false;
439 p = p->next;
440 }
441
442 return true;
443}
444
445template <typename N>
446bool Earcut<N>::isEarHashed(Node* ear)
447{
448 const Node* a = ear->prev;
449 const Node* b = ear;
450 const Node* c = ear->next;
451
452 // Create triangle with cached coordinates and bounding box
453 const Triangle tri(a, b, c);
454 if (tri.area() >= 0) return false; // reflex, can't be an ear
455
456 // triangle bbox; min & max are calculated like this for speed
457 const double minTX = std::min<double>(tri.ax, std::min<double>(tri.bx, tri.cx));
458 const double minTY = std::min<double>(tri.ay, std::min<double>(tri.by, tri.cy));
459 const double maxTX = std::max<double>(tri.ax, std::max<double>(tri.bx, tri.cx));
460 const double maxTY = std::max<double>(tri.ay, std::max<double>(tri.by, tri.cy));
461
462 // z-order range for the current triangle bbox;
463 const int32_t minZ = zOrder(minTX, minTY);
464 const int32_t maxZ = zOrder(maxTX, maxTY);
465
466 // first look for points inside the triangle in increasing z-order
467 Node* p = ear->nextZ;
468
469 while (p && p->z <= maxZ) {
470 if (p != ear->prev && p != ear->next && tri.containsPoint(p->x, p->y) &&
471 area(p->prev, p, p->next) >= 0)
472 return false;
473 p = p->nextZ;
474 }
475
476 // then look for points in decreasing z-order
477 p = ear->prevZ;
478
479 while (p && p->z >= minZ) {
480 if (p != ear->prev && p != ear->next && tri.containsPoint(p->x, p->y) &&
481 area(p->prev, p, p->next) >= 0)
482 return false;
483 p = p->prevZ;
484 }
485
486 return true;
487}
488
489// go through all polygon nodes and cure small local self-intersections
490template <typename N>
491typename Earcut<N>::Node* Earcut<N>::cureLocalIntersections(Node* start)
492{
493 Node* p = start;
494 do {
495 Node* a = p->prev;
496 Node* b = p->next->next;
497
498 // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2])
499 if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) &&
500 locallyInside(b, a)) {
501 indices.emplace_back(a->i);
502 indices.emplace_back(p->i);
503 indices.emplace_back(b->i);
504
505 // remove two nodes involved
506 removeNode(p);
507 removeNode(p->next);
508
509 p = start = b;
510 }
511 p = p->next;
512 } while (p != start);
513
514 return filterPoints(p);
515}
516
517// try splitting polygon into two and triangulate them independently
518template <typename N>
519void Earcut<N>::splitEarcut(Node* start)
520{
521 // look for a valid diagonal that divides the polygon into two
522 Node* a = start;
523 do {
524 Node* b = a->next->next;
525 while (b != a->prev) {
526 if (a->i != b->i && isValidDiagonal(a, b)) {
527 // split the polygon in two by the diagonal
528 Node* c = splitPolygon(a, b);
529
530 // filter colinear points around the cuts
531 a = filterPoints(a, a->next);
532 c = filterPoints(c, c->next);
533
534 // run earcut on each half
535 earcutLinked(a);
536 earcutLinked(c);
537 return;
538 }
539 b = b->next;
540 }
541 a = a->next;
542 } while (a != start);
543}
544
545// link every hole into the outer loop, producing a single-ring polygon without holes
546template <typename N>
547template <typename Polygon>
548typename Earcut<N>::Node* Earcut<N>::eliminateHoles(const Polygon& points, Node* outerNode)
549{
550 const size_t len = points.size();
551
552 holeQueue.clear();
553 for (size_t i = 1; i < len; i++) {
554 Node* list = linkedList(points[i], false);
555 if (list) {
556 if (list == list->next) list->steiner = true;
557 holeQueue.push_back(getLeftmost(list));
558 }
559 }
560 std::sort(holeQueue.begin(), holeQueue.end(), [](const Node* a, const Node* b) {
561 return a->x < b->x;
562 });
563
564 // process holes from left to right
565 for (size_t i = 0; i < holeQueue.size(); i++) {
566 outerNode = eliminateHole(holeQueue[i], outerNode);
567 }
568
569 return outerNode;
570}
571
572// find a bridge between vertices that connects hole with an outer ring and and link it
573template <typename N>
574typename Earcut<N>::Node* Earcut<N>::eliminateHole(Node* hole, Node* outerNode)
575{
576 Node* bridge = findHoleBridge(hole, outerNode);
577 if (!bridge) {
578 return outerNode;
579 }
580
581 Node* bridgeReverse = splitPolygon(bridge, hole);
582
583 // filter collinear points around the cuts
584 filterPoints(bridgeReverse, bridgeReverse->next);
585
586 // Check if input node was removed by the filtering
587 return filterPoints(bridge, bridge->next);
588}
589
590// David Eberly's algorithm for finding a bridge between hole and outer polygon
591template <typename N>
592typename Earcut<N>::Node* Earcut<N>::findHoleBridge(Node* hole, Node* outerNode)
593{
594 Node* p = outerNode;
595 double hx = hole->x;
596 double hy = hole->y;
597 double qx = -std::numeric_limits<double>::infinity();
598 Node* m = nullptr;
599
600 // find a segment intersected by a ray from the hole's leftmost Vertex to the left;
601 // segment's endpoint with lesser x will be potential connection Vertex
602 do {
603 if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) {
604 double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y);
605 if (x <= hx && x > qx) {
606 qx = x;
607 m = p->x < p->next->x ? p : p->next;
608 if (x == hx) return m; // hole touches outer segment; pick leftmost endpoint
609 }
610 }
611 p = p->next;
612 } while (p != outerNode);
613
614 if (!m) return 0;
615
616 // look for points inside the triangle of hole Vertex, segment intersection and endpoint;
617 // if there are no points found, we have a valid connection;
618 // otherwise choose the Vertex of the minimum angle with the ray as connection Vertex
619
620 const Node* stop = m;
621 double tanMin = std::numeric_limits<double>::infinity();
622 double tanCur = 0;
623
624 p = m;
625 double mx = m->x;
626 double my = m->y;
627
628 do {
629 if (hx >= p->x && p->x >= mx && hx != p->x &&
630 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) {
631 tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential
632
633 if (locallyInside(p, hole) &&
634 (tanCur < tanMin ||
635 (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) {
636 m = p;
637 tanMin = tanCur;
638 }
639 }
640
641 p = p->next;
642 } while (p != stop);
643
644 return m;
645}
646
647// whether sector in vertex m contains sector in vertex p in the same coordinates
648template <typename N>
649bool Earcut<N>::sectorContainsSector(const Node* m, const Node* p)
650{
651 return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0;
652}
653
654// interlink polygon nodes in z-order
655template <typename N>
656void Earcut<N>::indexCurve(Node* start)
657{
658 assert(start);
659 Node* p = start;
660
661 do {
662 p->z = p->z ? p->z : zOrder(p->x, p->y);
663 p->prevZ = p->prev;
664 p->nextZ = p->next;
665 p = p->next;
666 } while (p != start);
667
668 p->prevZ->nextZ = nullptr;
669 p->prevZ = nullptr;
670
671 sortLinked(p);
672}
673
674// Simon Tatham's linked list merge sort algorithm
675// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
676template <typename N>
677typename Earcut<N>::Node* Earcut<N>::sortLinked(Node* list)
678{
679 assert(list);
680 Node* p;
681 Node* q;
682 Node* e;
683 Node* tail;
684 int i, numMerges, pSize, qSize;
685 int inSize = 1;
686
687 for (;;) {
688 p = list;
689 list = nullptr;
690 tail = nullptr;
691 numMerges = 0;
692
693 while (p) {
694 numMerges++;
695 q = p;
696 pSize = 0;
697 for (i = 0; i < inSize; i++) {
698 pSize++;
699 q = q->nextZ;
700 if (!q) break;
701 }
702
703 qSize = inSize;
704
705 while (pSize > 0 || (qSize > 0 && q)) {
706 if (pSize == 0) {
707 e = q;
708 q = q->nextZ;
709 qSize--;
710 } else if (qSize == 0 || !q) {
711 e = p;
712 p = p->nextZ;
713 pSize--;
714 } else if (p->z <= q->z) {
715 e = p;
716 p = p->nextZ;
717 pSize--;
718 } else {
719 e = q;
720 q = q->nextZ;
721 qSize--;
722 }
723
724 if (tail)
725 tail->nextZ = e;
726 else
727 list = e;
728
729 e->prevZ = tail;
730 tail = e;
731 }
732
733 p = q;
734 }
735
736 tail->nextZ = nullptr;
737
738 if (numMerges <= 1) return list;
739
740 inSize *= 2;
741 }
742}
743
744// z-order of a Vertex given coords and size of the data bounding box
745template <typename N>
746int32_t Earcut<N>::zOrder(const double x_, const double y_)
747{
748 // coords are transformed into non-negative 15-bit integer range
749 int32_t x = static_cast<int32_t>((x_ - minX) * inv_size);
750 int32_t y = static_cast<int32_t>((y_ - minY) * inv_size);
751
752 x = (x | (x << 8)) & 0x00FF00FF;
753 x = (x | (x << 4)) & 0x0F0F0F0F;
754 x = (x | (x << 2)) & 0x33333333;
755 x = (x | (x << 1)) & 0x55555555;
756
757 y = (y | (y << 8)) & 0x00FF00FF;
758 y = (y | (y << 4)) & 0x0F0F0F0F;
759 y = (y | (y << 2)) & 0x33333333;
760 y = (y | (y << 1)) & 0x55555555;
761
762 return x | (y << 1);
763}
764
765// find the leftmost node of a polygon ring
766template <typename N>
767typename Earcut<N>::Node* Earcut<N>::getLeftmost(Node* start)
768{
769 Node* p = start;
770 Node* leftmost = start;
771 do {
772 if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) leftmost = p;
773 p = p->next;
774 } while (p != start);
775
776 return leftmost;
777}
778
779// check if a point lies within a convex triangle
780template <typename N>
781bool Earcut<N>::pointInTriangle(
782 double ax,
783 double ay,
784 double bx,
785 double by,
786 double cx,
787 double cy,
788 double px,
789 double py) const
790{
791 return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
792 (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
793 (bx - px) * (cy - py) >= (cx - px) * (by - py);
794}
795
796// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
797template <typename N>
798bool Earcut<N>::isValidDiagonal(Node* a, Node* b)
799{
800 return a->next->i != b->i && a->prev->i != b->i &&
801 !intersectsPolygon(a, b) && // dones't intersect other edges
802 ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
803 (area(a->prev, a, b->prev) != 0.0 ||
804 area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors
805 (equals(a, b) && area(a->prev, a, a->next) > 0 &&
806 area(b->prev, b, b->next) > 0)); // special zero-length case
807}
808
809// signed area of a triangle
810template <typename N>
811double Earcut<N>::area(const Node* p, const Node* q, const Node* r) const
812{
813 return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
814}
815
816// check if two points are equal
817template <typename N>
818bool Earcut<N>::equals(const Node* p1, const Node* p2)
819{
820 return p1->x == p2->x && p1->y == p2->y;
821}
822
823// check if two segments intersect
824template <typename N>
825bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2)
826{
827 int o1 = sign(area(p1, q1, p2));
828 int o2 = sign(area(p1, q1, q2));
829 int o3 = sign(area(p2, q2, p1));
830 int o4 = sign(area(p2, q2, q1));
831
832 if (o1 != o2 && o3 != o4) return true; // general case
833
834 if (o1 == 0 && onSegment(p1, p2, q1))
835 return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
836 if (o2 == 0 && onSegment(p1, q2, q1))
837 return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
838 if (o3 == 0 && onSegment(p2, p1, q2))
839 return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
840 if (o4 == 0 && onSegment(p2, q1, q2))
841 return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
842
843 return false;
844}
845
846// for collinear points p, q, r, check if point q lies on segment pr
847template <typename N>
848bool Earcut<N>::onSegment(const Node* p, const Node* q, const Node* r)
849{
850 return q->x <= std::max<double>(p->x, r->x) && q->x >= std::min<double>(p->x, r->x) &&
851 q->y <= std::max<double>(p->y, r->y) && q->y >= std::min<double>(p->y, r->y);
852}
853
854template <typename N>
855int Earcut<N>::sign(double val)
856{
857 return (0.0 < val) - (val < 0.0);
858}
859
860// check if a polygon diagonal intersects any polygon segments
861template <typename N>
862bool Earcut<N>::intersectsPolygon(const Node* a, const Node* b)
863{
864 const Node* p = a;
865 do {
866 if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i &&
867 intersects(p, p->next, a, b))
868 return true;
869 p = p->next;
870 } while (p != a);
871
872 return false;
873}
874
875// check if a polygon diagonal is locally inside the polygon
876template <typename N>
877bool Earcut<N>::locallyInside(const Node* a, const Node* b)
878{
879 return area(a->prev, a, a->next) < 0 ? area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0
880 : area(a, b, a->prev) < 0 || area(a, a->next, b) < 0;
881}
882
883// check if the middle Vertex of a polygon diagonal is inside the polygon
884template <typename N>
885bool Earcut<N>::middleInside(const Node* a, const Node* b)
886{
887 const Node* p = a;
888 bool inside = false;
889 double px = (a->x + b->x) / 2;
890 double py = (a->y + b->y) / 2;
891 do {
892 if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
893 (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
894 inside = !inside;
895 p = p->next;
896 } while (p != a);
897
898 return inside;
899}
900
901// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits
902// polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a
903// single ring
904template <typename N>
905typename Earcut<N>::Node* Earcut<N>::splitPolygon(Node* a, Node* b)
906{
907 Node* a2 = nodes->construct(a->i, a->x, a->y);
908 Node* b2 = nodes->construct(b->i, b->x, b->y);
909 Node* an = a->next;
910 Node* bp = b->prev;
911
912 a->next = b;
913 b->prev = a;
914
915 a2->next = an;
916 an->prev = a2;
917
918 b2->next = a2;
919 a2->prev = b2;
920
921 bp->next = b2;
922 b2->prev = bp;
923
924 return b2;
925}
926
927// create a node and util::optionally link it with previous one (in a circular doubly linked list)
928template <typename N>
929template <typename Point>
930typename Earcut<N>::Node* Earcut<N>::insertNode(std::size_t i, const Point& pt, Node* last)
931{
932 Node* p = nodes->construct(
933 static_cast<N>(i),
934 util::nth<0, Point>::get(pt),
935 util::nth<1, Point>::get(pt));
936
937 if (!last) {
938 p->prev = p;
939 p->next = p;
940
941 } else {
942 assert(last);
943 p->next = last->next;
944 p->prev = last;
945 last->next->prev = p;
946 last->next = p;
947 }
948 return p;
949}
950
951template <typename N>
952void Earcut<N>::removeNode(Node* p)
953{
954 p->next->prev = p->prev;
955 p->prev->next = p->next;
956
957 if (p->prevZ) p->prevZ->nextZ = p->nextZ;
958 if (p->nextZ) p->nextZ->prevZ = p->prevZ;
959}
960} // namespace detail
961
962template <typename N = uint32_t, typename Polygon>
963std::vector<N> earcut(const Polygon& poly)
964{
965 mapbox::detail::Earcut<N> earcut;
966 earcut(poly);
967 return std::move(earcut.indices);
968}
969} // namespace mapbox
970} // namespace lagrange
Definition earcut.h:39
Main namespace for Lagrange.
int sign(T val)
Get the sign of the value Returns either -1, 0, or 1.
Definition utils.h:44
Definition project.cpp:27
Definition earcut.h:26