side_of_intersection.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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.
  4. // Modifications copyright (c) 2015, 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. template <typename CmpVal>
  100. void check_value(CmpVal const& cmp_val) const
  101. {
  102. unsigned_type b = base; // a workaround for MinGW - undefined reference base
  103. CmpVal val = CmpVal(m_sign) * (CmpVal(m_ms) * CmpVal(b) + CmpVal(m_ls));
  104. BOOST_GEOMETRY_ASSERT(cmp_val == val);
  105. }
  106. };
  107. } // namespace detail
  108. // Calculates the side of the intersection-point (if any) of
  109. // of segment a//b w.r.t. segment c
  110. // This is calculated without (re)calculating the IP itself again and fully
  111. // based on integer mathematics; there are no divisions
  112. // It can be used for either integer (rescaled) points, and also for FP
  113. class side_of_intersection
  114. {
  115. private :
  116. template <typename T, typename U>
  117. static inline
  118. int sign_of_product(T const& a, U const& b)
  119. {
  120. return a == 0 || b == 0 ? 0
  121. : a > 0 && b > 0 ? 1
  122. : a < 0 && b < 0 ? 1
  123. : -1;
  124. }
  125. template <typename T>
  126. static inline
  127. int sign_of_compare(T const& a, T const& b, T const& c, T const& d)
  128. {
  129. // Both a*b and c*d are positive
  130. // We have to judge if a*b > c*d
  131. using side::detail::multiplicable_integral;
  132. multiplicable_integral<T> ab = multiplicable_integral<T>(a)
  133. * multiplicable_integral<T>(b);
  134. multiplicable_integral<T> cd = multiplicable_integral<T>(c)
  135. * multiplicable_integral<T>(d);
  136. int result = ab > cd ? 1
  137. : ab < cd ? -1
  138. : 0
  139. ;
  140. #ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG
  141. using namespace boost::multiprecision;
  142. cpp_int const lab = cpp_int(a) * cpp_int(b);
  143. cpp_int const lcd = cpp_int(c) * cpp_int(d);
  144. ab.check_value(lab);
  145. cd.check_value(lcd);
  146. int result2 = lab > lcd ? 1
  147. : lab < lcd ? -1
  148. : 0
  149. ;
  150. BOOST_GEOMETRY_ASSERT(result == result2);
  151. #endif
  152. return result;
  153. }
  154. template <typename T>
  155. static inline
  156. int sign_of_addition_of_two_products(T const& a, T const& b, T const& c, T const& d)
  157. {
  158. // sign of a*b+c*d, 1 if positive, -1 if negative, else 0
  159. int const ab = sign_of_product(a, b);
  160. int const cd = sign_of_product(c, d);
  161. if (ab == 0)
  162. {
  163. return cd;
  164. }
  165. if (cd == 0)
  166. {
  167. return ab;
  168. }
  169. if (ab == cd)
  170. {
  171. // Both positive or both negative
  172. return ab;
  173. }
  174. // One is positive, one is negative, both are non zero
  175. // If ab is positive, we have to judge if a*b > -c*d (then 1 because sum is positive)
  176. // If ab is negative, we have to judge if c*d > -a*b (idem)
  177. return ab == 1
  178. ? sign_of_compare(a, b, -c, d)
  179. : sign_of_compare(c, d, -a, b);
  180. }
  181. public :
  182. // Calculates the side of the intersection-point (if any) of
  183. // of segment a//b w.r.t. segment c
  184. // This is calculated without (re)calculating the IP itself again and fully
  185. // based on integer mathematics
  186. template <typename T, typename Segment, typename Point>
  187. static inline T side_value(Segment const& a, Segment const& b,
  188. Segment const& c, Point const& fallback_point)
  189. {
  190. // The first point of the three segments is reused several times
  191. T const ax = get<0, 0>(a);
  192. T const ay = get<0, 1>(a);
  193. T const bx = get<0, 0>(b);
  194. T const by = get<0, 1>(b);
  195. T const cx = get<0, 0>(c);
  196. T const cy = get<0, 1>(c);
  197. T const dx_a = get<1, 0>(a) - ax;
  198. T const dy_a = get<1, 1>(a) - ay;
  199. T const dx_b = get<1, 0>(b) - bx;
  200. T const dy_b = get<1, 1>(b) - by;
  201. T const dx_c = get<1, 0>(c) - cx;
  202. T const dy_c = get<1, 1>(c) - cy;
  203. // Cramer's rule: d (see cart_intersect.hpp)
  204. T const d = geometry::detail::determinant<T>
  205. (
  206. dx_a, dy_a,
  207. dx_b, dy_b
  208. );
  209. T const zero = T();
  210. if (d == zero)
  211. {
  212. // There is no IP of a//b, they are collinear or parallel
  213. // Assuming they intersect (this method should be called for
  214. // segments known to intersect), they are collinear and overlap.
  215. // They have one or two intersection points - we don't know and
  216. // have to rely on the fallback intersection point
  217. Point c1, c2;
  218. geometry::detail::assign_point_from_index<0>(c, c1);
  219. geometry::detail::assign_point_from_index<1>(c, c2);
  220. return side_by_triangle<>::apply(c1, c2, fallback_point);
  221. }
  222. // Cramer's rule: da (see cart_intersect.hpp)
  223. T const da = geometry::detail::determinant<T>
  224. (
  225. dx_b, dy_b,
  226. ax - bx, ay - by
  227. );
  228. // IP is at (ax + (da/d) * dx_a, ay + (da/d) * dy_a)
  229. // Side of IP is w.r.t. c is: determinant(dx_c, dy_c, ipx-cx, ipy-cy)
  230. // We replace ipx by expression above and multiply each term by d
  231. #ifdef BOOST_GEOMETRY_SIDE_OF_INTERSECTION_DEBUG
  232. T const result1 = geometry::detail::determinant<T>
  233. (
  234. dx_c * d, dy_c * d,
  235. d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da
  236. );
  237. // Note: result / (d * d)
  238. // is identical to the side_value of side_by_triangle
  239. // Therefore, the sign is always the same as that result, and the
  240. // resulting side (left,right,collinear) is the same
  241. // The first row we divide again by d because of determinant multiply rule
  242. T const result2 = d * geometry::detail::determinant<T>
  243. (
  244. dx_c, dy_c,
  245. d * (ax - cx) + dx_a * da, d * (ay - cy) + dy_a * da
  246. );
  247. // Write out:
  248. T const result3 = d * (dx_c * (d * (ay - cy) + dy_a * da)
  249. - dy_c * (d * (ax - cx) + dx_a * da));
  250. // Write out in braces:
  251. T const result4 = d * (dx_c * d * (ay - cy) + dx_c * dy_a * da
  252. - dy_c * d * (ax - cx) - dy_c * dx_a * da);
  253. // Write in terms of d * XX + da * YY
  254. T const result5 = d * (d * (dx_c * (ay - cy) - dy_c * (ax - cx))
  255. + da * (dx_c * dy_a - dy_c * dx_a));
  256. boost::ignore_unused(result1, result2, result3, result4, result5);
  257. //return result;
  258. #endif
  259. // We consider the results separately
  260. // (in the end we only have to return the side-value 1,0 or -1)
  261. // To avoid multiplications we judge the product (easy, avoids *d)
  262. // and the sign of p*q+r*s (more elaborate)
  263. T const result = sign_of_product
  264. (
  265. d,
  266. sign_of_addition_of_two_products
  267. (
  268. d, dx_c * (ay - cy) - dy_c * (ax - cx),
  269. da, dx_c * dy_a - dy_c * dx_a
  270. )
  271. );
  272. return result;
  273. }
  274. template <typename Segment, typename Point>
  275. static inline int apply(Segment const& a, Segment const& b,
  276. Segment const& c,
  277. Point const& fallback_point)
  278. {
  279. typedef typename geometry::coordinate_type<Segment>::type coordinate_type;
  280. coordinate_type const s = side_value<coordinate_type>(a, b, c, fallback_point);
  281. coordinate_type const zero = coordinate_type();
  282. return math::equals(s, zero) ? 0
  283. : s > zero ? 1
  284. : -1;
  285. }
  286. };
  287. }} // namespace strategy::side
  288. }} // namespace boost::geometry
  289. #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_SIDE_OF_INTERSECTION_HPP