enrich_intersection_points.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2017, 2019.
  5. // Modifications copyright (c) 2017, 2019 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP
  12. #include <cstddef>
  13. #include <algorithm>
  14. #include <map>
  15. #include <set>
  16. #include <vector>
  17. #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
  18. # include <iostream>
  19. # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
  20. # include <boost/geometry/io/wkt/wkt.hpp>
  21. # if ! defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
  22. # define BOOST_GEOMETRY_DEBUG_IDENTIFIER
  23. #endif
  24. #endif
  25. #include <boost/range.hpp>
  26. #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
  27. #include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
  28. #include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp>
  29. #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
  30. #include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp>
  31. #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
  32. #include <boost/geometry/policies/robustness/robust_type.hpp>
  33. #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
  34. # include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
  35. #endif
  36. namespace boost { namespace geometry
  37. {
  38. #ifndef DOXYGEN_NO_DETAIL
  39. namespace detail { namespace overlay
  40. {
  41. template <typename Turns>
  42. struct discarded_indexed_turn
  43. {
  44. discarded_indexed_turn(Turns const& turns)
  45. : m_turns(turns)
  46. {}
  47. template <typename IndexedTurn>
  48. inline bool operator()(IndexedTurn const& indexed) const
  49. {
  50. return m_turns[indexed.turn_index].discarded;
  51. }
  52. Turns const& m_turns;
  53. };
  54. // Sorts IP-s of this ring on segment-identifier, and if on same segment,
  55. // on distance.
  56. // Then assigns for each IP which is the next IP on this segment,
  57. // plus the vertex-index to travel to, plus the next IP
  58. // (might be on another segment)
  59. template
  60. <
  61. bool Reverse1, bool Reverse2,
  62. typename Operations,
  63. typename Turns,
  64. typename Geometry1, typename Geometry2,
  65. typename RobustPolicy,
  66. typename SideStrategy
  67. >
  68. inline void enrich_sort(Operations& operations,
  69. Turns const& turns,
  70. Geometry1 const& geometry1,
  71. Geometry2 const& geometry2,
  72. RobustPolicy const& robust_policy,
  73. SideStrategy const& strategy)
  74. {
  75. std::sort(boost::begin(operations),
  76. boost::end(operations),
  77. less_by_segment_ratio
  78. <
  79. Turns,
  80. typename boost::range_value<Operations>::type,
  81. Geometry1, Geometry2,
  82. RobustPolicy,
  83. SideStrategy,
  84. Reverse1, Reverse2
  85. >(turns, geometry1, geometry2, robust_policy, strategy));
  86. }
  87. template <typename Operations, typename Turns>
  88. inline void enrich_assign(Operations& operations, Turns& turns,
  89. bool check_turns)
  90. {
  91. typedef typename boost::range_value<Turns>::type turn_type;
  92. typedef typename turn_type::turn_operation_type op_type;
  93. typedef typename boost::range_iterator<Operations>::type iterator_type;
  94. if (operations.size() > 0)
  95. {
  96. // Assign travel-to-vertex/ip index for each turning point.
  97. // Iterator "next" is circular
  98. geometry::ever_circling_range_iterator<Operations const> next(operations);
  99. ++next;
  100. for (iterator_type it = boost::begin(operations);
  101. it != boost::end(operations); ++it)
  102. {
  103. turn_type& turn = turns[it->turn_index];
  104. op_type& op = turn.operations[it->operation_index];
  105. if (check_turns && it->turn_index == next->turn_index)
  106. {
  107. // Normal behaviour: next points at next turn, increase next.
  108. // For dissolve this should not be done, turn_index is often
  109. // the same for two consecutive operations
  110. ++next;
  111. }
  112. // Cluster behaviour: next should point after cluster, unless
  113. // their seg_ids are not the same
  114. // (For dissolve, this is still to be examined - TODO)
  115. while (turn.is_clustered()
  116. && it->turn_index != next->turn_index
  117. && turn.cluster_id == turns[next->turn_index].cluster_id
  118. && op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id)
  119. {
  120. ++next;
  121. }
  122. turn_type const& next_turn = turns[next->turn_index];
  123. op_type const& next_op = next_turn.operations[next->operation_index];
  124. op.enriched.travels_to_ip_index
  125. = static_cast<signed_size_type>(next->turn_index);
  126. op.enriched.travels_to_vertex_index
  127. = next->subject->seg_id.segment_index;
  128. if (op.seg_id.segment_index == next_op.seg_id.segment_index
  129. && op.fraction < next_op.fraction)
  130. {
  131. // Next turn is located further on same segment
  132. // assign next_ip_index
  133. // (this is one not circular therefore fraction is considered)
  134. op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index);
  135. }
  136. if (! check_turns)
  137. {
  138. ++next;
  139. }
  140. }
  141. }
  142. // DEBUG
  143. #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
  144. {
  145. for (iterator_type it = boost::begin(operations);
  146. it != boost::end(operations);
  147. ++it)
  148. {
  149. op_type const& op = turns[it->turn_index]
  150. .operations[it->operation_index];
  151. std::cout << it->turn_index
  152. << " cl=" << turns[it->turn_index].cluster_id
  153. << " meth=" << method_char(turns[it->turn_index].method)
  154. << " seg=" << op.seg_id
  155. << " dst=" << op.fraction // needs define
  156. << " op=" << operation_char(turns[it->turn_index].operations[0].operation)
  157. << operation_char(turns[it->turn_index].operations[1].operation)
  158. << " (" << operation_char(op.operation) << ")"
  159. << " nxt=" << op.enriched.next_ip_index
  160. << " / " << op.enriched.travels_to_ip_index
  161. << " [vx " << op.enriched.travels_to_vertex_index << "]"
  162. << std::boolalpha << turns[it->turn_index].discarded
  163. << std::endl;
  164. ;
  165. }
  166. }
  167. #endif
  168. // END DEBUG
  169. }
  170. template <typename Operations, typename Turns>
  171. inline void enrich_adapt(Operations& operations, Turns& turns)
  172. {
  173. typedef typename boost::range_value<Turns>::type turn_type;
  174. typedef typename turn_type::turn_operation_type op_type;
  175. typedef typename boost::range_value<Operations>::type indexed_turn_type;
  176. if (operations.size() < 3)
  177. {
  178. // If it is empty, or contains one or two turns, it makes no sense
  179. return;
  180. }
  181. // Operations is a vector of indexed_turn_operation<>
  182. // Last index:
  183. std::size_t const x = operations.size() - 1;
  184. bool next_phase = false;
  185. for (std::size_t i = 0; i < operations.size(); i++)
  186. {
  187. indexed_turn_type const& indexed = operations[i];
  188. turn_type& turn = turns[indexed.turn_index];
  189. op_type& op = turn.operations[indexed.operation_index];
  190. // Previous/next index
  191. std::size_t const p = i > 0 ? i - 1 : x;
  192. std::size_t const n = i < x ? i + 1 : 0;
  193. turn_type const& next_turn = turns[operations[n].turn_index];
  194. op_type const& next_op = next_turn.operations[operations[n].operation_index];
  195. if (op.seg_id.segment_index == next_op.seg_id.segment_index)
  196. {
  197. turn_type const& prev_turn = turns[operations[p].turn_index];
  198. op_type const& prev_op = prev_turn.operations[operations[p].operation_index];
  199. if (op.seg_id.segment_index == prev_op.seg_id.segment_index)
  200. {
  201. op.enriched.startable = false;
  202. next_phase = true;
  203. }
  204. }
  205. }
  206. if (! next_phase)
  207. {
  208. return;
  209. }
  210. // Discard turns which are both non-startable
  211. next_phase = false;
  212. for (typename boost::range_iterator<Turns>::type
  213. it = boost::begin(turns);
  214. it != boost::end(turns);
  215. ++it)
  216. {
  217. turn_type& turn = *it;
  218. if (! turn.operations[0].enriched.startable
  219. && ! turn.operations[1].enriched.startable)
  220. {
  221. turn.discarded = true;
  222. next_phase = true;
  223. }
  224. }
  225. if (! next_phase)
  226. {
  227. return;
  228. }
  229. // Remove discarded turns from operations to avoid having them as next turn
  230. discarded_indexed_turn<Turns> const predicate(turns);
  231. operations.erase(std::remove_if(boost::begin(operations),
  232. boost::end(operations), predicate), boost::end(operations));
  233. }
  234. template <typename Turns, typename MappedVector>
  235. inline void create_map(Turns const& turns, MappedVector& mapped_vector)
  236. {
  237. typedef typename boost::range_value<Turns>::type turn_type;
  238. typedef typename turn_type::container_type container_type;
  239. typedef typename MappedVector::mapped_type mapped_type;
  240. typedef typename boost::range_value<mapped_type>::type indexed_type;
  241. std::size_t index = 0;
  242. for (typename boost::range_iterator<Turns const>::type
  243. it = boost::begin(turns);
  244. it != boost::end(turns);
  245. ++it, ++index)
  246. {
  247. // Add all (non discarded) operations on this ring
  248. // Blocked operations or uu on clusters (for intersection)
  249. // should be included, to block potential paths in clusters
  250. turn_type const& turn = *it;
  251. if (turn.discarded)
  252. {
  253. continue;
  254. }
  255. std::size_t op_index = 0;
  256. for (typename boost::range_iterator<container_type const>::type
  257. op_it = boost::begin(turn.operations);
  258. op_it != boost::end(turn.operations);
  259. ++op_it, ++op_index)
  260. {
  261. ring_identifier const ring_id
  262. (
  263. op_it->seg_id.source_index,
  264. op_it->seg_id.multi_index,
  265. op_it->seg_id.ring_index
  266. );
  267. mapped_vector[ring_id].push_back
  268. (
  269. indexed_type(index, op_index, *op_it,
  270. it->operations[1 - op_index].seg_id)
  271. );
  272. }
  273. }
  274. }
  275. template <typename Point1, typename Point2>
  276. inline typename geometry::coordinate_type<Point1>::type
  277. distance_measure(Point1 const& a, Point2 const& b)
  278. {
  279. // TODO: use comparable distance for point-point instead - but that
  280. // causes currently cycling include problems
  281. typedef typename geometry::coordinate_type<Point1>::type ctype;
  282. ctype const dx = get<0>(a) - get<0>(b);
  283. ctype const dy = get<1>(a) - get<1>(b);
  284. return dx * dx + dy * dy;
  285. }
  286. template <typename Turns>
  287. inline void calculate_remaining_distance(Turns& turns)
  288. {
  289. typedef typename boost::range_value<Turns>::type turn_type;
  290. typedef typename turn_type::turn_operation_type op_type;
  291. for (typename boost::range_iterator<Turns>::type
  292. it = boost::begin(turns);
  293. it != boost::end(turns);
  294. ++it)
  295. {
  296. turn_type& turn = *it;
  297. op_type& op0 = turn.operations[0];
  298. op_type& op1 = turn.operations[1];
  299. if (op0.remaining_distance != 0
  300. || op1.remaining_distance != 0)
  301. {
  302. continue;
  303. }
  304. signed_size_type const to_index0 = op0.enriched.get_next_turn_index();
  305. signed_size_type const to_index1 = op1.enriched.get_next_turn_index();
  306. if (to_index0 >= 0
  307. && to_index1 >= 0
  308. && to_index0 != to_index1)
  309. {
  310. op0.remaining_distance = distance_measure(turn.point, turns[to_index0].point);
  311. op1.remaining_distance = distance_measure(turn.point, turns[to_index1].point);
  312. }
  313. }
  314. }
  315. }} // namespace detail::overlay
  316. #endif //DOXYGEN_NO_DETAIL
  317. /*!
  318. \brief All intersection points are enriched with successor information
  319. \ingroup overlay
  320. \tparam Turns type of intersection container
  321. (e.g. vector of "intersection/turn point"'s)
  322. \tparam Clusters type of cluster container
  323. \tparam Geometry1 \tparam_geometry
  324. \tparam Geometry2 \tparam_geometry
  325. \tparam PointInGeometryStrategy point in geometry strategy type
  326. \param turns container containing intersection points
  327. \param clusters container containing clusters
  328. \param geometry1 \param_geometry
  329. \param geometry2 \param_geometry
  330. \param robust_policy policy to handle robustness issues
  331. \param strategy point in geometry strategy
  332. */
  333. template
  334. <
  335. bool Reverse1, bool Reverse2,
  336. overlay_type OverlayType,
  337. typename Turns,
  338. typename Clusters,
  339. typename Geometry1, typename Geometry2,
  340. typename RobustPolicy,
  341. typename IntersectionStrategy
  342. >
  343. inline void enrich_intersection_points(Turns& turns,
  344. Clusters& clusters,
  345. Geometry1 const& geometry1, Geometry2 const& geometry2,
  346. RobustPolicy const& robust_policy,
  347. IntersectionStrategy const& strategy)
  348. {
  349. static const detail::overlay::operation_type target_operation
  350. = detail::overlay::operation_from_overlay<OverlayType>::value;
  351. static const detail::overlay::operation_type opposite_operation
  352. = target_operation == detail::overlay::operation_union
  353. ? detail::overlay::operation_intersection
  354. : detail::overlay::operation_union;
  355. static const bool is_dissolve = OverlayType == overlay_dissolve;
  356. typedef typename boost::range_value<Turns>::type turn_type;
  357. typedef typename turn_type::turn_operation_type op_type;
  358. typedef detail::overlay::indexed_turn_operation
  359. <
  360. op_type
  361. > indexed_turn_operation;
  362. typedef std::map
  363. <
  364. ring_identifier,
  365. std::vector<indexed_turn_operation>
  366. > mapped_vector_type;
  367. // From here on, turn indexes are used (in clusters, next_index, etc)
  368. // and may only be flagged as discarded
  369. bool has_cc = false;
  370. bool const has_colocations
  371. = detail::overlay::handle_colocations<Reverse1, Reverse2, OverlayType>(turns,
  372. clusters, geometry1, geometry2);
  373. // Discard turns not part of target overlay
  374. for (typename boost::range_iterator<Turns>::type
  375. it = boost::begin(turns);
  376. it != boost::end(turns);
  377. ++it)
  378. {
  379. turn_type& turn = *it;
  380. if (turn.both(detail::overlay::operation_none)
  381. || turn.both(opposite_operation)
  382. || turn.both(detail::overlay::operation_blocked)
  383. || (detail::overlay::is_self_turn<OverlayType>(turn)
  384. && ! turn.is_clustered()
  385. && ! turn.both(target_operation)))
  386. {
  387. // For all operations, discard xx and none/none
  388. // For intersections, remove uu to avoid the need to travel
  389. // a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33)
  390. // The ux is necessary to indicate impossible paths
  391. // (especially if rescaling is removed)
  392. // Similarly, for union, discard ii and ix
  393. // For self-turns, only keep uu / ii
  394. turn.discarded = true;
  395. turn.cluster_id = -1;
  396. continue;
  397. }
  398. if (! turn.discarded
  399. && turn.both(detail::overlay::operation_continue))
  400. {
  401. has_cc = true;
  402. }
  403. }
  404. if (! is_dissolve)
  405. {
  406. detail::overlay::discard_closed_turns
  407. <
  408. OverlayType,
  409. target_operation
  410. >::apply(turns, clusters, geometry1, geometry2,
  411. strategy);
  412. detail::overlay::discard_open_turns
  413. <
  414. OverlayType,
  415. target_operation
  416. >::apply(turns, clusters, geometry1, geometry2,
  417. strategy);
  418. }
  419. // Create a map of vectors of indexed operation-types to be able
  420. // to sort intersection points PER RING
  421. mapped_vector_type mapped_vector;
  422. detail::overlay::create_map(turns, mapped_vector);
  423. // No const-iterator; contents of mapped copy is temporary,
  424. // and changed by enrich
  425. for (typename mapped_vector_type::iterator mit
  426. = mapped_vector.begin();
  427. mit != mapped_vector.end();
  428. ++mit)
  429. {
  430. #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
  431. std::cout << "ENRICH-sort Ring "
  432. << mit->first << std::endl;
  433. #endif
  434. detail::overlay::enrich_sort<Reverse1, Reverse2>(
  435. mit->second, turns,
  436. geometry1, geometry2,
  437. robust_policy, strategy.get_side_strategy());
  438. }
  439. for (typename mapped_vector_type::iterator mit
  440. = mapped_vector.begin();
  441. mit != mapped_vector.end();
  442. ++mit)
  443. {
  444. #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
  445. std::cout << "ENRICH-assign Ring "
  446. << mit->first << std::endl;
  447. #endif
  448. if (is_dissolve)
  449. {
  450. detail::overlay::enrich_adapt(mit->second, turns);
  451. }
  452. detail::overlay::enrich_assign(mit->second, turns, ! is_dissolve);
  453. }
  454. if (has_colocations)
  455. {
  456. // First gather cluster properties (using even clusters with
  457. // discarded turns - for open turns), then clean up clusters
  458. detail::overlay::gather_cluster_properties
  459. <
  460. Reverse1,
  461. Reverse2,
  462. OverlayType
  463. >(clusters, turns, target_operation,
  464. geometry1, geometry2, strategy.get_side_strategy());
  465. detail::overlay::cleanup_clusters(turns, clusters);
  466. }
  467. if (has_cc)
  468. {
  469. detail::overlay::calculate_remaining_distance(turns);
  470. }
  471. #ifdef BOOST_GEOMETRY_DEBUG_ENRICH
  472. //detail::overlay::check_graph(turns, for_operation);
  473. #endif
  474. }
  475. }} // namespace boost::geometry
  476. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP