hypertidy / decido

@@ -1,6 +1,3 @@
Loading
1 -
// header earcut.hpp from https://github.com/mapbox/earcut.hpp
2 -
// see file inst/earcut_source/LICENSE
3 -
4 1
#pragma once
5 2
6 3
#include <algorithm>
@@ -9,15 +6,13 @@
Loading
9 6
#include <memory>
10 7
#include <vector>
11 8
12 -
static const double tol = 1.0e-16;
13 -
14 9
namespace mapbox {
15 10
16 11
namespace util {
17 12
18 13
template <std::size_t I, typename T> struct nth {
19 14
    inline static typename std::tuple_element<I, T>::type
20 -
    get(const T& t) { return std::get<I>(t); }
15 +
    get(const T& t) { return std::get<I>(t); };
21 16
};
22 17
23 18
}
@@ -70,6 +65,7 @@
Loading
70 65
    template <typename Polygon> Node* eliminateHoles(const Polygon& points, Node* outerNode);
71 66
    void eliminateHole(Node* hole, Node* outerNode);
72 67
    Node* findHoleBridge(Node* hole, Node* outerNode);
68 +
    bool sectorContainsSector(const Node* m, const Node* p);
73 69
    void indexCurve(Node* start);
74 70
    Node* sortLinked(Node* list);
75 71
    int32_t zOrder(const double x_, const double y_);
@@ -79,6 +75,8 @@
Loading
79 75
    double area(const Node* p, const Node* q, const Node* r) const;
80 76
    bool equals(const Node* p1, const Node* p2);
81 77
    bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2);
78 +
    bool onSegment(const Node* p, const Node* q, const Node* r);
79 +
    int sign(double val);
82 80
    bool intersectsPolygon(const Node* a, const Node* b);
83 81
    bool locallyInside(const Node* a, const Node* b);
84 82
    bool middleInside(const Node* a, const Node* b);
@@ -104,16 +102,18 @@
Loading
104 102
        template <typename... Args>
105 103
        T* construct(Args&&... args) {
106 104
            if (currentIndex >= blockSize) {
107 -
                currentBlock = alloc.allocate(blockSize);
105 +
                currentBlock = alloc_traits::allocate(alloc, blockSize);
108 106
                allocations.emplace_back(currentBlock);
109 107
                currentIndex = 0;
110 108
            }
111 109
            T* object = &currentBlock[currentIndex++];
112 -
            alloc.construct(object, std::forward<Args>(args)...);
110 +
            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
113 111
            return object;
114 112
        }
115 113
        void reset(std::size_t newBlockSize) {
116 -
            for (auto allocation : allocations) alloc.deallocate(allocation, blockSize);
114 +
            for (auto allocation : allocations) {
115 +
                alloc_traits::deallocate(alloc, allocation, blockSize);
116 +
            }
117 117
            allocations.clear();
118 118
            blockSize = std::max<std::size_t>(1, newBlockSize);
119 119
            currentBlock = nullptr;
@@ -126,6 +126,7 @@
Loading
126 126
        std::size_t blockSize = 1;
127 127
        std::vector<T*> allocations;
128 128
        Alloc alloc;
129 +
        typedef typename std::allocator_traits<Alloc> alloc_traits;
129 130
    };
130 131
    ObjectPool<Node> nodes;
131 132
};
@@ -153,7 +154,7 @@
Loading
153 154
    indices.reserve(len + points[0].size());
154 155
155 156
    Node* outerNode = linkedList(points[0], true);
156 -
    if (!outerNode) return;
157 +
    if (!outerNode || outerNode->prev == outerNode->next) return;
157 158
158 159
    if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
