LCOV - code coverage report
Current view: top level - app/libs/earcut.hpp/include/mapbox - earcut.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 360 0.0 %
Date: 2023-08-17 16:45:52 Functions: 0 28 0.0 %

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

Generated by: LCOV version 1.14