23template <std::
size_t I,
typename T>
26 inline static typename std::tuple_element<I, T>::type get(
const T& t)
28 return std::get<I>(t);
36template <
typename N = u
int32_t>
40 std::vector<N> indices;
41 std::size_t vertices = 0;
43 template <
typename Polygon>
44 void operator()(
const Polygon& points);
49 Node(N index,
double x_,
double y_)
54 Node(
const Node&) =
delete;
55 Node& operator=(
const Node&) =
delete;
56 Node(Node&&) =
delete;
57 Node& operator=(Node&&) =
delete;
71 Node* prevZ =
nullptr;
72 Node* nextZ =
nullptr;
78 template <
typename Ring>
79 Node* linkedList(
const Ring& points,
const bool clockwise);
80 Node* filterPoints(Node* start, Node* end =
nullptr);
81 void earcutLinked(Node* ear,
int pass = 0);
82 bool isEar(Node* ear);
83 bool isEarHashed(Node* ear);
84 Node* cureLocalIntersections(Node* start);
85 void splitEarcut(Node* start);
86 template <
typename Polygon>
87 Node* eliminateHoles(
const Polygon& points, Node* outerNode);
88 Node* eliminateHole(Node* hole, Node* outerNode);
89 Node* findHoleBridge(Node* hole, Node* outerNode);
90 bool sectorContainsSector(
const Node* m,
const Node* p);
91 void indexCurve(Node* start);
92 Node* sortLinked(Node* list);
93 int32_t zOrder(
const double x_,
const double y_);
94 Node* getLeftmost(Node* start);
104 bool isValidDiagonal(Node* a, Node* b);
105 double area(
const Node* p,
const Node* q,
const Node* r)
const;
106 bool equals(
const Node* p1,
const Node* p2);
107 bool intersects(
const Node* p1,
const Node* q1,
const Node* p2,
const Node* q2);
108 bool onSegment(
const Node* p,
const Node* q,
const Node* r);
109 int sign(
double val);
110 bool intersectsPolygon(
const Node* a,
const Node* b);
111 bool locallyInside(
const Node* a,
const Node* b);
112 bool middleInside(
const Node* a,
const Node* b);
113 Node* splitPolygon(Node* a, Node* b);
114 template <
typename Po
int>
115 Node* insertNode(std::size_t i,
const Point& p, Node* last);
116 void removeNode(Node* p);
123 template <
typename T,
typename Alloc = std::allocator<T>>
128 ObjectPool(std::size_t blockSize_) { reset(blockSize_); }
129 ~ObjectPool() { clear(); }
130 template <
typename...
Args>
131 T* construct(
Args&&... args)
133 if (currentIndex >= blockSize) {
134 currentBlock = alloc_traits::allocate(alloc, blockSize);
135 allocations.emplace_back(currentBlock);
138 T*
object = ¤tBlock[currentIndex++];
139 alloc_traits::construct(alloc,
object, std::forward<Args>(args)...);
142 void reset(std::size_t newBlockSize)
144 for (
auto allocation : allocations) {
145 alloc_traits::deallocate(alloc, allocation, blockSize);
148 blockSize = std::max<std::size_t>(1, newBlockSize);
149 currentBlock =
nullptr;
150 currentIndex = blockSize;
152 void clear() { reset(blockSize); }
155 T* currentBlock =
nullptr;
156 std::size_t currentIndex = 1;
157 std::size_t blockSize = 1;
158 std::vector<T*> allocations;
160 typedef typename std::allocator_traits<Alloc> alloc_traits;
162 ObjectPool<Node> nodes;
166template <
typename Polygon>
173 if (points.empty())
return;
180 for (
size_t i = 0; threshold >= 0 && i < points.size(); i++) {
181 threshold -=
static_cast<int>(points[i].size());
182 len += points[i].size();
186 nodes.reset(len * 3 / 2);
187 indices.reserve(len + points[0].size());
189 Node* outerNode = linkedList(points[0],
true);
190 if (!outerNode || outerNode->prev == outerNode->next)
return;
192 if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
195 hashing = threshold < 0;
197 Node* p = outerNode->next;
198 minX = maxX = outerNode->x;
199 minY = maxY = outerNode->y;
203 minX = std::min<double>(minX, x);
204 minY = std::min<double>(minY, y);
205 maxX = std::max<double>(maxX, x);
206 maxY = std::max<double>(maxY, y);
208 }
while (p != outerNode);
212 inv_size = std::max<double>(maxX - minX, maxY - minY);
213 inv_size = inv_size != .0 ? (1. / inv_size) : .0;
216 earcutLinked(outerNode);
223template <
typename Ring>
224typename Earcut<N>::Node* Earcut<N>::linkedList(
const Ring& points,
const bool clockwise)
226 using Point =
typename Ring::value_type;
228 const std::size_t len = points.size();
230 Node* last =
nullptr;
233 for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
234 const auto& p1 = points[i];
235 const auto& p2 = points[j];
236 const double p20 = util::nth<0, Point>::get(p2);
237 const double p10 = util::nth<0, Point>::get(p1);
238 const double p11 = util::nth<1, Point>::get(p1);
239 const double p21 = util::nth<1, Point>::get(p2);
240 sum += (p20 - p10) * (p11 + p21);
244 if (clockwise == (sum > 0)) {
245 for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
247 for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
250 if (last && equals(last, last->next)) {
262typename Earcut<N>::Node* Earcut<N>::filterPoints(Node* start, Node* end)
264 if (!end) end = start;
271 if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
275 if (p == p->next)
break;
281 }
while (again || p != end);
288void Earcut<N>::earcutLinked(Node* ear,
int pass)
293 if (!pass && hashing) indexCurve(ear);
301 while (ear->prev != ear->next) {
305 if (hashing ? isEarHashed(ear) : isEar(ear)) {
307 indices.emplace_back(prev->i);
308 indices.emplace_back(ear->i);
309 indices.emplace_back(next->i);
325 if (!pass) earcutLinked(filterPoints(ear), 1);
328 else if (pass == 1) {
329 ear = cureLocalIntersections(filterPoints(ear));
330 earcutLinked(ear, 2);
333 }
else if (pass == 2)
343bool Earcut<N>::isEar(Node* ear)
345 const Node* a = ear->prev;
347 const Node* c = ear->next;
349 if (area(a, b, c) >= 0)
return false;
352 Node* p = ear->next->next;
354 while (p != ear->prev) {
355 if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
356 area(p->prev, p, p->next) >= 0)
365bool Earcut<N>::isEarHashed(Node* ear)
367 const Node* a = ear->prev;
369 const Node* c = ear->next;
371 if (area(a, b, c) >= 0)
return false;
374 const double minTX = std::min<double>(a->x, std::min<double>(b->x, c->x));
375 const double minTY = std::min<double>(a->y, std::min<double>(b->y, c->y));
376 const double maxTX = std::max<double>(a->x, std::max<double>(b->x, c->x));
377 const double maxTY = std::max<double>(a->y, std::max<double>(b->y, c->y));
380 const int32_t minZ = zOrder(minTX, minTY);
381 const int32_t maxZ = zOrder(maxTX, maxTY);
384 Node* p = ear->nextZ;
386 while (p && p->z <= maxZ) {
387 if (p != ear->prev && p != ear->next &&
388 pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
389 area(p->prev, p, p->next) >= 0)
397 while (p && p->z >= minZ) {
398 if (p != ear->prev && p != ear->next &&
399 pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
400 area(p->prev, p, p->next) >= 0)
410typename Earcut<N>::Node* Earcut<N>::cureLocalIntersections(Node* start)
415 Node* b = p->next->next;
418 if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) &&
419 locallyInside(b, a)) {
420 indices.emplace_back(a->i);
421 indices.emplace_back(p->i);
422 indices.emplace_back(b->i);
431 }
while (p != start);
433 return filterPoints(p);
438void Earcut<N>::splitEarcut(Node* start)
443 Node* b = a->next->next;
444 while (b != a->prev) {
445 if (a->i != b->i && isValidDiagonal(a, b)) {
447 Node* c = splitPolygon(a, b);
450 a = filterPoints(a, a->next);
451 c = filterPoints(c, c->next);
461 }
while (a != start);
466template <
typename Polygon>
467typename Earcut<N>::Node* Earcut<N>::eliminateHoles(
const Polygon& points, Node* outerNode)
469 const size_t len = points.size();
471 std::vector<Node*> queue;
472 for (
size_t i = 1; i < len; i++) {
473 Node* list = linkedList(points[i],
false);
475 if (list == list->next) list->steiner =
true;
476 queue.push_back(getLeftmost(list));
479 std::sort(queue.begin(), queue.end(), [](
const Node* a,
const Node* b) { return a->x < b->x; });
482 for (
size_t i = 0; i < queue.size(); i++) {
483 outerNode = eliminateHole(queue[i], outerNode);
484 outerNode = filterPoints(outerNode, outerNode->next);
492typename Earcut<N>::Node* Earcut<N>::eliminateHole(Node* hole, Node* outerNode)
494 Node* bridge = findHoleBridge(hole, outerNode);
499 Node* bridgeReverse = splitPolygon(bridge, hole);
502 Node* filteredBridge = filterPoints(bridge, bridge->next);
503 filterPoints(bridgeReverse, bridgeReverse->next);
506 return outerNode == bridge ? filteredBridge : outerNode;
511typename Earcut<N>::Node* Earcut<N>::findHoleBridge(Node* hole, Node* outerNode)
516 double qx = -std::numeric_limits<double>::infinity();
522 if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) {
523 double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y);
524 if (x <= hx && x > qx) {
527 if (hy == p->y)
return p;
528 if (hy == p->next->y)
return p->next;
530 m = p->x < p->next->x ? p : p->next;
534 }
while (p != outerNode);
538 if (hx == qx)
return m;
544 const Node* stop = m;
545 double tanMin = std::numeric_limits<double>::infinity();
553 if (hx >= p->x && p->x >= mx && hx != p->x &&
554 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) {
555 tanCur = std::abs(hy - p->y) / (hx - p->x);
557 if (locallyInside(p, hole) &&
559 (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) {
573bool Earcut<N>::sectorContainsSector(
const Node* m,
const Node* p)
575 return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0;
580void Earcut<N>::indexCurve(Node* start)
586 p->z = p->z ? p->z : zOrder(p->x, p->y);
590 }
while (p != start);
592 p->prevZ->nextZ =
nullptr;
601typename Earcut<N>::Node* Earcut<N>::sortLinked(Node* list)
608 int i, numMerges, pSize, qSize;
621 for (i = 0; i < inSize; i++) {
629 while (pSize > 0 || (qSize > 0 && q)) {
634 }
else if (qSize == 0 || !q) {
638 }
else if (p->z <= q->z) {
660 tail->nextZ =
nullptr;
662 if (numMerges <= 1)
return list;
670int32_t Earcut<N>::zOrder(
const double x_,
const double y_)
673 int32_t x =
static_cast<int32_t
>(32767.0 * (x_ - minX) * inv_size);
674 int32_t y =
static_cast<int32_t
>(32767.0 * (y_ - minY) * inv_size);
676 x = (x | (x << 8)) & 0x00FF00FF;
677 x = (x | (x << 4)) & 0x0F0F0F0F;
678 x = (x | (x << 2)) & 0x33333333;
679 x = (x | (x << 1)) & 0x55555555;
681 y = (y | (y << 8)) & 0x00FF00FF;
682 y = (y | (y << 4)) & 0x0F0F0F0F;
683 y = (y | (y << 2)) & 0x33333333;
684 y = (y | (y << 1)) & 0x55555555;
691typename Earcut<N>::Node* Earcut<N>::getLeftmost(Node* start)
694 Node* leftmost = start;
696 if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) leftmost = p;
698 }
while (p != start);
705bool Earcut<N>::pointInTriangle(
715 return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
716 (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
717 (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
722bool Earcut<N>::isValidDiagonal(Node* a, Node* b)
724 return a->next->i != b->i && a->prev->i != b->i &&
725 !intersectsPolygon(a, b) &&
726 ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) &&
727 (area(a->prev, a, b->prev) != 0.0 ||
728 area(a, b->prev, b) != 0.0)) ||
729 (equals(a, b) && area(a->prev, a, a->next) > 0 &&
730 area(b->prev, b, b->next) > 0));
735double Earcut<N>::area(
const Node* p,
const Node* q,
const Node* r)
const
737 return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
742bool Earcut<N>::equals(
const Node* p1,
const Node* p2)
744 return p1->x == p2->x && p1->y == p2->y;
749bool Earcut<N>::intersects(
const Node* p1,
const Node* q1,
const Node* p2,
const Node* q2)
751 int o1 =
sign(area(p1, q1, p2));
752 int o2 =
sign(area(p1, q1, q2));
753 int o3 =
sign(area(p2, q2, p1));
754 int o4 =
sign(area(p2, q2, q1));
756 if (o1 != o2 && o3 != o4)
return true;
758 if (o1 == 0 && onSegment(p1, p2, q1))
760 if (o2 == 0 && onSegment(p1, q2, q1))
762 if (o3 == 0 && onSegment(p2, p1, q2))
764 if (o4 == 0 && onSegment(p2, q1, q2))
772bool Earcut<N>::onSegment(
const Node* p,
const Node* q,
const Node* r)
774 return q->x <= std::max<double>(p->x, r->x) && q->x >= std::min<double>(p->x, r->x) &&
775 q->y <= std::max<double>(p->y, r->y) && q->y >= std::min<double>(p->y, r->y);
779int Earcut<N>::sign(
double val)
781 return (0.0 < val) - (val < 0.0);
786bool Earcut<N>::intersectsPolygon(
const Node* a,
const Node* b)
790 if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i &&
791 intersects(p, p->next, a, b))
801bool Earcut<N>::locallyInside(
const Node* a,
const Node* b)
803 return area(a->prev, a, a->next) < 0 ? area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0
804 : area(a, b, a->prev) < 0 || area(a, a->next, b) < 0;
809bool Earcut<N>::middleInside(
const Node* a,
const Node* b)
813 double px = (a->x + b->x) / 2;
814 double py = (a->y + b->y) / 2;
816 if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
817 (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
829typename Earcut<N>::Node* Earcut<N>::splitPolygon(Node* a, Node* b)
831 Node* a2 = nodes.construct(a->i, a->x, a->y);
832 Node* b2 = nodes.construct(b->i, b->x, b->y);
853template <
typename Po
int>
854typename Earcut<N>::Node* Earcut<N>::insertNode(std::size_t i,
const Point& pt, Node* last)
856 Node* p = nodes.construct(
858 util::nth<0, Point>::get(pt),
859 util::nth<1, Point>::get(pt));
867 p->next = last->next;
869 last->next->prev = p;
876void Earcut<N>::removeNode(Node* p)
878 p->next->prev = p->prev;
879 p->prev->next = p->next;
881 if (p->prevZ) p->prevZ->nextZ = p->nextZ;
882 if (p->nextZ) p->nextZ->prevZ = p->prevZ;
886template <
typename N = u
int32_t,
typename Polygon>
887std::vector<N> earcut(
const Polygon& poly)
889 mapbox::detail::Earcut<N> earcut;
891 return std::move(earcut.indices);
Main namespace for Lagrange.
Definition: AABBIGL.h:30
int sign(T val)
Get the sign of the value Returns either -1, 0, or 1.
Definition: utils.h:43
Definition: project.cpp:27