24template <std::
size_t I,
typename T>
27 inline static typename std::tuple_element<I, T>::type get(
const T& t)
29 return std::get<I>(t);
37template <
typename N = u
int32_t>
41 std::vector<N> indices;
42 std::size_t vertices = 0;
44 template <
typename Polygon>
45 void operator()(
const Polygon& points);
50 Node(N index,
double x_,
double y_)
56 Node(
const Node&) =
delete;
57 Node& operator=(
const Node&) =
delete;
58 Node(Node&&) =
delete;
59 Node& operator=(Node&&) =
delete;
72 const N i : (
sizeof(N) * 8 - 1);
78 Node* prevZ =
nullptr;
79 Node* nextZ =
nullptr;
89 Triangle(
const Node* a,
const Node* b,
const Node* c)
98 inline double area()
const {
return (by - ay) * (cx - bx) - (bx - ax) * (cy - by); }
100 inline bool containsPoint(
double px,
double py)
const
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);
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(
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 Po
int>
145 Node* insertNode(std::size_t i,
const Point& p, Node* last);
146 void removeNode(Node* p);
153 template <
typename T,
typename Alloc = std::allocator<T>>
157 ObjectPool() { allocateNewBlock(256); }
158 ObjectPool(std::size_t blockSize_)
159 : baseBlockSize(blockSize_)
161 allocateNewBlock(std::max<std::size_t>(blockSize_, 256));
163 ~ObjectPool() { clear(); }
164 template <
typename...
Args>
165 T* construct(
Args&&... args)
168 if (currentIndex >= baseBlockSize) {
170 if (currentBlockIndex < memoryBlocks.size()) {
175 allocateNewBlock(baseBlockSize);
179 T*
object = memoryBlocks[currentBlockIndex].get() + currentIndex;
180 alloc_traits::construct(alloc,
object, std::forward<Args>(args)...);
185 void reset() { clear(); }
189 std::size_t objectsDestroyed = 0;
190 for (std::size_t blockIdx = 0;
191 blockIdx < memoryBlocks.size() && objectsDestroyed < totalObjects;
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);
200 objectsDestroyed += objectsInThisBlock;
203 currentBlockIndex = 0;
210 typedef typename std::allocator_traits<Alloc> alloc_traits;
216 std::size_t capacity;
217 void operator()(T* ptr) { alloc_traits::deallocate(alloc, ptr, capacity); }
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;
227 void allocateNewBlock(std::size_t capacity)
229 T* rawMemory = alloc_traits::allocate(alloc, capacity);
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;
239 std::unique_ptr<ObjectPool<Node>> nodes;
240 std::vector<Node*> holeQueue;
244template <
typename Polygon>
245void Earcut<N>::operator()(
const Polygon& points)
251 if (points.empty())
return;
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();
265 std::size_t estimatedNodes = len * 3 / 2;
266 nodes = std::make_unique<ObjectPool<Node>>(std::max<std::size_t>(estimatedNodes, 256));
268 indices.reserve(len + points[0].size());
270 Node* outerNode = linkedList(points[0],
true);
271 if (!outerNode || outerNode->prev == outerNode->next)
return;
273 if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
276 hashing = threshold < 0;
278 Node* p = outerNode->next;
279 minX = maxX = outerNode->x;
280 minY = maxY = outerNode->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);
289 }
while (p != outerNode);
293 inv_size = std::max<double>(maxX - minX, maxY - minY);
294 inv_size = inv_size != .0 ? (32767. / inv_size) : .0;
297 earcutLinked(outerNode);
305template <
typename Ring>
306typename Earcut<N>::Node* Earcut<N>::linkedList(
const Ring& points,
const bool clockwise)
308 using Point =
typename Ring::value_type;
310 const std::size_t len = points.size();
312 Node* last =
nullptr;
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);
326 if (clockwise == (sum > 0)) {
327 for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
329 for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
332 if (last && equals(last, last->next)) {
344typename Earcut<N>::Node* Earcut<N>::filterPoints(Node* start, Node* end)
346 if (!end) end = start;
353 if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
357 if (p == p->next)
break;
363 }
while (again || p != end);
370void Earcut<N>::earcutLinked(Node* ear,
int pass)
375 if (!pass && hashing) indexCurve(ear);
382 while (ear->prev != ear->next) {
386 if (hashing ? isEarHashed(ear) : isEar(ear)) {
388 indices.emplace_back(prev->i);
389 indices.emplace_back(ear->i);
390 indices.emplace_back(next->i);
406 if (!pass) earcutLinked(filterPoints(ear), 1);
409 else if (pass == 1) {
410 ear = cureLocalIntersections(filterPoints(ear));
411 earcutLinked(ear, 2);
414 }
else if (pass == 2)
424bool Earcut<N>::isEar(Node* ear)
426 const Node* a = ear->prev;
428 const Node* c = ear->next;
431 const Triangle tri(a, b, c);
432 if (tri.area() >= 0)
return false;
435 Node* p = ear->next->next;
437 while (p != ear->prev) {
438 if (tri.containsPoint(p->x, p->y) && area(p->prev, p, p->next) >= 0)
return false;
446bool Earcut<N>::isEarHashed(Node* ear)
448 const Node* a = ear->prev;
450 const Node* c = ear->next;
453 const Triangle tri(a, b, c);
454 if (tri.area() >= 0)
return false;
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));
463 const int32_t minZ = zOrder(minTX, minTY);
464 const int32_t maxZ = zOrder(maxTX, maxTY);
467 Node* p = ear->nextZ;
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)
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)
491typename Earcut<N>::Node* Earcut<N>::cureLocalIntersections(Node* start)
496 Node* b = p->next->next;
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);
512 }
while (p != start);
514 return filterPoints(p);
519void Earcut<N>::splitEarcut(Node* start)
524 Node* b = a->next->next;
525 while (b != a->prev) {
526 if (a->i != b->i && isValidDiagonal(a, b)) {
528 Node* c = splitPolygon(a, b);
531 a = filterPoints(a, a->next);
532 c = filterPoints(c, c->next);
542 }
while (a != start);
547template <
typename Polygon>
548typename Earcut<N>::Node* Earcut<N>::eliminateHoles(
const Polygon& points, Node* outerNode)
550 const size_t len = points.size();
553 for (
size_t i = 1; i < len; i++) {
554 Node* list = linkedList(points[i],
false);
556 if (list == list->next) list->steiner =
true;
557 holeQueue.push_back(getLeftmost(list));
560 std::sort(holeQueue.begin(), holeQueue.end(), [](
const Node* a,
const Node* b) {
565 for (
size_t i = 0; i < holeQueue.size(); i++) {
566 outerNode = eliminateHole(holeQueue[i], outerNode);
574typename Earcut<N>::Node* Earcut<N>::eliminateHole(Node* hole, Node* outerNode)
576 Node* bridge = findHoleBridge(hole, outerNode);
581 Node* bridgeReverse = splitPolygon(bridge, hole);
584 filterPoints(bridgeReverse, bridgeReverse->next);
587 return filterPoints(bridge, bridge->next);
592typename Earcut<N>::Node* Earcut<N>::findHoleBridge(Node* hole, Node* outerNode)
597 double qx = -std::numeric_limits<double>::infinity();
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) {
607 m = p->x < p->next->x ? p : p->next;
608 if (x == hx)
return m;
612 }
while (p != outerNode);
620 const Node* stop = m;
621 double tanMin = std::numeric_limits<double>::infinity();
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);
633 if (locallyInside(p, hole) &&
635 (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) {
649bool Earcut<N>::sectorContainsSector(
const Node* m,
const Node* p)
651 return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0;
656void Earcut<N>::indexCurve(Node* start)
662 p->z = p->z ? p->z : zOrder(p->x, p->y);
666 }
while (p != start);
668 p->prevZ->nextZ =
nullptr;
677typename Earcut<N>::Node* Earcut<N>::sortLinked(Node* list)
684 int i, numMerges, pSize, qSize;
697 for (i = 0; i < inSize; i++) {
705 while (pSize > 0 || (qSize > 0 && q)) {
710 }
else if (qSize == 0 || !q) {
714 }
else if (p->z <= q->z) {
736 tail->nextZ =
nullptr;
738 if (numMerges <= 1)
return list;
746int32_t Earcut<N>::zOrder(
const double x_,
const double y_)
749 int32_t x =
static_cast<int32_t
>((x_ - minX) * inv_size);
750 int32_t y =
static_cast<int32_t
>((y_ - minY) * inv_size);
752 x = (x | (x << 8)) & 0x00FF00FF;
753 x = (x | (x << 4)) & 0x0F0F0F0F;
754 x = (x | (x << 2)) & 0x33333333;
755 x = (x | (x << 1)) & 0x55555555;
757 y = (y | (y << 8)) & 0x00FF00FF;
758 y = (y | (y << 4)) & 0x0F0F0F0F;
759 y = (y | (y << 2)) & 0x33333333;
760 y = (y | (y << 1)) & 0x55555555;
767typename Earcut<N>::Node* Earcut<N>::getLeftmost(Node* start)
770 Node* leftmost = start;
772 if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) leftmost = p;
774 }
while (p != start);
781bool Earcut<N>::pointInTriangle(
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);
798bool Earcut<N>::isValidDiagonal(Node* a, Node* b)
800 return a->next->i != b->i && a->prev->i != b->i &&
801 !intersectsPolygon(a, b) &&
802 ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) &&
803 (area(a->prev, a, b->prev) != 0.0 ||
804 area(a, b->prev, b) != 0.0)) ||
805 (equals(a, b) && area(a->prev, a, a->next) > 0 &&
806 area(b->prev, b, b->next) > 0));
811double Earcut<N>::area(
const Node* p,
const Node* q,
const Node* r)
const
813 return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
818bool Earcut<N>::equals(
const Node* p1,
const Node* p2)
820 return p1->x == p2->x && p1->y == p2->y;
825bool Earcut<N>::intersects(
const Node* p1,
const Node* q1,
const Node* p2,
const Node* q2)
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));
832 if (o1 != o2 && o3 != o4)
return true;
834 if (o1 == 0 && onSegment(p1, p2, q1))
836 if (o2 == 0 && onSegment(p1, q2, q1))
838 if (o3 == 0 && onSegment(p2, p1, q2))
840 if (o4 == 0 && onSegment(p2, q1, q2))
848bool Earcut<N>::onSegment(
const Node* p,
const Node* q,
const Node* r)
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);
855int Earcut<N>::sign(
double val)
857 return (0.0 < val) - (val < 0.0);
862bool Earcut<N>::intersectsPolygon(
const Node* a,
const Node* b)
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))
877bool Earcut<N>::locallyInside(
const Node* a,
const Node* b)
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;
885bool Earcut<N>::middleInside(
const Node* a,
const Node* b)
889 double px = (a->x + b->x) / 2;
890 double py = (a->y + b->y) / 2;
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))
905typename Earcut<N>::Node* Earcut<N>::splitPolygon(Node* a, Node* b)
907 Node* a2 = nodes->construct(a->i, a->x, a->y);
908 Node* b2 = nodes->construct(b->i, b->x, b->y);
929template <
typename Po
int>
930typename Earcut<N>::Node* Earcut<N>::insertNode(std::size_t i,
const Point& pt, Node* last)
932 Node* p = nodes->construct(
934 util::nth<0, Point>::get(pt),
935 util::nth<1, Point>::get(pt));
943 p->next = last->next;
945 last->next->prev = p;
952void Earcut<N>::removeNode(Node* p)
954 p->next->prev = p->prev;
955 p->prev->next = p->next;
957 if (p->prevZ) p->prevZ->nextZ = p->nextZ;
958 if (p->nextZ) p->nextZ->prevZ = p->prevZ;
962template <
typename N = u
int32_t,
typename Polygon>
963std::vector<N> earcut(
const Polygon& poly)
965 mapbox::detail::Earcut<N> earcut;
967 return std::move(earcut.indices);
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