handle_self_turns.hpp 7.5 KB

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