side_of_intersection.hpp 12 KB

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