turns.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2019.
  4. // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP
  12. #include <boost/geometry/strategies/distance.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
  14. #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
  15. #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
  16. #include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
  17. #include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
  18. #include <boost/geometry/strategies/cartesian/point_in_point.hpp>
  19. #include <boost/geometry/strategies/spherical/point_in_point.hpp>
  20. #include <boost/type_traits/is_base_of.hpp>
  21. namespace boost { namespace geometry {
  22. #ifndef DOXYGEN_NO_DETAIL
  23. namespace detail { namespace relate { namespace turns {
  24. template <bool IncludeDegenerate = false>
  25. struct assign_policy
  26. : overlay::assign_null_policy
  27. {
  28. static bool const include_degenerate = IncludeDegenerate;
  29. };
  30. // GET_TURNS
  31. template
  32. <
  33. typename Geometry1,
  34. typename Geometry2,
  35. typename GetTurnPolicy = detail::get_turns::get_turn_info_type
  36. <
  37. Geometry1, Geometry2, assign_policy<>
  38. >
  39. >
  40. struct get_turns
  41. {
  42. typedef typename geometry::point_type<Geometry1>::type point1_type;
  43. template <typename Strategy>
  44. struct robust_policy_type
  45. : geometry::rescale_overlay_policy_type
  46. <
  47. Geometry1,
  48. Geometry2,
  49. typename Strategy::cs_tag
  50. >
  51. {};
  52. template
  53. <
  54. typename Strategy,
  55. typename RobustPolicy = typename robust_policy_type<Strategy>::type
  56. >
  57. struct turn_info_type
  58. {
  59. typedef typename segment_ratio_type<point1_type, RobustPolicy>::type ratio_type;
  60. typedef overlay::turn_info
  61. <
  62. point1_type,
  63. ratio_type,
  64. typename detail::get_turns::turn_operation_type
  65. <
  66. Geometry1, Geometry2, ratio_type
  67. >::type
  68. > type;
  69. };
  70. template <typename Turns>
  71. static inline void apply(Turns & turns,
  72. Geometry1 const& geometry1,
  73. Geometry2 const& geometry2)
  74. {
  75. detail::get_turns::no_interrupt_policy interrupt_policy;
  76. typename strategy::intersection::services::default_strategy
  77. <
  78. typename cs_tag<Geometry1>::type
  79. >::type intersection_strategy;
  80. apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy);
  81. }
  82. template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy>
  83. static inline void apply(Turns & turns,
  84. Geometry1 const& geometry1,
  85. Geometry2 const& geometry2,
  86. InterruptPolicy & interrupt_policy,
  87. IntersectionStrategy const& intersection_strategy)
  88. {
  89. typedef typename robust_policy_type<IntersectionStrategy>::type robust_policy_t;
  90. robust_policy_t robust_policy
  91. = geometry::get_rescale_policy<robust_policy_t>(
  92. geometry1, geometry2, intersection_strategy);
  93. apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy, robust_policy);
  94. }
  95. template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy, typename RobustPolicy>
  96. static inline void apply(Turns & turns,
  97. Geometry1 const& geometry1,
  98. Geometry2 const& geometry2,
  99. InterruptPolicy & interrupt_policy,
  100. IntersectionStrategy const& intersection_strategy,
  101. RobustPolicy const& robust_policy)
  102. {
  103. static const bool reverse1 = detail::overlay::do_reverse
  104. <
  105. geometry::point_order<Geometry1>::value
  106. >::value;
  107. static const bool reverse2 = detail::overlay::do_reverse
  108. <
  109. geometry::point_order<Geometry2>::value
  110. >::value;
  111. dispatch::get_turns
  112. <
  113. typename geometry::tag<Geometry1>::type,
  114. typename geometry::tag<Geometry2>::type,
  115. Geometry1,
  116. Geometry2,
  117. reverse1,
  118. reverse2,
  119. GetTurnPolicy
  120. >::apply(0, geometry1, 1, geometry2,
  121. intersection_strategy, robust_policy,
  122. turns, interrupt_policy);
  123. }
  124. };
  125. // TURNS SORTING AND SEARCHING
  126. template <int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0>
  127. struct op_to_int
  128. {
  129. template <typename Operation>
  130. inline int operator()(Operation const& op) const
  131. {
  132. switch(op.operation)
  133. {
  134. case detail::overlay::operation_none : return N;
  135. case detail::overlay::operation_union : return U;
  136. case detail::overlay::operation_intersection : return I;
  137. case detail::overlay::operation_blocked : return B;
  138. case detail::overlay::operation_continue : return C;
  139. case detail::overlay::operation_opposite : return O;
  140. }
  141. return -1;
  142. }
  143. };
  144. template <std::size_t OpId, typename OpToInt>
  145. struct less_op_xxx_linear
  146. {
  147. template <typename Turn>
  148. inline bool operator()(Turn const& left, Turn const& right) const
  149. {
  150. static OpToInt op_to_int;
  151. return op_to_int(left.operations[OpId]) < op_to_int(right.operations[OpId]);
  152. }
  153. };
  154. template <std::size_t OpId>
  155. struct less_op_linear_linear
  156. : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> >
  157. {};
  158. template <std::size_t OpId>
  159. struct less_op_linear_areal_single
  160. {
  161. template <typename Turn>
  162. inline bool operator()(Turn const& left, Turn const& right) const
  163. {
  164. static const std::size_t other_op_id = (OpId + 1) % 2;
  165. static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic;
  166. static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc;
  167. segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
  168. segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
  169. typedef typename Turn::turn_operation_type operation_type;
  170. operation_type const& left_operation = left.operations[OpId];
  171. operation_type const& right_operation = right.operations[OpId];
  172. if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
  173. {
  174. return op_to_int_xuic(left_operation)
  175. < op_to_int_xuic(right_operation);
  176. }
  177. else
  178. {
  179. return op_to_int_xiuc(left_operation)
  180. < op_to_int_xiuc(right_operation);
  181. }
  182. }
  183. };
  184. template <std::size_t OpId>
  185. struct less_op_areal_linear
  186. : less_op_xxx_linear< OpId, op_to_int<0,1,0,0,2,0> >
  187. {};
  188. template <std::size_t OpId>
  189. struct less_op_areal_areal
  190. {
  191. template <typename Turn>
  192. inline bool operator()(Turn const& left, Turn const& right) const
  193. {
  194. static const std::size_t other_op_id = (OpId + 1) % 2;
  195. static op_to_int<0, 1, 2, 3, 4, 0> op_to_int_uixc;
  196. static op_to_int<0, 2, 1, 3, 4, 0> op_to_int_iuxc;
  197. segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id;
  198. segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id;
  199. typedef typename Turn::turn_operation_type operation_type;
  200. operation_type const& left_operation = left.operations[OpId];
  201. operation_type const& right_operation = right.operations[OpId];
  202. if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index )
  203. {
  204. if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index )
  205. {
  206. return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
  207. }
  208. else
  209. {
  210. if ( left_other_seg_id.ring_index == -1 )
  211. {
  212. if ( left_operation.operation == overlay::operation_union )
  213. return false;
  214. else if ( left_operation.operation == overlay::operation_intersection )
  215. return true;
  216. }
  217. else if ( right_other_seg_id.ring_index == -1 )
  218. {
  219. if ( right_operation.operation == overlay::operation_union )
  220. return true;
  221. else if ( right_operation.operation == overlay::operation_intersection )
  222. return false;
  223. }
  224. return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation);
  225. }
  226. }
  227. else
  228. {
  229. return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation);
  230. }
  231. }
  232. };
  233. template <std::size_t OpId>
  234. struct less_other_multi_index
  235. {
  236. static const std::size_t other_op_id = (OpId + 1) % 2;
  237. template <typename Turn>
  238. inline bool operator()(Turn const& left, Turn const& right) const
  239. {
  240. return left.operations[other_op_id].seg_id.multi_index
  241. < right.operations[other_op_id].seg_id.multi_index;
  242. }
  243. };
  244. // sort turns by G1 - source_index == 0 by:
  245. // seg_id -> distance and coordinates -> operation
  246. template <std::size_t OpId, typename LessOp, typename CSTag>
  247. struct less
  248. {
  249. BOOST_STATIC_ASSERT(OpId < 2);
  250. template <typename Turn>
  251. static inline bool use_fraction(Turn const& left, Turn const& right)
  252. {
  253. typedef typename geometry::strategy::within::services::default_strategy
  254. <
  255. typename Turn::point_type, typename Turn::point_type,
  256. point_tag, point_tag,
  257. pointlike_tag, pointlike_tag,
  258. typename tag_cast<CSTag, spherical_tag>::type,
  259. typename tag_cast<CSTag, spherical_tag>::type
  260. >::type eq_pp_strategy_type;
  261. static LessOp less_op;
  262. // NOTE: Assuming fraction is more permissive and faster than
  263. // comparison of points with strategy.
  264. return geometry::math::equals(left.operations[OpId].fraction,
  265. right.operations[OpId].fraction)
  266. && eq_pp_strategy_type::apply(left.point, right.point)
  267. ?
  268. less_op(left, right)
  269. :
  270. (left.operations[OpId].fraction < right.operations[OpId].fraction)
  271. ;
  272. }
  273. template <typename Turn>
  274. inline bool operator()(Turn const& left, Turn const& right) const
  275. {
  276. segment_identifier const& sl = left.operations[OpId].seg_id;
  277. segment_identifier const& sr = right.operations[OpId].seg_id;
  278. return sl < sr || ( sl == sr && use_fraction(left, right) );
  279. }
  280. };
  281. }}} // namespace detail::relate::turns
  282. #endif // DOXYGEN_NO_DETAIL
  283. }} // namespace boost::geometry
  284. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP