1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. 4 5 // This file was modified by Oracle on 2015, 2019. 6 // Modifications copyright (c) 2015-2019, Oracle and/or its affiliates. 7 8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle 9 10 // Use, modification and distribution is subject to the Boost Software License, 11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 12 // http://www.boost.org/LICENSE_1_0.txt) 13 14 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP 15 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP 16 17 18 #include <limits> 19 20 #include <boost/core/ignore_unused.hpp> 21 #include <boost/type_traits/is_integral.hpp> 22 #include <boost/type_traits/make_unsigned.hpp> 23 24 #include <boost/geometry/arithmetic/determinant.hpp> 25 #include <boost/geometry/core/access.hpp> 26 #include <boost/geometry/core/assert.hpp> 27 #include <boost/geometry/core/coordinate_type.hpp> 28 #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> 29 #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> 30 #include <boost/geometry/util/math.hpp> 31 32 #ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG 33 #include <boost/math/common_factor_ct.hpp> 34 #include <boost/math/common_factor_rt.hpp> 35 #include <boost/multiprecision/cpp_int.hpp> 36 #endif 37 38 namespace boost { namespace geometry 39 { 40 41 namespace strategy { namespace side 42 { 43 44 namespace detail 45 { 46 47 // A tool for multiplication of integers avoiding overflow 48 // It's a temporary workaround until we can use Multiprecision 49 // The algorithm is based on Karatsuba algorithm 50 // see: http://en.wikipedia.org/wiki/Karatsuba_algorithm 51 template <typename T> 52 struct multiplicable_integral 53 { 54 // Currently this tool can't be used with non-integral coordinate types. 55 // Also side_of_intersection strategy sign_of_product() and sign_of_compare() 56 // functions would have to be modified to properly support floating-point 57 // types (comparisons and multiplication). 58 BOOST_STATIC_ASSERT(boost::is_integral<T>::value); 59 60 static const std::size_t bits = CHAR_BIT * sizeof(T); 61 static const std::size_t half_bits = bits / 2; 62 typedef typename boost::make_unsigned<T>::type unsigned_type; 63 static const unsigned_type base = unsigned_type(1) << half_bits; // 2^half_bits 64 65 int m_sign; 66 unsigned_type m_ms; 67 unsigned_type m_ls; 68 multiplicable_integralboost::geometry::strategy::side::detail::multiplicable_integral69 multiplicable_integral(int sign, unsigned_type ms, unsigned_type ls) 70 : m_sign(sign), m_ms(ms), m_ls(ls) 71 {} 72 multiplicable_integralboost::geometry::strategy::side::detail::multiplicable_integral73 explicit multiplicable_integral(T const& val) 74 { 75 unsigned_type val_u = val > 0 ? 76 unsigned_type(val) 77 : val == (std::numeric_limits<T>::min)() ? 78 unsigned_type((std::numeric_limits<T>::max)()) + 1 79 : unsigned_type(-val); 80 // MMLL -> S 00MM 00LL 81 m_sign = math::sign(val); 82 m_ms = val_u >> half_bits; // val_u / base 83 m_ls = val_u - m_ms * base; 84 } 85 operator *(multiplicable_integral const & a,multiplicable_integral const & b)86 friend multiplicable_integral operator*(multiplicable_integral const& a, 87 multiplicable_integral const& b) 88 { 89 // (S 00MM 00LL) * (S 00MM 00LL) -> (S Z2MM 00LL) 90 unsigned_type z2 = a.m_ms * b.m_ms; 91 unsigned_type z0 = a.m_ls * b.m_ls; 92 unsigned_type z1 = (a.m_ms + a.m_ls) * (b.m_ms + b.m_ls) - z2 - z0; 93 // z0 may be >= base so it must be normalized to allow comparison 94 unsigned_type z0_ms = z0 >> half_bits; // z0 / base 95 return multiplicable_integral(a.m_sign * b.m_sign, 96 z2 * base + z1 + z0_ms, 97 z0 - base * z0_ms); 98 } 99 operator <(multiplicable_integral const & a,multiplicable_integral const & b)100 friend bool operator<(multiplicable_integral const& a, 101 multiplicable_integral const& b) 102 { 103 if ( a.m_sign == b.m_sign ) 104 { 105 bool u_less = a.m_ms < b.m_ms 106 || (a.m_ms == b.m_ms && a.m_ls < b.m_ls); 107 return a.m_sign > 0 ? u_less : (! u_less); 108 } 109 else 110 { 111 return a.m_sign < b.m_sign; 112 } 113 } 114 operator >(multiplicable_integral const & a,multiplicable_integral const & b)115 friend bool operator>(multiplicable_integral const& a, 116 multiplicable_integral const& b) 117 { 118 return b < a; 119 } 120 121 #ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG 122 template <typename CmpVal> check_valueboost::geometry::strategy::side::detail::multiplicable_integral123 void check_value(CmpVal const& cmp_val) const 124 { 125 unsigned_type b = base; // a workaround for MinGW - undefined reference base 126 CmpVal val = CmpVal(m_sign) * (CmpVal(m_ms) * CmpVal(b) + CmpVal(m_ls)); 127 BOOST_GEOMETRY_ASSERT(cmp_val == val); 128 } 129 #endif // BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG 130 }; 131 132 } // namespace detail 133 134 // Calculates the side of the intersection-point (if any) of 135 // of segment a//b w.r.t. segment c 136 // This is calculated without (re)calculating the IP itself again and fully 137 // based on integer mathematics; there are no divisions 138 // It can be used for either integer (rescaled) points, and also for FP 139 class side_of_intersection 140 { 141 private : 142 template <typename T, typename U> 143 static inline sign_of_product(T const & a,U const & b)144 int sign_of_product(T const& a, U const& b) 145 { 146 return a == 0 || b == 0 ? 0 147 : a > 0 && b > 0 ? 1 148 : a < 0 && b < 0 ? 1 149 : -1; 150 } 151 152 template <typename T> 153 static inline sign_of_compare(T const & a,T const & b,T const & c,T const & d)154 int sign_of_compare(T const& a, T const& b, T const& c, T const& d) 155 { 156 // Both a*b and c*d are positive 157 // We have to judge if a*b > c*d 158 159 using side::detail::multiplicable_integral; 160 multiplicable_integral<T> ab = multiplicable_integral<T>(a) 161 * multiplicable_integral<T>(b); 162 multiplicable_integral<T> cd = multiplicable_integral<T>(c) 163 * multiplicable_integral<T>(d); 164 165 int result = ab > cd ? 1 166 : ab < cd ? -1 167 : 0 168 ; 169 170 #ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG 171 using namespace boost::multiprecision; 172 cpp_int const lab = cpp_int(a) * cpp_int(b); 173 cpp_int const lcd = cpp_int(c) * cpp_int(d); 174 175 ab.check_value(lab); 176 cd.check_value(lcd); 177 178 int result2 = lab > lcd ? 1 179 : lab < lcd ? -1 180 : 0 181 ; 182 BOOST_GEOMETRY_ASSERT(result == result2); 183 #endif 184 185 return result; 186 } 187 188 template <typename T> 189 static inline sign_of_addition_of_two_products(T const & a,T const & b,T const & c,T const & d)190 int sign_of_addition_of_two_products(T const& a, T const& b, T const& c, T const& d) 191 { 192 // sign of a*b+c*d, 1 if positive, -1 if negative, else 0 193 int const ab = sign_of_product(a, b); 194 int const cd = sign_of_product(c, d); 195 if (ab == 0) 196 { 197 return cd; 198 } 199 if (cd == 0) 200 { 201 return ab; 202 } 203 204 if (ab == cd) 205 { 206 // Both positive or both negative 207 return ab; 208 } 209 210 // One is positive, one is negative, both are non zero 211 // If ab is positive, we have to judge if a*b > -c*d (then 1 because sum is positive) 212 // If ab is negative, we have to judge if c*d > -a*b (idem) 213 return ab == 1 214 ? sign_of_compare(a, b, -c, d) 215 : sign_of_compare(c, d, -a, b); 216 } 217 218 219 public : 220 221 // Calculates the side of the intersection-point (if any) of 222 // of segment a//b w.r.t. segment c 223 // This is calculated without (re)calculating the IP itself again and fully 224 // based on integer mathematics 225 template <typename T, typename Segment, typename Point> side_value(Segment const & a,Segment const & b,Segment const & c,Point const & fallback_point)226 static inline T side_value(Segment const& a, Segment const& b, 227 Segment const& c, Point const& fallback_point) 228 { 229 // The first point of the three segments is reused several times 230 T const ax = get<0, 0>(a); 231 T const ay = get<0, 1>(a); 232 T const bx = get<0, 0>(b); 233 T const by = get<0, 1>(b); 234 T const cx = get<0, 0>(c); 235 T const cy = get<0, 1>(c); 236 237 T const dx_a = get<1, 0>(a) - ax; 238 T const dy_a = get<1, 1>(a) - ay; 239 240 T const dx_b = get<1, 0>(b) - bx; 241 T const dy_b = get<1, 1>(b) - by; 242 243 T const dx_c = get<1, 0>(c) - cx; 244 T const dy_c = get<1, 1>(c) - cy; 245 246 // Cramer's rule: d (see cart_intersect.hpp) 247 T const d = geometry::detail::determinant<T> 248 ( 249 dx_a, dy_a, 250 dx_b, dy_b 251 ); 252 253 T const zero = T(); 254 if (d == zero) 255 { 256 // There is no IP of a//b, they are collinear or parallel 257 // Assuming they intersect (this method should be called for 258 // segments known to intersect), they are collinear and overlap. 259 // They have one or two intersection points - we don't know and 260 // have to rely on the fallback intersection point 261 262 Point c1, c2; 263 geometry::detail::assign_point_from_index<0>(c, c1); 264 geometry::detail::assign_point_from_index<1>(c, c2); 265 return side_by_triangle<>::apply(c1, c2, fallback_point); 266 } 267 268 // Cramer's rule: da (see cart_intersect.hpp) 269 T const da = geometry::detail::determinant<T> 270 ( 271 dx_b, dy_b, 272 ax - bx, ay - by 273 ); 274 275 // IP is at (ax + (da/d) * dx_a, ay + (da/d) * dy_a) 276 // Side of IP is w.r.t. c is: determinant(dx_c, dy_c, ipx-cx, ipy-cy) 277 // We replace ipx by expression above and multiply each term by d 278 279 #ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG 280 T const result1 = geometry::detail::determinant<T> 281 ( 282 dx_c * d, dy_c * d, 283 d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da 284 ); 285 286 // Note: result / (d * d) 287 // is identical to the side_value of side_by_triangle 288 // Therefore, the sign is always the same as that result, and the 289 // resulting side (left,right,collinear) is the same 290 291 // The first row we divide again by d because of determinant multiply rule 292 T const result2 = d * geometry::detail::determinant<T> 293 ( 294 dx_c, dy_c, 295 d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da 296 ); 297 // Write out: 298 T const result3 = d * (dx_c * (d * (ay - cy) + dy_a * da) 299 - dy_c * (d * (ax - cx) + dx_a * da)); 300 // Write out in braces: 301 T const result4 = d * (dx_c * d * (ay - cy) + dx_c * dy_a * da 302 - dy_c * d * (ax - cx) - dy_c * dx_a * da); 303 // Write in terms of d * XX + da * YY 304 T const result5 = d * (d * (dx_c * (ay - cy) - dy_c * (ax - cx)) 305 + da * (dx_c * dy_a - dy_c * dx_a)); 306 307 boost::ignore_unused(result1, result2, result3, result4, result5); 308 //return result; 309 #endif 310 311 // We consider the results separately 312 // (in the end we only have to return the side-value 1,0 or -1) 313 314 // To avoid multiplications we judge the product (easy, avoids *d) 315 // and the sign of p*q+r*s (more elaborate) 316 T const result = sign_of_product 317 ( 318 d, 319 sign_of_addition_of_two_products 320 ( 321 d, dx_c * (ay - cy) - dy_c * (ax - cx), 322 da, dx_c * dy_a - dy_c * dx_a 323 ) 324 ); 325 return result; 326 327 328 } 329 330 template <typename Segment, typename Point> apply(Segment const & a,Segment const & b,Segment const & c,Point const & fallback_point)331 static inline int apply(Segment const& a, Segment const& b, 332 Segment const& c, 333 Point const& fallback_point) 334 { 335 typedef typename geometry::coordinate_type<Segment>::type coordinate_type; 336 coordinate_type const s = side_value<coordinate_type>(a, b, c, fallback_point); 337 coordinate_type const zero = coordinate_type(); 338 return math::equals(s, zero) ? 0 339 : s > zero ? 1 340 : -1; 341 } 342 343 }; 344 345 346 }} // namespace strategy::side 347 348 }} // namespace boost::geometry 349 350 351 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP 352