From 553d82c2beead82beee59b85b6ea7d55cbc27c22 Mon Sep 17 00:00:00 2001 From: c0rp3n Date: Wed, 8 Jul 2020 15:33:19 +0100 Subject: [PATCH 1/6] Add support to switch to using single precision instead of double ... precision floating point values in delaunator. This allows the user to define DELAUNATOR_SINGLE_PRECISION to toggle the usage of single precision floating point values. Further had to include the header `cassert` in order for this to compile on MSVC 19.26.28806 --- include/delaunator.cpp | 255 +++++++++++++++++++++-------------------- include/delaunator.hpp | 40 ++++--- 2 files changed, 151 insertions(+), 144 deletions(-) diff --git a/include/delaunator.cpp b/include/delaunator.cpp index ce54ffa..ea80c60 100644 --- a/include/delaunator.cpp +++ b/include/delaunator.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -19,37 +20,37 @@ inline size_t fast_mod(const size_t i, const size_t c) { } // Kahan and Babuska summation, Neumaier variant; accumulates less FP error -inline double sum(const std::vector& x) { - double sum = x[0]; - double err = 0.0; +inline dfloat sum(const std::vector& x) { + dfloat sum = x[0]; + dfloat err = 0.0; for (size_t i = 1; i < x.size(); i++) { - const double k = x[i]; - const double m = sum + k; + const dfloat k = x[i]; + const dfloat m = sum + k; err += std::fabs(sum) >= std::fabs(k) ? sum - m + k : k - m + sum; sum = m; } return sum + err; } -inline double dist( - const double ax, - const double ay, - const double bx, - const double by) { - const double dx = ax - bx; - const double dy = ay - by; +inline dfloat dist( + const dfloat ax, + const dfloat ay, + const dfloat bx, + const dfloat by) { + const dfloat dx = ax - bx; + const dfloat dy = ay - by; return dx * dx + dy * dy; } -inline double circumradius(const Point& p1, const Point& p2, const Point& p3) +inline dfloat circumradius(const Point& p1, const Point& p2, const Point& p3) { Point d = Point::vector(p1, p2); Point e = Point::vector(p1, p3); - const double bl = d.magnitude2(); - const double cl = e.magnitude2(); - const double det = Point::determinant(d, e); + const dfloat bl = d.magnitude2(); + const dfloat cl = e.magnitude2(); + const dfloat det = Point::determinant(d, e); Point radius((e.y() * bl - d.y() * cl) * 0.5 / det, (d.x() * cl - e.x() * bl) * 0.5 / det); @@ -58,32 +59,32 @@ inline double circumradius(const Point& p1, const Point& p2, const Point& p3) (cl > 0.0 || cl < 0.0) && (det > 0.0 || det < 0.0)) return radius.magnitude2(); - return (std::numeric_limits::max)(); + return (std::numeric_limits::max)(); } -inline double circumradius( - const double ax, - const double ay, - const double bx, - const double by, - const double cx, - const double cy) { - const double dx = bx - ax; - const double dy = by - ay; - const double ex = cx - ax; - const double ey = cy - ay; - - const double bl = dx * dx + dy * dy; - const double cl = ex * ex + ey * ey; - const double d = dx * ey - dy * ex; - - const double x = (ey * bl - dy * cl) * 0.5 / d; - const double y = (dx * cl - ex * bl) * 0.5 / d; +inline dfloat circumradius( + const dfloat ax, + const dfloat ay, + const dfloat bx, + const dfloat by, + const dfloat cx, + const dfloat cy) { + const dfloat dx = bx - ax; + const dfloat dy = by - ay; + const dfloat ex = cx - ax; + const dfloat ey = cy - ay; + + const dfloat bl = dx * dx + dy * dy; + const dfloat cl = ex * ex + ey * ey; + const dfloat d = dx * ey - dy * ex; + + const dfloat x = (ey * bl - dy * cl) * 0.5 / d; + const dfloat y = (dx * cl - ex * bl) * 0.5 / d; if ((bl > 0.0 || bl < 0.0) && (cl > 0.0 || cl < 0.0) && (d > 0.0 || d < 0.0)) { return x * x + y * y; } else { - return (std::numeric_limits::max)(); + return (std::numeric_limits::max)(); } } @@ -91,21 +92,21 @@ inline bool clockwise(const Point& p0, const Point& p1, const Point& p2) { Point v0 = Point::vector(p0, p1); Point v1 = Point::vector(p0, p2); - double det = Point::determinant(v0, v1); - double dist = v0.magnitude2() + v1.magnitude2(); - double dist2 = Point::dist2(v0, v1); + dfloat det = Point::determinant(v0, v1); + dfloat dist = v0.magnitude2() + v1.magnitude2(); + dfloat dist2 = Point::dist2(v0, v1); if (det == 0) { return false; } - double reldet = std::abs(dist / det); + dfloat reldet = std::abs(dist / det); if (reldet > 1e14) return false; return det < 0; } -inline bool clockwise(double px, double py, double qx, double qy, - double rx, double ry) +inline bool clockwise(dfloat px, dfloat py, dfloat qx, dfloat qy, + dfloat rx, dfloat ry) { Point p0(px, py); Point p1(qx, qy); @@ -117,19 +118,19 @@ inline bool counterclockwise(const Point& p0, const Point& p1, const Point& p2) { Point v0 = Point::vector(p0, p1); Point v1 = Point::vector(p0, p2); - double det = Point::determinant(v0, v1); - double dist = v0.magnitude2() + v1.magnitude2(); - double dist2 = Point::dist2(v0, v1); + dfloat det = Point::determinant(v0, v1); + dfloat dist = v0.magnitude2() + v1.magnitude2(); + dfloat dist2 = Point::dist2(v0, v1); if (det == 0) return false; - double reldet = std::abs(dist / det); + dfloat reldet = std::abs(dist / det); if (reldet > 1e14) return false; return det > 0; } -inline bool counterclockwise(double px, double py, double qx, double qy, - double rx, double ry) +inline bool counterclockwise(dfloat px, dfloat py, dfloat qx, dfloat qy, + dfloat rx, dfloat ry) { Point p0(px, py); Point p1(qx, qy); @@ -139,68 +140,68 @@ inline bool counterclockwise(double px, double py, double qx, double qy, inline Point circumcenter( - const double ax, - const double ay, - const double bx, - const double by, - const double cx, - const double cy) { - const double dx = bx - ax; - const double dy = by - ay; - const double ex = cx - ax; - const double ey = cy - ay; - - const double bl = dx * dx + dy * dy; - const double cl = ex * ex + ey * ey; + const dfloat ax, + const dfloat ay, + const dfloat bx, + const dfloat by, + const dfloat cx, + const dfloat cy) { + const dfloat dx = bx - ax; + const dfloat dy = by - ay; + const dfloat ex = cx - ax; + const dfloat ey = cy - ay; + + const dfloat bl = dx * dx + dy * dy; + const dfloat cl = ex * ex + ey * ey; //ABELL - This is suspect for div-by-0. - const double d = dx * ey - dy * ex; + const dfloat d = dx * ey - dy * ex; - const double x = ax + (ey * bl - dy * cl) * 0.5 / d; - const double y = ay + (dx * cl - ex * bl) * 0.5 / d; + const dfloat x = ax + (ey * bl - dy * cl) * 0.5 / d; + const dfloat y = ay + (dx * cl - ex * bl) * 0.5 / d; return Point(x, y); } inline bool in_circle( - const double ax, - const double ay, - const double bx, - const double by, - const double cx, - const double cy, - const double px, - const double py) { - const double dx = ax - px; - const double dy = ay - py; - const double ex = bx - px; - const double ey = by - py; - const double fx = cx - px; - const double fy = cy - py; - - const double ap = dx * dx + dy * dy; - const double bp = ex * ex + ey * ey; - const double cp = fx * fx + fy * fy; + const dfloat ax, + const dfloat ay, + const dfloat bx, + const dfloat by, + const dfloat cx, + const dfloat cy, + const dfloat px, + const dfloat py) { + const dfloat dx = ax - px; + const dfloat dy = ay - py; + const dfloat ex = bx - px; + const dfloat ey = by - py; + const dfloat fx = cx - px; + const dfloat fy = cy - py; + + const dfloat ap = dx * dx + dy * dy; + const dfloat bp = ex * ex + ey * ey; + const dfloat cp = fx * fx + fy * fy; return (dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx)) < 0.0; } -constexpr double EPSILON = std::numeric_limits::epsilon(); +constexpr dfloat EPSILON = std::numeric_limits::epsilon(); -inline bool check_pts_equal(double x1, double y1, double x2, double y2) { +inline bool check_pts_equal(dfloat x1, dfloat y1, dfloat x2, dfloat y2) { return std::fabs(x1 - x2) <= EPSILON && std::fabs(y1 - y2) <= EPSILON; } // monotonically increases with real angle, but doesn't need expensive trigonometry -inline double pseudo_angle(const double dx, const double dy) { - const double p = dx / (std::abs(dx) + std::abs(dy)); +inline dfloat pseudo_angle(const dfloat dx, const dfloat dy) { + const dfloat p = dx / (std::abs(dx) + std::abs(dy)); return (dy > 0.0 ? 3.0 - p : 1.0 + p) / 4.0; // [0..1) } -Delaunator::Delaunator(std::vector const& in_coords) +Delaunator::Delaunator(std::vector const& in_coords) : coords(in_coords), m_points(in_coords) { std::size_t n = coords.size() >> 1; @@ -208,10 +209,10 @@ Delaunator::Delaunator(std::vector const& in_coords) std::vector ids(n); std::iota(ids.begin(), ids.end(), 0); - double max_x = std::numeric_limits::lowest(); - double max_y = std::numeric_limits::lowest(); - double min_x = (std::numeric_limits::max)(); - double min_y = (std::numeric_limits::max)(); + dfloat max_x = std::numeric_limits::lowest(); + dfloat max_y = std::numeric_limits::lowest(); + dfloat min_x = (std::numeric_limits::max)(); + dfloat min_y = (std::numeric_limits::max)(); for (const Point& p : m_points) { min_x = std::min(p.x(), min_x); @@ -219,9 +220,9 @@ Delaunator::Delaunator(std::vector const& in_coords) max_x = std::max(p.x(), max_x); max_y = std::max(p.y(), max_y); } - double width = max_x - min_x; - double height = max_y - min_y; - double span = width * width + height * height; // Everything is square dist. + dfloat width = max_x - min_x; + dfloat height = max_y - min_y; + dfloat span = width * width + height * height; // Everything is square dist. Point center((min_x + max_x) / 2, (min_y + max_y) / 2); @@ -230,11 +231,11 @@ Delaunator::Delaunator(std::vector const& in_coords) std::size_t i2 = INVALID_INDEX; // pick a seed point close to the centroid - double min_dist = (std::numeric_limits::max)(); + dfloat min_dist = (std::numeric_limits::max)(); for (size_t i = 0; i < m_points.size(); ++i) { const Point& p = m_points[i]; - const double d = Point::dist2(center, p); + const dfloat d = Point::dist2(center, p); if (d < min_dist) { i0 = i; min_dist = d; @@ -243,12 +244,12 @@ Delaunator::Delaunator(std::vector const& in_coords) const Point& p0 = m_points[i0]; - min_dist = (std::numeric_limits::max)(); + min_dist = (std::numeric_limits::max)(); // find the point closest to the seed for (std::size_t i = 0; i < n; i++) { if (i == i0) continue; - const double d = Point::dist2(p0, m_points[i]); + const dfloat d = Point::dist2(p0, m_points[i]); if (d < min_dist && d > 0.0) { i1 = i; min_dist = d; @@ -257,21 +258,21 @@ Delaunator::Delaunator(std::vector const& in_coords) const Point& p1 = m_points[i1]; - double min_radius = (std::numeric_limits::max)(); + dfloat min_radius = (std::numeric_limits::max)(); // find the third point which forms the smallest circumcircle // with the first two for (std::size_t i = 0; i < n; i++) { if (i == i0 || i == i1) continue; - const double r = circumradius(p0, p1, m_points[i]); + const dfloat r = circumradius(p0, p1, m_points[i]); if (r < min_radius) { i2 = i; min_radius = r; } } - if (!(min_radius < (std::numeric_limits::max)())) { + if (!(min_radius < (std::numeric_limits::max)())) { throw std::runtime_error("not triangulation"); } @@ -280,12 +281,12 @@ Delaunator::Delaunator(std::vector const& in_coords) if (counterclockwise(p0, p1, p2)) std::swap(i1, i2); - double i0x = p0.x(); - double i0y = p0.y(); - double i1x = m_points[i1].x(); - double i1y = m_points[i1].y(); - double i2x = m_points[i2].x(); - double i2y = m_points[i2].y(); + dfloat i0x = p0.x(); + dfloat i0y = p0.y(); + dfloat i1x = m_points[i1].x(); + dfloat i1y = m_points[i1].y(); + dfloat i2x = m_points[i2].x(); + dfloat i2y = m_points[i2].y(); m_center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y); @@ -294,7 +295,7 @@ Delaunator::Delaunator(std::vector const& in_coords) // but GCC 7.5+ would copy the comparator to iterators used in the // sort, and this was excruciatingly slow when there were many points // because you had to copy the vector of distances. - std::vector dists; + std::vector dists; dists.reserve(m_points.size()); for (const Point& p : m_points) dists.push_back(dist(p.x(), p.y(), m_center.x(), m_center.y())); @@ -337,14 +338,14 @@ Delaunator::Delaunator(std::vector const& in_coords) triangles.reserve(max_triangles * 3); halfedges.reserve(max_triangles * 3); add_triangle(i0, i1, i2, INVALID_INDEX, INVALID_INDEX, INVALID_INDEX); - double xp = std::numeric_limits::quiet_NaN(); - double yp = std::numeric_limits::quiet_NaN(); + dfloat xp = std::numeric_limits::quiet_NaN(); + dfloat yp = std::numeric_limits::quiet_NaN(); // Go through points based on distance from the center. for (std::size_t k = 0; k < n; k++) { const std::size_t i = ids[k]; - const double x = coords[2 * i]; - const double y = coords[2 * i + 1]; + const dfloat x = coords[2 * i]; + const dfloat y = coords[2 * i + 1]; // skip near-duplicate points if (k > 0 && check_pts_equal(x, y, xp, yp)) @@ -467,9 +468,9 @@ Delaunator::Delaunator(std::vector const& in_coords) } } -double Delaunator::get_hull_area() +dfloat Delaunator::get_hull_area() { - std::vector hull_area; + std::vector hull_area; size_t e = hull_start; size_t cnt = 1; do { @@ -481,18 +482,18 @@ double Delaunator::get_hull_area() return sum(hull_area); } -double Delaunator::get_triangle_area() +dfloat Delaunator::get_triangle_area() { - std::vector vals; + std::vector vals; for (size_t i = 0; i < triangles.size(); i += 3) { - const double ax = coords[2 * triangles[i]]; - const double ay = coords[2 * triangles[i] + 1]; - const double bx = coords[2 * triangles[i + 1]]; - const double by = coords[2 * triangles[i + 1] + 1]; - const double cx = coords[2 * triangles[i + 2]]; - const double cy = coords[2 * triangles[i + 2] + 1]; - double val = std::fabs((by - ay) * (cx - bx) - (bx - ax) * (cy - by)); + const dfloat ax = coords[2 * triangles[i]]; + const dfloat ay = coords[2 * triangles[i] + 1]; + const dfloat bx = coords[2 * triangles[i + 1]]; + const dfloat by = coords[2 * triangles[i + 1] + 1]; + const dfloat cx = coords[2 * triangles[i + 2]]; + const dfloat cy = coords[2 * triangles[i + 2] + 1]; + dfloat val = std::fabs((by - ay) * (cx - bx) - (bx - ax) * (cy - by)); vals.push_back(val); } return sum(vals); @@ -598,11 +599,11 @@ std::size_t Delaunator::legalize(std::size_t a) { return ar; } -std::size_t Delaunator::hash_key(const double x, const double y) const { - const double dx = x - m_center.x(); - const double dy = y - m_center.y(); +std::size_t Delaunator::hash_key(const dfloat x, const dfloat y) const { + const dfloat dx = x - m_center.x(); + const dfloat dy = y - m_center.y(); return fast_mod( - static_cast(std::llround(std::floor(pseudo_angle(dx, dy) * static_cast(m_hash_size)))), + static_cast(std::llround(std::floor(pseudo_angle(dx, dy) * static_cast(m_hash_size)))), m_hash_size); } diff --git a/include/delaunator.hpp b/include/delaunator.hpp index 854263f..a252112 100644 --- a/include/delaunator.hpp +++ b/include/delaunator.hpp @@ -6,6 +6,12 @@ #define INLINE #endif +#ifdef DELAUNATOR_SINGLE_PRECISION +typedef float dfloat; +#else +typedef double dfloat; +#endif + #include #include #include @@ -18,21 +24,21 @@ constexpr std::size_t INVALID_INDEX = class Point { public: - Point(double x, double y) : m_x(x), m_y(y) + Point(dfloat x, dfloat y) : m_x(x), m_y(y) {} Point() : m_x(0), m_y(0) {} - double x() const + dfloat x() const { return m_x; } - double y() const + dfloat y() const { return m_y; } - double magnitude2() const + dfloat magnitude2() const { return m_x * m_x + m_y * m_y; } - static double determinant(const Point& p1, const Point& p2) + static dfloat determinant(const Point& p1, const Point& p2) { return p1.m_x * p2.m_y - p1.m_y * p2.m_x; } @@ -42,15 +48,15 @@ class Point return Point(p2.m_x - p1.m_x, p2.m_y - p1.m_y); } - static double dist2(const Point& p1, const Point& p2) + static dfloat dist2(const Point& p1, const Point& p2) { Point vec = vector(p1, p2); return vec.m_x * vec.m_x + vec.m_y * vec.m_y; } - static bool equal(const Point& p1, const Point& p2, double span) + static bool equal(const Point& p1, const Point& p2, dfloat span) { - double dist = dist2(p1, p2) / span; + dfloat dist = dist2(p1, p2) / span; // ABELL - This number should be examined to figure how how // it correlates with the breakdown of calculating determinants. @@ -58,8 +64,8 @@ class Point } private: - double m_x; - double m_y; + dfloat m_x; + dfloat m_y; }; inline std::ostream& operator<<(std::ostream& out, const Point& p) @@ -74,7 +80,7 @@ class Points public: using const_iterator = Point const *; - Points(const std::vector& coords) : m_coords(coords) + Points(const std::vector& coords) : m_coords(coords) {} const Point& operator[](size_t offset) @@ -92,13 +98,13 @@ class Points { return m_coords.size() / 2; } private: - const std::vector& m_coords; + const std::vector& m_coords; }; class Delaunator { public: - std::vector const& coords; + std::vector const& coords; Points m_points; // 'triangles' stores the indices to the 'X's of the input @@ -120,9 +126,9 @@ class Delaunator { std::vector hull_tri; std::size_t hull_start; - INLINE Delaunator(std::vector const& in_coords); - INLINE double get_hull_area(); - INLINE double get_triangle_area(); + INLINE Delaunator(std::vector const& in_coords); + INLINE dfloat get_hull_area(); + INLINE dfloat get_triangle_area(); private: std::vector m_hash; @@ -131,7 +137,7 @@ class Delaunator { std::vector m_edge_stack; INLINE std::size_t legalize(std::size_t a); - INLINE std::size_t hash_key(double x, double y) const; + INLINE std::size_t hash_key(dfloat x, dfloat y) const; INLINE std::size_t add_triangle( std::size_t i0, std::size_t i1, From 5a08e9b8de440b542603f95bb5275287c1b7eb54 Mon Sep 17 00:00:00 2001 From: c0rp3n Date: Wed, 8 Jul 2020 15:43:11 +0100 Subject: [PATCH 2/6] Add base test support This is more of a hack to check run the tests with float's instead of double's, really need to added a config header to handle this instead of passing a public define to the target. Currently 3 fail due to precision errors. --- CMakeLists.txt | 4 ++++ cmake/options.cmake | 2 ++ test/delaunator.test.cpp | 28 ++++++++++++++-------------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96b38de..c9f4840 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${D_BIN_DIR}) add_library(delaunator include/delaunator.cpp) d_target_compile_settings(delaunator) +if (DELAUNATOR_SINGLE_PRECISION) + target_compile_definitions(delaunator PUBLIC DELAUNATOR_SINGLE_PRECISION) +endif() + add_subdirectory(test) #examples diff --git a/cmake/options.cmake b/cmake/options.cmake index 0f8c76e..a259dda 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -1,3 +1,5 @@ option(WITH_TESTS "Choose if delaunator tests should be built" TRUE) add_feature_info("Unit tests" WITH_TESTS "Delaunator unit tests") + +option(DELAUNATOR_SINGLE_PRECISION "Whether to use single precision floating point values." OFF) diff --git a/test/delaunator.test.cpp b/test/delaunator.test.cpp index 9dbe829..f27a188 100644 --- a/test/delaunator.test.cpp +++ b/test/delaunator.test.cpp @@ -12,7 +12,7 @@ namespace { // ABELL - This isn't a sufficient test. We need to verify against known // good results. We should at least make sure we're getting the right // number of triangles out. -inline void validate(const std::vector& coords) { +inline void validate(const std::vector& coords) { delaunator::Delaunator d(coords); // validate halfedges @@ -54,23 +54,25 @@ TEST(Delaunator, "triangles match JS version ouput") TEST(Delaunator, correct) { - std::vector coords = { 168, 180, 168, 178, 168, 179, 168, 181, 168, 183, 167, 183, 167, 184, 165, 184, 162, 186, 164, 188, 161, 188, 160, 191, 158, 193, 156, 193, 152, 195, 152, 198, 150, 198, 147, 198, 148, 205, 150, 210, 148, 210, 148, 208, 145, 206, 142, 206, 140, 206, 138, 206, 135, 206, 135, 209, 131, 209, 131, 211, 127, 211, 124, 210, 120, 207, 120, 204, 120, 202, 124, 201, 123, 201, 125, 198, 125, 194, 127, 194, 127, 191, 130, 191, 132, 189, 134, 189, 134, 186, 136, 184, 134, 182, 134, 179, 134, 176, 136, 174, 139, 174, 141, 177, 142, 176, 144, 176, 147, 178, 148, 176, 151, 178, 154, 178, 153, 175, 152, 174, 152, 170, 152, 168, 150, 166, 148, 166, 147, 165, 145, 162, 146, 160, 146, 157, 146, 155, 144, 155, 142, 152, 140, 150, 138, 150, 138, 148, 140, 145, 140, 142, 140, 138, 139, 138, 137, 138, 135, 138, 133, 135, 132, 132, 129, 132, 128, 132, 124, 132, 124, 130, 123, 130, 118, 126, 116, 124, 112, 122, 109, 122, 105, 122, 102, 124, 100, 124, 97, 124, 95, 126, 92, 127, 89, 127, 88, 130, 85, 132, 80, 134, 72, 134, 69, 134, 65, 138, 64, 138, 58, 137, 56, 133, 52, 133, 51, 133, 48, 133, 44, 133, 41, 131, 38, 130, 35, 130, 32, 127, 30, 127, 27, 127, 24, 127, 24, 126, 23, 124, 20, 122, 17, 122, 16, 118, 15, 116, 15, 110, 18, 108, 20, 102, 24, 97, 28, 102, 28, 98, 26, 97, 28, 94, 27, 85, 29, 79, 32, 76, 39, 70, 44, 66, 48, 65, 53, 61, 53, 58, 51, 54, 54, 54, 52, 48, 51, 43, 48, 42, 49, 38, 48, 34, 51, 30, 53, 33, 58, 30, 61, 30, 60, 27, 64, 26, 68, 24, 74, 24, 80, 24, 85, 26, 92, 26, 96, 29, 103, 32, 109, 33, 112, 37, 116, 37, 120, 37, 124, 35, 126, 35, 128, 38, 132, 38, 134, 41, 138, 38, 140, 36, 142, 40, 144, 43, 145, 41, 149, 41, 155, 41, 159, 41, 161, 46, 165, 46, 164, 42, 164, 39, 164, 34, 167, 30, 173, 24, 178, 24, 184, 24, 189, 26, 195, 21, 195, 20, 199, 20, 203, 20, 207, 17, 211, 17, 216, 17, 218, 16, 222, 22, 225, 27, 228, 31, 226, 34, 224, 34, 226, 39, 228, 43, 230, 46, 236, 46, 242, 46, 243, 50, 245, 50, 247, 54, 247, 56, 248, 60, 248, 65, 253, 66, 255, 64, 260, 64, 264, 67, 268, 71, 272, 66, 275, 66, 281, 61, 285, 66, 286, 70, 292, 74, 294, 74, 296, 74, 296, 71, 301, 74, 307, 74, 311, 78, 315, 74, 315, 77, 319, 77, 322, 82, 328, 82, 331, 81, 331, 84, 333, 86, 333, 90, 330, 95, 326, 98, 328, 99, 332, 98, 333, 101, 331, 104, 329, 104, 327, 106, 329, 111, 332, 116, 333, 119, 333, 122, 332, 126, 332, 130, 327, 130, 321, 130, 317, 130, 315, 134, 312, 134, 308, 138, 306, 138, 306, 144, 306, 149, 306, 152, 301, 152, 297, 154, 295, 154, 292, 154, 292, 158, 288, 158, 283, 162, 281, 164, 279, 163, 276, 163, 273, 166, 272, 169, 268, 168, 265, 170, 260, 172, 256, 176, 252, 176, 248, 181, 246, 182, 246, 189, 246, 194, 248, 197, 250, 198, 252, 200, 252, 203, 254, 205, 260, 205, 264, 202, 267, 202, 269, 202, 272, 199, 280, 199, 278, 202, 278, 207, 278, 211, 276, 211, 272, 213, 268, 213, 265, 213, 264, 211, 262, 210, 260, 210, 257, 212, 257, 214, 255, 217, 253, 217, 253, 221, 249, 220, 247, 220, 243, 222, 240, 223, 239, 226, 234, 231, 229, 231, 224, 231, 219, 227, 220, 227, 222, 224, 222, 222, 222, 219, 224, 217, 222, 214, 220, 212, 217, 210, 215, 210, 211, 209, 208, 206, 202, 209, 202, 205, 206, 202, 211, 198, 216, 195, 220, 192, 224, 192, 221, 186, 218, 186, 214, 185, 208, 185, 204, 186, 200, 186, 193, 183, 190, 182, 188, 182, 190, 178, 186, 178, 184, 174, 182, 171, 178, 171, 173, 174, 169, 174, 169, 175, 169, 179, 167, 182, 164, 186, 160, 192, 155, 195, 152, 198, 150, 198, 148, 198, 148, 202, 151, 208, 148, 210, 146, 208, 144, 205, 140, 205, 137, 208, 132, 208, 132, 210, 127, 210, 124, 210, 120, 206, 120, 202, 123, 202, 124, 201, 124, 198, 128, 195, 131, 191, 133, 187, 135, 183, 130, 203, 129, 208, 123, 203, 129, 203, 129, 198, 133, 198, 136, 200, 142, 200, 143, 199, 143, 197, 137, 196, 136, 194, 133, 194, 136, 186, 136, 182, 141, 186, 144, 186, 150, 186, 150, 190, 155, 190, 159, 188, 156, 182, 151, 182, 144, 182, 164, 176, 161, 177, 157, 177, 166, 176, 168, 165, 175, 167, 180, 167, 188, 159, 195, 164, 195, 162, 187, 162, 178, 163, 173, 166, 168, 170, 156, 170, 157, 165, 164, 165, 164, 161, 170, 159, 167, 158, 159, 154, 149, 151, 145, 145, 145, 138, 152, 138, 152, 146, 159, 146, 165, 153, 176, 153, 180, 153, 187, 153, 194, 153, 202, 153, 202, 158, 197, 158, 193, 158, 193, 142, 180, 142, 171, 142, 163, 135, 176, 135, 186, 139, 201, 139, 206, 139, 205, 147, 205, 160, 198, 160, 206, 174, 205, 178, 196, 178, 196, 182, 202, 182, 206, 181, 209, 181, 215, 181, 222, 181, 230, 177, 238, 175, 241, 175, 237, 175, 237, 168, 237, 161, 232, 156, 231, 162, 225, 166, 217, 169, 210, 173, 224, 173, 227, 173, 235, 175, 237, 178, 228, 192, 222, 199, 216, 199, 211, 204, 205, 206, 219, 207, 222, 211, 229, 214, 236, 214, 244, 211, 247, 211, 268, 206, 277, 201, 279, 201, 281, 202, 278, 202, 242, 178, 236, 170, 236, 162, 255, 162, 251, 156, 240, 156, 253, 152, 261, 152, 277, 157, 268, 151, 255, 143, 260, 142, 267, 145, 271, 149, 273, 154, 258, 146, 257, 131, 256, 134, 248, 137, 260, 137, 260, 134, 271, 137, 276, 138, 276, 144, 289, 144, 285, 150, 294, 150, 298, 149, 301, 145, 292, 145, 282, 134, 276, 134, 283, 127, 282, 116, 277, 113, 283, 113, 288, 106, 296, 106, 297, 113, 297, 118, 298, 118, 310, 122, 310, 128, 300, 130, 300, 140, 292, 129, 292, 114, 283, 122, 289, 122, 299, 122, 299, 134, 294, 134, 288, 124, 314, 121, 311, 113, 308, 110, 304, 96, 299, 90, 299, 82, 305, 87, 309, 94, 311, 101, 312, 102, 314, 107, 320, 112, 320, 115, 326, 116, 323, 109, 321, 102, 321, 94, 321, 90, 328, 90, 328, 88, 316, 88, 316, 84, 307, 84, 290, 77, 289, 88, 289, 97, 278, 97, 268, 106, 268, 110, 261, 105, 255, 103, 244, 103, 252, 100, 252, 91, 252, 82, 242, 78, 252, 78, 259, 78, 264, 87, 267, 92, 272, 91, 272, 83, 264, 83, 260, 79, 276, 79, 283, 84, 283, 94, 289, 94, 284, 86, 272, 77, 253, 110, 248, 110, 239, 110, 234, 114, 222, 125, 219, 127, 219, 131, 219, 138, 219, 141, 224, 139, 224, 135, 225, 130, 232, 136, 240, 138, 237, 131, 237, 118, 248, 120, 256, 122, 262, 127, 255, 118, 245, 110, 207, 129, 199, 134, 195, 134, 188, 130, 180, 130, 165, 129, 156, 129, 165, 128, 173, 125, 185, 126, 193, 126, 201, 124, 204, 123, 208, 116, 214, 114, 207, 114, 196, 114, 183, 121, 183, 111, 189, 117, 196, 112, 172, 126, 164, 126, 159, 114, 174, 106, 186, 106, 192, 105, 184, 105, 184, 96, 173, 96, 163, 111, 159, 110, 152, 110, 168, 110, 171, 106, 183, 98, 193, 101, 219, 96, 225, 97, 225, 104, 232, 92, 240, 92, 237, 86, 229, 86, 216, 88, 214, 79, 203, 79, 203, 75, 212, 75, 221, 75, 229, 80, 230, 89, 217, 88, 217, 77, 228, 77, 228, 69, 235, 71, 240, 71, 244, 66, 236, 54, 236, 62, 232, 68, 229, 61, 216, 61, 212, 58, 212, 47, 212, 39, 214, 28, 215, 48, 225, 55, 236, 55, 202, 65, 202, 54, 202, 44, 202, 24, 198, 32, 199, 38, 192, 38, 185, 38, 174, 42, 174, 48, 178, 51, 184, 51, 194, 55, 191, 68, 182, 68, 174, 69, 167, 67, 153, 59, 153, 49, 147, 49, 152, 58, 152, 74, 154, 83, 161, 83, 165, 88, 153, 97, 153, 89, 152, 82, 168, 88, 168, 101, 156, 102, 156, 119, 173, 110, 184, 110, 177, 106, 160, 106, 145, 125, 137, 122, 131, 120, 124, 120, 122, 118, 113, 118, 114, 111, 129, 111, 140, 110, 143, 106, 137, 102, 127, 102, 119, 98, 126, 93, 139, 93, 139, 99, 141, 95, 128, 89, 118, 74, 128, 76, 135, 76, 141, 83, 141, 71, 137, 61, 137, 50, 129, 50, 118, 50, 109, 52, 112, 61, 123, 60, 134, 60, 129, 76, 121, 67, 124, 76, 123, 76, 111, 74, 128, 73, 109, 83, 109, 94, 105, 103, 102, 118, 92, 113, 98, 105, 99, 93, 94, 93, 94, 81, 99, 81, 100, 73, 100, 89, 100, 60, 100, 55, 105, 37, 101, 34, 93, 37, 90, 37, 90, 49, 99, 49, 88, 68, 80, 68, 78, 64, 88, 62, 86, 77, 76, 89, 71, 91, 71, 106, 78, 106, 82, 118, 84, 110, 71, 104, 76, 103, 76, 91, 78, 83, 85, 89, 83, 103, 83, 119, 76, 130, 62, 130, 68, 127, 74, 126, 83, 123, 62, 123, 56, 123, 59, 129, 59, 120, 49, 110, 46, 106, 56, 100, 62, 94, 62, 109, 72, 112, 67, 112, 57, 112, 61, 122, 60, 102, 52, 125, 44, 121, 36, 114, 32, 110, 20, 110, 22, 118, 35, 118, 44, 124, 32, 119, 22, 111, 44, 96, 36, 106, 36, 94, 32, 94, 35, 83, 44, 91, 52, 91, 52, 80, 59, 80, 62, 76, 62, 70, 47, 78, 55, 75, 64, 71, 64, 60, 58, 53, 58, 43, 65, 43, 65, 60, 76, 52, 73, 38, 76, 36, 93, 48, 89, 39, 99, 40, 98, 50, 94, 63, 117, 63, 131, 67, 131, 74, 142, 78, 140, 61, 124, 58, 124, 48, 136, 55, 236, 200, 228, 200, 226, 192, 232, 198, 238, 210, 248, 210, 236, 220, 230, 223, 230, 213, 175, 32, 172, 32, 171, 38, 184, 30 }; validate(coords); } + std::vector coords = { 168, 180, 168, 178, 168, 179, 168, 181, 168, 183, 167, 183, 167, 184, 165, 184, 162, 186, 164, 188, 161, 188, 160, 191, 158, 193, 156, 193, 152, 195, 152, 198, 150, 198, 147, 198, 148, 205, 150, 210, 148, 210, 148, 208, 145, 206, 142, 206, 140, 206, 138, 206, 135, 206, 135, 209, 131, 209, 131, 211, 127, 211, 124, 210, 120, 207, 120, 204, 120, 202, 124, 201, 123, 201, 125, 198, 125, 194, 127, 194, 127, 191, 130, 191, 132, 189, 134, 189, 134, 186, 136, 184, 134, 182, 134, 179, 134, 176, 136, 174, 139, 174, 141, 177, 142, 176, 144, 176, 147, 178, 148, 176, 151, 178, 154, 178, 153, 175, 152, 174, 152, 170, 152, 168, 150, 166, 148, 166, 147, 165, 145, 162, 146, 160, 146, 157, 146, 155, 144, 155, 142, 152, 140, 150, 138, 150, 138, 148, 140, 145, 140, 142, 140, 138, 139, 138, 137, 138, 135, 138, 133, 135, 132, 132, 129, 132, 128, 132, 124, 132, 124, 130, 123, 130, 118, 126, 116, 124, 112, 122, 109, 122, 105, 122, 102, 124, 100, 124, 97, 124, 95, 126, 92, 127, 89, 127, 88, 130, 85, 132, 80, 134, 72, 134, 69, 134, 65, 138, 64, 138, 58, 137, 56, 133, 52, 133, 51, 133, 48, 133, 44, 133, 41, 131, 38, 130, 35, 130, 32, 127, 30, 127, 27, 127, 24, 127, 24, 126, 23, 124, 20, 122, 17, 122, 16, 118, 15, 116, 15, 110, 18, 108, 20, 102, 24, 97, 28, 102, 28, 98, 26, 97, 28, 94, 27, 85, 29, 79, 32, 76, 39, 70, 44, 66, 48, 65, 53, 61, 53, 58, 51, 54, 54, 54, 52, 48, 51, 43, 48, 42, 49, 38, 48, 34, 51, 30, 53, 33, 58, 30, 61, 30, 60, 27, 64, 26, 68, 24, 74, 24, 80, 24, 85, 26, 92, 26, 96, 29, 103, 32, 109, 33, 112, 37, 116, 37, 120, 37, 124, 35, 126, 35, 128, 38, 132, 38, 134, 41, 138, 38, 140, 36, 142, 40, 144, 43, 145, 41, 149, 41, 155, 41, 159, 41, 161, 46, 165, 46, 164, 42, 164, 39, 164, 34, 167, 30, 173, 24, 178, 24, 184, 24, 189, 26, 195, 21, 195, 20, 199, 20, 203, 20, 207, 17, 211, 17, 216, 17, 218, 16, 222, 22, 225, 27, 228, 31, 226, 34, 224, 34, 226, 39, 228, 43, 230, 46, 236, 46, 242, 46, 243, 50, 245, 50, 247, 54, 247, 56, 248, 60, 248, 65, 253, 66, 255, 64, 260, 64, 264, 67, 268, 71, 272, 66, 275, 66, 281, 61, 285, 66, 286, 70, 292, 74, 294, 74, 296, 74, 296, 71, 301, 74, 307, 74, 311, 78, 315, 74, 315, 77, 319, 77, 322, 82, 328, 82, 331, 81, 331, 84, 333, 86, 333, 90, 330, 95, 326, 98, 328, 99, 332, 98, 333, 101, 331, 104, 329, 104, 327, 106, 329, 111, 332, 116, 333, 119, 333, 122, 332, 126, 332, 130, 327, 130, 321, 130, 317, 130, 315, 134, 312, 134, 308, 138, 306, 138, 306, 144, 306, 149, 306, 152, 301, 152, 297, 154, 295, 154, 292, 154, 292, 158, 288, 158, 283, 162, 281, 164, 279, 163, 276, 163, 273, 166, 272, 169, 268, 168, 265, 170, 260, 172, 256, 176, 252, 176, 248, 181, 246, 182, 246, 189, 246, 194, 248, 197, 250, 198, 252, 200, 252, 203, 254, 205, 260, 205, 264, 202, 267, 202, 269, 202, 272, 199, 280, 199, 278, 202, 278, 207, 278, 211, 276, 211, 272, 213, 268, 213, 265, 213, 264, 211, 262, 210, 260, 210, 257, 212, 257, 214, 255, 217, 253, 217, 253, 221, 249, 220, 247, 220, 243, 222, 240, 223, 239, 226, 234, 231, 229, 231, 224, 231, 219, 227, 220, 227, 222, 224, 222, 222, 222, 219, 224, 217, 222, 214, 220, 212, 217, 210, 215, 210, 211, 209, 208, 206, 202, 209, 202, 205, 206, 202, 211, 198, 216, 195, 220, 192, 224, 192, 221, 186, 218, 186, 214, 185, 208, 185, 204, 186, 200, 186, 193, 183, 190, 182, 188, 182, 190, 178, 186, 178, 184, 174, 182, 171, 178, 171, 173, 174, 169, 174, 169, 175, 169, 179, 167, 182, 164, 186, 160, 192, 155, 195, 152, 198, 150, 198, 148, 198, 148, 202, 151, 208, 148, 210, 146, 208, 144, 205, 140, 205, 137, 208, 132, 208, 132, 210, 127, 210, 124, 210, 120, 206, 120, 202, 123, 202, 124, 201, 124, 198, 128, 195, 131, 191, 133, 187, 135, 183, 130, 203, 129, 208, 123, 203, 129, 203, 129, 198, 133, 198, 136, 200, 142, 200, 143, 199, 143, 197, 137, 196, 136, 194, 133, 194, 136, 186, 136, 182, 141, 186, 144, 186, 150, 186, 150, 190, 155, 190, 159, 188, 156, 182, 151, 182, 144, 182, 164, 176, 161, 177, 157, 177, 166, 176, 168, 165, 175, 167, 180, 167, 188, 159, 195, 164, 195, 162, 187, 162, 178, 163, 173, 166, 168, 170, 156, 170, 157, 165, 164, 165, 164, 161, 170, 159, 167, 158, 159, 154, 149, 151, 145, 145, 145, 138, 152, 138, 152, 146, 159, 146, 165, 153, 176, 153, 180, 153, 187, 153, 194, 153, 202, 153, 202, 158, 197, 158, 193, 158, 193, 142, 180, 142, 171, 142, 163, 135, 176, 135, 186, 139, 201, 139, 206, 139, 205, 147, 205, 160, 198, 160, 206, 174, 205, 178, 196, 178, 196, 182, 202, 182, 206, 181, 209, 181, 215, 181, 222, 181, 230, 177, 238, 175, 241, 175, 237, 175, 237, 168, 237, 161, 232, 156, 231, 162, 225, 166, 217, 169, 210, 173, 224, 173, 227, 173, 235, 175, 237, 178, 228, 192, 222, 199, 216, 199, 211, 204, 205, 206, 219, 207, 222, 211, 229, 214, 236, 214, 244, 211, 247, 211, 268, 206, 277, 201, 279, 201, 281, 202, 278, 202, 242, 178, 236, 170, 236, 162, 255, 162, 251, 156, 240, 156, 253, 152, 261, 152, 277, 157, 268, 151, 255, 143, 260, 142, 267, 145, 271, 149, 273, 154, 258, 146, 257, 131, 256, 134, 248, 137, 260, 137, 260, 134, 271, 137, 276, 138, 276, 144, 289, 144, 285, 150, 294, 150, 298, 149, 301, 145, 292, 145, 282, 134, 276, 134, 283, 127, 282, 116, 277, 113, 283, 113, 288, 106, 296, 106, 297, 113, 297, 118, 298, 118, 310, 122, 310, 128, 300, 130, 300, 140, 292, 129, 292, 114, 283, 122, 289, 122, 299, 122, 299, 134, 294, 134, 288, 124, 314, 121, 311, 113, 308, 110, 304, 96, 299, 90, 299, 82, 305, 87, 309, 94, 311, 101, 312, 102, 314, 107, 320, 112, 320, 115, 326, 116, 323, 109, 321, 102, 321, 94, 321, 90, 328, 90, 328, 88, 316, 88, 316, 84, 307, 84, 290, 77, 289, 88, 289, 97, 278, 97, 268, 106, 268, 110, 261, 105, 255, 103, 244, 103, 252, 100, 252, 91, 252, 82, 242, 78, 252, 78, 259, 78, 264, 87, 267, 92, 272, 91, 272, 83, 264, 83, 260, 79, 276, 79, 283, 84, 283, 94, 289, 94, 284, 86, 272, 77, 253, 110, 248, 110, 239, 110, 234, 114, 222, 125, 219, 127, 219, 131, 219, 138, 219, 141, 224, 139, 224, 135, 225, 130, 232, 136, 240, 138, 237, 131, 237, 118, 248, 120, 256, 122, 262, 127, 255, 118, 245, 110, 207, 129, 199, 134, 195, 134, 188, 130, 180, 130, 165, 129, 156, 129, 165, 128, 173, 125, 185, 126, 193, 126, 201, 124, 204, 123, 208, 116, 214, 114, 207, 114, 196, 114, 183, 121, 183, 111, 189, 117, 196, 112, 172, 126, 164, 126, 159, 114, 174, 106, 186, 106, 192, 105, 184, 105, 184, 96, 173, 96, 163, 111, 159, 110, 152, 110, 168, 110, 171, 106, 183, 98, 193, 101, 219, 96, 225, 97, 225, 104, 232, 92, 240, 92, 237, 86, 229, 86, 216, 88, 214, 79, 203, 79, 203, 75, 212, 75, 221, 75, 229, 80, 230, 89, 217, 88, 217, 77, 228, 77, 228, 69, 235, 71, 240, 71, 244, 66, 236, 54, 236, 62, 232, 68, 229, 61, 216, 61, 212, 58, 212, 47, 212, 39, 214, 28, 215, 48, 225, 55, 236, 55, 202, 65, 202, 54, 202, 44, 202, 24, 198, 32, 199, 38, 192, 38, 185, 38, 174, 42, 174, 48, 178, 51, 184, 51, 194, 55, 191, 68, 182, 68, 174, 69, 167, 67, 153, 59, 153, 49, 147, 49, 152, 58, 152, 74, 154, 83, 161, 83, 165, 88, 153, 97, 153, 89, 152, 82, 168, 88, 168, 101, 156, 102, 156, 119, 173, 110, 184, 110, 177, 106, 160, 106, 145, 125, 137, 122, 131, 120, 124, 120, 122, 118, 113, 118, 114, 111, 129, 111, 140, 110, 143, 106, 137, 102, 127, 102, 119, 98, 126, 93, 139, 93, 139, 99, 141, 95, 128, 89, 118, 74, 128, 76, 135, 76, 141, 83, 141, 71, 137, 61, 137, 50, 129, 50, 118, 50, 109, 52, 112, 61, 123, 60, 134, 60, 129, 76, 121, 67, 124, 76, 123, 76, 111, 74, 128, 73, 109, 83, 109, 94, 105, 103, 102, 118, 92, 113, 98, 105, 99, 93, 94, 93, 94, 81, 99, 81, 100, 73, 100, 89, 100, 60, 100, 55, 105, 37, 101, 34, 93, 37, 90, 37, 90, 49, 99, 49, 88, 68, 80, 68, 78, 64, 88, 62, 86, 77, 76, 89, 71, 91, 71, 106, 78, 106, 82, 118, 84, 110, 71, 104, 76, 103, 76, 91, 78, 83, 85, 89, 83, 103, 83, 119, 76, 130, 62, 130, 68, 127, 74, 126, 83, 123, 62, 123, 56, 123, 59, 129, 59, 120, 49, 110, 46, 106, 56, 100, 62, 94, 62, 109, 72, 112, 67, 112, 57, 112, 61, 122, 60, 102, 52, 125, 44, 121, 36, 114, 32, 110, 20, 110, 22, 118, 35, 118, 44, 124, 32, 119, 22, 111, 44, 96, 36, 106, 36, 94, 32, 94, 35, 83, 44, 91, 52, 91, 52, 80, 59, 80, 62, 76, 62, 70, 47, 78, 55, 75, 64, 71, 64, 60, 58, 53, 58, 43, 65, 43, 65, 60, 76, 52, 73, 38, 76, 36, 93, 48, 89, 39, 99, 40, 98, 50, 94, 63, 117, 63, 131, 67, 131, 74, 142, 78, 140, 61, 124, 58, 124, 48, 136, 55, 236, 200, 228, 200, 226, 192, 232, 198, 238, 210, 248, 210, 236, 220, 230, 223, 230, 213, 175, 32, 172, 32, 171, 38, 184, 30 }; + validate(coords); +} TEST(Delaunator, mapbox_issue_11) { - std::vector coords = { 516, 661, 369, 793, 426, 539, 273, 525, 204, 694, 747, 750, 454, 390 }; + std::vector coords = { 516, 661, 369, 793, 426, 539, 273, 525, 204, 694, 747, 750, 454, 390 }; validate(coords); } TEST(Delaunator, mapbox_issue_24) { - std::vector coords = { 382, 302, 382, 328, 382, 205, 623, 175, 382, 188, 382, 284, 623, 87, 623, 341, 141, 227 }; + std::vector coords = { 382, 302, 382, 328, 382, 205, 623, 175, 382, 188, 382, 284, 623, 87, 623, 341, 141, 227 }; validate(coords); } TEST(Delaunator, mapbox_issue_13) { - std::vector coords = { 4, 1, 3.7974166882130675, 2.0837249985614585, 3.2170267516619773, 3.0210869309396715, 2.337215067329615, 3.685489874065187, 1.276805078389906, 3.9872025288851036, 0.17901102978375127, 3.885476929518457, -0.8079039091377689, 3.3940516818407187, -1.550651407188842, 2.5792964886320684, -1.9489192990517052, 1.5512485534497125, -1.9489192990517057, 0.44875144655029087, -1.5506514071888438, -0.5792964886320653, -0.8079039091377715, -1.394051681840717, 0.17901102978374794, -1.8854769295184561, 1.276805078389902, -1.987202528885104, 2.337215067329611, -1.6854898740651891, 3.217026751661974, -1.021086930939675, 3.7974166882130653, -0.08372499856146409 }; + std::vector coords = { 4, 1, 3.7974166882130675, 2.0837249985614585, 3.2170267516619773, 3.0210869309396715, 2.337215067329615, 3.685489874065187, 1.276805078389906, 3.9872025288851036, 0.17901102978375127, 3.885476929518457, -0.8079039091377689, 3.3940516818407187, -1.550651407188842, 2.5792964886320684, -1.9489192990517052, 1.5512485534497125, -1.9489192990517057, 0.44875144655029087, -1.5506514071888438, -0.5792964886320653, -0.8079039091377715, -1.394051681840717, 0.17901102978374794, -1.8854769295184561, 1.276805078389902, -1.987202528885104, 2.337215067329611, -1.6854898740651891, 3.217026751661974, -1.021086930939675, 3.7974166882130653, -0.08372499856146409 }; validate(coords); } @@ -86,9 +88,8 @@ TEST(Delaunator, grow) } **/ -void robustness(double factor) -{ - std::vector coords = { +void robustness(dfloat factor) { + std::vector coords = { 66.103648384371410, 68.588612471664760, 146.680713462100413, 121.680713462100428, 128.868896560467447, 117.261797559041411, @@ -170,10 +171,9 @@ void robustness(double factor) 165.560237820700137, 140.560237820700137 }; - std::vector coords_result(coords.size()); + std::vector coords_result(coords.size()); - std::transform(coords.begin(), coords.end(), coords_result.begin(), - [factor](double d) { return d * factor; } ); + std::transform(coords.begin(), coords.end(), coords_result.begin(), [factor](dfloat d) { return d * factor; }); validate(coords_result); } @@ -206,7 +206,7 @@ TEST(Delaunator, robusthuge) TEST(Delaunator, robustmod1) { - std::vector coords + std::vector coords { 66.103648384371410, 68.588612471664760, 146.680713462100413, 121.680713462100428, @@ -294,7 +294,7 @@ TEST(Delaunator, robustmod1) TEST(Delaunator, robustmod2) { - std::vector coords + std::vector coords { 0.226270008640849, -0.5484478681473859, 0.22627000864084906, -0.5484478681473857, @@ -1302,7 +1302,7 @@ TEST(Delaunator, robustmod2) TEST(Delaunator, mapbox_issue_16) { - std::vector coords = + std::vector coords = { 0, 0, 1022, 0, From 591e47c1903637d9900ac88b63ab5edbf90f6833 Mon Sep 17 00:00:00 2001 From: c0rp3n Date: Wed, 8 Jul 2020 15:54:27 +0100 Subject: [PATCH 3/6] Add cmake config file support --- CMakeLists.txt | 10 +++++---- cmake/delaunator_config.hpp.in | 3 +++ include/delaunator.hpp | 2 ++ include/delaunator_config.hpp | 5 +++++ test/issue-8.cpp | 40 +++++++++++++++++----------------- 5 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 cmake/delaunator_config.hpp.in create mode 100644 include/delaunator_config.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c9f4840..58abd2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,15 +14,17 @@ include(FeatureSummary) include(${D_CMAKE_DIR}/options.cmake) include(${D_CMAKE_DIR}/gtest.cmake) +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/cmake/delaunator_config.hpp.in + ${CMAKE_CURRENT_LIST_DIR}/include/delaunator_config.hpp + @ONLY +) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${D_BIN_DIR}) add_library(delaunator include/delaunator.cpp) d_target_compile_settings(delaunator) -if (DELAUNATOR_SINGLE_PRECISION) - target_compile_definitions(delaunator PUBLIC DELAUNATOR_SINGLE_PRECISION) -endif() - add_subdirectory(test) #examples diff --git a/cmake/delaunator_config.hpp.in b/cmake/delaunator_config.hpp.in new file mode 100644 index 0000000..f9a8b59 --- /dev/null +++ b/cmake/delaunator_config.hpp.in @@ -0,0 +1,3 @@ +#pragma once + +#cmakedefine DELAUNATOR_SINGLE_PRECISION diff --git a/include/delaunator.hpp b/include/delaunator.hpp index a252112..a9edcce 100644 --- a/include/delaunator.hpp +++ b/include/delaunator.hpp @@ -1,5 +1,7 @@ #pragma once +#include "delaunator_config.hpp" + #ifdef DELAUNATOR_HEADER_ONLY #define INLINE inline #else diff --git a/include/delaunator_config.hpp b/include/delaunator_config.hpp new file mode 100644 index 0000000..489df52 --- /dev/null +++ b/include/delaunator_config.hpp @@ -0,0 +1,5 @@ +#pragma once + +/* #undef DELAUNATOR_HEADER_ONLY */ + +#define DELAUNATOR_SINGLE_PRECISION diff --git a/test/issue-8.cpp b/test/issue-8.cpp index 0f2c9a1..b3d9a6e 100644 --- a/test/issue-8.cpp +++ b/test/issue-8.cpp @@ -7,14 +7,14 @@ using namespace std; struct Point2D { - double x, y; + dfloat x, y; Point2D() - : x(std::numeric_limits::quiet_NaN()) - , y(std::numeric_limits::quiet_NaN()) + : x(std::numeric_limits::quiet_NaN()), + y(std::numeric_limits::quiet_NaN()) {} - Point2D(double x, double y) + Point2D(dfloat x, dfloat y) : x(x) , y(y) {} @@ -26,40 +26,40 @@ std::ostream& operator<<(std::ostream& out, const Point2D& p) return out; } -Point2D rotate(Point2D const& p_in, double const& angle_deg) +Point2D rotate(Point2D const& p_in, dfloat const& angle_deg) { - const double pi = 3.14159265358979323846; - const double angle_rad = angle_deg * pi / 180.0; - const double s = sin(angle_rad); - const double c = cos(angle_rad); + const dfloat pi = 3.14159265358979323846; + const dfloat angle_rad = angle_deg * pi / 180.0; + const dfloat s = sin(angle_rad); + const dfloat c = cos(angle_rad); Point2D p; p = p_in; // rotate point - double tmp = p.x * c - p.y * s; + dfloat tmp = p.x * c - p.y * s; p.y = p.x * s + p.y * c; p.x = tmp; return p; } -double distance(Point2D const& p1, Point2D const& p2) +dfloat distance(Point2D const& p1, Point2D const& p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } -bool approx(double v1, double v2) +bool approx(dfloat v1, dfloat v2) { - const double eps = 0.01; + const dfloat eps = 0.01; return fabs(v1 - v2) < eps; } -void testRotation(double angle) +void testRotation(dfloat angle) { const size_t grid_size = 6; - std::vector points; + std::vector points; // Generate rotated point grid of 1-by-1 squares. for (size_t x = 0; x < grid_size; ++x) { @@ -95,10 +95,10 @@ void testRotation(double angle) points[1 + 2 * delaunator.triangles[i + 2]]); // Determine edge lengths and triangle area. - double len_1 = distance(p1, p2); - double len_2 = distance(p2, p3); - double len_3 = distance(p3, p1); - double area = fabs((p1.x * (p2.y - p3.y) + + dfloat len_1 = distance(p1, p2); + dfloat len_2 = distance(p2, p3); + dfloat len_3 = distance(p3, p1); + dfloat area = fabs((p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) / 2.0); @@ -132,7 +132,7 @@ void testRotation(double angle) TEST(Delaunator, issue_8) { - for (double angle = 0; angle < 360; angle += .1) + for (dfloat angle = 0; angle < 360; angle += .1) testRotation(angle); } From cbcf9900bc911d88e0d58bea23407f0b36aa054f Mon Sep 17 00:00:00 2001 From: c0rp3n Date: Wed, 8 Jul 2020 16:09:54 +0100 Subject: [PATCH 4/6] Ignore and delete delaunator_config.hpp --- .gitignore | 2 ++ include/delaunator_config.hpp | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 include/delaunator_config.hpp diff --git a/.gitignore b/.gitignore index 07d840d..20b747e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ local.env xcode-project build .*.sw* + +include/delaunator_config.hpp diff --git a/include/delaunator_config.hpp b/include/delaunator_config.hpp deleted file mode 100644 index 489df52..0000000 --- a/include/delaunator_config.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -/* #undef DELAUNATOR_HEADER_ONLY */ - -#define DELAUNATOR_SINGLE_PRECISION From b89bde5c532c8d6e1d1a27892cbf4dbcbd100ce1 Mon Sep 17 00:00:00 2001 From: c0rp3n Date: Fri, 10 Jul 2020 20:11:39 +0100 Subject: [PATCH 5/6] issue 8 rever formatting change --- test/issue-8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/issue-8.cpp b/test/issue-8.cpp index b3d9a6e..67fca05 100644 --- a/test/issue-8.cpp +++ b/test/issue-8.cpp @@ -98,7 +98,7 @@ void testRotation(dfloat angle) dfloat len_1 = distance(p1, p2); dfloat len_2 = distance(p2, p3); dfloat len_3 = distance(p3, p1); - dfloat area = fabs((p1.x * (p2.y - p3.y) + + dfloat area = fabs((p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) / 2.0); From 551c913db0a0ca016d98f1cce2225938aa214ea1 Mon Sep 17 00:00:00 2001 From: c0rp3n Date: Fri, 10 Jul 2020 20:12:08 +0100 Subject: [PATCH 6/6] Tests use EXPECT_FLOAT_EQ when delaunator is using singles --- test/delaunator.test.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/delaunator.test.cpp b/test/delaunator.test.cpp index f27a188..b67c4fc 100644 --- a/test/delaunator.test.cpp +++ b/test/delaunator.test.cpp @@ -23,10 +23,14 @@ inline void validate(const std::vector& coords) { } //validate triangulation - double hull_area = d.get_hull_area(); - double tri_area = d.get_triangle_area(); + dfloat hull_area = d.get_hull_area(); + dfloat tri_area = d.get_triangle_area(); +#ifdef DELAUNATOR_USE_SINGLE + EXPECT_FLOAT_EQ(tri_area, hull_area); +#else EXPECT_DOUBLE_EQ(tri_area, hull_area); +#endif } } // namespace