159 160
@@ -232,9 +233,7 @@
Loading
232 233
    do {
233 234
        again = false;
234 235
235 -
        //if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
236 -
        if (!p->steiner && (equals(p, p->next) ||
237 -
                    fabs (area(p->prev, p, p->next)) < tol)) {
236 +
        if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
238 237
            removeNode(p);
239 238
            p = end = p->prev;
240 239
@@ -293,7 +292,7 @@
Loading
293 292
294 293
            // if this didn't work, try curing all small self-intersections locally
295 294
            else if (pass == 1) {
296 -
                ear = cureLocalIntersections(ear);
295 +
                ear = cureLocalIntersections(filterPoints(ear));
297 296
                earcutLinked(ear, 2);
298 297
299 298
            // as a last resort, try splitting the remaining polygon into two
@@ -390,7 +389,7 @@
Loading
390 389
        p = p->next;
391 390
    } while (p != start);
392 391
393 -
    return p;
392 +
    return filterPoints(p);
394 393
}
395 394
396 395
// try splitting polygon into two and triangulate them independently
@@ -453,6 +452,9 @@
Loading
453 452
    outerNode = findHoleBridge(hole, outerNode);
454 453
    if (outerNode) {
455 454
        Node* b = splitPolygon(outerNode, hole);
455 +
456 +
        // filter out colinear points around cuts
457 +
        filterPoints(outerNode, outerNode->next);
456 458
        filterPoints(b, b->next);
457 459
    }
458 460
}
@@ -470,18 +472,13 @@
Loading
470 472
    // find a segment intersected by a ray from the hole's leftmost Vertex to the left;
471 473
    // segment's endpoint with lesser x will be potential connection Vertex
472 474
    do {
473 -
        //if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) {
474 -
        if (hy <= p->y && hy >= p->next->y && fabs (p->next->y - p->y) > tol) {
475 +
        if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) {
475 476
          double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y);
476 477
          if (x <= hx && x > qx) {
477 478
            qx = x;
478 -
            //if (x == hx) {
479 -
            //    if (hy == p->y) return p;
480 -
            //    if (hy == p->next->y) return p->next;
481 -
            //}
482 -
            if (fabs (x - hx) < tol) {
483 -
                if (fabs (hy - p->y) < tol) return p;
484 -
                if (fabs (hy - p->next->y) < tol) return p->next;
479 +
            if (x == hx) {
480 +
                if (hy == p->y) return p;
481 +
                if (hy == p->next->y) return p->next;
485 482
            }
486 483
            m = p->x < p->next->x ? p : p->next;
487 484
          }
@@ -489,10 +486,9 @@
Loading
489 486
        p = p->next;
490 487
    } while (p != outerNode);
491 488
492 -
    if (!m) return nullptr;
489 +
    if (!m) return 0;
493 490
494 -
    //if (hx == qx) return m->prev;
495 -
    if (fabs (hx - qx) < tol) return m->prev;
491 +
    if (hx == qx) return m; // hole touches outer segment; pick leftmost endpoint
496 492
497 493
    // look for points inside the triangle of hole Vertex, segment intersection and endpoint;
498 494
    // if there are no points found, we have a valid connection;
@@ -502,30 +498,35 @@
Loading
502 498
    double tanMin = std::numeric_limits<double>::infinity();
503 499
    double tanCur = 0;
504 500
505 -
    p = m->next;
501 +
    p = m;
506 502
    double mx = m->x;
507 503
    double my = m->y;
508 504
509 -
    while (p != stop) {
510 -
        //if (hx >= p->x && p->x >= mx && hx != p->x &&
511 -
        if (hx >= p->x && p->x >= mx && fabs (hx - p->x) > tol &&
505 +
    do {
506 +
        if (hx >= p->x && p->x >= mx && hx != p->x &&
512 507
            pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) {
513 508
514 509
            tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential
515 510
516 -
            //if ((tanCur < tanMin || (tanCur == tanMin && p->x > m->x)) && locallyInside(p, hole)) {
517 -
            if ((tanCur < tanMin || (fabs (tanCur - tanMin) < tol && p->x > m->x)) && locallyInside(p, hole)) {
511 +
            if (locallyInside(p, hole) &&
512 +
                (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) {
518 513
                m = p;
519 514
                tanMin = tanCur;
520 515
            }
521 516
        }
522 517
523 518
        p = p->next;
524 -
    }
519 +
    } while (p != stop);
525 520
526 521
    return m;
527 522
}
528 523
524 +
// whether sector in vertex m contains sector in vertex p in the same coordinates
525 +
template <typename N>
526 +
bool Earcut<N>::sectorContainsSector(const Node* m, const Node* p) {
527 +
    return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0;
528 +
}
529 +
529 530
// interlink polygon nodes in z-order
530 531
template <typename N>
531 532
void Earcut<N>::indexCurve(Node* start) {
@@ -641,7 +642,8 @@
Loading
641 642
    Node* p = start;
642 643
    Node* leftmost = start;
643 644
    do {
644 -
        if (p->x < leftmost->x) leftmost = p;
645 +
        if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y))
646 +
            leftmost = p;
645 647
        p = p->next;
646 648
    } while (p != start);
647 649
@@ -659,8 +661,10 @@
Loading
659 661
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
660 662
template <typename N>
661 663
bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
662 -
    return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) &&
663 -
           locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
664 +
    return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges
665 +
           ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
666 +
            (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors
667 +
            (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case
664 668
}
665 669
666 670
// signed area of a triangle
@@ -672,17 +676,39 @@
Loading
672 676
// check if two points are equal
673 677
template <typename N>
674 678
bool Earcut<N>::equals(const Node* p1, const Node* p2) {
675 -
    //return p1->x == p2->x && p1->y == p2->y;
676 -
    return (fabs (p1->x - p2->x) < tol && fabs (p1->y - p2->y) < tol);
679 +
    return p1->x == p2->x && p1->y == p2->y;
677 680
}
678 681
679 682
// check if two segments intersect
680 683
template <typename N>
681 684
bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
682 -
    if ((equals(p1, q1) && equals(p2, q2)) ||
683 -
        (equals(p1, q2) && equals(p2, q1))) return true;
684 -
    return (area(p1, q1, p2) > 0) != (area(p1, q1, q2) > 0) &&
685 -
           (area(p2, q2, p1) > 0) != (area(p2, q2, q1) > 0);
685 +
    int o1 = sign(area(p1, q1, p2));
686 +
    int o2 = sign(area(p1, q1, q2));
687 +
    int o3 = sign(area(p2, q2, p1));
688 +
    int o4 = sign(area(p2, q2, q1));
689 +
690 +
    if (o1 != o2 && o3 != o4) return true; // general case
691 +
692 +
    if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
693 +
    if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
694 +
    if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
695 +
    if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
696 +
697 +
    return false;
698 +
}
699 +
700 +
// for collinear points p, q, r, check if point q lies on segment pr
701 +
template <typename N>
702 +
bool Earcut<N>::onSegment(const Node* p, const Node* q, const Node* r) {
703 +
    return q->x <= std::max<double>(p->x, r->x) &&
704 +
        q->x >= std::min<double>(p->x, r->x) &&
705 +
        q->y <= std::max<double>(p->y, r->y) &&
706 +
        q->y >= std::min<double>(p->y, r->y);
707 +
}
708 +
709 +
template <typename N>
710 +
int Earcut<N>::sign(double val) {
711 +
    return (0.0 < val) - (val < 0.0);
686 712
}
687 713
688 714
// check if a polygon diagonal intersects any polygon segments
@@ -714,9 +740,7 @@
Loading
714 740
    double px = (a->x + b->x) / 2;
715 741
    double py = (a->y + b->y) / 2;
716 742
    do {
717 -
        //if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
718 -
        if (((p->y > py) != (p->next->y > py)) &&
719 -
                fabs (p->next->y - p->y) > tol &&
743 +
        if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
720 744
                (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
721 745
            inside = !inside;
722 746
        p = p->next;
@@ -783,7 +807,6 @@
Loading
783 807
784 808
template <typename N = uint32_t, typename Polygon>
785 809
std::vector<N> earcut(const Polygon& poly) {
786 -
787 810
    mapbox::detail::Earcut<N> earcut;
788 811
    earcut(poly);
789 812
    return std::move(earcut.indices);
Files Coverage
inst/include 79.61%
R/earcut.R 100.00%
src/decido.cpp 100.00%
Project Totals (4 files) 81.09%
1
comment: false
2

3
coverage:
4
  status:
5
    project:
6
      default:
7
        target: auto
8
        threshold: 1%
9
    patch:
10
      default:
11
        target: auto
12
        threshold: 1%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading