traversal.hpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  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_HPP
  10. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP
  11. #include <cstddef>
  12. #include <set>
  13. #include <boost/range.hpp>
  14. #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
  15. #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
  16. #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
  17. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  18. #include <boost/geometry/core/access.hpp>
  19. #include <boost/geometry/core/assert.hpp>
  20. #include <boost/geometry/util/condition.hpp>
  21. #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \
  22. || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \
  23. || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
  24. # include <string>
  25. # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
  26. # include <boost/geometry/io/wkt/wkt.hpp>
  27. #endif
  28. namespace boost { namespace geometry
  29. {
  30. #ifndef DOXYGEN_NO_DETAIL
  31. namespace detail { namespace overlay
  32. {
  33. template <typename Turn, typename Operation>
  34. #ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
  35. inline void debug_traverse(Turn const& turn, Operation op,
  36. std::string const& header, bool condition = true)
  37. {
  38. if (! condition)
  39. {
  40. return;
  41. }
  42. std::cout << " " << header
  43. << " at " << op.seg_id
  44. << " meth: " << method_char(turn.method)
  45. << " op: " << operation_char(op.operation)
  46. << " vis: " << visited_char(op.visited)
  47. << " of: " << operation_char(turn.operations[0].operation)
  48. << operation_char(turn.operations[1].operation)
  49. << " " << geometry::wkt(turn.point)
  50. << std::endl;
  51. if (boost::contains(header, "Finished"))
  52. {
  53. std::cout << std::endl;
  54. }
  55. }
  56. #else
  57. inline void debug_traverse(Turn const& , Operation, const char*, bool = true)
  58. {
  59. }
  60. #endif
  61. //! Metafunction to define side_order (clockwise, ccw) by operation_type
  62. template <operation_type OpType>
  63. struct side_compare {};
  64. template <>
  65. struct side_compare<operation_union>
  66. {
  67. typedef std::greater<int> type;
  68. };
  69. template <>
  70. struct side_compare<operation_intersection>
  71. {
  72. typedef std::less<int> type;
  73. };
  74. template
  75. <
  76. bool Reverse1,
  77. bool Reverse2,
  78. overlay_type OverlayType,
  79. typename Geometry1,
  80. typename Geometry2,
  81. typename Turns,
  82. typename Clusters,
  83. typename RobustPolicy,
  84. typename SideStrategy,
  85. typename Visitor
  86. >
  87. struct traversal
  88. {
  89. private :
  90. struct linked_turn_op_info
  91. {
  92. explicit linked_turn_op_info(signed_size_type ti = -1, int oi = -1,
  93. signed_size_type nti = -1)
  94. : turn_index(ti)
  95. , op_index(oi)
  96. , next_turn_index(nti)
  97. , rank_index(-1)
  98. {}
  99. signed_size_type turn_index;
  100. int op_index;
  101. signed_size_type next_turn_index;
  102. signed_size_type rank_index;
  103. };
  104. static const operation_type target_operation = operation_from_overlay<OverlayType>::value;
  105. typedef typename side_compare<target_operation>::type side_compare_type;
  106. typedef typename boost::range_value<Turns>::type turn_type;
  107. typedef typename turn_type::turn_operation_type turn_operation_type;
  108. typedef typename geometry::point_type<Geometry1>::type point_type;
  109. typedef sort_by_side::side_sorter
  110. <
  111. Reverse1, Reverse2, OverlayType,
  112. point_type, SideStrategy, side_compare_type
  113. > sbs_type;
  114. public :
  115. inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2,
  116. Turns& turns, Clusters const& clusters,
  117. RobustPolicy const& robust_policy, SideStrategy const& strategy,
  118. Visitor& visitor)
  119. : m_geometry1(geometry1)
  120. , m_geometry2(geometry2)
  121. , m_turns(turns)
  122. , m_clusters(clusters)
  123. , m_robust_policy(robust_policy)
  124. , m_strategy(strategy)
  125. , m_visitor(visitor)
  126. {
  127. }
  128. template <typename TurnInfoMap>
  129. inline void finalize_visit_info(TurnInfoMap& turn_info_map)
  130. {
  131. for (typename boost::range_iterator<Turns>::type
  132. it = boost::begin(m_turns);
  133. it != boost::end(m_turns);
  134. ++it)
  135. {
  136. turn_type& turn = *it;
  137. for (int i = 0; i < 2; i++)
  138. {
  139. turn_operation_type& op = turn.operations[i];
  140. if (op.visited.visited()
  141. || op.visited.started()
  142. || op.visited.finished() )
  143. {
  144. ring_identifier const ring_id
  145. (
  146. op.seg_id.source_index,
  147. op.seg_id.multi_index,
  148. op.seg_id.ring_index
  149. );
  150. turn_info_map[ring_id].has_traversed_turn = true;
  151. if (op.operation == operation_continue)
  152. {
  153. // Continue operations should mark the other operation
  154. // as traversed too
  155. turn_operation_type& other_op = turn.operations[1 - i];
  156. ring_identifier const other_ring_id
  157. (
  158. other_op.seg_id.source_index,
  159. other_op.seg_id.multi_index,
  160. other_op.seg_id.ring_index
  161. );
  162. turn_info_map[other_ring_id].has_traversed_turn = true;
  163. }
  164. }
  165. op.visited.finalize();
  166. }
  167. }
  168. }
  169. //! Sets visited for ALL turns traveling to the same turn
  170. inline void set_visited_in_cluster(signed_size_type cluster_id,
  171. signed_size_type rank)
  172. {
  173. typename Clusters::const_iterator mit = m_clusters.find(cluster_id);
  174. BOOST_ASSERT(mit != m_clusters.end());
  175. cluster_info const& cinfo = mit->second;
  176. std::set<signed_size_type> const& ids = cinfo.turn_indices;
  177. for (typename std::set<signed_size_type>::const_iterator it = ids.begin();
  178. it != ids.end(); ++it)
  179. {
  180. signed_size_type const turn_index = *it;
  181. turn_type& turn = m_turns[turn_index];
  182. for (int i = 0; i < 2; i++)
  183. {
  184. turn_operation_type& op = turn.operations[i];
  185. if (op.visited.none()
  186. && op.enriched.rank == rank)
  187. {
  188. op.visited.set_visited();
  189. }
  190. }
  191. }
  192. }
  193. inline void set_visited(turn_type& turn, turn_operation_type& op)
  194. {
  195. if (op.operation == detail::overlay::operation_continue)
  196. {
  197. // On "continue", all go in same direction so set "visited" for ALL
  198. for (int i = 0; i < 2; i++)
  199. {
  200. turn_operation_type& turn_op = turn.operations[i];
  201. if (turn_op.visited.none())
  202. {
  203. turn_op.visited.set_visited();
  204. }
  205. }
  206. }
  207. else
  208. {
  209. op.visited.set_visited();
  210. }
  211. if (turn.is_clustered())
  212. {
  213. set_visited_in_cluster(turn.cluster_id, op.enriched.rank);
  214. }
  215. }
  216. inline bool is_visited(turn_type const& , turn_operation_type const& op,
  217. signed_size_type , int) const
  218. {
  219. return op.visited.visited();
  220. }
  221. template <signed_size_type segment_identifier::*Member>
  222. inline bool select_source_generic(turn_type const& turn,
  223. segment_identifier const& current,
  224. segment_identifier const& previous) const
  225. {
  226. turn_operation_type const& op0 = turn.operations[0];
  227. turn_operation_type const& op1 = turn.operations[1];
  228. bool const switch_source = op0.enriched.region_id != -1
  229. && op0.enriched.region_id == op1.enriched.region_id;
  230. #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
  231. if (switch_source)
  232. {
  233. std::cout << "Switch source at " << &turn << std::endl;
  234. }
  235. else
  236. {
  237. std::cout << "DON'T SWITCH SOURCES at " << &turn << std::endl;
  238. }
  239. #endif
  240. return switch_source
  241. ? current.*Member != previous.*Member
  242. : current.*Member == previous.*Member;
  243. }
  244. inline bool select_source(turn_type const& turn,
  245. segment_identifier const& candidate_seg_id,
  246. segment_identifier const& previous_seg_id) const
  247. {
  248. // For uu/ii, only switch sources if indicated
  249. if (OverlayType == overlay_buffer)
  250. {
  251. // Buffer does not use source_index (always 0).
  252. return select_source_generic<&segment_identifier::multi_index>(
  253. turn, candidate_seg_id, previous_seg_id);
  254. }
  255. if (is_self_turn<OverlayType>(turn))
  256. {
  257. // Also, if it is a self-turn, stay on same ring (multi/ring)
  258. return select_source_generic<&segment_identifier::multi_index>(
  259. turn, candidate_seg_id, previous_seg_id);
  260. }
  261. // Use source_index
  262. return select_source_generic<&segment_identifier::source_index>(
  263. turn, candidate_seg_id, previous_seg_id);
  264. }
  265. inline bool traverse_possible(signed_size_type turn_index) const
  266. {
  267. if (turn_index == -1)
  268. {
  269. return false;
  270. }
  271. turn_type const& turn = m_turns[turn_index];
  272. // It is not a dead end if there is an operation to continue, or of
  273. // there is a cluster (assuming for now we can get out of the cluster)
  274. return turn.is_clustered()
  275. || turn.has(target_operation)
  276. || turn.has(operation_continue);
  277. }
  278. inline std::size_t get_shortcut_level(turn_operation_type const& op,
  279. signed_size_type start_turn_index,
  280. signed_size_type origin_turn_index,
  281. std::size_t level = 1) const
  282. {
  283. signed_size_type next_turn_index = op.enriched.get_next_turn_index();
  284. if (next_turn_index == -1)
  285. {
  286. return 0;
  287. }
  288. if (next_turn_index == start_turn_index)
  289. {
  290. // This operation finishes the ring
  291. return 0;
  292. }
  293. if (next_turn_index == origin_turn_index)
  294. {
  295. // This operation travels to itself
  296. return level;
  297. }
  298. if (level > 10)
  299. {
  300. // Avoid infinite recursion
  301. return 0;
  302. }
  303. turn_type const& next_turn = m_turns[next_turn_index];
  304. for (int i = 0; i < 2; i++)
  305. {
  306. turn_operation_type const& next_op = next_turn.operations[i];
  307. if (next_op.operation == target_operation
  308. && ! next_op.visited.finished()
  309. && ! next_op.visited.visited())
  310. {
  311. // Recursively continue verifying
  312. if (get_shortcut_level(next_op, start_turn_index,
  313. origin_turn_index, level + 1))
  314. {
  315. return level + 1;
  316. }
  317. }
  318. }
  319. return 0;
  320. }
  321. inline
  322. bool select_cc_operation(turn_type const& turn,
  323. signed_size_type start_turn_index,
  324. int& selected_op_index) const
  325. {
  326. // For "cc", take either one, but if there is a starting one,
  327. // take that one. If next is dead end, skip that one.
  328. // If both are valid candidates, take the one with minimal remaining
  329. // distance (important for #mysql_23023665 in buffer).
  330. signed_size_type next[2] = {0};
  331. bool possible[2] = {0};
  332. bool close[2] = {0};
  333. for (int i = 0; i < 2; i++)
  334. {
  335. next[i] = turn.operations[i].enriched.get_next_turn_index();
  336. possible[i] = traverse_possible(next[i]);
  337. close[i] = possible[i] && next[i] == start_turn_index;
  338. }
  339. if (close[0] != close[1])
  340. {
  341. // One of the operations will finish the ring. Take that one.
  342. selected_op_index = close[0] ? 0 : 1;
  343. debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc closing");
  344. return true;
  345. }
  346. if (OverlayType == overlay_buffer && possible[0] && possible[1])
  347. {
  348. // Buffers sometimes have multiple overlapping pieces, where remaining
  349. // distance could lead to the wrong choice. Take the matching operation.
  350. bool is_target[2] = {0};
  351. for (int i = 0; i < 2; i++)
  352. {
  353. turn_operation_type const& next_op = m_turns[next[i]].operations[i];
  354. is_target[i] = next_op.operation == target_operation;
  355. }
  356. if (is_target[0] != is_target[1])
  357. {
  358. // Take the matching operation
  359. selected_op_index = is_target[0] ? 0 : 1;
  360. debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc target");
  361. return true;
  362. }
  363. }
  364. static bool const is_union = target_operation == operation_union;
  365. typename turn_operation_type::comparable_distance_type
  366. best_remaining_distance = 0;
  367. bool result = false;
  368. for (int i = 0; i < 2; i++)
  369. {
  370. if (!possible[i])
  371. {
  372. continue;
  373. }
  374. turn_operation_type const& op = turn.operations[i];
  375. if (! result
  376. || (is_union && op.remaining_distance > best_remaining_distance)
  377. || (!is_union && op.remaining_distance < best_remaining_distance))
  378. {
  379. debug_traverse(turn, op, "First candidate cc", ! result);
  380. debug_traverse(turn, op, "Candidate cc override (remaining)",
  381. result && op.remaining_distance < best_remaining_distance);
  382. selected_op_index = i;
  383. best_remaining_distance = op.remaining_distance;
  384. result = true;
  385. }
  386. }
  387. return result;
  388. }
  389. inline
  390. bool select_noncc_operation(turn_type const& turn,
  391. segment_identifier const& previous_seg_id,
  392. int& selected_op_index) const
  393. {
  394. bool result = false;
  395. for (int i = 0; i < 2; i++)
  396. {
  397. turn_operation_type const& op = turn.operations[i];
  398. if (op.operation == target_operation
  399. && ! op.visited.finished()
  400. && ! op.visited.visited()
  401. && (! result || select_source(turn, op.seg_id, previous_seg_id)))
  402. {
  403. selected_op_index = i;
  404. debug_traverse(turn, op, "Candidate");
  405. result = true;
  406. }
  407. }
  408. return result;
  409. }
  410. inline
  411. bool select_preferred_operation(turn_type const& turn,
  412. signed_size_type turn_index,
  413. signed_size_type start_turn_index,
  414. int& selected_op_index) const
  415. {
  416. bool option[2] = {0};
  417. bool finishing[2] = {0};
  418. bool preferred[2] = {0};
  419. std::size_t shortcut_level[2] = {0};
  420. for (int i = 0; i < 2; i++)
  421. {
  422. turn_operation_type const& op = turn.operations[i];
  423. if (op.operation == target_operation
  424. && ! op.visited.finished()
  425. && ! op.visited.visited())
  426. {
  427. option[i] = true;
  428. if (op.enriched.get_next_turn_index() == start_turn_index)
  429. {
  430. finishing[i] = true;
  431. }
  432. else
  433. {
  434. shortcut_level[i] = get_shortcut_level(op, start_turn_index,
  435. turn_index);
  436. }
  437. if (op.enriched.prefer_start)
  438. {
  439. preferred[i] = true;
  440. }
  441. }
  442. }
  443. if (option[0] != option[1])
  444. {
  445. // Only one operation is acceptable, take that one
  446. selected_op_index = option[0] ? 0 : 1;
  447. return true;
  448. }
  449. if (option[0] && option[1])
  450. {
  451. // Both operations are acceptable
  452. if (finishing[0] != finishing[1])
  453. {
  454. // Prefer operation finishing the ring
  455. selected_op_index = finishing[0] ? 0 : 1;
  456. return true;
  457. }
  458. if (shortcut_level[0] != shortcut_level[1])
  459. {
  460. // If a turn can travel to itself again (without closing the
  461. // ring), take the shortest one
  462. selected_op_index = shortcut_level[0] < shortcut_level[1] ? 0 : 1;
  463. return true;
  464. }
  465. if (preferred[0] != preferred[1])
  466. {
  467. // Only one operation is preferred (== was not intersection)
  468. selected_op_index = preferred[0] ? 0 : 1;
  469. return true;
  470. }
  471. }
  472. for (int i = 0; i < 2; i++)
  473. {
  474. if (option[i])
  475. {
  476. selected_op_index = 0;
  477. return true;
  478. }
  479. }
  480. return false;
  481. }
  482. inline
  483. bool select_operation(const turn_type& turn,
  484. signed_size_type turn_index,
  485. signed_size_type start_turn_index,
  486. segment_identifier const& previous_seg_id,
  487. int& selected_op_index) const
  488. {
  489. bool result = false;
  490. selected_op_index = -1;
  491. if (turn.both(operation_continue))
  492. {
  493. result = select_cc_operation(turn, start_turn_index,
  494. selected_op_index);
  495. }
  496. else if (OverlayType == overlay_dissolve)
  497. {
  498. result = select_preferred_operation(turn, turn_index,
  499. start_turn_index, selected_op_index);
  500. }
  501. else
  502. {
  503. result = select_noncc_operation(turn, previous_seg_id,
  504. selected_op_index);
  505. }
  506. if (result)
  507. {
  508. debug_traverse(turn, turn.operations[selected_op_index], "Accepted");
  509. }
  510. return result;
  511. }
  512. inline int starting_operation_index(const turn_type& turn) const
  513. {
  514. for (int i = 0; i < 2; i++)
  515. {
  516. if (turn.operations[i].visited.started())
  517. {
  518. return i;
  519. }
  520. }
  521. return -1;
  522. }
  523. inline bool both_finished(const turn_type& turn) const
  524. {
  525. for (int i = 0; i < 2; i++)
  526. {
  527. if (! turn.operations[i].visited.finished())
  528. {
  529. return false;
  530. }
  531. }
  532. return true;
  533. }
  534. template <typename RankedPoint>
  535. inline turn_operation_type const& operation_from_rank(RankedPoint const& rp) const
  536. {
  537. return m_turns[rp.turn_index].operations[rp.operation_index];
  538. }
  539. inline int select_turn_in_cluster_union(sort_by_side::rank_type selected_rank,
  540. typename sbs_type::rp const& ranked_point,
  541. signed_size_type start_turn_index, int start_op_index) const
  542. {
  543. // Returns 0 if it not OK
  544. // Returns 1 if it OK
  545. // Returns 2 if it OK and start turn matches
  546. // Returns 3 if it OK and start turn and start op both match
  547. if (ranked_point.rank != selected_rank
  548. || ranked_point.direction != sort_by_side::dir_to)
  549. {
  550. return 0;
  551. }
  552. turn_operation_type const& op = operation_from_rank(ranked_point);
  553. // Check finalized: TODO: this should be finetuned, it is not necessary
  554. if (op.visited.finalized())
  555. {
  556. return 0;
  557. }
  558. if (OverlayType != overlay_dissolve
  559. && (op.enriched.count_left != 0 || op.enriched.count_right == 0))
  560. {
  561. // Check counts: in some cases interior rings might be generated with
  562. // polygons on both sides. For dissolve it can be anything.
  563. return 0;
  564. }
  565. return ranked_point.turn_index == start_turn_index
  566. && ranked_point.operation_index == start_op_index ? 3
  567. : ranked_point.turn_index == start_turn_index ? 2
  568. : 1
  569. ;
  570. }
  571. inline sort_by_side::rank_type select_rank(sbs_type const& sbs,
  572. bool skip_isolated) const
  573. {
  574. // Take the first outgoing rank corresponding to incoming region,
  575. // or take another region if it is not isolated
  576. turn_operation_type const& incoming_op
  577. = operation_from_rank(sbs.m_ranked_points.front());
  578. for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
  579. {
  580. typename sbs_type::rp const& rp = sbs.m_ranked_points[i];
  581. if (rp.rank == 0 || rp.direction == sort_by_side::dir_from)
  582. {
  583. continue;
  584. }
  585. turn_operation_type const& op = operation_from_rank(rp);
  586. if (op.operation != target_operation
  587. && op.operation != operation_continue)
  588. {
  589. continue;
  590. }
  591. if (op.enriched.region_id == incoming_op.enriched.region_id
  592. || (skip_isolated && ! op.enriched.isolated))
  593. {
  594. // Region corresponds to incoming region, or (for intersection)
  595. // there is a non-isolated other region which should be taken
  596. return rp.rank;
  597. }
  598. }
  599. return -1;
  600. }
  601. inline bool select_from_cluster_union(signed_size_type& turn_index,
  602. int& op_index, sbs_type const& sbs,
  603. signed_size_type start_turn_index, int start_op_index) const
  604. {
  605. sort_by_side::rank_type const selected_rank = select_rank(sbs, false);
  606. int best_code = 0;
  607. bool result = false;
  608. for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++)
  609. {
  610. typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
  611. if (ranked_point.rank > selected_rank)
  612. {
  613. // Sorted on rank, so it makes no sense to continue
  614. break;
  615. }
  616. int const code
  617. = select_turn_in_cluster_union(selected_rank, ranked_point,
  618. start_turn_index, start_op_index);
  619. if (code > best_code)
  620. {
  621. // It is 1 or higher and matching better than previous
  622. best_code = code;
  623. turn_index = ranked_point.turn_index;
  624. op_index = ranked_point.operation_index;
  625. result = true;
  626. }
  627. }
  628. return result;
  629. }
  630. inline bool analyze_cluster_intersection(signed_size_type& turn_index,
  631. int& op_index, sbs_type const& sbs) const
  632. {
  633. sort_by_side::rank_type const selected_rank = select_rank(sbs, true);
  634. if (selected_rank > 0)
  635. {
  636. typename turn_operation_type::comparable_distance_type
  637. min_remaining_distance = 0;
  638. std::size_t selected_index = sbs.m_ranked_points.size();
  639. for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
  640. {
  641. typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
  642. if (ranked_point.rank == selected_rank)
  643. {
  644. turn_operation_type const& op = operation_from_rank(ranked_point);
  645. if (op.visited.finalized())
  646. {
  647. // This direction is already traveled before, the same
  648. // cannot be traveled again
  649. continue;
  650. }
  651. // Take turn with the smallest remaining distance
  652. if (selected_index == sbs.m_ranked_points.size()
  653. || op.remaining_distance < min_remaining_distance)
  654. {
  655. selected_index = i;
  656. min_remaining_distance = op.remaining_distance;
  657. }
  658. }
  659. }
  660. if (selected_index < sbs.m_ranked_points.size())
  661. {
  662. typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[selected_index];
  663. turn_index = ranked_point.turn_index;
  664. op_index = ranked_point.operation_index;
  665. return true;
  666. }
  667. }
  668. return false;
  669. }
  670. inline signed_size_type get_rank(sbs_type const& sbs,
  671. linked_turn_op_info const& info) const
  672. {
  673. for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
  674. {
  675. typename sbs_type::rp const& rp = sbs.m_ranked_points[i];
  676. if (rp.turn_index == info.turn_index
  677. && rp.operation_index == info.op_index
  678. && rp.direction == sort_by_side::dir_to)
  679. {
  680. return rp.rank;
  681. }
  682. }
  683. return -1;
  684. }
  685. // Function checks simple cases, such as a cluster with two turns,
  686. // arriving at the first turn, first turn points to second turn,
  687. // second turn points further.
  688. inline bool select_turn_from_cluster_linked(signed_size_type& turn_index,
  689. int& op_index,
  690. std::set<signed_size_type> const& ids,
  691. segment_identifier const& previous_seg_id) const
  692. {
  693. typedef typename std::set<signed_size_type>::const_iterator sit_type;
  694. std::vector<linked_turn_op_info> possibilities;
  695. std::vector<linked_turn_op_info> blocked;
  696. for (sit_type it = ids.begin(); it != ids.end(); ++it)
  697. {
  698. signed_size_type cluster_turn_index = *it;
  699. turn_type const& cluster_turn = m_turns[cluster_turn_index];
  700. if (cluster_turn.discarded)
  701. {
  702. continue;
  703. }
  704. if (is_self_turn<OverlayType>(cluster_turn)
  705. || cluster_turn.both(target_operation))
  706. {
  707. // Not (yet) supported, can be cluster of u/u turns
  708. return false;
  709. }
  710. for (int i = 0; i < 2; i++)
  711. {
  712. turn_operation_type const& op = cluster_turn.operations[i];
  713. turn_operation_type const& other_op = cluster_turn.operations[1 - i];
  714. signed_size_type const ni = op.enriched.get_next_turn_index();
  715. if (op.operation == target_operation
  716. || op.operation == operation_continue)
  717. {
  718. if (ni == cluster_turn_index)
  719. {
  720. // Not (yet) supported, traveling to itself, can be
  721. // hole
  722. return false;
  723. }
  724. possibilities.push_back(
  725. linked_turn_op_info(cluster_turn_index, i, ni));
  726. }
  727. else if (op.operation == operation_blocked
  728. && ! (ni == other_op.enriched.get_next_turn_index())
  729. && ids.count(ni) == 0)
  730. {
  731. // Points to turn, not part of this cluster,
  732. // and that way is blocked. But if the other operation
  733. // points at the same turn, it is still fine.
  734. blocked.push_back(
  735. linked_turn_op_info(cluster_turn_index, i, ni));
  736. }
  737. }
  738. }
  739. typedef typename std::vector<linked_turn_op_info>::const_iterator const_it_type;
  740. if (! blocked.empty())
  741. {
  742. sbs_type sbs(m_strategy);
  743. if (! fill_sbs(sbs, turn_index, ids, previous_seg_id))
  744. {
  745. return false;
  746. }
  747. for (typename std::vector<linked_turn_op_info>::iterator it = possibilities.begin();
  748. it != possibilities.end(); ++it)
  749. {
  750. linked_turn_op_info& info = *it;
  751. info.rank_index = get_rank(sbs, info);
  752. }
  753. for (typename std::vector<linked_turn_op_info>::iterator it = blocked.begin();
  754. it != blocked.end(); ++it)
  755. {
  756. linked_turn_op_info& info = *it;
  757. info.rank_index = get_rank(sbs, info);
  758. }
  759. for (const_it_type it = possibilities.begin();
  760. it != possibilities.end(); ++it)
  761. {
  762. linked_turn_op_info const& lti = *it;
  763. for (const_it_type bit = blocked.begin();
  764. bit != blocked.end(); ++bit)
  765. {
  766. linked_turn_op_info const& blti = *bit;
  767. if (blti.next_turn_index == lti.next_turn_index
  768. && blti.rank_index == lti.rank_index)
  769. {
  770. return false;
  771. }
  772. }
  773. }
  774. }
  775. // Traversal can either enter the cluster in the first turn,
  776. // or it can start halfway.
  777. // If there is one (and only one) possibility pointing outside
  778. // the cluster, take that one.
  779. linked_turn_op_info target;
  780. for (const_it_type it = possibilities.begin();
  781. it != possibilities.end(); ++it)
  782. {
  783. linked_turn_op_info const& lti = *it;
  784. if (ids.count(lti.next_turn_index) == 0)
  785. {
  786. if (target.turn_index >= 0
  787. && target.next_turn_index != lti.next_turn_index)
  788. {
  789. // Points to different target
  790. return false;
  791. }
  792. if (OverlayType == overlay_buffer && target.turn_index > 0)
  793. {
  794. // Target already assigned, so there are more targets
  795. // or more ways to the same target
  796. return false;
  797. }
  798. target = lti;
  799. }
  800. }
  801. if (target.turn_index < 0)
  802. {
  803. return false;
  804. }
  805. turn_index = target.turn_index;
  806. op_index = target.op_index;
  807. return true;
  808. }
  809. inline bool fill_sbs(sbs_type& sbs,
  810. signed_size_type turn_index,
  811. std::set<signed_size_type> const& ids,
  812. segment_identifier const& previous_seg_id) const
  813. {
  814. for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
  815. sit != ids.end(); ++sit)
  816. {
  817. signed_size_type cluster_turn_index = *sit;
  818. turn_type const& cluster_turn = m_turns[cluster_turn_index];
  819. bool const departure_turn = cluster_turn_index == turn_index;
  820. if (cluster_turn.discarded)
  821. {
  822. // Defensive check, discarded turns should not be in cluster
  823. continue;
  824. }
  825. for (int i = 0; i < 2; i++)
  826. {
  827. sbs.add(cluster_turn.operations[i],
  828. cluster_turn_index, i, previous_seg_id,
  829. m_geometry1, m_geometry2,
  830. departure_turn);
  831. }
  832. }
  833. if (! sbs.has_origin())
  834. {
  835. return false;
  836. }
  837. turn_type const& turn = m_turns[turn_index];
  838. sbs.apply(turn.point);
  839. return true;
  840. }
  841. inline bool select_turn_from_cluster(signed_size_type& turn_index,
  842. int& op_index,
  843. signed_size_type start_turn_index, int start_op_index,
  844. segment_identifier const& previous_seg_id) const
  845. {
  846. bool const is_union = target_operation == operation_union;
  847. turn_type const& turn = m_turns[turn_index];
  848. BOOST_ASSERT(turn.is_clustered());
  849. typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id);
  850. BOOST_ASSERT(mit != m_clusters.end());
  851. cluster_info const& cinfo = mit->second;
  852. std::set<signed_size_type> const& ids = cinfo.turn_indices;
  853. if (select_turn_from_cluster_linked(turn_index, op_index, ids, previous_seg_id))
  854. {
  855. return true;
  856. }
  857. sbs_type sbs(m_strategy);
  858. if (! fill_sbs(sbs, turn_index, ids, previous_seg_id))
  859. {
  860. return false;
  861. }
  862. bool result = false;
  863. if (is_union)
  864. {
  865. result = select_from_cluster_union(turn_index, op_index, sbs,
  866. start_turn_index, start_op_index);
  867. }
  868. else
  869. {
  870. result = analyze_cluster_intersection(turn_index, op_index, sbs);
  871. }
  872. return result;
  873. }
  874. inline bool analyze_ii_intersection(signed_size_type& turn_index, int& op_index,
  875. turn_type const& current_turn,
  876. segment_identifier const& previous_seg_id)
  877. {
  878. sbs_type sbs(m_strategy);
  879. // Add this turn to the sort-by-side sorter
  880. for (int i = 0; i < 2; i++)
  881. {
  882. sbs.add(current_turn.operations[i],
  883. turn_index, i, previous_seg_id,
  884. m_geometry1, m_geometry2,
  885. true);
  886. }
  887. if (! sbs.has_origin())
  888. {
  889. return false;
  890. }
  891. sbs.apply(current_turn.point);
  892. bool result = analyze_cluster_intersection(turn_index, op_index, sbs);
  893. return result;
  894. }
  895. inline void change_index_for_self_turn(signed_size_type& to_vertex_index,
  896. turn_type const& start_turn,
  897. turn_operation_type const& start_op,
  898. int start_op_index) const
  899. {
  900. if (OverlayType != overlay_buffer && OverlayType != overlay_dissolve)
  901. {
  902. return;
  903. }
  904. const bool allow_uu = OverlayType != overlay_buffer;
  905. // It travels to itself, can happen. If this is a buffer, it can
  906. // sometimes travel to itself in the following configuration:
  907. //
  908. // +---->--+
  909. // | |
  910. // | +---*----+ *: one turn, with segment index 2/7
  911. // | | | |
  912. // | +---C | C: closing point (start/end)
  913. // | |
  914. // +------------+
  915. //
  916. // If it starts on segment 2 and travels to itself on segment 2, that
  917. // should be corrected to 7 because that is the shortest path
  918. //
  919. // Also a uu turn (touching with another buffered ring) might have this
  920. // apparent configuration, but there it should
  921. // always travel the whole ring
  922. turn_operation_type const& other_op
  923. = start_turn.operations[1 - start_op_index];
  924. bool const correct
  925. = (allow_uu || ! start_turn.both(operation_union))
  926. && start_op.seg_id.source_index == other_op.seg_id.source_index
  927. && start_op.seg_id.multi_index == other_op.seg_id.multi_index
  928. && start_op.seg_id.ring_index == other_op.seg_id.ring_index
  929. && start_op.seg_id.segment_index == to_vertex_index;
  930. #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
  931. std::cout << " WARNING: self-buffer "
  932. << " correct=" << correct
  933. << " turn=" << operation_char(start_turn.operations[0].operation)
  934. << operation_char(start_turn.operations[1].operation)
  935. << " start=" << start_op.seg_id.segment_index
  936. << " from=" << to_vertex_index
  937. << " to=" << other_op.enriched.travels_to_vertex_index
  938. << std::endl;
  939. #endif
  940. if (correct)
  941. {
  942. to_vertex_index = other_op.enriched.travels_to_vertex_index;
  943. }
  944. }
  945. bool select_turn_from_enriched(signed_size_type& turn_index,
  946. segment_identifier& previous_seg_id,
  947. signed_size_type& to_vertex_index,
  948. signed_size_type start_turn_index,
  949. int start_op_index,
  950. turn_type const& previous_turn,
  951. turn_operation_type const& previous_op,
  952. bool is_start) const
  953. {
  954. to_vertex_index = -1;
  955. if (previous_op.enriched.next_ip_index < 0)
  956. {
  957. // There is no next IP on this segment
  958. if (previous_op.enriched.travels_to_vertex_index < 0
  959. || previous_op.enriched.travels_to_ip_index < 0)
  960. {
  961. return false;
  962. }
  963. to_vertex_index = previous_op.enriched.travels_to_vertex_index;
  964. if (is_start &&
  965. previous_op.enriched.travels_to_ip_index == start_turn_index)
  966. {
  967. change_index_for_self_turn(to_vertex_index, previous_turn,
  968. previous_op, start_op_index);
  969. }
  970. turn_index = previous_op.enriched.travels_to_ip_index;
  971. previous_seg_id = previous_op.seg_id;
  972. }
  973. else
  974. {
  975. // Take the next IP on this segment
  976. turn_index = previous_op.enriched.next_ip_index;
  977. previous_seg_id = previous_op.seg_id;
  978. }
  979. return true;
  980. }
  981. bool select_turn(signed_size_type start_turn_index, int start_op_index,
  982. signed_size_type& turn_index,
  983. int& op_index,
  984. int previous_op_index,
  985. signed_size_type previous_turn_index,
  986. segment_identifier const& previous_seg_id,
  987. bool is_start)
  988. {
  989. turn_type const& current_turn = m_turns[turn_index];
  990. if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection))
  991. {
  992. bool const back_at_start_cluster
  993. = current_turn.is_clustered()
  994. && m_turns[start_turn_index].cluster_id == current_turn.cluster_id;
  995. if (turn_index == start_turn_index || back_at_start_cluster)
  996. {
  997. // Intersection can always be finished if returning
  998. turn_index = start_turn_index;
  999. op_index = start_op_index;
  1000. return true;
  1001. }
  1002. if (! current_turn.is_clustered()
  1003. && current_turn.both(operation_intersection))
  1004. {
  1005. if (analyze_ii_intersection(turn_index, op_index,
  1006. current_turn, previous_seg_id))
  1007. {
  1008. return true;
  1009. }
  1010. }
  1011. }
  1012. if (current_turn.is_clustered())
  1013. {
  1014. if (! select_turn_from_cluster(turn_index, op_index,
  1015. start_turn_index, start_op_index, previous_seg_id))
  1016. {
  1017. return false;
  1018. }
  1019. if (is_start && turn_index == previous_turn_index)
  1020. {
  1021. op_index = previous_op_index;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. op_index = starting_operation_index(current_turn);
  1027. if (op_index == -1)
  1028. {
  1029. if (both_finished(current_turn))
  1030. {
  1031. return false;
  1032. }
  1033. if (! select_operation(current_turn, turn_index,
  1034. start_turn_index,
  1035. previous_seg_id,
  1036. op_index))
  1037. {
  1038. return false;
  1039. }
  1040. }
  1041. }
  1042. return true;
  1043. }
  1044. private :
  1045. Geometry1 const& m_geometry1;
  1046. Geometry2 const& m_geometry2;
  1047. Turns& m_turns;
  1048. Clusters const& m_clusters;
  1049. RobustPolicy const& m_robust_policy;
  1050. SideStrategy m_strategy;
  1051. Visitor& m_visitor;
  1052. };
  1053. }} // namespace detail::overlay
  1054. #endif // DOXYGEN_NO_DETAIL
  1055. }} // namespace boost::geometry
  1056. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP