handle_self_turns.hpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2019.
  5. // Modifications copyright (c) 2019 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, 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_OVERLAY_HANDLE_SELF_TURNS_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
  12. #include <boost/range.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
  14. #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
  15. #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
  16. #include <boost/geometry/algorithms/covered_by.hpp>
  17. #include <boost/geometry/algorithms/within.hpp>
  18. namespace boost { namespace geometry
  19. {
  20. #ifndef DOXYGEN_NO_DETAIL
  21. namespace detail { namespace overlay
  22. {
  23. template
  24. <
  25. typename Point, typename Geometry,
  26. typename Tag2 = typename geometry::tag<Geometry>::type
  27. >
  28. struct check_within_strategy
  29. {
  30. template <typename Strategy>
  31. static inline typename Strategy::template point_in_geometry_strategy<Point, Geometry>::type
  32. within(Strategy const& strategy)
  33. {
  34. return strategy.template get_point_in_geometry_strategy<Point, Geometry>();
  35. }
  36. template <typename Strategy>
  37. static inline typename Strategy::template point_in_geometry_strategy<Point, Geometry>::type
  38. covered_by(Strategy const& strategy)
  39. {
  40. return strategy.template get_point_in_geometry_strategy<Point, Geometry>();
  41. }
  42. };
  43. template <typename Point, typename Geometry>
  44. struct check_within_strategy<Point, Geometry, box_tag>
  45. {
  46. template <typename Strategy>
  47. static inline typename Strategy::within_point_box_strategy_type
  48. within(Strategy const& )
  49. {
  50. return typename Strategy::within_point_box_strategy_type();
  51. }
  52. template <typename Strategy>
  53. static inline typename Strategy::covered_by_point_box_strategy_type
  54. covered_by(Strategy const&)
  55. {
  56. return typename Strategy::covered_by_point_box_strategy_type();
  57. }
  58. };
  59. template <overlay_type OverlayType>
  60. struct check_within
  61. {
  62. template
  63. <
  64. typename Turn, typename Geometry0, typename Geometry1,
  65. typename UmbrellaStrategy
  66. >
  67. static inline
  68. bool apply(Turn const& turn, Geometry0 const& geometry0,
  69. Geometry1 const& geometry1, UmbrellaStrategy const& strategy)
  70. {
  71. typedef typename Turn::point_type point_type;
  72. // Operations 0 and 1 have the same source index in self-turns
  73. return turn.operations[0].seg_id.source_index == 0
  74. ? geometry::within(turn.point, geometry1,
  75. check_within_strategy<point_type, Geometry1>::within(strategy))
  76. : geometry::within(turn.point, geometry0,
  77. check_within_strategy<point_type, Geometry0>::within(strategy));
  78. }
  79. };
  80. template <>
  81. struct check_within<overlay_difference>
  82. {
  83. template
  84. <
  85. typename Turn, typename Geometry0, typename Geometry1,
  86. typename UmbrellaStrategy
  87. >
  88. static inline
  89. bool apply(Turn const& turn, Geometry0 const& geometry0,
  90. Geometry1 const& geometry1, UmbrellaStrategy const& strategy)
  91. {
  92. typedef typename Turn::point_type point_type;
  93. // difference = intersection(a, reverse(b))
  94. // therefore we should reverse the meaning of within for geometry1
  95. return turn.operations[0].seg_id.source_index == 0
  96. ? ! geometry::covered_by(turn.point, geometry1,
  97. check_within_strategy<point_type, Geometry1>::covered_by(strategy))
  98. : geometry::within(turn.point, geometry0,
  99. check_within_strategy<point_type, Geometry0>::within(strategy));
  100. }
  101. };
  102. struct discard_turns
  103. {
  104. template
  105. <
  106. typename Turns, typename Clusters,
  107. typename Geometry0, typename Geometry1,
  108. typename Strategy
  109. >
  110. static inline
  111. void apply(Turns& , Clusters const& ,
  112. Geometry0 const& , Geometry1 const& ,
  113. Strategy const& )
  114. {}
  115. };
  116. template <overlay_type OverlayType, operation_type OperationType>
  117. struct discard_closed_turns : discard_turns {};
  118. // It is only implemented for operation_union, not in buffer
  119. template <>
  120. struct discard_closed_turns<overlay_union, operation_union>
  121. {
  122. // Point in Geometry Strategy
  123. template
  124. <
  125. typename Turns, typename Clusters,
  126. typename Geometry0, typename Geometry1,
  127. typename Strategy
  128. >
  129. static inline
  130. void apply(Turns& turns, Clusters const& /*clusters*/,
  131. Geometry0 const& geometry0, Geometry1 const& geometry1,
  132. Strategy const& strategy)
  133. {
  134. typedef typename boost::range_value<Turns>::type turn_type;
  135. for (typename boost::range_iterator<Turns>::type
  136. it = boost::begin(turns);
  137. it != boost::end(turns);
  138. ++it)
  139. {
  140. turn_type& turn = *it;
  141. if (! turn.discarded
  142. && is_self_turn<overlay_union>(turn)
  143. && check_within<overlay_union>::apply(turn, geometry0,
  144. geometry1, strategy))
  145. {
  146. // Turn is in the interior of other geometry
  147. turn.discarded = true;
  148. }
  149. }
  150. }
  151. };
  152. template <overlay_type OverlayType>
  153. struct discard_self_intersection_turns
  154. {
  155. private :
  156. template <typename Turns, typename Clusters>
  157. static inline
  158. bool is_self_cluster(signed_size_type cluster_id,
  159. const Turns& turns, Clusters const& clusters)
  160. {
  161. typename Clusters::const_iterator cit = clusters.find(cluster_id);
  162. if (cit == clusters.end())
  163. {
  164. return false;
  165. }
  166. cluster_info const& cinfo = cit->second;
  167. for (std::set<signed_size_type>::const_iterator it
  168. = cinfo.turn_indices.begin();
  169. it != cinfo.turn_indices.end(); ++it)
  170. {
  171. if (! is_self_turn<OverlayType>(turns[*it]))
  172. {
  173. return false;
  174. }
  175. }
  176. return true;
  177. }
  178. template <typename Turns, typename Clusters,
  179. typename Geometry0, typename Geometry1, typename Strategy>
  180. static inline
  181. void discard_clusters(Turns& turns, Clusters const& clusters,
  182. Geometry0 const& geometry0, Geometry1 const& geometry1,
  183. Strategy const& strategy)
  184. {
  185. for (typename Clusters::const_iterator cit = clusters.begin();
  186. cit != clusters.end(); ++cit)
  187. {
  188. signed_size_type const cluster_id = cit->first;
  189. // If there are only self-turns in the cluster, the cluster should
  190. // be located within the other geometry, for intersection
  191. if (! cit->second.turn_indices.empty()
  192. && is_self_cluster(cluster_id, turns, clusters))
  193. {
  194. cluster_info const& cinfo = cit->second;
  195. signed_size_type const index = *cinfo.turn_indices.begin();
  196. if (! check_within<OverlayType>::apply(turns[index],
  197. geometry0, geometry1,
  198. strategy))
  199. {
  200. // Discard all turns in cluster
  201. for (std::set<signed_size_type>::const_iterator sit
  202. = cinfo.turn_indices.begin();
  203. sit != cinfo.turn_indices.end(); ++sit)
  204. {
  205. turns[*sit].discarded = true;
  206. }
  207. }
  208. }
  209. }
  210. }
  211. public :
  212. template <typename Turns, typename Clusters,
  213. typename Geometry0, typename Geometry1, typename Strategy>
  214. static inline
  215. void apply(Turns& turns, Clusters const& clusters,
  216. Geometry0 const& geometry0, Geometry1 const& geometry1,
  217. Strategy const& strategy)
  218. {
  219. discard_clusters(turns, clusters, geometry0, geometry1, strategy);
  220. typedef typename boost::range_value<Turns>::type turn_type;
  221. for (typename boost::range_iterator<Turns>::type
  222. it = boost::begin(turns);
  223. it != boost::end(turns);
  224. ++it)
  225. {
  226. turn_type& turn = *it;
  227. // It is a ii self-turn
  228. // Check if it is within the other geometry
  229. if (! turn.discarded
  230. && is_self_turn<overlay_intersection>(turn)
  231. && ! check_within<OverlayType>::apply(turn, geometry0,
  232. geometry1, strategy))
  233. {
  234. // It is not within another geometry, set it as non startable.
  235. // It still might be traveled (#case_recursive_boxes_70)
  236. turn.operations[0].enriched.startable = false;
  237. turn.operations[1].enriched.startable = false;
  238. }
  239. }
  240. }
  241. };
  242. template <overlay_type OverlayType, operation_type OperationType>
  243. struct discard_open_turns : discard_turns {};
  244. // Handler for intersection
  245. template <>
  246. struct discard_open_turns<overlay_intersection, operation_intersection>
  247. : discard_self_intersection_turns<overlay_intersection> {};
  248. // Handler for difference, with different meaning of 'within'
  249. template <>
  250. struct discard_open_turns<overlay_difference, operation_intersection>
  251. : discard_self_intersection_turns<overlay_difference> {};
  252. }} // namespace detail::overlay
  253. #endif //DOXYGEN_NO_DETAIL
  254. }} // namespace boost::geometry
  255. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP