traverse.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
  8. #include <cstddef>
  9. #include <boost/range.hpp>
  10. #include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
  11. #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
  12. #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
  13. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  14. #include <boost/geometry/algorithms/num_points.hpp>
  15. #include <boost/geometry/core/access.hpp>
  16. #include <boost/geometry/core/closure.hpp>
  17. #include <boost/geometry/core/coordinate_dimension.hpp>
  18. #include <boost/geometry/geometries/concepts/check.hpp>
  19. #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \
  20. || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \
  21. || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
  22. # include <string>
  23. # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
  24. # include <boost/geometry/io/wkt/wkt.hpp>
  25. #endif
  26. namespace boost { namespace geometry
  27. {
  28. #ifndef DOXYGEN_NO_DETAIL
  29. namespace detail { namespace overlay
  30. {
  31. template <typename Turn, typename Operation>
  32. #ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
  33. inline void debug_traverse(Turn const& turn, Operation op,
  34. std::string const& header)
  35. {
  36. std::cout << header
  37. << " at " << op.seg_id
  38. << " meth: " << method_char(turn.method)
  39. << " op: " << operation_char(op.operation)
  40. << " vis: " << visited_char(op.visited)
  41. << " of: " << operation_char(turn.operations[0].operation)
  42. << operation_char(turn.operations[1].operation)
  43. << " " << geometry::wkt(turn.point)
  44. << std::endl;
  45. if (boost::contains(header, "Finished"))
  46. {
  47. std::cout << std::endl;
  48. }
  49. }
  50. #else
  51. inline void debug_traverse(Turn const& , Operation, const char*)
  52. {
  53. }
  54. #endif
  55. template <typename Info, typename Turn>
  56. inline void set_visited_for_continue(Info& info, Turn const& turn)
  57. {
  58. // On "continue", set "visited" for ALL directions
  59. if (turn.operation == detail::overlay::operation_continue)
  60. {
  61. for (typename boost::range_iterator
  62. <
  63. typename Info::container_type
  64. >::type it = boost::begin(info.operations);
  65. it != boost::end(info.operations);
  66. ++it)
  67. {
  68. if (it->visited.none())
  69. {
  70. it->visited.set_visited();
  71. }
  72. }
  73. }
  74. }
  75. template
  76. <
  77. bool Reverse1, bool Reverse2,
  78. typename GeometryOut,
  79. typename G1,
  80. typename G2,
  81. typename Turns,
  82. typename IntersectionInfo
  83. >
  84. inline bool assign_next_ip(G1 const& g1, G2 const& g2,
  85. Turns& turns,
  86. typename boost::range_iterator<Turns>::type& ip,
  87. GeometryOut& current_output,
  88. IntersectionInfo& info,
  89. segment_identifier& seg_id)
  90. {
  91. info.visited.set_visited();
  92. set_visited_for_continue(*ip, info);
  93. // If there is no next IP on this segment
  94. if (info.enriched.next_ip_index < 0)
  95. {
  96. if (info.enriched.travels_to_vertex_index < 0
  97. || info.enriched.travels_to_ip_index < 0)
  98. {
  99. return false;
  100. }
  101. BOOST_ASSERT(info.enriched.travels_to_vertex_index >= 0);
  102. BOOST_ASSERT(info.enriched.travels_to_ip_index >= 0);
  103. if (info.seg_id.source_index == 0)
  104. {
  105. geometry::copy_segments<Reverse1>(g1, info.seg_id,
  106. info.enriched.travels_to_vertex_index,
  107. current_output);
  108. }
  109. else
  110. {
  111. geometry::copy_segments<Reverse2>(g2, info.seg_id,
  112. info.enriched.travels_to_vertex_index,
  113. current_output);
  114. }
  115. seg_id = info.seg_id;
  116. ip = boost::begin(turns) + info.enriched.travels_to_ip_index;
  117. }
  118. else
  119. {
  120. ip = boost::begin(turns) + info.enriched.next_ip_index;
  121. seg_id = info.seg_id;
  122. }
  123. detail::overlay::append_no_dups_or_spikes(current_output, ip->point);
  124. return true;
  125. }
  126. inline bool select_source(operation_type operation, int source1, int source2)
  127. {
  128. return (operation == operation_intersection && source1 != source2)
  129. || (operation == operation_union && source1 == source2)
  130. ;
  131. }
  132. template
  133. <
  134. typename Turn,
  135. typename Iterator
  136. >
  137. inline bool select_next_ip(operation_type operation,
  138. Turn& turn,
  139. segment_identifier const& seg_id,
  140. Iterator& selected)
  141. {
  142. if (turn.discarded)
  143. {
  144. return false;
  145. }
  146. bool has_tp = false;
  147. selected = boost::end(turn.operations);
  148. for (Iterator it = boost::begin(turn.operations);
  149. it != boost::end(turn.operations);
  150. ++it)
  151. {
  152. if (it->visited.started())
  153. {
  154. selected = it;
  155. //std::cout << " RETURN";
  156. return true;
  157. }
  158. // In some cases there are two alternatives.
  159. // For "ii", take the other one (alternate)
  160. // UNLESS the other one is already visited
  161. // For "uu", take the same one (see above);
  162. // For "cc", take either one, but if there is a starting one,
  163. // take that one.
  164. if ( (it->operation == operation_continue
  165. && (! has_tp || it->visited.started()
  166. )
  167. )
  168. || (it->operation == operation
  169. && ! it->visited.finished()
  170. && (! has_tp
  171. || select_source(operation,
  172. it->seg_id.source_index, seg_id.source_index)
  173. )
  174. )
  175. )
  176. {
  177. selected = it;
  178. debug_traverse(turn, *it, " Candidate");
  179. has_tp = true;
  180. }
  181. }
  182. if (has_tp)
  183. {
  184. debug_traverse(turn, *selected, " Accepted");
  185. }
  186. return has_tp;
  187. }
  188. /*!
  189. \brief Traverses through intersection points / geometries
  190. \ingroup overlay
  191. */
  192. template
  193. <
  194. bool Reverse1, bool Reverse2,
  195. typename Geometry1,
  196. typename Geometry2,
  197. typename Backtrack = backtrack_check_self_intersections<Geometry1, Geometry2>
  198. >
  199. class traverse
  200. {
  201. public :
  202. template <typename Turns, typename Rings>
  203. static inline void apply(Geometry1 const& geometry1,
  204. Geometry2 const& geometry2,
  205. detail::overlay::operation_type operation,
  206. Turns& turns, Rings& rings)
  207. {
  208. typedef typename boost::range_value<Rings>::type ring_type;
  209. typedef typename boost::range_iterator<Turns>::type turn_iterator;
  210. typedef typename boost::range_value<Turns>::type turn_type;
  211. typedef typename boost::range_iterator
  212. <
  213. typename turn_type::container_type
  214. >::type turn_operation_iterator_type;
  215. std::size_t const min_num_points
  216. = core_detail::closure::minimum_ring_size
  217. <
  218. geometry::closure<ring_type>::value
  219. >::value;
  220. std::size_t size_at_start = boost::size(rings);
  221. typename Backtrack::state_type state;
  222. do
  223. {
  224. state.reset();
  225. // Iterate through all unvisited points
  226. for (turn_iterator it = boost::begin(turns);
  227. state.good() && it != boost::end(turns);
  228. ++it)
  229. {
  230. // Skip discarded ones
  231. if (! (it->is_discarded() || it->blocked()))
  232. {
  233. for (turn_operation_iterator_type iit = boost::begin(it->operations);
  234. state.good() && iit != boost::end(it->operations);
  235. ++iit)
  236. {
  237. if (iit->visited.none()
  238. && ! iit->visited.rejected()
  239. && (iit->operation == operation
  240. || iit->operation == detail::overlay::operation_continue)
  241. )
  242. {
  243. set_visited_for_continue(*it, *iit);
  244. ring_type current_output;
  245. geometry::append(current_output, it->point);
  246. turn_iterator current = it;
  247. turn_operation_iterator_type current_iit = iit;
  248. segment_identifier current_seg_id;
  249. if (! detail::overlay::assign_next_ip<Reverse1, Reverse2>(
  250. geometry1, geometry2,
  251. turns,
  252. current, current_output,
  253. *iit, current_seg_id))
  254. {
  255. Backtrack::apply(
  256. size_at_start,
  257. rings, current_output, turns, *current_iit,
  258. "No next IP",
  259. geometry1, geometry2, state);
  260. }
  261. if (! detail::overlay::select_next_ip(
  262. operation,
  263. *current,
  264. current_seg_id,
  265. current_iit))
  266. {
  267. Backtrack::apply(
  268. size_at_start,
  269. rings, current_output, turns, *iit,
  270. "Dead end at start",
  271. geometry1, geometry2, state);
  272. }
  273. else
  274. {
  275. iit->visited.set_started();
  276. detail::overlay::debug_traverse(*it, *iit, "-> Started");
  277. detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
  278. unsigned int i = 0;
  279. while (current_iit != iit && state.good())
  280. {
  281. if (current_iit->visited.visited())
  282. {
  283. // It visits a visited node again, without passing the start node.
  284. // This makes it suspicious for endless loops
  285. Backtrack::apply(
  286. size_at_start,
  287. rings, current_output, turns, *iit,
  288. "Visit again",
  289. geometry1, geometry2, state);
  290. }
  291. else
  292. {
  293. // We assume clockwise polygons only, non self-intersecting, closed.
  294. // However, the input might be different, and checking validity
  295. // is up to the library user.
  296. // Therefore we make here some sanity checks. If the input
  297. // violates the assumptions, the output polygon will not be correct
  298. // but the routine will stop and output the current polygon, and
  299. // will continue with the next one.
  300. // Below three reasons to stop.
  301. detail::overlay::assign_next_ip<Reverse1, Reverse2>(
  302. geometry1, geometry2,
  303. turns, current, current_output,
  304. *current_iit, current_seg_id);
  305. if (! detail::overlay::select_next_ip(
  306. operation,
  307. *current,
  308. current_seg_id,
  309. current_iit))
  310. {
  311. // Should not occur in valid (non-self-intersecting) polygons
  312. // Should not occur in self-intersecting polygons without spikes
  313. // Might occur in polygons with spikes
  314. Backtrack::apply(
  315. size_at_start,
  316. rings, current_output, turns, *iit,
  317. "Dead end",
  318. geometry1, geometry2, state);
  319. }
  320. else
  321. {
  322. detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
  323. }
  324. if (i++ > 2 + 2 * turns.size())
  325. {
  326. // Sanity check: there may be never more loops
  327. // than turn points.
  328. // Turn points marked as "ii" can be visited twice.
  329. Backtrack::apply(
  330. size_at_start,
  331. rings, current_output, turns, *iit,
  332. "Endless loop",
  333. geometry1, geometry2, state);
  334. }
  335. }
  336. }
  337. if (state.good())
  338. {
  339. iit->visited.set_finished();
  340. detail::overlay::debug_traverse(*current, *iit, "->Finished");
  341. if (geometry::num_points(current_output) >= min_num_points)
  342. {
  343. rings.push_back(current_output);
  344. }
  345. }
  346. }
  347. }
  348. }
  349. }
  350. }
  351. } while (! state.good());
  352. }
  353. };
  354. }} // namespace detail::overlay
  355. #endif // DOXYGEN_NO_DETAIL
  356. }} // namespace boost::geometry
  357. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP