follow_linear_linear.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2014-2020, Oracle and/or its affiliates.
  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_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
  10. #include <cstddef>
  11. #include <algorithm>
  12. #include <iterator>
  13. #include <boost/range/begin.hpp>
  14. #include <boost/range/end.hpp>
  15. #include <boost/range/size.hpp>
  16. #include <boost/range/value_type.hpp>
  17. #include <boost/throw_exception.hpp>
  18. #include <boost/geometry/core/assert.hpp>
  19. #include <boost/geometry/core/tag.hpp>
  20. #include <boost/geometry/core/tags.hpp>
  21. #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
  22. #include <boost/geometry/algorithms/detail/overlay/follow.hpp>
  23. #include <boost/geometry/algorithms/detail/overlay/inconsistent_turns_exception.hpp>
  24. #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
  25. #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
  26. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  27. #include <boost/geometry/algorithms/detail/turns/debug_turn.hpp>
  28. #include <boost/geometry/algorithms/detail/tupled_output.hpp>
  29. #include <boost/geometry/algorithms/convert.hpp>
  30. #include <boost/geometry/algorithms/not_implemented.hpp>
  31. #include <boost/geometry/util/condition.hpp>
  32. namespace boost { namespace geometry
  33. {
  34. #ifndef DOXYGEN_NO_DETAIL
  35. namespace detail { namespace overlay
  36. {
  37. namespace following { namespace linear
  38. {
  39. // follower for linear/linear geometries set operations
  40. template <typename Turn, typename Operation>
  41. static inline bool is_entering(Turn const& turn,
  42. Operation const& operation)
  43. {
  44. if ( turn.method != method_touch && turn.method != method_touch_interior )
  45. {
  46. return false;
  47. }
  48. return operation.operation == operation_intersection;
  49. }
  50. template <typename Turn, typename Operation>
  51. static inline bool is_staying_inside(Turn const& turn,
  52. Operation const& operation,
  53. bool entered)
  54. {
  55. if ( !entered )
  56. {
  57. return false;
  58. }
  59. if ( turn.method != method_equal && turn.method != method_collinear )
  60. {
  61. return false;
  62. }
  63. return operation.operation == operation_continue;
  64. }
  65. template <typename Turn, typename Operation>
  66. static inline bool is_leaving(Turn const& turn,
  67. Operation const& operation,
  68. bool entered)
  69. {
  70. if ( !entered )
  71. {
  72. return false;
  73. }
  74. if ( turn.method != method_touch
  75. && turn.method != method_touch_interior
  76. && turn.method != method_equal
  77. && turn.method != method_collinear )
  78. {
  79. return false;
  80. }
  81. if ( operation.operation == operation_blocked )
  82. {
  83. return true;
  84. }
  85. if ( operation.operation != operation_union )
  86. {
  87. return false;
  88. }
  89. return operation.is_collinear;
  90. }
  91. template <typename Turn, typename Operation>
  92. static inline bool is_isolated_point(Turn const& turn,
  93. Operation const& operation,
  94. bool entered)
  95. {
  96. if ( entered )
  97. {
  98. return false;
  99. }
  100. if ( turn.method == method_none )
  101. {
  102. BOOST_GEOMETRY_ASSERT( operation.operation == operation_continue );
  103. return true;
  104. }
  105. if ( turn.method == method_crosses )
  106. {
  107. return true;
  108. }
  109. if ( turn.method != method_touch && turn.method != method_touch_interior )
  110. {
  111. return false;
  112. }
  113. if ( operation.operation == operation_blocked )
  114. {
  115. return true;
  116. }
  117. if ( operation.operation != operation_union )
  118. {
  119. return false;
  120. }
  121. return !operation.is_collinear;
  122. }
  123. // GeometryOut - linestring or tuple of at least point and linestring
  124. template
  125. <
  126. typename GeometryOut,
  127. typename Linestring,
  128. typename Linear,
  129. overlay_type OverlayType,
  130. bool FollowIsolatedPoints,
  131. bool FollowContinueTurns
  132. >
  133. class follow_linestring_linear
  134. {
  135. protected:
  136. // allow spikes (false indicates: do not remove spikes)
  137. typedef following::action_selector<OverlayType, false> action;
  138. typedef geometry::detail::output_geometry_access
  139. <
  140. GeometryOut, linestring_tag, linestring_tag
  141. > linear;
  142. typedef geometry::detail::output_geometry_access
  143. <
  144. GeometryOut, point_tag, linestring_tag
  145. > pointlike;
  146. template
  147. <
  148. typename TurnIterator,
  149. typename TurnOperationIterator,
  150. typename LinestringOut,
  151. typename SegmentIdentifier,
  152. typename OutputIterator,
  153. typename SideStrategy
  154. >
  155. static inline OutputIterator
  156. process_turn(TurnIterator it,
  157. TurnOperationIterator op_it,
  158. bool& entered,
  159. std::size_t& enter_count,
  160. Linestring const& linestring,
  161. LinestringOut& current_piece,
  162. SegmentIdentifier& current_segment_id,
  163. OutputIterator oit,
  164. SideStrategy const& strategy)
  165. {
  166. // We don't rescale linear/linear
  167. detail::no_rescale_policy robust_policy;
  168. if ( is_entering(*it, *op_it) )
  169. {
  170. detail::turns::debug_turn(*it, *op_it, "-> Entering");
  171. entered = true;
  172. if ( enter_count == 0 )
  173. {
  174. action::enter(current_piece,
  175. linestring,
  176. current_segment_id,
  177. op_it->seg_id.segment_index,
  178. it->point, *op_it, strategy, robust_policy,
  179. linear::get(oit));
  180. }
  181. ++enter_count;
  182. }
  183. else if ( is_leaving(*it, *op_it, entered) )
  184. {
  185. detail::turns::debug_turn(*it, *op_it, "-> Leaving");
  186. --enter_count;
  187. if ( enter_count == 0 )
  188. {
  189. entered = false;
  190. action::leave(current_piece,
  191. linestring,
  192. current_segment_id,
  193. op_it->seg_id.segment_index,
  194. it->point, *op_it, strategy, robust_policy,
  195. linear::get(oit));
  196. }
  197. }
  198. else if ( BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints)
  199. && is_isolated_point(*it, *op_it, entered) )
  200. {
  201. detail::turns::debug_turn(*it, *op_it, "-> Isolated point");
  202. action::template isolated_point
  203. <
  204. typename pointlike::type
  205. >(it->point, pointlike::get(oit));
  206. }
  207. else if ( BOOST_GEOMETRY_CONDITION(FollowContinueTurns)
  208. && is_staying_inside(*it, *op_it, entered) )
  209. {
  210. detail::turns::debug_turn(*it, *op_it, "-> Staying inside");
  211. entered = true;
  212. }
  213. return oit;
  214. }
  215. template
  216. <
  217. typename SegmentIdentifier,
  218. typename LinestringOut,
  219. typename OutputIterator,
  220. typename SideStrategy
  221. >
  222. static inline OutputIterator
  223. process_end(bool entered,
  224. Linestring const& linestring,
  225. SegmentIdentifier const& current_segment_id,
  226. LinestringOut& current_piece,
  227. OutputIterator oit,
  228. SideStrategy const& strategy)
  229. {
  230. if ( action::is_entered(entered) )
  231. {
  232. // We don't rescale linear/linear
  233. detail::no_rescale_policy robust_policy;
  234. detail::copy_segments::copy_segments_linestring
  235. <
  236. false, false // do not reverse; do not remove spikes
  237. >::apply(linestring,
  238. current_segment_id,
  239. static_cast<signed_size_type>(boost::size(linestring) - 1),
  240. strategy,
  241. robust_policy,
  242. current_piece);
  243. }
  244. // Output the last one, if applicable
  245. if (::boost::size(current_piece) > 1)
  246. {
  247. *linear::get(oit)++ = current_piece;
  248. }
  249. return oit;
  250. }
  251. public:
  252. template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
  253. static inline OutputIterator
  254. apply(Linestring const& linestring, Linear const&,
  255. TurnIterator first, TurnIterator beyond,
  256. OutputIterator oit,
  257. SideStrategy const& strategy)
  258. {
  259. // Iterate through all intersection points (they are
  260. // ordered along the each line)
  261. typename linear::type current_piece;
  262. geometry::segment_identifier current_segment_id(0, -1, -1, -1);
  263. bool entered = false;
  264. std::size_t enter_count = 0;
  265. for (TurnIterator it = first; it != beyond; ++it)
  266. {
  267. oit = process_turn(it, boost::begin(it->operations),
  268. entered, enter_count,
  269. linestring,
  270. current_piece, current_segment_id,
  271. oit,
  272. strategy);
  273. }
  274. if (enter_count != 0)
  275. {
  276. return oit;
  277. }
  278. return process_end(entered, linestring,
  279. current_segment_id, current_piece,
  280. oit,
  281. strategy);
  282. }
  283. };
  284. template
  285. <
  286. typename LinestringOut,
  287. typename MultiLinestring,
  288. typename Linear,
  289. overlay_type OverlayType,
  290. bool FollowIsolatedPoints,
  291. bool FollowContinueTurns
  292. >
  293. class follow_multilinestring_linear
  294. : follow_linestring_linear
  295. <
  296. LinestringOut,
  297. typename boost::range_value<MultiLinestring>::type,
  298. Linear,
  299. OverlayType,
  300. FollowIsolatedPoints,
  301. FollowContinueTurns
  302. >
  303. {
  304. protected:
  305. typedef typename boost::range_value<MultiLinestring>::type Linestring;
  306. typedef follow_linestring_linear
  307. <
  308. LinestringOut, Linestring, Linear,
  309. OverlayType, FollowIsolatedPoints, FollowContinueTurns
  310. > Base;
  311. typedef following::action_selector<OverlayType> action;
  312. typedef typename boost::range_iterator
  313. <
  314. MultiLinestring const
  315. >::type linestring_iterator;
  316. template <typename OutputIt, overlay_type OT>
  317. struct copy_linestrings_in_range
  318. {
  319. static inline OutputIt
  320. apply(linestring_iterator, linestring_iterator, OutputIt oit)
  321. {
  322. return oit;
  323. }
  324. };
  325. template <typename OutputIt>
  326. struct copy_linestrings_in_range<OutputIt, overlay_difference>
  327. {
  328. static inline OutputIt
  329. apply(linestring_iterator first, linestring_iterator beyond,
  330. OutputIt oit)
  331. {
  332. for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it)
  333. {
  334. LinestringOut line_out;
  335. geometry::convert(*ls_it, line_out);
  336. *oit++ = line_out;
  337. }
  338. return oit;
  339. }
  340. };
  341. template <typename TurnIterator>
  342. static inline signed_size_type get_multi_index(TurnIterator it)
  343. {
  344. return boost::begin(it->operations)->seg_id.multi_index;
  345. }
  346. class has_other_multi_id
  347. {
  348. private:
  349. signed_size_type m_multi_id;
  350. public:
  351. has_other_multi_id(signed_size_type multi_id)
  352. : m_multi_id(multi_id) {}
  353. template <typename Turn>
  354. bool operator()(Turn const& turn) const
  355. {
  356. return boost::begin(turn.operations)->seg_id.multi_index
  357. != m_multi_id;
  358. }
  359. };
  360. public:
  361. template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
  362. static inline OutputIterator
  363. apply(MultiLinestring const& multilinestring, Linear const& linear,
  364. TurnIterator first, TurnIterator beyond,
  365. OutputIterator oit,
  366. SideStrategy const& strategy)
  367. {
  368. BOOST_GEOMETRY_ASSERT( first != beyond );
  369. typedef copy_linestrings_in_range
  370. <
  371. OutputIterator, OverlayType
  372. > copy_linestrings;
  373. linestring_iterator ls_first = boost::begin(multilinestring);
  374. linestring_iterator ls_beyond = boost::end(multilinestring);
  375. // Iterate through all intersection points (they are
  376. // ordered along the each linestring)
  377. signed_size_type current_multi_id = get_multi_index(first);
  378. oit = copy_linestrings::apply(ls_first,
  379. ls_first + current_multi_id,
  380. oit);
  381. TurnIterator per_ls_next = first;
  382. do {
  383. TurnIterator per_ls_current = per_ls_next;
  384. // find turn with different multi-index
  385. per_ls_next = std::find_if(per_ls_current, beyond,
  386. has_other_multi_id(current_multi_id));
  387. oit = Base::apply(*(ls_first + current_multi_id),
  388. linear, per_ls_current, per_ls_next, oit, strategy);
  389. signed_size_type next_multi_id = -1;
  390. linestring_iterator ls_next = ls_beyond;
  391. if ( per_ls_next != beyond )
  392. {
  393. next_multi_id = get_multi_index(per_ls_next);
  394. ls_next = ls_first + next_multi_id;
  395. }
  396. oit = copy_linestrings::apply(ls_first + current_multi_id + 1,
  397. ls_next,
  398. oit);
  399. current_multi_id = next_multi_id;
  400. }
  401. while ( per_ls_next != beyond );
  402. return oit;
  403. }
  404. };
  405. template
  406. <
  407. typename LinestringOut,
  408. typename Geometry1,
  409. typename Geometry2,
  410. overlay_type OverlayType,
  411. bool FollowIsolatedPoints,
  412. bool FollowContinueTurns,
  413. typename TagIn1 = typename tag<Geometry1>::type
  414. >
  415. struct follow
  416. : not_implemented<Geometry1>
  417. {};
  418. template
  419. <
  420. typename LinestringOut,
  421. typename Linestring,
  422. typename Linear,
  423. overlay_type OverlayType,
  424. bool FollowIsolatedPoints,
  425. bool FollowContinueTurns
  426. >
  427. struct follow
  428. <
  429. LinestringOut, Linestring, Linear,
  430. OverlayType, FollowIsolatedPoints, FollowContinueTurns,
  431. linestring_tag
  432. > : follow_linestring_linear
  433. <
  434. LinestringOut, Linestring, Linear,
  435. OverlayType, FollowIsolatedPoints, FollowContinueTurns
  436. >
  437. {};
  438. template
  439. <
  440. typename LinestringOut,
  441. typename MultiLinestring,
  442. typename Linear,
  443. overlay_type OverlayType,
  444. bool FollowIsolatedPoints,
  445. bool FollowContinueTurns
  446. >
  447. struct follow
  448. <
  449. LinestringOut, MultiLinestring, Linear,
  450. OverlayType, FollowIsolatedPoints, FollowContinueTurns,
  451. multi_linestring_tag
  452. > : follow_multilinestring_linear
  453. <
  454. LinestringOut, MultiLinestring, Linear,
  455. OverlayType, FollowIsolatedPoints, FollowContinueTurns
  456. >
  457. {};
  458. }} // namespace following::linear
  459. }} // namespace detail::overlay
  460. #endif // DOXYGEN_NO_DETAIL
  461. }} // namespace boost::geometry
  462. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP