follow_linear_linear.hpp 15 KB

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