linear.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2014-2021, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  4. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Licensed under the Boost Software License version 1.0.
  7. // http://www.boost.org/users/license.html
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
  10. #include <algorithm>
  11. #include <deque>
  12. #include <boost/range/begin.hpp>
  13. #include <boost/range/empty.hpp>
  14. #include <boost/range/end.hpp>
  15. #include <boost/range/size.hpp>
  16. #include <boost/range/value_type.hpp>
  17. #include <boost/geometry/core/assert.hpp>
  18. #include <boost/geometry/core/closure.hpp>
  19. #include <boost/geometry/core/coordinate_type.hpp>
  20. #include <boost/geometry/core/point_type.hpp>
  21. #include <boost/geometry/core/tag.hpp>
  22. #include <boost/geometry/core/tags.hpp>
  23. #include <boost/geometry/util/range.hpp>
  24. #include <boost/geometry/policies/predicate_based_interrupt_policy.hpp>
  25. #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
  26. #include <boost/geometry/policies/robustness/segment_ratio.hpp>
  27. #include <boost/geometry/algorithms/intersects.hpp>
  28. #include <boost/geometry/algorithms/not_implemented.hpp>
  29. #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
  30. #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
  31. #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
  32. #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
  33. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  34. #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
  35. #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp>
  36. #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
  37. #include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp>
  38. #include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp>
  39. #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp>
  40. #include <boost/geometry/algorithms/dispatch/is_simple.hpp>
  41. #include <boost/geometry/strategies/intersection.hpp>
  42. namespace boost { namespace geometry
  43. {
  44. #ifndef DOXYGEN_NO_DETAIL
  45. namespace detail { namespace is_simple
  46. {
  47. template <typename Turn>
  48. inline bool check_segment_indices(Turn const& turn,
  49. signed_size_type last_index)
  50. {
  51. return
  52. (turn.operations[0].seg_id.segment_index == 0
  53. && turn.operations[1].seg_id.segment_index == last_index)
  54. ||
  55. (turn.operations[0].seg_id.segment_index == 0
  56. && turn.operations[1].seg_id.segment_index == last_index);
  57. }
  58. template
  59. <
  60. typename Geometry,
  61. typename Strategy,
  62. typename Tag = typename tag<Geometry>::type
  63. >
  64. class is_acceptable_turn
  65. : not_implemented<Geometry>
  66. {};
  67. template <typename Linestring, typename Strategy>
  68. class is_acceptable_turn<Linestring, Strategy, linestring_tag>
  69. {
  70. public:
  71. is_acceptable_turn(Linestring const& linestring, Strategy const& strategy)
  72. : m_linestring(linestring)
  73. , m_is_closed(geometry::detail::equals::equals_point_point(
  74. range::front(linestring), range::back(linestring), strategy))
  75. {}
  76. template <typename Turn>
  77. inline bool apply(Turn const& turn) const
  78. {
  79. BOOST_GEOMETRY_ASSERT(boost::size(m_linestring) > 1);
  80. return m_is_closed
  81. && turn.method == overlay::method_none
  82. && check_segment_indices(turn, boost::size(m_linestring) - 2)
  83. && turn.operations[0].fraction.is_zero();
  84. }
  85. private:
  86. Linestring const& m_linestring;
  87. bool const m_is_closed;
  88. };
  89. template <typename MultiLinestring, typename Strategy>
  90. class is_acceptable_turn<MultiLinestring, Strategy, multi_linestring_tag>
  91. {
  92. private:
  93. template <typename Point, typename Linestring>
  94. inline bool is_boundary_point_of(Point const& point, Linestring const& linestring) const
  95. {
  96. BOOST_GEOMETRY_ASSERT(boost::size(linestring) > 1);
  97. using geometry::detail::equals::equals_point_point;
  98. return ! equals_point_point(range::front(linestring), range::back(linestring), m_strategy)
  99. && (equals_point_point(point, range::front(linestring), m_strategy)
  100. || equals_point_point(point, range::back(linestring), m_strategy));
  101. }
  102. template <typename Turn, typename Linestring>
  103. inline bool is_closing_point_of(Turn const& turn, Linestring const& linestring) const
  104. {
  105. BOOST_GEOMETRY_ASSERT(boost::size(linestring) > 1);
  106. using geometry::detail::equals::equals_point_point;
  107. return turn.method == overlay::method_none
  108. && check_segment_indices(turn, boost::size(linestring) - 2)
  109. && equals_point_point(range::front(linestring), range::back(linestring), m_strategy)
  110. && turn.operations[0].fraction.is_zero();
  111. }
  112. template <typename Linestring1, typename Linestring2>
  113. inline bool have_same_boundary_points(Linestring1 const& ls1, Linestring2 const& ls2) const
  114. {
  115. using geometry::detail::equals::equals_point_point;
  116. return equals_point_point(range::front(ls1), range::front(ls2), m_strategy)
  117. ? equals_point_point(range::back(ls1), range::back(ls2), m_strategy)
  118. : (equals_point_point(range::front(ls1), range::back(ls2), m_strategy)
  119. && equals_point_point(range::back(ls1), range::front(ls2), m_strategy));
  120. }
  121. public:
  122. is_acceptable_turn(MultiLinestring const& multilinestring, Strategy const& strategy)
  123. : m_multilinestring(multilinestring)
  124. , m_strategy(strategy)
  125. {}
  126. template <typename Turn>
  127. inline bool apply(Turn const& turn) const
  128. {
  129. typedef typename boost::range_value<MultiLinestring>::type linestring_type;
  130. linestring_type const& ls1 =
  131. range::at(m_multilinestring, turn.operations[0].seg_id.multi_index);
  132. linestring_type const& ls2 =
  133. range::at(m_multilinestring, turn.operations[1].seg_id.multi_index);
  134. if (turn.operations[0].seg_id.multi_index
  135. == turn.operations[1].seg_id.multi_index)
  136. {
  137. return is_closing_point_of(turn, ls1);
  138. }
  139. return
  140. is_boundary_point_of(turn.point, ls1)
  141. && is_boundary_point_of(turn.point, ls2)
  142. &&
  143. ( boost::size(ls1) != 2
  144. || boost::size(ls2) != 2
  145. || ! have_same_boundary_points(ls1, ls2) );
  146. }
  147. private:
  148. MultiLinestring const& m_multilinestring;
  149. Strategy const& m_strategy;
  150. };
  151. template <typename Linear, typename Strategy>
  152. inline bool has_self_intersections(Linear const& linear, Strategy const& strategy)
  153. {
  154. typedef typename point_type<Linear>::type point_type;
  155. // compute self turns
  156. typedef detail::overlay::turn_info<point_type> turn_info;
  157. std::deque<turn_info> turns;
  158. typedef detail::overlay::get_turn_info
  159. <
  160. detail::disjoint::assign_disjoint_policy
  161. > turn_policy;
  162. typedef is_acceptable_turn
  163. <
  164. Linear, Strategy
  165. > is_acceptable_turn_type;
  166. is_acceptable_turn_type predicate(linear, strategy);
  167. detail::overlay::predicate_based_interrupt_policy
  168. <
  169. is_acceptable_turn_type
  170. > interrupt_policy(predicate);
  171. // TODO: skip_adjacent should be set to false
  172. detail::self_get_turn_points::get_turns
  173. <
  174. false, turn_policy
  175. >::apply(linear,
  176. strategy,
  177. detail::no_rescale_policy(),
  178. turns,
  179. interrupt_policy, 0, true);
  180. detail::is_valid::debug_print_turns(turns.begin(), turns.end());
  181. debug_print_boundary_points(linear);
  182. return interrupt_policy.has_intersections;
  183. }
  184. template <typename Linestring, bool CheckSelfIntersections = true>
  185. struct is_simple_linestring
  186. {
  187. template <typename Strategy>
  188. static inline bool apply(Linestring const& linestring,
  189. Strategy const& strategy)
  190. {
  191. simplicity_failure_policy policy;
  192. return ! boost::empty(linestring)
  193. && ! detail::is_valid::has_duplicates<Linestring>::apply(linestring, policy, strategy)
  194. && ! detail::is_valid::has_spikes<Linestring>::apply(linestring, policy, strategy);
  195. }
  196. };
  197. template <typename Linestring>
  198. struct is_simple_linestring<Linestring, true>
  199. {
  200. template <typename Strategy>
  201. static inline bool apply(Linestring const& linestring,
  202. Strategy const& strategy)
  203. {
  204. return is_simple_linestring<Linestring, false>::apply(linestring, strategy)
  205. && ! has_self_intersections(linestring, strategy);
  206. }
  207. };
  208. template <typename MultiLinestring>
  209. struct is_simple_multilinestring
  210. {
  211. private:
  212. template <typename Strategy>
  213. struct not_simple
  214. {
  215. not_simple(Strategy const& strategy)
  216. : m_strategy(strategy)
  217. {}
  218. template <typename Linestring>
  219. inline bool operator()(Linestring const& linestring) const
  220. {
  221. return ! detail::is_simple::is_simple_linestring
  222. <
  223. Linestring,
  224. false // do not compute self-intersections
  225. >::apply(linestring, m_strategy);
  226. }
  227. Strategy const& m_strategy;
  228. };
  229. public:
  230. template <typename Strategy>
  231. static inline bool apply(MultiLinestring const& multilinestring,
  232. Strategy const& strategy)
  233. {
  234. // check each of the linestrings for simplicity
  235. // but do not compute self-intersections yet; these will be
  236. // computed for the entire multilinestring
  237. // return true for empty multilinestring
  238. using not_simple = not_simple<Strategy>; // do not compute self-intersections
  239. if (std::any_of(boost::begin(multilinestring),
  240. boost::end(multilinestring),
  241. not_simple(strategy)))
  242. {
  243. return false;
  244. }
  245. return ! has_self_intersections(multilinestring, strategy);
  246. }
  247. };
  248. }} // namespace detail::is_simple
  249. #endif // DOXYGEN_NO_DETAIL
  250. #ifndef DOXYGEN_NO_DISPATCH
  251. namespace dispatch
  252. {
  253. // A linestring is a curve.
  254. // A curve is simple if it does not pass through the same point twice,
  255. // with the possible exception of its two endpoints
  256. //
  257. // Reference: OGC 06-103r4 (6.1.6.1)
  258. template <typename Linestring>
  259. struct is_simple<Linestring, linestring_tag>
  260. : detail::is_simple::is_simple_linestring<Linestring>
  261. {};
  262. // A MultiLinestring is a MultiCurve
  263. // A MultiCurve is simple if all of its elements are simple and the
  264. // only intersections between any two elements occur at Points that
  265. // are on the boundaries of both elements.
  266. //
  267. // Reference: OGC 06-103r4 (6.1.8.1; Fig. 9)
  268. template <typename MultiLinestring>
  269. struct is_simple<MultiLinestring, multi_linestring_tag>
  270. : detail::is_simple::is_simple_multilinestring<MultiLinestring>
  271. {};
  272. } // namespace dispatch
  273. #endif // DOXYGEN_NO_DISPATCH
  274. }} // namespace boost::geometry
  275. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP