traversal_ring_creator.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2017, 2018.
  4. // Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Use, modification and distribution is subject to the Boost Software License,
  7. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP
  11. #include <cstddef>
  12. #include <boost/range.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
  14. #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
  15. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  16. #include <boost/geometry/algorithms/detail/overlay/traversal.hpp>
  17. #include <boost/geometry/algorithms/num_points.hpp>
  18. #include <boost/geometry/core/access.hpp>
  19. #include <boost/geometry/core/assert.hpp>
  20. #include <boost/geometry/core/closure.hpp>
  21. namespace boost { namespace geometry
  22. {
  23. #ifndef DOXYGEN_NO_DETAIL
  24. namespace detail { namespace overlay
  25. {
  26. template
  27. <
  28. bool Reverse1,
  29. bool Reverse2,
  30. overlay_type OverlayType,
  31. typename Geometry1,
  32. typename Geometry2,
  33. typename Turns,
  34. typename TurnInfoMap,
  35. typename Clusters,
  36. typename IntersectionStrategy,
  37. typename RobustPolicy,
  38. typename Visitor,
  39. typename Backtrack
  40. >
  41. struct traversal_ring_creator
  42. {
  43. typedef traversal
  44. <
  45. Reverse1, Reverse2, OverlayType,
  46. Geometry1, Geometry2, Turns, Clusters,
  47. RobustPolicy, typename IntersectionStrategy::side_strategy_type,
  48. Visitor
  49. > traversal_type;
  50. typedef typename boost::range_value<Turns>::type turn_type;
  51. typedef typename turn_type::turn_operation_type turn_operation_type;
  52. static const operation_type target_operation
  53. = operation_from_overlay<OverlayType>::value;
  54. inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2,
  55. Turns& turns, TurnInfoMap& turn_info_map,
  56. Clusters const& clusters,
  57. IntersectionStrategy const& intersection_strategy,
  58. RobustPolicy const& robust_policy, Visitor& visitor)
  59. : m_trav(geometry1, geometry2, turns, clusters,
  60. robust_policy, intersection_strategy.get_side_strategy(),
  61. visitor)
  62. , m_geometry1(geometry1)
  63. , m_geometry2(geometry2)
  64. , m_turns(turns)
  65. , m_turn_info_map(turn_info_map)
  66. , m_clusters(clusters)
  67. , m_intersection_strategy(intersection_strategy)
  68. , m_robust_policy(robust_policy)
  69. , m_visitor(visitor)
  70. {
  71. }
  72. template <typename Ring>
  73. inline traverse_error_type travel_to_next_turn(signed_size_type start_turn_index,
  74. int start_op_index,
  75. signed_size_type& turn_index,
  76. int& op_index,
  77. Ring& current_ring,
  78. bool is_start)
  79. {
  80. int const previous_op_index = op_index;
  81. signed_size_type const previous_turn_index = turn_index;
  82. turn_type& previous_turn = m_turns[turn_index];
  83. turn_operation_type& previous_op = previous_turn.operations[op_index];
  84. segment_identifier previous_seg_id;
  85. signed_size_type to_vertex_index = -1;
  86. if (! m_trav.select_turn_from_enriched(turn_index, previous_seg_id,
  87. to_vertex_index, start_turn_index, start_op_index,
  88. previous_turn, previous_op, is_start))
  89. {
  90. return is_start
  91. ? traverse_error_no_next_ip_at_start
  92. : traverse_error_no_next_ip;
  93. }
  94. if (to_vertex_index >= 0)
  95. {
  96. if (previous_op.seg_id.source_index == 0)
  97. {
  98. geometry::copy_segments<Reverse1>(m_geometry1,
  99. previous_op.seg_id, to_vertex_index,
  100. m_intersection_strategy.get_side_strategy(),
  101. m_robust_policy, current_ring);
  102. }
  103. else
  104. {
  105. geometry::copy_segments<Reverse2>(m_geometry2,
  106. previous_op.seg_id, to_vertex_index,
  107. m_intersection_strategy.get_side_strategy(),
  108. m_robust_policy, current_ring);
  109. }
  110. }
  111. if (m_turns[turn_index].discarded)
  112. {
  113. return is_start
  114. ? traverse_error_dead_end_at_start
  115. : traverse_error_dead_end;
  116. }
  117. if (is_start)
  118. {
  119. // Register the start
  120. previous_op.visited.set_started();
  121. m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start");
  122. }
  123. if (! m_trav.select_turn(start_turn_index, start_op_index,
  124. turn_index, op_index,
  125. previous_op_index, previous_turn_index, previous_seg_id,
  126. is_start, current_ring.size() > 1))
  127. {
  128. return is_start
  129. ? traverse_error_no_next_ip_at_start
  130. : traverse_error_no_next_ip;
  131. }
  132. {
  133. // Check operation (TODO: this might be redundant or should be catched before)
  134. const turn_type& current_turn = m_turns[turn_index];
  135. const turn_operation_type& op = current_turn.operations[op_index];
  136. if (op.visited.finalized()
  137. || m_trav.is_visited(current_turn, op, turn_index, op_index))
  138. {
  139. return traverse_error_visit_again;
  140. }
  141. }
  142. // Update registration and append point
  143. turn_type& current_turn = m_turns[turn_index];
  144. turn_operation_type& op = current_turn.operations[op_index];
  145. detail::overlay::append_no_collinear(current_ring, current_turn.point,
  146. m_intersection_strategy.get_side_strategy(),
  147. m_robust_policy);
  148. // Register the visit
  149. m_trav.set_visited(current_turn, op);
  150. m_visitor.visit_traverse(m_turns, current_turn, op, "Visit");
  151. return traverse_error_none;
  152. }
  153. template <typename Ring>
  154. inline traverse_error_type traverse(Ring& ring,
  155. signed_size_type start_turn_index, int start_op_index)
  156. {
  157. turn_type const& start_turn = m_turns[start_turn_index];
  158. turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
  159. detail::overlay::append_no_collinear(ring, start_turn.point,
  160. m_intersection_strategy.get_side_strategy(),
  161. m_robust_policy);
  162. signed_size_type current_turn_index = start_turn_index;
  163. int current_op_index = start_op_index;
  164. traverse_error_type error = travel_to_next_turn(start_turn_index,
  165. start_op_index,
  166. current_turn_index, current_op_index,
  167. ring, true);
  168. if (error != traverse_error_none)
  169. {
  170. // This is not necessarily a problem, it happens for clustered turns
  171. // which are "build in" or otherwise point inwards
  172. return error;
  173. }
  174. if (current_turn_index == start_turn_index)
  175. {
  176. start_op.visited.set_finished();
  177. m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish");
  178. return traverse_error_none;
  179. }
  180. if (start_turn.is_clustered())
  181. {
  182. turn_type& turn = m_turns[current_turn_index];
  183. turn_operation_type& op = turn.operations[current_op_index];
  184. if (turn.cluster_id == start_turn.cluster_id
  185. && op.enriched.get_next_turn_index() == start_turn_index)
  186. {
  187. op.visited.set_finished();
  188. m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish (cluster)");
  189. return traverse_error_none;
  190. }
  191. }
  192. std::size_t const max_iterations = 2 + 2 * m_turns.size();
  193. for (std::size_t i = 0; i <= max_iterations; i++)
  194. {
  195. // We assume clockwise polygons only, non self-intersecting, closed.
  196. // However, the input might be different, and checking validity
  197. // is up to the library user.
  198. // Therefore we make here some sanity checks. If the input
  199. // violates the assumptions, the output polygon will not be correct
  200. // but the routine will stop and output the current polygon, and
  201. // will continue with the next one.
  202. // Below three reasons to stop.
  203. error = travel_to_next_turn(start_turn_index, start_op_index,
  204. current_turn_index, current_op_index,
  205. ring, false);
  206. if (error != traverse_error_none)
  207. {
  208. return error;
  209. }
  210. if (current_turn_index == start_turn_index
  211. && current_op_index == start_op_index)
  212. {
  213. start_op.visited.set_finished();
  214. m_visitor.visit_traverse(m_turns, start_turn, start_op, "Finish");
  215. return traverse_error_none;
  216. }
  217. }
  218. return traverse_error_endless_loop;
  219. }
  220. template <typename Rings>
  221. void traverse_with_operation(turn_type const& start_turn,
  222. std::size_t turn_index, int op_index,
  223. Rings& rings, std::size_t& finalized_ring_size,
  224. typename Backtrack::state_type& state)
  225. {
  226. typedef typename boost::range_value<Rings>::type ring_type;
  227. turn_operation_type const& start_op = start_turn.operations[op_index];
  228. if (! start_op.visited.none()
  229. || ! start_op.enriched.startable
  230. || start_op.visited.rejected()
  231. || ! (start_op.operation == target_operation
  232. || start_op.operation == detail::overlay::operation_continue))
  233. {
  234. return;
  235. }
  236. ring_type ring;
  237. traverse_error_type traverse_error = traverse(ring, turn_index, op_index);
  238. if (traverse_error == traverse_error_none)
  239. {
  240. std::size_t const min_num_points
  241. = core_detail::closure::minimum_ring_size
  242. <
  243. geometry::closure<ring_type>::value
  244. >::value;
  245. if (geometry::num_points(ring) >= min_num_points)
  246. {
  247. clean_closing_dups_and_spikes(ring,
  248. m_intersection_strategy.get_side_strategy(),
  249. m_robust_policy);
  250. rings.push_back(ring);
  251. m_trav.finalize_visit_info(m_turn_info_map);
  252. finalized_ring_size++;
  253. }
  254. }
  255. else
  256. {
  257. Backtrack::apply(
  258. finalized_ring_size,
  259. rings, ring, m_turns, start_turn,
  260. m_turns[turn_index].operations[op_index],
  261. traverse_error,
  262. m_geometry1, m_geometry2,
  263. m_intersection_strategy, m_robust_policy,
  264. state, m_visitor);
  265. }
  266. }
  267. int get_operation_index(turn_type const& turn) const
  268. {
  269. // When starting with a continue operation, the one
  270. // with the smallest (for intersection) or largest (for union)
  271. // remaining distance (#8310b)
  272. // Also to avoid skipping a turn in between, which can happen
  273. // in rare cases (e.g. #130)
  274. static const bool is_union
  275. = operation_from_overlay<OverlayType>::value == operation_union;
  276. turn_operation_type const& op0 = turn.operations[0];
  277. turn_operation_type const& op1 = turn.operations[1];
  278. return op0.remaining_distance <= op1.remaining_distance
  279. ? (is_union ? 1 : 0)
  280. : (is_union ? 0 : 1);
  281. }
  282. template <typename Rings>
  283. void iterate(Rings& rings, std::size_t& finalized_ring_size,
  284. typename Backtrack::state_type& state)
  285. {
  286. for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
  287. {
  288. turn_type const& turn = m_turns[turn_index];
  289. if (turn.discarded || turn.blocked())
  290. {
  291. // Skip discarded and blocked turns
  292. continue;
  293. }
  294. if (turn.both(operation_continue))
  295. {
  296. traverse_with_operation(turn, turn_index,
  297. get_operation_index(turn),
  298. rings, finalized_ring_size, state);
  299. }
  300. else
  301. {
  302. for (int op_index = 0; op_index < 2; op_index++)
  303. {
  304. traverse_with_operation(turn, turn_index, op_index,
  305. rings, finalized_ring_size, state);
  306. }
  307. }
  308. }
  309. }
  310. template <typename Rings>
  311. void iterate_with_preference(std::size_t phase,
  312. Rings& rings, std::size_t& finalized_ring_size,
  313. typename Backtrack::state_type& state)
  314. {
  315. for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
  316. {
  317. turn_type const& turn = m_turns[turn_index];
  318. if (turn.discarded || turn.blocked())
  319. {
  320. // Skip discarded and blocked turns
  321. continue;
  322. }
  323. turn_operation_type const& op0 = turn.operations[0];
  324. turn_operation_type const& op1 = turn.operations[1];
  325. if (phase == 0)
  326. {
  327. if (! op0.enriched.prefer_start && ! op1.enriched.prefer_start)
  328. {
  329. // Not preferred, take next one
  330. continue;
  331. }
  332. }
  333. if (turn.both(operation_continue))
  334. {
  335. traverse_with_operation(turn, turn_index,
  336. get_operation_index(turn),
  337. rings, finalized_ring_size, state);
  338. }
  339. else
  340. {
  341. bool const forward = op0.enriched.prefer_start;
  342. int op_index = forward ? 0 : 1;
  343. int const increment = forward ? 1 : -1;
  344. for (int i = 0; i < 2; i++, op_index += increment)
  345. {
  346. traverse_with_operation(turn, turn_index, op_index,
  347. rings, finalized_ring_size, state);
  348. }
  349. }
  350. }
  351. }
  352. private:
  353. traversal_type m_trav;
  354. Geometry1 const& m_geometry1;
  355. Geometry2 const& m_geometry2;
  356. Turns& m_turns;
  357. TurnInfoMap& m_turn_info_map; // contains turn-info information per ring
  358. Clusters const& m_clusters;
  359. IntersectionStrategy const& m_intersection_strategy;
  360. RobustPolicy const& m_robust_policy;
  361. Visitor& m_visitor;
  362. };
  363. }} // namespace detail::overlay
  364. #endif // DOXYGEN_NO_DETAIL
  365. }} // namespace boost::geometry
  366. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP