follow.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2014, 2017, 2018, 2019, 2020.
  5. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  8. // Use, modification and distribution is subject to the Boost Software License,
  9. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
  12. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
  13. #include <cstddef>
  14. #include <boost/range.hpp>
  15. #include <boost/mpl/assert.hpp>
  16. #include <boost/geometry/algorithms/detail/point_on_border.hpp>
  17. #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
  18. #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
  19. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  20. #include <boost/geometry/algorithms/covered_by.hpp>
  21. #include <boost/geometry/algorithms/clear.hpp>
  22. #include <boost/geometry/algorithms/detail/relate/turns.hpp>
  23. #include <boost/geometry/algorithms/detail/tupled_output.hpp>
  24. namespace boost { namespace geometry
  25. {
  26. #ifndef DOXYGEN_NO_DETAIL
  27. namespace detail { namespace overlay
  28. {
  29. namespace following
  30. {
  31. template <typename Turn, typename Operation>
  32. inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
  33. {
  34. // (Blocked means: blocked for polygon/polygon intersection, because
  35. // they are reversed. But for polygon/line it is similar to continue)
  36. return op.operation == operation_intersection
  37. || op.operation == operation_continue
  38. || op.operation == operation_blocked
  39. ;
  40. }
  41. template
  42. <
  43. typename Turn,
  44. typename Operation,
  45. typename LineString,
  46. typename Polygon,
  47. typename PtInPolyStrategy
  48. >
  49. inline bool last_covered_by(Turn const& /*turn*/, Operation const& op,
  50. LineString const& linestring, Polygon const& polygon,
  51. PtInPolyStrategy const& strategy)
  52. {
  53. return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
  54. }
  55. template
  56. <
  57. typename Turn,
  58. typename Operation,
  59. typename LineString,
  60. typename Polygon,
  61. typename PtInPolyStrategy
  62. >
  63. inline bool is_leaving(Turn const& turn, Operation const& op,
  64. bool entered, bool first,
  65. LineString const& linestring, Polygon const& polygon,
  66. PtInPolyStrategy const& strategy)
  67. {
  68. if (op.operation == operation_union)
  69. {
  70. return entered
  71. || turn.method == method_crosses
  72. || (first
  73. && op.position != position_front
  74. && last_covered_by(turn, op, linestring, polygon, strategy))
  75. ;
  76. }
  77. return false;
  78. }
  79. template
  80. <
  81. typename Turn,
  82. typename Operation,
  83. typename LineString,
  84. typename Polygon,
  85. typename PtInPolyStrategy
  86. >
  87. inline bool is_staying_inside(Turn const& turn, Operation const& op,
  88. bool entered, bool first,
  89. LineString const& linestring, Polygon const& polygon,
  90. PtInPolyStrategy const& strategy)
  91. {
  92. if (turn.method == method_crosses)
  93. {
  94. // The normal case, this is completely covered with entering/leaving
  95. // so stay out of this time consuming "covered_by"
  96. return false;
  97. }
  98. if (is_entering(turn, op))
  99. {
  100. return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy));
  101. }
  102. return false;
  103. }
  104. template
  105. <
  106. typename Turn,
  107. typename Operation,
  108. typename Linestring,
  109. typename Polygon,
  110. typename PtInPolyStrategy
  111. >
  112. inline bool was_entered(Turn const& turn, Operation const& op, bool first,
  113. Linestring const& linestring, Polygon const& polygon,
  114. PtInPolyStrategy const& strategy)
  115. {
  116. if (first && (turn.method == method_collinear || turn.method == method_equal))
  117. {
  118. return last_covered_by(turn, op, linestring, polygon, strategy);
  119. }
  120. return false;
  121. }
  122. template
  123. <
  124. typename Turn,
  125. typename Operation
  126. >
  127. inline bool is_touching(Turn const& turn, Operation const& op,
  128. bool entered)
  129. {
  130. return (op.operation == operation_union || op.operation == operation_blocked)
  131. && (turn.method == method_touch || turn.method == method_touch_interior)
  132. && !entered
  133. && !op.is_collinear;
  134. }
  135. template
  136. <
  137. typename GeometryOut,
  138. typename Tag = typename geometry::tag<GeometryOut>::type
  139. >
  140. struct add_isolated_point
  141. {};
  142. template <typename LineStringOut>
  143. struct add_isolated_point<LineStringOut, linestring_tag>
  144. {
  145. template <typename Point, typename OutputIterator>
  146. static inline void apply(Point const& point, OutputIterator& out)
  147. {
  148. LineStringOut isolated_point_ls;
  149. geometry::append(isolated_point_ls, point);
  150. #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
  151. geometry::append(isolated_point_ls, point);
  152. #endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
  153. *out++ = isolated_point_ls;
  154. }
  155. };
  156. template <typename PointOut>
  157. struct add_isolated_point<PointOut, point_tag>
  158. {
  159. template <typename Point, typename OutputIterator>
  160. static inline void apply(Point const& point, OutputIterator& out)
  161. {
  162. PointOut isolated_point;
  163. geometry::detail::conversion::convert_point_to_point(point, isolated_point);
  164. *out++ = isolated_point;
  165. }
  166. };
  167. // Template specialization structure to call the right actions for the right type
  168. template <overlay_type OverlayType, bool RemoveSpikes = true>
  169. struct action_selector
  170. {
  171. // If you get here the overlay type is not intersection or difference
  172. // BOOST_MPL_ASSERT(false);
  173. };
  174. // Specialization for intersection, containing the implementation
  175. template <bool RemoveSpikes>
  176. struct action_selector<overlay_intersection, RemoveSpikes>
  177. {
  178. template
  179. <
  180. typename OutputIterator,
  181. typename LineStringOut,
  182. typename LineString,
  183. typename Point,
  184. typename Operation,
  185. typename Strategy,
  186. typename RobustPolicy
  187. >
  188. static inline void enter(LineStringOut& current_piece,
  189. LineString const& ,
  190. segment_identifier& segment_id,
  191. signed_size_type , Point const& point,
  192. Operation const& operation,
  193. Strategy const& strategy,
  194. RobustPolicy const& ,
  195. OutputIterator& )
  196. {
  197. // On enter, append the intersection point and remember starting point
  198. // TODO: we don't check on spikes for linestrings (?). Consider this.
  199. detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
  200. segment_id = operation.seg_id;
  201. }
  202. template
  203. <
  204. typename OutputIterator,
  205. typename LineStringOut,
  206. typename LineString,
  207. typename Point,
  208. typename Operation,
  209. typename Strategy,
  210. typename RobustPolicy
  211. >
  212. static inline void leave(LineStringOut& current_piece,
  213. LineString const& linestring,
  214. segment_identifier& segment_id,
  215. signed_size_type index, Point const& point,
  216. Operation const& ,
  217. Strategy const& strategy,
  218. RobustPolicy const& robust_policy,
  219. OutputIterator& out)
  220. {
  221. // On leave, copy all segments from starting point, append the intersection point
  222. // and add the output piece
  223. detail::copy_segments::copy_segments_linestring
  224. <
  225. false, RemoveSpikes
  226. >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
  227. detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy());
  228. if (::boost::size(current_piece) > 1)
  229. {
  230. *out++ = current_piece;
  231. }
  232. geometry::clear(current_piece);
  233. }
  234. template
  235. <
  236. typename LineStringOrPointOut,
  237. typename Point,
  238. typename OutputIterator
  239. >
  240. static inline void isolated_point(Point const& point,
  241. OutputIterator& out)
  242. {
  243. add_isolated_point<LineStringOrPointOut>::apply(point, out);
  244. }
  245. static inline bool is_entered(bool entered)
  246. {
  247. return entered;
  248. }
  249. static inline bool included(int inside_value)
  250. {
  251. return inside_value >= 0; // covered_by
  252. }
  253. };
  254. // Specialization for difference, which reverses these actions
  255. template <bool RemoveSpikes>
  256. struct action_selector<overlay_difference, RemoveSpikes>
  257. {
  258. typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
  259. template
  260. <
  261. typename OutputIterator,
  262. typename LineStringOut,
  263. typename LineString,
  264. typename Point,
  265. typename Operation,
  266. typename Strategy,
  267. typename RobustPolicy
  268. >
  269. static inline void enter(LineStringOut& current_piece,
  270. LineString const& linestring,
  271. segment_identifier& segment_id,
  272. signed_size_type index, Point const& point,
  273. Operation const& operation,
  274. Strategy const& strategy,
  275. RobustPolicy const& robust_policy,
  276. OutputIterator& out)
  277. {
  278. normal_action::leave(current_piece, linestring, segment_id, index,
  279. point, operation, strategy, robust_policy, out);
  280. }
  281. template
  282. <
  283. typename OutputIterator,
  284. typename LineStringOut,
  285. typename LineString,
  286. typename Point,
  287. typename Operation,
  288. typename Strategy,
  289. typename RobustPolicy
  290. >
  291. static inline void leave(LineStringOut& current_piece,
  292. LineString const& linestring,
  293. segment_identifier& segment_id,
  294. signed_size_type index, Point const& point,
  295. Operation const& operation,
  296. Strategy const& strategy,
  297. RobustPolicy const& robust_policy,
  298. OutputIterator& out)
  299. {
  300. normal_action::enter(current_piece, linestring, segment_id, index,
  301. point, operation, strategy, robust_policy, out);
  302. }
  303. template
  304. <
  305. typename LineStringOrPointOut,
  306. typename Point,
  307. typename OutputIterator
  308. >
  309. static inline void isolated_point(Point const&,
  310. OutputIterator const&)
  311. {
  312. }
  313. static inline bool is_entered(bool entered)
  314. {
  315. return ! normal_action::is_entered(entered);
  316. }
  317. static inline bool included(int inside_value)
  318. {
  319. return ! normal_action::included(inside_value);
  320. }
  321. };
  322. } // namespace following
  323. /*!
  324. \brief Follows a linestring from intersection point to intersection point, outputting which
  325. is inside, or outside, a ring or polygon
  326. \ingroup overlay
  327. */
  328. template
  329. <
  330. typename GeometryOut,
  331. typename LineString,
  332. typename Polygon,
  333. overlay_type OverlayType,
  334. bool RemoveSpikes,
  335. bool FollowIsolatedPoints
  336. >
  337. class follow
  338. {
  339. typedef geometry::detail::output_geometry_access
  340. <
  341. GeometryOut, linestring_tag, linestring_tag
  342. > linear;
  343. typedef geometry::detail::output_geometry_access
  344. <
  345. GeometryOut, point_tag, linestring_tag
  346. > pointlike;
  347. public :
  348. static inline bool included(int inside_value)
  349. {
  350. return following::action_selector
  351. <
  352. OverlayType, RemoveSpikes
  353. >::included(inside_value);
  354. }
  355. template
  356. <
  357. typename Turns,
  358. typename OutputIterator,
  359. typename RobustPolicy,
  360. typename Strategy
  361. >
  362. static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
  363. detail::overlay::operation_type , // TODO: this parameter might be redundant
  364. Turns& turns,
  365. RobustPolicy const& robust_policy,
  366. OutputIterator out,
  367. Strategy const& strategy)
  368. {
  369. typedef typename boost::range_iterator<Turns>::type turn_iterator;
  370. typedef typename boost::range_value<Turns>::type turn_type;
  371. typedef typename boost::range_iterator
  372. <
  373. typename turn_type::container_type
  374. >::type turn_operation_iterator_type;
  375. typedef following::action_selector<OverlayType, RemoveSpikes> action;
  376. typedef typename Strategy::cs_tag cs_tag;
  377. typename Strategy::template point_in_geometry_strategy
  378. <
  379. LineString, Polygon
  380. >::type const pt_in_poly_strategy
  381. = strategy.template get_point_in_geometry_strategy<LineString, Polygon>();
  382. // Sort intersection points on segments-along-linestring, and distance
  383. // (like in enrich is done for poly/poly)
  384. // sort turns by Linear seg_id, then by fraction, then
  385. // for same ring id: x, u, i, c
  386. // for different ring id: c, i, u, x
  387. typedef relate::turns::less
  388. <
  389. 0, relate::turns::less_op_linear_areal_single<0>, cs_tag
  390. > turn_less;
  391. std::sort(boost::begin(turns), boost::end(turns), turn_less());
  392. typename linear::type current_piece;
  393. geometry::segment_identifier current_segment_id(0, -1, -1, -1);
  394. // Iterate through all intersection points (they are ordered along the line)
  395. bool entered = false;
  396. bool first = true;
  397. for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
  398. {
  399. turn_operation_iterator_type iit = boost::begin(it->operations);
  400. if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
  401. {
  402. debug_traverse(*it, *iit, "-> Was entered");
  403. entered = true;
  404. }
  405. if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
  406. {
  407. debug_traverse(*it, *iit, "-> Staying inside");
  408. entered = true;
  409. }
  410. else if (following::is_entering(*it, *iit))
  411. {
  412. debug_traverse(*it, *iit, "-> Entering");
  413. entered = true;
  414. action::enter(current_piece, linestring, current_segment_id,
  415. iit->seg_id.segment_index, it->point, *iit,
  416. strategy, robust_policy,
  417. linear::get(out));
  418. }
  419. else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
  420. {
  421. debug_traverse(*it, *iit, "-> Leaving");
  422. entered = false;
  423. action::leave(current_piece, linestring, current_segment_id,
  424. iit->seg_id.segment_index, it->point, *iit,
  425. strategy, robust_policy,
  426. linear::get(out));
  427. }
  428. else if (FollowIsolatedPoints
  429. && following::is_touching(*it, *iit, entered))
  430. {
  431. debug_traverse(*it, *iit, "-> Isolated point");
  432. action::template isolated_point
  433. <
  434. typename pointlike::type
  435. >(it->point, pointlike::get(out));
  436. }
  437. first = false;
  438. }
  439. if (action::is_entered(entered))
  440. {
  441. detail::copy_segments::copy_segments_linestring
  442. <
  443. false, RemoveSpikes
  444. >::apply(linestring,
  445. current_segment_id,
  446. static_cast<signed_size_type>(boost::size(linestring) - 1),
  447. strategy, robust_policy,
  448. current_piece);
  449. }
  450. // Output the last one, if applicable
  451. std::size_t current_piece_size = ::boost::size(current_piece);
  452. if (current_piece_size > 1)
  453. {
  454. *linear::get(out)++ = current_piece;
  455. }
  456. else if (FollowIsolatedPoints
  457. && current_piece_size == 1)
  458. {
  459. action::template isolated_point
  460. <
  461. typename pointlike::type
  462. >(range::front(current_piece), pointlike::get(out));
  463. }
  464. return out;
  465. }
  466. };
  467. }} // namespace detail::overlay
  468. #endif // DOXYGEN_NO_DETAIL
  469. }} // namespace boost::geometry
  470. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP