27#pragma GCC visibility push(default)
32template <std::
size_t I,
typename T>
struct nth {
33 inline static typename std::tuple_element<I, T>::type
34 get(
const T& t) {
return std::get<I>(t); };
41template <
typename N = u
int32_t>
47 template <
typename Polygon>
52 Node(N index,
double x_,
double y_) :
i(index),
x(x_),
y(y_) {}
77 template <
typename Ring>
Node*
linkedList(
const Ring& points,
const bool clockwise);
89 int32_t
zOrder(
const double x_,
const double y_);
91 bool pointInTriangle(
double ax,
double ay,
double bx,
double by,
double cx,
double cy,
double px,
double py)
const;
100 template <
typename Po
int>
Node*
insertNode(std::size_t i,
const Point& p,
Node* last);
108 template <
typename T,
typename Alloc = std::allocator<T>>
118 template <
typename... Args>
126 alloc_traits::construct(
alloc,
object, std::forward<Args>(args)...);
129 void reset(std::size_t newBlockSize) {
134 blockSize = std::max<std::size_t>(1, newBlockSize);
150template <
typename N>
template <
typename Polygon>
156 if (points.empty())
return;
163 for (
size_t i = 0; threshold >= 0 && i < points.size(); i++) {
164 threshold -=
static_cast<int>(points[i].size());
165 len += points[i].size();
169 nodes.reset(len * 3 / 2);
170 indices.reserve(len + points[0].size());
172 Node* outerNode = linkedList(points[0],
true);
173 if (!outerNode || outerNode->
prev == outerNode->
next)
return;
175 if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
178 hashing = threshold < 0;
181 minX = maxX = outerNode->
x;
182 minY = maxY = outerNode->
y;
186 minX = std::min<double>(minX, x);
187 minY = std::min<double>(minY, y);
188 maxX = std::max<double>(maxX, x);
189 maxY = std::max<double>(maxY, y);
191 }
while (p != outerNode);
194 inv_size = std::max<double>(maxX - minX, maxY - minY);
195 inv_size = inv_size != .0 ? (1. / inv_size) : .0;
198 earcutLinked(outerNode);
204template <
typename N>
template <
typename Ring>
207 using Point =
typename Ring::value_type;
209 const std::size_t len = points.size();
211 Node* last =
nullptr;
214 for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
215 const auto& p1 = points[i];
216 const auto& p2 = points[j];
221 sum += (p20 - p10) * (p11 + p21);
225 if (clockwise == (sum > 0)) {
226 for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
228 for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
231 if (last && equals(last, last->
next)) {
245 if (!end) end = start;
256 if (p == p->
next)
break;
262 }
while (again || p != end);
273 if (!pass && hashing) indexCurve(ear);
284 if (hashing ? isEarHashed(ear) : isEar(ear)) {
286 indices.emplace_back(prev->
i);
287 indices.emplace_back(ear->
i);
288 indices.emplace_back(next->
i);
304 if (!pass) earcutLinked(filterPoints(ear), 1);
307 else if (pass == 1) {
308 ear = cureLocalIntersections(ear);
309 earcutLinked(ear, 2);
312 }
else if (pass == 2) splitEarcut(ear);
326 if (area(a, b, c) >= 0)
return false;
331 while (p != ear->
prev) {
332 if (pointInTriangle(a->
x, a->
y, b->
x, b->
y, c->
x, c->
y, p->
x, p->
y) &&
333 area(p->
prev, p, p->
next) >= 0)
return false;
346 if (area(a, b, c) >= 0)
return false;
349 const double minTX = std::min<double>(a->
x, std::min<double>(b->
x, c->
x));
350 const double minTY = std::min<double>(a->
y, std::min<double>(b->
y, c->
y));
351 const double maxTX = std::max<double>(a->
x, std::max<double>(b->
x, c->
x));
352 const double maxTY = std::max<double>(a->
y, std::max<double>(b->
y, c->
y));
355 const int32_t minZ = zOrder(minTX, minTY);
356 const int32_t maxZ = zOrder(maxTX, maxTY);
361 while (p && p->
z <= maxZ) {
362 if (p != ear->
prev && p != ear->
next &&
363 pointInTriangle(a->
x, a->
y, b->
x, b->
y, c->
x, c->
y, p->
x, p->
y) &&
364 area(p->
prev, p, p->
next) >= 0)
return false;
371 while (p && p->
z >= minZ) {
372 if (p != ear->
prev && p != ear->
next &&
373 pointInTriangle(a->
x, a->
y, b->
x, b->
y, c->
x, c->
y, p->
x, p->
y) &&
374 area(p->
prev, p, p->
next) >= 0)
return false;
391 if (!equals(a, b) && intersects(a, p, p->
next, b) && locallyInside(a, b) && locallyInside(b, a)) {
392 indices.emplace_back(a->
i);
393 indices.emplace_back(p->
i);
394 indices.emplace_back(b->
i);
403 }
while (p != start);
415 while (b != a->
prev) {
416 if (a->
i != b->
i && isValidDiagonal(a, b)) {
418 Node* c = splitPolygon(a, b);
421 a = filterPoints(a, a->
next);
422 c = filterPoints(c, c->
next);
432 }
while (a != start);
436template <
typename N>
template <
typename Polygon>
439 const size_t len = points.size();
441 std::vector<Node*> queue;
442 for (
size_t i = 1; i < len; i++) {
443 Node* list = linkedList(points[i],
false);
446 queue.push_back(getLeftmost(list));
449 std::sort(queue.begin(), queue.end(), [](
const Node* a,
const Node* b) {
454 for (
size_t i = 0; i < queue.size(); i++) {
455 eliminateHole(queue[i], outerNode);
456 outerNode = filterPoints(outerNode, outerNode->
next);
465 outerNode = findHoleBridge(hole, outerNode);
467 Node* b = splitPolygon(outerNode, hole);
468 filterPoints(b, b->
next);
479 double qx = -std::numeric_limits<double>::infinity();
485 if (hy <= p->y && hy >= p->
next->
y && p->
next->
y != p->
y) {
486 double x = p->
x + (hy - p->
y) * (p->
next->
x - p->
x) / (p->
next->
y - p->
y);
487 if (x <= hx && x > qx) {
490 if (hy == p->
y)
return p;
497 }
while (p != outerNode);
501 if (hx == qx)
return m->
prev;
507 const Node* stop = m;
508 double tanMin = std::numeric_limits<double>::infinity();
516 if (hx >= p->
x && p->
x >= mx && hx != p->
x &&
517 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->
x, p->
y)) {
519 tanCur = std::abs(hy - p->
y) / (hx - p->
x);
521 if ((tanCur < tanMin || (tanCur == tanMin && p->
x > m->
x)) && locallyInside(p, hole)) {
540 p->
z = p->
z ? p->
z : zOrder(p->
x, p->
y);
544 }
while (p != start);
562 int i, numMerges, pSize, qSize;
575 for (i = 0; i < inSize; i++) {
583 while (pSize > 0 || (qSize > 0 && q)) {
589 }
else if (qSize == 0 || !q) {
593 }
else if (p->
z <= q->
z) {
603 if (tail) tail->
nextZ = e;
613 tail->
nextZ =
nullptr;
615 if (numMerges <= 1)
return list;
625 int32_t x =
static_cast<int32_t
>(32767.0 * (x_ - minX) * inv_size);
626 int32_t y =
static_cast<int32_t
>(32767.0 * (y_ - minY) * inv_size);
628 x = (x | (x << 8)) & 0x00FF00FF;
629 x = (x | (x << 4)) & 0x0F0F0F0F;
630 x = (x | (x << 2)) & 0x33333333;
631 x = (x | (x << 1)) & 0x55555555;
633 y = (y | (y << 8)) & 0x00FF00FF;
634 y = (y | (y << 4)) & 0x0F0F0F0F;
635 y = (y | (y << 2)) & 0x33333333;
636 y = (y | (y << 1)) & 0x55555555;
646 Node* leftmost = start;
648 if (p->
x < leftmost->
x || (p->
x == leftmost->
x && p->
y < leftmost->
y))
651 }
while (p != start);
659 return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
660 (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
661 (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
667 return a->
next->
i != b->
i && a->
prev->
i != b->
i && !intersectsPolygon(a, b) &&
668 locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
674 return (q->
y - p->
y) * (
r->x - q->
x) - (q->
x - p->
x) * (
r->y - q->
y);
680 return p1->
x == p2->
x && p1->
y == p2->
y;
686 if ((equals(p1, q1) && equals(p2, q2)) ||
687 (equals(p1, q2) && equals(p2, q1)))
return true;
688 return (area(p1, q1, p2) > 0) != (area(p1, q1, q2) > 0) &&
689 (area(p2, q2, p1) > 0) != (area(p2, q2, q1) > 0);
697 if (p->
i != a->
i && p->
next->
i != a->
i && p->
i != b->
i && p->
next->
i != b->
i &&
698 intersects(p, p->
next, a, b))
return true;
708 return area(a->
prev, a, a->
next) < 0 ?
709 area(a, b, a->
next) >= 0 && area(a, a->
prev, b) >= 0 :
710 area(a, b, a->
prev) < 0 || area(a, a->
next, b) < 0;
718 double px = (a->
x + b->
x) / 2;
719 double py = (a->
y + b->
y) / 2;
721 if (((p->
y > py) != (p->
next->
y > py)) && p->
next->
y != p->
y &&
722 (px < (p->
next->
x - p->
x) * (py - p->
y) / (p->
next->
y - p->
y) + p->
x))
736 Node* a2 = nodes.construct(a->
i, a->
x, a->
y);
737 Node* b2 = nodes.construct(b->
i, b->
x, b->
y);
757template <
typename N>
template <
typename Po
int>
786template <
typename N = u
int32_t,
typename Polygon>
787std::vector<N>
earcut(
const Polygon& poly) {
790 return std::move(
earcut.indices);
793#pragma GCC visibility pop
T * construct(Args &&... args)
void reset(std::size_t newBlockSize)
typename std::allocator_traits< Alloc > alloc_traits
ObjectPool(std::size_t blockSize_)
std::vector< T * > allocations
bool isEarHashed(Node *ear)
Node * cureLocalIntersections(Node *start)
Node * eliminateHoles(const Polygon &points, Node *outerNode)
Node * splitPolygon(Node *a, Node *b)
bool middleInside(const Node *a, const Node *b)
double area(const Node *p, const Node *q, const Node *r) const
bool intersectsPolygon(const Node *a, const Node *b)
void eliminateHole(Node *hole, Node *outerNode)
void splitEarcut(Node *start)
Node * sortLinked(Node *list)
void indexCurve(Node *start)
bool isValidDiagonal(Node *a, Node *b)
bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const
bool locallyInside(const Node *a, const Node *b)
void operator()(const Polygon &points)
Node * findHoleBridge(Node *hole, Node *outerNode)
Node * getLeftmost(Node *start)
void earcutLinked(Node *ear, int pass=0)
Node * insertNode(std::size_t i, const Point &p, Node *last)
bool equals(const Node *p1, const Node *p2)
int32_t zOrder(const double x_, const double y_)
bool intersects(const Node *p1, const Node *q1, const Node *p2, const Node *q2)
Node * filterPoints(Node *start, Node *end=nullptr)
Node * linkedList(const Ring &points, const bool clockwise)
std::vector< N > earcut(const Polygon &poly)
Node(const Node &)=delete
Node & operator=(const Node &)=delete
Node & operator=(Node &&)=delete
Node(N index, double x_, double y_)
static std::tuple_element< I, T >::type get(const T &t)