├── LICENSE ├── README.md ├── demo.cpp └── predicates.h /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2016, wlenthe 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GeometricPredicates 2 | robust/exact 2d/3d geometric tests based on [Jonathan Shewchuk's papers and c code](https://www.cs.cmu.edu/~quake/robust.html) 3 | -------------------------------------------------------------------------------- /demo.cpp: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * * 3 | * Copyright (c) 2016, William C. Lenthe * 4 | * All rights reserved. * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions are met: * 8 | * * 9 | * 1. Redistributions of source code must retain the above copyright notice, this * 10 | * list of conditions and the following disclaimer. * 11 | * * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | * this list of conditions and the following disclaimer in the documentation * 14 | * and/or other materials provided with the distribution. * 15 | * * 16 | * 3. Neither the name of the copyright holder nor the names of its * 17 | * contributors may be used to endorse or promote products derived from * 18 | * this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 30 | * * 31 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 32 | 33 | #include 34 | #include 35 | 36 | #include "predicates.h" 37 | 38 | #if( __cplusplus == 201103L || __cplusplus == 201703L || __cplusplus == 201703L || __cplusplus > 201703L) 39 | #define CXX_RANDOM//better random number generation 40 | #include 41 | #endif 42 | 43 | //@brief : generate a random number in [0,1] 44 | //@return: number in [0,1] 45 | double rand01() { 46 | #ifdef CXX_RANDOM 47 | //prefer c++11 random number generation 48 | static std::random_device device; 49 | static const size_t seed = device(); 50 | static std::mt19937 engine(seed); 51 | static std::uniform_real_distribution dist(0.0, 1.0); 52 | return dist(engine); 53 | #else 54 | //fall back to bad random numbers 55 | static bool once = true; 56 | if(once) { 57 | srand(time(NULL)); 58 | once = false; 59 | } 60 | return double(rand()) / RAND_MAX; 61 | #endif 62 | } 63 | 64 | int main() { 65 | std::vector points(15); 66 | for(size_t i = 0; i < points.size(); i++) points[i] = rand01(); 67 | 68 | double x = predicates::adaptive::orient2d(&points[0], &points[2], &points[4]); 69 | std::cout << "(" << points[4] << " " << points[5]; 70 | if(x < 0.0) std::cout << ") is below the line defined by:\n"; 71 | else if(x > 0.0) std::cout << ") is above the line defined by:\n"; 72 | else std::cout << ") is on the line defined by:\n"; 73 | std::cout << "\t(" << points[0] << " " << points[1] << ")\n"; 74 | std::cout << "\t(" << points[2] << " " << points[3] << ")\n\n"; 75 | 76 | x = predicates::adaptive::incircle(&points[0], &points[2], &points[4], &points[6]); 77 | std::cout << "(" << points[6] << " " << points[7]; 78 | if(x < 0.0) std::cout << ") is outside the circle defined by:\n"; 79 | else if(x > 0.0) std::cout << ") is inside the circle defined by:\n"; 80 | else std::cout << ") is on the circle defined by:\n"; 81 | std::cout << "\t(" << points[0] << " " << points[1] << ")\n"; 82 | std::cout << "\t(" << points[2] << " " << points[3] << ")\n"; 83 | std::cout << "\t(" << points[4] << " " << points[5] << ")\n\n"; 84 | 85 | x = predicates::adaptive::orient3d(&points[0], &points[3], &points[6], &points[9]); 86 | std::cout << "(" << points[9] << " " << points[10] << " " << points[11]; 87 | if(x < 0.0) std::cout << ") is below the plane defined by:\n"; 88 | else if(x > 0.0) std::cout << ") is above the plane defined by:\n"; 89 | else std::cout << ") is on the plane defined by:\n"; 90 | std::cout << "\t(" << points[0] << " " << points[1] << " " << points[2] << ")\n"; 91 | std::cout << "\t(" << points[3] << " " << points[4] << " " << points[5] << ")\n"; 92 | std::cout << "\t(" << points[6] << " " << points[7] << " " << points[8] << ")\n\n"; 93 | 94 | x = predicates::adaptive::insphere(&points[0], &points[3], &points[6], &points[9], &points[12]); 95 | std::cout << "(" << points[12] << " " << points[13] << " " << points[14]; 96 | if(x < 0.0) std::cout << ") is outside the sphere defined by:\n"; 97 | else if(x > 0.0) std::cout << ") is inside the sphere defined by:\n"; 98 | else std::cout << ") is on the sphere defined by:\n"; 99 | std::cout << "\t(" << points[0] << " " << points[ 1] << " " << points[ 2] << ")\n"; 100 | std::cout << "\t(" << points[3] << " " << points[ 4] << " " << points[ 5] << ")\n"; 101 | std::cout << "\t(" << points[6] << " " << points[ 7] << " " << points[ 8] << ")\n"; 102 | std::cout << "\t(" << points[9] << " " << points[10] << " " << points[11] << ")\n"; 103 | 104 | // robustness test and visualization 105 | { 106 | const double p1[2] = { 0.0, 0.0 }; 107 | const double p2[2] = { 24., 24. }; 108 | const int resolution = 80; 109 | const double eps = std::pow(2.0, -53); 110 | std::cout << "Testing 2D orientation robustness" << std::endl; 111 | std::cout << "line : from (0, 0) to (24, 24)" << std::endl; 112 | std::cout << "bottom-left point: (0.5, 0.5)" << std::endl; 113 | std::cout << "step-size : 2^-53" << std::endl; 114 | for (int iy = resolution - 1; iy >= 0; --iy) 115 | { 116 | for (int ix = 0; ix < resolution; ++ix) 117 | { 118 | const double p[2] = { 0.5 + ix * eps, 0.5 + iy * eps }; 119 | using predicates::adaptive::orient2d; 120 | const double res = orient2d(&p1[0], &p2[0], &p[0]); 121 | std::cout << (res == 0.0 ? "0" : res < 0.0 ? "-" : "+"); 122 | } 123 | std::cout << std::endl; 124 | } 125 | } 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /predicates.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * * 3 | * Copyright (c) 2019, William C. Lenthe * 4 | * All rights reserved. * 5 | * * 6 | * Redistribution and use in source and binary forms, with or without * 7 | * modification, are permitted provided that the following conditions are met: * 8 | * * 9 | * 1. Redistributions of source code must retain the above copyright notice, this * 10 | * list of conditions and the following disclaimer. * 11 | * * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, * 13 | * this list of conditions and the following disclaimer in the documentation * 14 | * and/or other materials provided with the distribution. * 15 | * * 16 | * 3. Neither the name of the copyright holder nor the names of its * 17 | * contributors may be used to endorse or promote products derived from * 18 | * this software without specific prior written permission. * 19 | * * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 30 | * * 31 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 32 | 33 | #ifndef PREDICATES_H_INCLUDED 34 | #define PREDICATES_H_INCLUDED 35 | 36 | //@reference: https://www.cs.cmu.edu/~quake/robust.html 37 | 38 | namespace predicates { 39 | //@brief: geometric predicates using arbitrary precision arithmetic 40 | //@note : these are provided primarily for illustrative purposes and adaptive routines should be preferred 41 | namespace exact { 42 | //@brief : determine if the 2d point c is above, on, or below the line defined by a and b 43 | //@param pa: pointer to a as {x, y} 44 | //@param pb: pointer to b as {x, y} 45 | //@param pc: pointer to c as {x, y} 46 | //@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}} 47 | //@note : positive, 0, negative result for c above, on, or below the line defined by a -> b 48 | template T orient2d(T const*const pa, T const*const pb, T const*const pc); 49 | 50 | //@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c 51 | //@param pa: pointer to a as {x, y} 52 | //@param pb: pointer to b as {x, y} 53 | //@param pc: pointer to c as {x, y} 54 | //@param pc: pointer to d as {x, y} 55 | //@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}} 56 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 57 | template T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd); 58 | 59 | //@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c 60 | //@param pa: pointer to a as {x, y, z} 61 | //@param pb: pointer to b as {x, y, z} 62 | //@param pc: pointer to c as {x, y, z} 63 | //@param pd: pointer to d as {x, y, z} 64 | //@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}} 65 | //@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c 66 | template T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd); 67 | 68 | //@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d 69 | //@param pa: pointer to a as {x, y, z} 70 | //@param pb: pointer to b as {x, y, z} 71 | //@param pc: pointer to c as {x, y, z} 72 | //@param pd: pointer to d as {x, y, z} 73 | //@param pe: pointer to e as {x, y, z} 74 | //@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}} 75 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 76 | template T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe); 77 | } 78 | 79 | //@brief: geometric predicates using normal floating point arithmetic but falling back to arbitrary precision when needed 80 | //@note : these should have the same accuracy but are significantly faster when determinants are large 81 | namespace adaptive { 82 | //@brief : determine if the 2d point c is above, on, or below the line defined by a and b 83 | //@param pa: pointer to a as {x, y} 84 | //@param pb: pointer to b as {x, y} 85 | //@param pc: pointer to c as {x, y} 86 | //@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}} 87 | //@note : positive, 0, negative result for c above, on, or below the line defined by a -> b 88 | template T orient2d(T const*const pa, T const*const pb, T const*const pc); 89 | 90 | //@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c 91 | //@param pa: pointer to a as {x, y} 92 | //@param pb: pointer to b as {x, y} 93 | //@param pc: pointer to c as {x, y} 94 | //@param pc: pointer to d as {x, y} 95 | //@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}} 96 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 97 | template T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd); 98 | 99 | //@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c 100 | //@param pa: pointer to a as {x, y, z} 101 | //@param pb: pointer to b as {x, y, z} 102 | //@param pc: pointer to c as {x, y, z} 103 | //@param pd: pointer to d as {x, y, z} 104 | //@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}} 105 | //@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c 106 | template T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd); 107 | 108 | //@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d 109 | //@param pa: pointer to a as {x, y, z} 110 | //@param pb: pointer to b as {x, y, z} 111 | //@param pc: pointer to c as {x, y, z} 112 | //@param pd: pointer to d as {x, y, z} 113 | //@param pe: pointer to e as {x, y, z} 114 | //@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}} 115 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 116 | template T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe); 117 | } 118 | } 119 | 120 | #include //abs, fma 121 | #include 122 | #include //pair 123 | #include //accumulate 124 | #include //transform, copy_n, merge 125 | #include //negate 126 | 127 | // a macro based static assert for pre c++11 128 | #define PREDICATES_PORTABLE_STATIC_ASSERT(condition, message) typedef char message[(condition) ? 1 : -1] 129 | 130 | // check if c++11 is supported 131 | #if !defined(__cplusplus) && !defined(_MSC_VER) 132 | PREDICATES_PORTABLE_STATIC_ASSERT(false, couldnt_parse_cxx_standard) 133 | #endif 134 | #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) 135 | #define PREDICATES_CXX11_IS_SUPPORTED 136 | #endif 137 | 138 | // choose to use c++11 features or their backports 139 | #ifdef PREDICATES_CXX11_IS_SUPPORTED 140 | #include 141 | #include // is_same, enable_if 142 | #undef PREDICATES_PORTABLE_STATIC_ASSERT 143 | #define PREDICATES_TOKEN_TO_STRING1(x) #x 144 | #define PREDICATES_TOKEN_TO_STRING(x) PREDICATES_TOKEN_TO_STRING1(x) 145 | #define PREDICATES_PORTABLE_STATIC_ASSERT(condition, message) static_assert(condition, PREDICATES_TOKEN_TO_STRING(message)) 146 | namespace stdx { 147 | using std::array; 148 | using std::copy_n; 149 | } 150 | #else 151 | namespace stdx { 152 | // array 153 | template 154 | class array { 155 | T buff[N]; 156 | public: 157 | T& operator[](const size_t& i) { return buff[i]; } 158 | const T& operator[](const size_t& i) const { return buff[i]; } 159 | 160 | T * data() { return buff; } 161 | T const * data() const { return buff; } 162 | 163 | T * begin() { return buff; } 164 | T const * cbegin() const { return buff; } 165 | }; 166 | // copy_n 167 | template< class InputIt, class Size, class OutputIt> 168 | OutputIt copy_n(InputIt first, Size count, OutputIt result) 169 | { 170 | if (count > 0) { 171 | *result++ = *first; 172 | for (Size i = 1; i < count; ++i) { 173 | *result++ = *++first; 174 | } 175 | } 176 | return result; 177 | } 178 | } 179 | #endif // CXX11_IS_SUPPORTED 180 | 181 | namespace detail { 182 | template class ExpansionBase; 183 | 184 | //@brief: class to exactly represent the result of a sequence of arithmetic operations as an sequence of values that sum to the result 185 | template 186 | class Expansion : private ExpansionBase, public stdx::array { 187 | private: 188 | public: 189 | size_t m_size; 190 | template friend class ExpansionBase;//access for base class 191 | template friend class Expansion;//access for expansions of different size 192 | 193 | Expansion() : m_size(0) {} 194 | template Expansion& operator=(const Expansion& e) { 195 | PREDICATES_PORTABLE_STATIC_ASSERT(M <= N, cannot_assign_a_larger_expansion_to_a_smaller_expansion); 196 | stdx::copy_n(e.cbegin(), e.size(), stdx::array::begin()); 197 | m_size = e.size(); 198 | return *this; 199 | } 200 | 201 | Expansion(const Expansion& other) { *this = other; } 202 | 203 | //vector like convenience functions 204 | size_t size() const {return m_size;} 205 | bool empty() const {return 0 == m_size;} 206 | void push_back(const T v) {stdx::array::operator[](m_size++) = v;} 207 | 208 | public: 209 | //estimates of expansion value 210 | T mostSignificant() const {return empty() ? T(0) : stdx::array::operator[](m_size - 1);} 211 | T estimate() const {return std::accumulate(stdx::array::cbegin(), stdx::array::cbegin() + size(), T(0));} 212 | 213 | template Expansion operator+(const Expansion& f) const { 214 | Expansion h; 215 | h.m_size = ExpansionBase::ExpansionSum(this->data(), this->size(), f.data(), f.size(), h.data()); 216 | return h; 217 | } 218 | 219 | void negate() {std::transform(stdx::array::cbegin(), stdx::array::cbegin() + size(), stdx::array::begin(), std::negate());} 220 | Expansion operator-() const {Expansion e = *this; e.negate(); return e;} 221 | template Expansion operator-(const Expansion& f) const {return operator+(-f);} 222 | 223 | Expansion operator*(const T b) const { 224 | Expansion h; 225 | h.m_size = ExpansionBase::ScaleExpansion(this->data(), this->size(), b, h.data()); 226 | return h; 227 | } 228 | }; 229 | 230 | //std::fma is faster than dekker's product when the processor instruction is available 231 | #ifdef FP_FAST_FMAF 232 | static const bool fp_fast_fmaf = true; 233 | #else 234 | static const bool fp_fast_fmaf = false; 235 | #endif 236 | 237 | #ifdef FP_FAST_FMA 238 | static const bool fp_fast_fma = true; 239 | #else 240 | static const bool fp_fast_fma = false; 241 | #endif 242 | 243 | #ifdef FP_FAST_FMAL 244 | static const bool fp_fast_fmal = true; 245 | #else 246 | static const bool fp_fast_fmal = false; 247 | #endif 248 | 249 | #ifdef PREDICATES_CXX11_IS_SUPPORTED 250 | template struct use_fma {static const bool value = (std::is_same::value && fp_fast_fmaf) || 251 | (std::is_same::value && fp_fast_fma) || 252 | (std::is_same::value && fp_fast_fmal);}; 253 | #endif 254 | 255 | //@brief : helper function to sort by absolute value 256 | //@param a: lhs item to compare 257 | //@param b: rhs item to compare 258 | //@return : true if |a| < |b| 259 | //@note : defined since lambda functions aren't allow in c++03 260 | template bool absLess(const T& a, const T& b) {return std::abs(a) < std::abs(b);} 261 | 262 | template 263 | class ExpansionBase { 264 | private: 265 | static const T Splitter; 266 | 267 | PREDICATES_PORTABLE_STATIC_ASSERT(std::numeric_limits::is_iec559, Requires_IEC_559_IEEE_754_floating_point_type); 268 | PREDICATES_PORTABLE_STATIC_ASSERT(2 == std::numeric_limits::radix, Requires_base_2_floating_point_type); 269 | 270 | //combine result + roundoff error into expansion 271 | static inline Expansion MakeExpansion(const T value, const T tail) { 272 | Expansion e; 273 | if(T(0) != tail) e.push_back(tail); 274 | if(T(0) != value) e.push_back(value); 275 | return e; 276 | } 277 | 278 | protected: 279 | //add 2 expansions 280 | static size_t ExpansionSum(T const * const e, const size_t n, T const * const f, const size_t m, T * const h) { 281 | std::merge(e, e + n, f, f + m, h, absLess); 282 | if(m == 0) return n; 283 | if(n == 0) return m; 284 | size_t hIndex = 0; 285 | T Q = h[0]; 286 | T Qnew = h[1] + Q; 287 | T hh = FastPlusTail(h[1], Q, Qnew); 288 | Q = Qnew; 289 | if(T(0) != hh) h[hIndex++] = hh; 290 | for(size_t g = 2; g != n + m; ++g) { 291 | Qnew = Q + h[g]; 292 | hh = PlusTail(Q, h[g], Qnew); 293 | Q = Qnew; 294 | if(T(0) != hh) h[hIndex++] = hh; 295 | } 296 | if(T(0) != Q) h[hIndex++] = Q; 297 | return hIndex; 298 | } 299 | 300 | //scale an expansion by a constant 301 | static size_t ScaleExpansion(T const * const e, const size_t n, const T b, T * const h) { 302 | if(n == 0 || T(0) == b) return 0; 303 | size_t hIndex = 0; 304 | T Q = e[0] * b; 305 | const std::pair bSplit = Split(b); 306 | T hh = MultTailPreSplit(e[0], b, bSplit, Q); 307 | if(T(0) != hh) h[hIndex++] = hh; 308 | for(size_t eIndex = 1; eIndex < n; ++eIndex) { 309 | T Ti = e[eIndex] * b; 310 | T ti = MultTailPreSplit(e[eIndex], b, bSplit, Ti); 311 | T Qi = Q + ti; 312 | hh = PlusTail(Q, ti, Qi); 313 | if(T(0) != hh) h[hIndex++] = hh; 314 | Q = Ti + Qi; 315 | hh = FastPlusTail(Ti, Qi, Q); 316 | if(T(0) != hh) h[hIndex++] = hh; 317 | } 318 | if(T(0) != Q) h[hIndex++] = Q; 319 | return hIndex; 320 | } 321 | 322 | public: 323 | //roundoff error of x = a + b 324 | static inline T PlusTail(const T a, const T b, const T x) { 325 | const T bVirtual = x - a; 326 | const T aVirtual = x - bVirtual; 327 | const T bRoundoff = b - bVirtual; 328 | const T aRoundoff = a - aVirtual; 329 | return aRoundoff + bRoundoff; 330 | } 331 | 332 | //roundoff error of x = a + b if |a| > |b| 333 | static inline T FastPlusTail(const T a, const T b, const T x) { 334 | const T bVirtual = x - a; 335 | return b - bVirtual; 336 | } 337 | 338 | //roundoff error of x = a - b 339 | static inline T MinusTail(const T a, const T b, const T x) { 340 | const T bVirtual = a - x; 341 | const T aVirtual = x + bVirtual; 342 | const T bRoundoff = bVirtual - b; 343 | const T aRoundoff = a - aVirtual; 344 | return aRoundoff + bRoundoff; 345 | } 346 | 347 | //split a into 2 nonoverlapping values 348 | static inline std::pair Split(const T a) { 349 | const T c = a * Splitter; 350 | const T aBig = c - a; 351 | const T aHi = c - aBig; 352 | return std::pair(aHi, a - aHi); 353 | } 354 | 355 | //roundoff error of x = a * b via dekkers product 356 | static inline T DekkersProduct(const T /*a*/, const std::pair aSplit, const T /*b*/, const std::pair bSplit, const T p) { 357 | T y = p - T(aSplit.first * bSplit.first); 358 | y -= T(aSplit.second * bSplit.first); 359 | y -= T(aSplit.first * bSplit.second); 360 | return T(aSplit.second * bSplit.second) - y; 361 | } 362 | 363 | //roundoff error of x = a * b 364 | #ifdef PREDICATES_CXX11_IS_SUPPORTED 365 | template static typename std::enable_if< use_fma::value, S>::type MultTail(const T a, const T b, const T p) {return std::fma(a, b, -p);} 366 | template static typename std::enable_if::value, S>::type MultTail(const T a, const T b, const T p) {return DekkersProduct(a, Split(a), b, Split(b), p);} 367 | 368 | template static typename std::enable_if< use_fma::value, S>::type MultTailPreSplit(const T a, const T b, const std::pair /*bSplit*/, const T p) {return std::fma(a, b, -p);} 369 | template static typename std::enable_if::value, S>::type MultTailPreSplit(const T a, const T b, const std::pair bSplit, const T p) {return DekkersProduct(a, Split(a), b, bSplit, p);} 370 | #else 371 | static T MultTail(const T a, const T b, const T p) {return DekkersProduct(a, Split(a), b, Split(b), p);} 372 | static T MultTailPreSplit(const T a, const T b, const std::pair bSplit, const T p) {return DekkersProduct(a, Split(a), b, bSplit, p);} 373 | #endif 374 | //expand a + b 375 | static inline Expansion Plus(const T a, const T b) { 376 | const T x = a + b; 377 | return MakeExpansion(x, PlusTail(a, b, x)); 378 | } 379 | 380 | //expand a - b 381 | static inline Expansion Minus(const T a, const T b) {return Plus(a, -b);} 382 | 383 | //expand a * b 384 | static inline Expansion Mult(const T a, const T b) { 385 | const T x = a * b; 386 | return MakeExpansion(x, MultTail(a, b, x)); 387 | } 388 | 389 | //expand the determinant of {{ax, ay}, {bx, by}} (unrolled Mult(ax, by) - Mult(ay, bx)) 390 | static inline Expansion TwoTwoDiff(const T ax, const T by, const T ay, const T bx) { 391 | const T axby1 = ax * by; 392 | const T axby0 = MultTail(ax, by, axby1); 393 | const T bxay1 = bx * ay; 394 | const T bxay0 = MultTail(bx, ay, bxay1); 395 | const T _i0 = axby0 - bxay0; 396 | const T x0 = MinusTail(axby0, bxay0, _i0); 397 | const T _j = axby1 + _i0; 398 | const T _0 = PlusTail(axby1, _i0, _j); 399 | const T _i1 = _0 - bxay1; 400 | const T x1 = MinusTail(_0, bxay1, _i1); 401 | const T x3 = _j + _i1; 402 | const T x2 = PlusTail(_j, _i1, x3); 403 | Expansion e; 404 | if(T(0) != x0) e.push_back(x0); 405 | if(T(0) != x1) e.push_back(x1); 406 | if(T(0) != x2) e.push_back(x2); 407 | if(T(0) != x3) e.push_back(x3); 408 | return e; 409 | } 410 | 411 | //TwoTwoDiff checking for zeros to avoid extra splitting 412 | static inline Expansion TwoTwoDiffZeroCheck(const T ax, const T by, const T ay, const T bx) { 413 | Expansion e; 414 | if(T(0) == ax && T(0) == ay) return e; 415 | else if(T(0) == ax) e = Mult(ay, bx); 416 | else if(T(0) == ay) e = Mult(ax, by); 417 | else e = TwoTwoDiff(ax, by, ay, bx); 418 | return e; 419 | } 420 | 421 | //(a * b) * c checking for zeros 422 | static inline Expansion ThreeProd(const T a, const T b, const T c) {return (T(0) == a || T(0) == b || T(0) == c) ? Expansion() : Mult(a, b) * c;} 423 | }; 424 | 425 | template const T ExpansionBase::Splitter = static_cast( 426 | #ifdef PREDICATES_CXX11_IS_SUPPORTED 427 | std::exp2((std::numeric_limits::digits + std::numeric_limits::digits%2)/2 + 1) 428 | #else 429 | std::ldexp(T(1), (std::numeric_limits::digits + std::numeric_limits::digits%2)/2 + 1) 430 | #endif 431 | ); 432 | } 433 | 434 | namespace predicates { 435 | namespace exact { 436 | //@brief : determine if the 2d point c is above, on, or below the line defined by a and b 437 | //@param pa: pointer to a as {x, y} 438 | //@param pb: pointer to b as {x, y} 439 | //@param pc: pointer to c as {x, y} 440 | //@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}} 441 | //@note : positive, 0, negative result for c above, on, or below the line defined by a -> b 442 | template T orient2d(T const*const pa, T const*const pb, T const*const pc) { 443 | const detail::Expansion aterms = detail::ExpansionBase::TwoTwoDiff(pa[0], pb[1], pa[0], pc[1]); 444 | const detail::Expansion bterms = detail::ExpansionBase::TwoTwoDiff(pb[0], pc[1], pb[0], pa[1]); 445 | const detail::Expansion cterms = detail::ExpansionBase::TwoTwoDiff(pc[0], pa[1], pc[0], pb[1]); 446 | const detail::Expansion w = aterms + bterms + cterms; 447 | return w.mostSignificant(); 448 | } 449 | 450 | //@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c 451 | //@param pa: pointer to a as {x, y} 452 | //@param pb: pointer to b as {x, y} 453 | //@param pc: pointer to c as {x, y} 454 | //@param pc: pointer to d as {x, y} 455 | //@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}} 456 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 457 | template T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd) { 458 | const detail::Expansion ab = detail::ExpansionBase::TwoTwoDiff(pa[0], pb[1], pb[0], pa[1]); 459 | const detail::Expansion bc = detail::ExpansionBase::TwoTwoDiff(pb[0], pc[1], pc[0], pb[1]); 460 | const detail::Expansion cd = detail::ExpansionBase::TwoTwoDiff(pc[0], pd[1], pd[0], pc[1]); 461 | const detail::Expansion da = detail::ExpansionBase::TwoTwoDiff(pd[0], pa[1], pa[0], pd[1]); 462 | const detail::Expansion ac = detail::ExpansionBase::TwoTwoDiff(pa[0], pc[1], pc[0], pa[1]); 463 | const detail::Expansion bd = detail::ExpansionBase::TwoTwoDiff(pb[0], pd[1], pd[0], pb[1]); 464 | 465 | const detail::Expansion abc = ab + bc - ac; 466 | const detail::Expansion bcd = bc + cd - bd; 467 | const detail::Expansion cda = cd + da + ac; 468 | const detail::Expansion dab = da + ab + bd; 469 | 470 | const detail::Expansion adet = bcd * pa[0] * pa[0] + bcd * pa[1] * pa[1]; 471 | const detail::Expansion bdet = cda * pb[0] * -pb[0] + cda * pb[1] * -pb[1]; 472 | const detail::Expansion cdet = dab * pc[0] * pc[0] + dab * pc[1] * pc[1]; 473 | const detail::Expansion ddet = abc * pd[0] * -pd[0] + abc * pd[1] * -pd[1]; 474 | 475 | const detail::Expansion deter = (adet + bdet) + (cdet + ddet); 476 | return deter.mostSignificant(); 477 | } 478 | 479 | //@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c 480 | //@param pa: pointer to a as {x, y, z} 481 | //@param pb: pointer to b as {x, y, z} 482 | //@param pc: pointer to c as {x, y, z} 483 | //@param pd: pointer to d as {x, y, z} 484 | //@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}} 485 | //@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c 486 | template T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd) { 487 | const detail::Expansion ab = detail::ExpansionBase::TwoTwoDiff(pa[0], pb[1], pb[0], pa[1]); 488 | const detail::Expansion bc = detail::ExpansionBase::TwoTwoDiff(pb[0], pc[1], pc[0], pb[1]); 489 | const detail::Expansion cd = detail::ExpansionBase::TwoTwoDiff(pc[0], pd[1], pd[0], pc[1]); 490 | const detail::Expansion da = detail::ExpansionBase::TwoTwoDiff(pd[0], pa[1], pa[0], pd[1]); 491 | const detail::Expansion ac = detail::ExpansionBase::TwoTwoDiff(pa[0], pc[1], pc[0], pa[1]); 492 | const detail::Expansion bd = detail::ExpansionBase::TwoTwoDiff(pb[0], pd[1], pd[0], pb[1]); 493 | 494 | const detail::Expansion abc = ab + bc - ac; 495 | const detail::Expansion bcd = bc + cd - bd; 496 | const detail::Expansion cda = cd + da + ac; 497 | const detail::Expansion dab = da + ab + bd; 498 | 499 | const detail::Expansion adet = bcd * pa[2]; 500 | const detail::Expansion bdet = cda * -pb[2]; 501 | const detail::Expansion cdet = dab * pc[2]; 502 | const detail::Expansion ddet = abc * -pd[2]; 503 | 504 | const detail::Expansion deter = (adet + bdet) + (cdet + ddet); 505 | return deter.mostSignificant(); 506 | } 507 | 508 | //@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d 509 | //@param pa: pointer to a as {x, y, z} 510 | //@param pb: pointer to b as {x, y, z} 511 | //@param pc: pointer to c as {x, y, z} 512 | //@param pd: pointer to d as {x, y, z} 513 | //@param pe: pointer to e as {x, y, z} 514 | //@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}} 515 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 516 | template T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe) { 517 | const detail::Expansion ab = detail::ExpansionBase::TwoTwoDiff(pa[0], pb[1], pb[0], pa[1]); 518 | const detail::Expansion bc = detail::ExpansionBase::TwoTwoDiff(pb[0], pc[1], pc[0], pb[1]); 519 | const detail::Expansion cd = detail::ExpansionBase::TwoTwoDiff(pc[0], pd[1], pd[0], pc[1]); 520 | const detail::Expansion de = detail::ExpansionBase::TwoTwoDiff(pd[0], pe[1], pe[0], pd[1]); 521 | const detail::Expansion ea = detail::ExpansionBase::TwoTwoDiff(pe[0], pa[1], pa[0], pe[1]); 522 | const detail::Expansion ac = detail::ExpansionBase::TwoTwoDiff(pa[0], pc[1], pc[0], pa[1]); 523 | const detail::Expansion bd = detail::ExpansionBase::TwoTwoDiff(pb[0], pd[1], pd[0], pb[1]); 524 | const detail::Expansion ce = detail::ExpansionBase::TwoTwoDiff(pc[0], pe[1], pe[0], pc[1]); 525 | const detail::Expansion da = detail::ExpansionBase::TwoTwoDiff(pd[0], pa[1], pa[0], pd[1]); 526 | const detail::Expansion eb = detail::ExpansionBase::TwoTwoDiff(pe[0], pb[1], pb[0], pe[1]); 527 | 528 | const detail::Expansion abc = bc * pa[2] + ac * -pb[2] + ab * pc[2]; 529 | const detail::Expansion bcd = cd * pb[2] + bd * -pc[2] + bc * pd[2]; 530 | const detail::Expansion cde = de * pc[2] + ce * -pd[2] + cd * pe[2]; 531 | const detail::Expansion dea = ea * pd[2] + da * -pe[2] + de * pa[2]; 532 | const detail::Expansion eab = ab * pe[2] + eb * -pa[2] + ea * pb[2]; 533 | const detail::Expansion abd = bd * pa[2] + da * pb[2] + ab * pd[2]; 534 | const detail::Expansion bce = ce * pb[2] + eb * pc[2] + bc * pe[2]; 535 | const detail::Expansion cda = da * pc[2] + ac * pd[2] + cd * pa[2]; 536 | const detail::Expansion deb = eb * pd[2] + bd * pe[2] + de * pb[2]; 537 | const detail::Expansion eac = ac * pe[2] + ce * pa[2] + ea * pc[2]; 538 | 539 | const detail::Expansion bcde = (cde + bce) - (deb + bcd); 540 | const detail::Expansion cdea = (dea + cda) - (eac + cde); 541 | const detail::Expansion deab = (eab + deb) - (abd + dea); 542 | const detail::Expansion eabc = (abc + eac) - (bce + eab); 543 | const detail::Expansion abcd = (bcd + abd) - (cda + abc); 544 | 545 | const detail::Expansion adet = bcde * pa[0] * pa[0] + bcde * pa[1] * pa[1] + bcde * pa[2] * pa[2]; 546 | const detail::Expansion bdet = cdea * pb[0] * pb[0] + cdea * pb[1] * pb[1] + cdea * pb[2] * pb[2]; 547 | const detail::Expansion cdet = deab * pc[0] * pc[0] + deab * pc[1] * pc[1] + deab * pc[2] * pc[2]; 548 | const detail::Expansion ddet = eabc * pd[0] * pd[0] + eabc * pd[1] * pd[1] + eabc * pd[2] * pd[2]; 549 | const detail::Expansion edet = abcd * pe[0] * pe[0] + abcd * pe[1] * pe[1] + abcd * pe[2] * pe[2]; 550 | 551 | const detail::Expansion deter = (adet + bdet) + ((cdet + ddet) + edet); 552 | return deter.mostSignificant(); 553 | } 554 | } 555 | 556 | template 557 | class Constants { 558 | public: 559 | static const T epsilon, resulterrbound; 560 | static const T ccwerrboundA, ccwerrboundB, ccwerrboundC; 561 | static const T o3derrboundA, o3derrboundB, o3derrboundC; 562 | static const T iccerrboundA, iccerrboundB, iccerrboundC; 563 | static const T isperrboundA, isperrboundB, isperrboundC; 564 | }; 565 | 566 | template const T Constants::epsilon = static_cast( 567 | #ifdef PREDICATES_CXX11_IS_SUPPORTED 568 | std::exp2(-std::numeric_limits::digits) 569 | #else 570 | std::ldexp(T(1), -std::numeric_limits::digits) 571 | #endif 572 | ); 573 | 574 | template const T Constants::resulterrbound = (T( 3) + T( 8) * Constants::epsilon) * Constants::epsilon; 575 | template const T Constants::ccwerrboundA = (T( 3) + T( 16) * Constants::epsilon) * Constants::epsilon; 576 | template const T Constants::ccwerrboundB = (T( 2) + T( 12) * Constants::epsilon) * Constants::epsilon; 577 | template const T Constants::ccwerrboundC = (T( 9) + T( 64) * Constants::epsilon) * Constants::epsilon * Constants::epsilon; 578 | template const T Constants::o3derrboundA = (T( 7) + T( 56) * Constants::epsilon) * Constants::epsilon; 579 | template const T Constants::o3derrboundB = (T( 3) + T( 28) * Constants::epsilon) * Constants::epsilon; 580 | template const T Constants::o3derrboundC = (T(26) + T( 288) * Constants::epsilon) * Constants::epsilon * Constants::epsilon; 581 | template const T Constants::iccerrboundA = (T(10) + T( 96) * Constants::epsilon) * Constants::epsilon; 582 | template const T Constants::iccerrboundB = (T( 4) + T( 48) * Constants::epsilon) * Constants::epsilon; 583 | template const T Constants::iccerrboundC = (T(44) + T( 576) * Constants::epsilon) * Constants::epsilon * Constants::epsilon; 584 | template const T Constants::isperrboundA = (T(16) + T( 224) * Constants::epsilon) * Constants::epsilon; 585 | template const T Constants::isperrboundB = (T( 5) + T( 72) * Constants::epsilon) * Constants::epsilon; 586 | template const T Constants::isperrboundC = (T(71) + T(1408) * Constants::epsilon) * Constants::epsilon * Constants::epsilon; 587 | 588 | namespace adaptive { 589 | //@brief : determine if the 2d point c is above, on, or below the line defined by a and b 590 | //@param pa: pointer to a as {x, y} 591 | //@param pb: pointer to b as {x, y} 592 | //@param pc: pointer to c as {x, y} 593 | //@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}} 594 | //@note : positive, 0, negative result for c above, on, or below the line defined by a -> b 595 | template T orient2d(T const*const pa, T const*const pb, T const*const pc) { 596 | const T acx = pa[0] - pc[0]; 597 | const T bcx = pb[0] - pc[0]; 598 | const T acy = pa[1] - pc[1]; 599 | const T bcy = pb[1] - pc[1]; 600 | const T detleft = acx * bcy; 601 | const T detright = acy * bcx; 602 | T det = detleft - detright; 603 | if((detleft < 0) != (detright < 0)) return det; 604 | if(T(0) == detleft || T(0) == detright) return det; 605 | 606 | const T detsum = std::abs(detleft + detright); 607 | T errbound = Constants::ccwerrboundA * detsum; 608 | if(std::abs(det) >= std::abs(errbound)) return det; 609 | 610 | const detail::Expansion B = detail::ExpansionBase::TwoTwoDiff(acx, bcy, acy, bcx); 611 | det = B.estimate(); 612 | errbound = Constants::ccwerrboundB * detsum; 613 | if(std::abs(det) >= std::abs(errbound)) return det; 614 | 615 | const T acxtail = detail::ExpansionBase::MinusTail(pa[0], pc[0], acx); 616 | const T bcxtail = detail::ExpansionBase::MinusTail(pb[0], pc[0], bcx); 617 | const T acytail = detail::ExpansionBase::MinusTail(pa[1], pc[1], acy); 618 | const T bcytail = detail::ExpansionBase::MinusTail(pb[1], pc[1], bcy); 619 | if(T(0) == acxtail && T(0) == bcxtail && T(0) == acytail && T(0) == bcytail) return det; 620 | 621 | errbound = Constants::ccwerrboundC * detsum + Constants::resulterrbound * std::abs(det); 622 | det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail); 623 | if(std::abs(det) >= std::abs(errbound)) return det; 624 | 625 | const detail::Expansion D = ((B + detail::ExpansionBase::TwoTwoDiff(acxtail, bcy, acytail, bcx)) + detail::ExpansionBase::TwoTwoDiff(acx, bcytail, acy, bcxtail)) + detail::ExpansionBase::TwoTwoDiff(acxtail, bcytail, acytail, bcxtail); 626 | return D.mostSignificant(); 627 | } 628 | 629 | //@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c 630 | //@param pa: pointer to a as {x, y} 631 | //@param pb: pointer to b as {x, y} 632 | //@param pc: pointer to c as {x, y} 633 | //@param pc: pointer to d as {x, y} 634 | //@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}} 635 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 636 | template T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd) { 637 | const T adx = pa[0] - pd[0]; 638 | const T bdx = pb[0] - pd[0]; 639 | const T cdx = pc[0] - pd[0]; 640 | const T ady = pa[1] - pd[1]; 641 | const T bdy = pb[1] - pd[1]; 642 | const T cdy = pc[1] - pd[1]; 643 | const T bdxcdy = bdx * cdy; 644 | const T cdxbdy = cdx * bdy; 645 | const T cdxady = cdx * ady; 646 | const T adxcdy = adx * cdy; 647 | const T adxbdy = adx * bdy; 648 | const T bdxady = bdx * ady; 649 | const T alift = adx * adx + ady * ady; 650 | const T blift = bdx * bdx + bdy * bdy; 651 | const T clift = cdx * cdx + cdy * cdy; 652 | T det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady); 653 | const T permanent = (std::abs(bdxcdy) + std::abs(cdxbdy)) * alift 654 | + (std::abs(cdxady) + std::abs(adxcdy)) * blift 655 | + (std::abs(adxbdy) + std::abs(bdxady)) * clift; 656 | T errbound = Constants::iccerrboundA * permanent; 657 | if(std::abs(det) >= std::abs(errbound)) return det; 658 | 659 | const detail::Expansion bc = detail::ExpansionBase::TwoTwoDiff(bdx, cdy, cdx, bdy); 660 | const detail::Expansion ca = detail::ExpansionBase::TwoTwoDiff(cdx, ady, adx, cdy); 661 | const detail::Expansion ab = detail::ExpansionBase::TwoTwoDiff(adx, bdy, bdx, ady); 662 | const detail::Expansion adet = bc * adx * adx + bc * ady * ady; 663 | const detail::Expansion bdet = ca * bdx * bdx + ca * bdy * bdy; 664 | const detail::Expansion cdet = ab * cdx * cdx + ab * cdy * cdy; 665 | const detail::Expansion fin1 = adet + bdet + cdet; 666 | det = fin1.estimate(); 667 | errbound = Constants::iccerrboundB * permanent; 668 | if(std::abs(det) >= std::abs(errbound)) return det; 669 | 670 | const T adxtail = detail::ExpansionBase::MinusTail(pa[0], pd[0], adx); 671 | const T adytail = detail::ExpansionBase::MinusTail(pa[1], pd[1], ady); 672 | const T bdxtail = detail::ExpansionBase::MinusTail(pb[0], pd[0], bdx); 673 | const T bdytail = detail::ExpansionBase::MinusTail(pb[1], pd[1], bdy); 674 | const T cdxtail = detail::ExpansionBase::MinusTail(pc[0], pd[0], cdx); 675 | const T cdytail = detail::ExpansionBase::MinusTail(pc[1], pd[1], cdy); 676 | if(T(0) == adxtail && T(0) == bdxtail && T(0) == cdxtail && T(0) == adytail && T(0) == bdytail && T(0) == cdytail) return det; 677 | 678 | errbound = Constants::iccerrboundC * permanent + Constants::resulterrbound * std::abs(det); 679 | det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) 680 | + (bdx * cdy - bdy * cdx) * (adx * adxtail + ady * adytail) * T(2)) 681 | + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) 682 | + (cdx * ady - cdy * adx) * (bdx * bdxtail + bdy * bdytail) * T(2)) 683 | + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) 684 | + (adx * bdy - ady * bdx) * (cdx * cdxtail + cdy * cdytail) * T(2)); 685 | if(std::abs(det) >= std::abs(errbound)) return det; 686 | return exact::incircle(pa, pb, pc, pd); 687 | } 688 | 689 | //@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c 690 | //@param pa: pointer to a as {x, y, z} 691 | //@param pb: pointer to b as {x, y, z} 692 | //@param pc: pointer to c as {x, y, z} 693 | //@param pd: pointer to d as {x, y, z} 694 | //@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}} 695 | //@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c 696 | template T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd) { 697 | const T adx = pa[0] - pd[0]; 698 | const T bdx = pb[0] - pd[0]; 699 | const T cdx = pc[0] - pd[0]; 700 | const T ady = pa[1] - pd[1]; 701 | const T bdy = pb[1] - pd[1]; 702 | const T cdy = pc[1] - pd[1]; 703 | const T adz = pa[2] - pd[2]; 704 | const T bdz = pb[2] - pd[2]; 705 | const T cdz = pc[2] - pd[2]; 706 | const T bdxcdy = bdx * cdy; 707 | const T cdxbdy = cdx * bdy; 708 | const T cdxady = cdx * ady; 709 | const T adxcdy = adx * cdy; 710 | const T adxbdy = adx * bdy; 711 | const T bdxady = bdx * ady; 712 | T det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady); 713 | const T permanent = (std::abs(bdxcdy) + std::abs(cdxbdy)) * std::abs(adz) + (std::abs(cdxady) + std::abs(adxcdy)) * std::abs(bdz) + (std::abs(adxbdy) + std::abs(bdxady)) * std::abs(cdz); 714 | T errbound = Constants::o3derrboundA * permanent; 715 | if(std::abs(det) >= std::abs(errbound)) return det; 716 | 717 | const detail::Expansion bc = detail::ExpansionBase::TwoTwoDiff(bdx, cdy, cdx, bdy); 718 | const detail::Expansion ca = detail::ExpansionBase::TwoTwoDiff(cdx, ady, adx, cdy); 719 | const detail::Expansion ab = detail::ExpansionBase::TwoTwoDiff(adx, bdy, bdx, ady); 720 | const detail::Expansion fin1 = (bc * adz + ca * bdz) + ab * cdz; 721 | det = fin1.estimate(); 722 | errbound = Constants::o3derrboundB * permanent; 723 | if(std::abs(det) >= std::abs(errbound)) return det; 724 | 725 | const T adxtail = detail::ExpansionBase::MinusTail(pa[0], pd[0], adx); 726 | const T bdxtail = detail::ExpansionBase::MinusTail(pb[0], pd[0], bdx); 727 | const T cdxtail = detail::ExpansionBase::MinusTail(pc[0], pd[0], cdx); 728 | const T adytail = detail::ExpansionBase::MinusTail(pa[1], pd[1], ady); 729 | const T bdytail = detail::ExpansionBase::MinusTail(pb[1], pd[1], bdy); 730 | const T cdytail = detail::ExpansionBase::MinusTail(pc[1], pd[1], cdy); 731 | const T adztail = detail::ExpansionBase::MinusTail(pa[2], pd[2], adz); 732 | const T bdztail = detail::ExpansionBase::MinusTail(pb[2], pd[2], bdz); 733 | const T cdztail = detail::ExpansionBase::MinusTail(pc[2], pd[2], cdz); 734 | if(T(0) == adxtail && T(0) == adytail && T(0) == adztail && 735 | T(0) == bdxtail && T(0) == bdytail && T(0) == bdztail && 736 | T(0) == cdxtail && T(0) == cdytail && T(0) == cdztail) return det; 737 | 738 | errbound = Constants::o3derrboundC * permanent + Constants::resulterrbound * std::abs(det); 739 | det += (adz * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) + adztail * (bdx * cdy - bdy * cdx)) 740 | + (bdz * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) + bdztail * (cdx * ady - cdy * adx)) 741 | + (cdz * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) + cdztail * (adx * bdy - ady * bdx)); 742 | if(std::abs(det) >= std::abs(errbound)) return det; 743 | 744 | const detail::Expansion bct = detail::ExpansionBase::TwoTwoDiffZeroCheck(bdxtail, cdy, bdytail, cdx) + detail::ExpansionBase::TwoTwoDiffZeroCheck(cdytail, bdx, cdxtail, bdy); 745 | const detail::Expansion cat = detail::ExpansionBase::TwoTwoDiffZeroCheck(cdxtail, ady, cdytail, adx) + detail::ExpansionBase::TwoTwoDiffZeroCheck(adytail, cdx, adxtail, cdy); 746 | const detail::Expansion abt = detail::ExpansionBase::TwoTwoDiffZeroCheck(adxtail, bdy, adytail, bdx) + detail::ExpansionBase::TwoTwoDiffZeroCheck(bdytail, adx, bdxtail, ady); 747 | const detail::Expansion fin2 = fin1 + bct * adz + cat * bdz + abt * cdz + bc * adztail + ca * bdztail + ab * cdztail 748 | + detail::ExpansionBase::ThreeProd( adxtail, bdytail, cdz) + detail::ExpansionBase::ThreeProd( adxtail, bdytail, cdztail) 749 | + detail::ExpansionBase::ThreeProd(-adxtail, cdytail, bdz) + detail::ExpansionBase::ThreeProd(-adxtail, cdytail, bdztail) 750 | + detail::ExpansionBase::ThreeProd( bdxtail, cdytail, adz) + detail::ExpansionBase::ThreeProd( bdxtail, cdytail, adztail) 751 | + detail::ExpansionBase::ThreeProd(-bdxtail, adytail, cdz) + detail::ExpansionBase::ThreeProd(-bdxtail, adytail, cdztail) 752 | + detail::ExpansionBase::ThreeProd( cdxtail, adytail, bdz) + detail::ExpansionBase::ThreeProd( cdxtail, adytail, bdztail) 753 | + detail::ExpansionBase::ThreeProd(-cdxtail, bdytail, adz) + detail::ExpansionBase::ThreeProd(-cdxtail, bdytail, adztail) 754 | + bct * adztail + cat * bdztail + abt * cdztail; 755 | return fin2.mostSignificant(); 756 | } 757 | 758 | //@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d 759 | //@param pa: pointer to a as {x, y, z} 760 | //@param pb: pointer to b as {x, y, z} 761 | //@param pc: pointer to c as {x, y, z} 762 | //@param pd: pointer to d as {x, y, z} 763 | //@param pe: pointer to e as {x, y, z} 764 | //@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}} 765 | //@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c 766 | template T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe) { 767 | T permanent; 768 | const T aex = pa[0] - pe[0]; 769 | const T bex = pb[0] - pe[0]; 770 | const T cex = pc[0] - pe[0]; 771 | const T dex = pd[0] - pe[0]; 772 | const T aey = pa[1] - pe[1]; 773 | const T bey = pb[1] - pe[1]; 774 | const T cey = pc[1] - pe[1]; 775 | const T dey = pd[1] - pe[1]; 776 | const T aez = pa[2] - pe[2]; 777 | const T bez = pb[2] - pe[2]; 778 | const T cez = pc[2] - pe[2]; 779 | const T dez = pd[2] - pe[2]; 780 | { 781 | const T aexbey = aex * bey; 782 | const T bexaey = bex * aey; 783 | const T bexcey = bex * cey; 784 | const T cexbey = cex * bey; 785 | const T cexdey = cex * dey; 786 | const T dexcey = dex * cey; 787 | const T dexaey = dex * aey; 788 | const T aexdey = aex * dey; 789 | const T aexcey = aex * cey; 790 | const T cexaey = cex * aey; 791 | const T bexdey = bex * dey; 792 | const T dexbey = dex * bey; 793 | const T ab = aexbey - bexaey; 794 | const T bc = bexcey - cexbey; 795 | const T cd = cexdey - dexcey; 796 | const T da = dexaey - aexdey; 797 | const T ac = aexcey - cexaey; 798 | const T bd = bexdey - dexbey; 799 | const T abc = aez * bc - bez * ac + cez * ab; 800 | const T bcd = bez * cd - cez * bd + dez * bc; 801 | const T cda = cez * da + dez * ac + aez * cd; 802 | const T dab = dez * ab + aez * bd + bez * da; 803 | const T alift = aex * aex + aey * aey + aez * aez; 804 | const T blift = bex * bex + bey * bey + bez * bez; 805 | const T clift = cex * cex + cey * cey + cez * cez; 806 | const T dlift = dex * dex + dey * dey + dez * dez; 807 | const T det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); 808 | const T aezplus = std::abs(aez); 809 | const T bezplus = std::abs(bez); 810 | const T cezplus = std::abs(cez); 811 | const T dezplus = std::abs(dez); 812 | const T aexbeyplus = std::abs(aexbey); 813 | const T bexaeyplus = std::abs(bexaey); 814 | const T bexceyplus = std::abs(bexcey); 815 | const T cexbeyplus = std::abs(cexbey); 816 | const T cexdeyplus = std::abs(cexdey); 817 | const T dexceyplus = std::abs(dexcey); 818 | const T dexaeyplus = std::abs(dexaey); 819 | const T aexdeyplus = std::abs(aexdey); 820 | const T aexceyplus = std::abs(aexcey); 821 | const T cexaeyplus = std::abs(cexaey); 822 | const T bexdeyplus = std::abs(bexdey); 823 | const T dexbeyplus = std::abs(dexbey); 824 | permanent = ((cexdeyplus + dexceyplus) * bezplus + (dexbeyplus + bexdeyplus) * cezplus + (bexceyplus + cexbeyplus) * dezplus) * alift 825 | + ((dexaeyplus + aexdeyplus) * cezplus + (aexceyplus + cexaeyplus) * dezplus + (cexdeyplus + dexceyplus) * aezplus) * blift 826 | + ((aexbeyplus + bexaeyplus) * dezplus + (bexdeyplus + dexbeyplus) * aezplus + (dexaeyplus + aexdeyplus) * bezplus) * clift 827 | + ((bexceyplus + cexbeyplus) * aezplus + (cexaeyplus + aexceyplus) * bezplus + (aexbeyplus + bexaeyplus) * cezplus) * dlift; 828 | const T errbound = Constants::isperrboundA * permanent; 829 | if(std::abs(det) >= std::abs(errbound)) return det; 830 | } 831 | 832 | const detail::Expansion ab = detail::ExpansionBase::TwoTwoDiff(aex, bey, bex, aey); 833 | const detail::Expansion bc = detail::ExpansionBase::TwoTwoDiff(bex, cey, cex, bey); 834 | const detail::Expansion cd = detail::ExpansionBase::TwoTwoDiff(cex, dey, dex, cey); 835 | const detail::Expansion da = detail::ExpansionBase::TwoTwoDiff(dex, aey, aex, dey); 836 | const detail::Expansion ac = detail::ExpansionBase::TwoTwoDiff(aex, cey, cex, aey); 837 | const detail::Expansion bd = detail::ExpansionBase::TwoTwoDiff(bex, dey, dex, bey); 838 | const detail::Expansion temp24a = bc * dez + (cd * bez + bd * -cez); 839 | const detail::Expansion temp24b = cd * aez + (da * cez + ac * dez); 840 | const detail::Expansion temp24c = da * bez + (ab * dez + bd * aez); 841 | const detail::Expansion temp24d = ab * cez + (bc * aez + ac * -bez); 842 | const detail::Expansion adet = temp24a * aex * -aex + temp24a * aey * -aey + temp24a * aez * -aez; 843 | const detail::Expansion bdet = temp24b * bex * bex + temp24b * bey * bey + temp24b * bez * bez; 844 | const detail::Expansion cdet = temp24c * cex * -cex + temp24c * cey * -cey + temp24c * cez * -cez; 845 | const detail::Expansion ddet = temp24d * dex * dex + temp24d * dey * dey + temp24d * dez * dez; 846 | const detail::Expansion fin1 = (adet + bdet) + (cdet + ddet); 847 | T det = fin1.estimate(); 848 | T errbound = Constants::isperrboundB * permanent; 849 | if(std::abs(det) >= std::abs(errbound)) return det; 850 | 851 | const T aextail = detail::ExpansionBase::MinusTail(pa[0], pe[0], aex); 852 | const T aeytail = detail::ExpansionBase::MinusTail(pa[1], pe[1], aey); 853 | const T aeztail = detail::ExpansionBase::MinusTail(pa[2], pe[2], aez); 854 | const T bextail = detail::ExpansionBase::MinusTail(pb[0], pe[0], bex); 855 | const T beytail = detail::ExpansionBase::MinusTail(pb[1], pe[1], bey); 856 | const T beztail = detail::ExpansionBase::MinusTail(pb[2], pe[2], bez); 857 | const T cextail = detail::ExpansionBase::MinusTail(pc[0], pe[0], cex); 858 | const T ceytail = detail::ExpansionBase::MinusTail(pc[1], pe[1], cey); 859 | const T ceztail = detail::ExpansionBase::MinusTail(pc[2], pe[2], cez); 860 | const T dextail = detail::ExpansionBase::MinusTail(pd[0], pe[0], dex); 861 | const T deytail = detail::ExpansionBase::MinusTail(pd[1], pe[1], dey); 862 | const T deztail = detail::ExpansionBase::MinusTail(pd[2], pe[2], dez); 863 | if (T(0) == aextail && T(0) == aeytail && T(0) == aeztail && 864 | T(0) == bextail && T(0) == beytail && T(0) == beztail && 865 | T(0) == cextail && T(0) == ceytail && T(0) == ceztail && 866 | T(0) == dextail && T(0) == deytail && T(0) == deztail) return det; 867 | 868 | errbound = Constants::isperrboundC * permanent + Constants::resulterrbound * std::abs(det); 869 | const T abeps = (aex * beytail + bey * aextail) - (aey * bextail + bex * aeytail); 870 | const T bceps = (bex * ceytail + cey * bextail) - (bey * cextail + cex * beytail); 871 | const T cdeps = (cex * deytail + dey * cextail) - (cey * dextail + dex * ceytail); 872 | const T daeps = (dex * aeytail + aey * dextail) - (dey * aextail + aex * deytail); 873 | const T aceps = (aex * ceytail + cey * aextail) - (aey * cextail + cex * aeytail); 874 | const T bdeps = (bex * deytail + dey * bextail) - (bey * dextail + dex * beytail); 875 | const T ab3 = ab.mostSignificant(); 876 | const T bc3 = bc.mostSignificant(); 877 | const T cd3 = cd.mostSignificant(); 878 | const T da3 = da.mostSignificant(); 879 | const T ac3 = ac.mostSignificant(); 880 | const T bd3 = bd.mostSignificant(); 881 | det += ( ( (bex * bex + bey * bey + bez * bez) * ((cez * daeps + dez * aceps + aez * cdeps) + (ceztail * da3 + deztail * ac3 + aeztail * cd3)) 882 | + (dex * dex + dey * dey + dez * dez) * ((aez * bceps - bez * aceps + cez * abeps) + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)) ) 883 | - ( (aex * aex + aey * aey + aez * aez) * ((bez * cdeps - cez * bdeps + dez * bceps) + (beztail * cd3 - ceztail * bd3 + deztail * bc3)) 884 | + (cex * cex + cey * cey + cez * cez) * ((dez * abeps + aez * bdeps + bez * daeps) + (deztail * ab3 + aeztail * bd3 + beztail * da3)) ) ) 885 | + T(2) * ( ( (bex * bextail + bey * beytail + bez * beztail) * (cez * da3 + dez * ac3 + aez * cd3) 886 | + (dex * dextail + dey * deytail + dez * deztail) * (aez * bc3 - bez * ac3 + cez * ab3)) 887 | - ( (aex * aextail + aey * aeytail + aez * aeztail) * (bez * cd3 - cez * bd3 + dez * bc3) 888 | + (cex * cextail + cey * ceytail + cez * ceztail) * (dez * ab3 + aez * bd3 + bez * da3))); 889 | if(std::abs(det) >= std::abs(errbound)) return det; 890 | return exact::insphere(pa, pb, pc, pd, pe); 891 | } 892 | } 893 | } 894 | 895 | #endif 896 | --------------------------------------------------------------------------------