linear.hpp 12 KB

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