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