handle_colocations.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2017.
  5. // Modifications copyright (c) 2017 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_HANDLE_COLOCATIONS_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_COLOCATIONS_HPP
  12. #include <cstddef>
  13. #include <algorithm>
  14. #include <map>
  15. #include <vector>
  16. #include <boost/core/ignore_unused.hpp>
  17. #include <boost/range.hpp>
  18. #include <boost/geometry/core/assert.hpp>
  19. #include <boost/geometry/core/point_order.hpp>
  20. #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
  21. #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
  22. #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
  23. #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
  24. #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
  25. #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
  26. #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
  27. #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
  28. #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
  29. #include <boost/geometry/util/condition.hpp>
  30. #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
  31. # include <iostream>
  32. # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
  33. # include <boost/geometry/io/wkt/wkt.hpp>
  34. # define BOOST_GEOMETRY_DEBUG_IDENTIFIER
  35. #endif
  36. namespace boost { namespace geometry
  37. {
  38. #ifndef DOXYGEN_NO_DETAIL
  39. namespace detail { namespace overlay
  40. {
  41. template <typename SegmentRatio>
  42. struct segment_fraction
  43. {
  44. segment_identifier seg_id;
  45. SegmentRatio fraction;
  46. segment_fraction(segment_identifier const& id, SegmentRatio const& fr)
  47. : seg_id(id)
  48. , fraction(fr)
  49. {}
  50. segment_fraction()
  51. {}
  52. bool operator<(segment_fraction<SegmentRatio> const& other) const
  53. {
  54. return seg_id == other.seg_id
  55. ? fraction < other.fraction
  56. : seg_id < other.seg_id;
  57. }
  58. };
  59. struct turn_operation_index
  60. {
  61. turn_operation_index(signed_size_type ti = -1,
  62. signed_size_type oi = -1)
  63. : turn_index(ti)
  64. , op_index(oi)
  65. {}
  66. signed_size_type turn_index;
  67. signed_size_type op_index; // only 0,1
  68. };
  69. template <typename Turns>
  70. struct less_by_fraction_and_type
  71. {
  72. inline less_by_fraction_and_type(Turns const& turns)
  73. : m_turns(turns)
  74. {
  75. }
  76. inline bool operator()(turn_operation_index const& left,
  77. turn_operation_index const& right) const
  78. {
  79. typedef typename boost::range_value<Turns>::type turn_type;
  80. typedef typename turn_type::turn_operation_type turn_operation_type;
  81. turn_type const& left_turn = m_turns[left.turn_index];
  82. turn_type const& right_turn = m_turns[right.turn_index];
  83. turn_operation_type const& left_op
  84. = left_turn.operations[left.op_index];
  85. turn_operation_type const& right_op
  86. = right_turn.operations[right.op_index];
  87. if (! (left_op.fraction == right_op.fraction))
  88. {
  89. return left_op.fraction < right_op.fraction;
  90. }
  91. // Order xx first - used to discard any following colocated turn
  92. bool const left_both_xx = left_turn.both(operation_blocked);
  93. bool const right_both_xx = right_turn.both(operation_blocked);
  94. if (left_both_xx && ! right_both_xx)
  95. {
  96. return true;
  97. }
  98. if (! left_both_xx && right_both_xx)
  99. {
  100. return false;
  101. }
  102. bool const left_both_uu = left_turn.both(operation_union);
  103. bool const right_both_uu = right_turn.both(operation_union);
  104. if (left_both_uu && ! right_both_uu)
  105. {
  106. return true;
  107. }
  108. if (! left_both_uu && right_both_uu)
  109. {
  110. return false;
  111. }
  112. turn_operation_type const& left_other_op
  113. = left_turn.operations[1 - left.op_index];
  114. turn_operation_type const& right_other_op
  115. = right_turn.operations[1 - right.op_index];
  116. // Fraction is the same, now sort on ring id, first outer ring,
  117. // then interior rings
  118. return left_other_op.seg_id < right_other_op.seg_id;
  119. }
  120. private:
  121. Turns const& m_turns;
  122. };
  123. template <typename Operation, typename ClusterPerSegment>
  124. inline signed_size_type get_cluster_id(Operation const& op, ClusterPerSegment const& cluster_per_segment)
  125. {
  126. typedef typename ClusterPerSegment::key_type segment_fraction_type;
  127. segment_fraction_type seg_frac(op.seg_id, op.fraction);
  128. typename ClusterPerSegment::const_iterator it
  129. = cluster_per_segment.find(seg_frac);
  130. if (it == cluster_per_segment.end())
  131. {
  132. return -1;
  133. }
  134. return it->second;
  135. }
  136. template <typename Operation, typename ClusterPerSegment>
  137. inline void add_cluster_id(Operation const& op,
  138. ClusterPerSegment& cluster_per_segment, signed_size_type id)
  139. {
  140. typedef typename ClusterPerSegment::key_type segment_fraction_type;
  141. segment_fraction_type seg_frac(op.seg_id, op.fraction);
  142. cluster_per_segment[seg_frac] = id;
  143. }
  144. template <typename Turn, typename ClusterPerSegment>
  145. inline signed_size_type add_turn_to_cluster(Turn const& turn,
  146. ClusterPerSegment& cluster_per_segment, signed_size_type& cluster_id)
  147. {
  148. signed_size_type cid0 = get_cluster_id(turn.operations[0], cluster_per_segment);
  149. signed_size_type cid1 = get_cluster_id(turn.operations[1], cluster_per_segment);
  150. if (cid0 == -1 && cid1 == -1)
  151. {
  152. // Because of this, first cluster ID will be 1
  153. ++cluster_id;
  154. add_cluster_id(turn.operations[0], cluster_per_segment, cluster_id);
  155. add_cluster_id(turn.operations[1], cluster_per_segment, cluster_id);
  156. return cluster_id;
  157. }
  158. else if (cid0 == -1 && cid1 != -1)
  159. {
  160. add_cluster_id(turn.operations[0], cluster_per_segment, cid1);
  161. return cid1;
  162. }
  163. else if (cid0 != -1 && cid1 == -1)
  164. {
  165. add_cluster_id(turn.operations[1], cluster_per_segment, cid0);
  166. return cid0;
  167. }
  168. else if (cid0 == cid1)
  169. {
  170. // Both already added to same cluster, no action
  171. return cid0;
  172. }
  173. // Both operations.seg_id/fraction were already part of any cluster, and
  174. // these clusters are not the same. Merge of two clusters is necessary
  175. #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
  176. std::cout << " TODO: merge " << cid0 << " and " << cid1 << std::endl;
  177. #endif
  178. return cid0;
  179. }
  180. template
  181. <
  182. typename Turns,
  183. typename ClusterPerSegment,
  184. typename Operations,
  185. typename Geometry1,
  186. typename Geometry2
  187. >
  188. inline void handle_colocation_cluster(Turns& turns,
  189. signed_size_type& cluster_id,
  190. ClusterPerSegment& cluster_per_segment,
  191. Operations const& operations,
  192. Geometry1 const& /*geometry1*/, Geometry2 const& /*geometry2*/)
  193. {
  194. typedef typename boost::range_value<Turns>::type turn_type;
  195. typedef typename turn_type::turn_operation_type turn_operation_type;
  196. std::vector<turn_operation_index>::const_iterator vit = operations.begin();
  197. turn_operation_index ref_toi = *vit;
  198. signed_size_type ref_id = -1;
  199. for (++vit; vit != operations.end(); ++vit)
  200. {
  201. turn_type& ref_turn = turns[ref_toi.turn_index];
  202. turn_operation_type const& ref_op
  203. = ref_turn.operations[ref_toi.op_index];
  204. turn_operation_index const& toi = *vit;
  205. turn_type& turn = turns[toi.turn_index];
  206. turn_operation_type const& op = turn.operations[toi.op_index];
  207. BOOST_GEOMETRY_ASSERT(ref_op.seg_id == op.seg_id);
  208. if (ref_op.fraction == op.fraction)
  209. {
  210. turn_operation_type const& other_op = turn.operations[1 - toi.op_index];
  211. if (ref_id == -1)
  212. {
  213. ref_id = add_turn_to_cluster(ref_turn, cluster_per_segment, cluster_id);
  214. }
  215. BOOST_GEOMETRY_ASSERT(ref_id != -1);
  216. // ref_turn (both operations) are already added to cluster,
  217. // so also "op" is already added to cluster,
  218. // We only need to add other_op
  219. signed_size_type id = get_cluster_id(other_op, cluster_per_segment);
  220. if (id != -1 && id != ref_id)
  221. {
  222. }
  223. else if (id == -1)
  224. {
  225. // Add to same cluster
  226. add_cluster_id(other_op, cluster_per_segment, ref_id);
  227. id = ref_id;
  228. }
  229. }
  230. else
  231. {
  232. // Not on same fraction on this segment
  233. // assign for next
  234. ref_toi = toi;
  235. ref_id = -1;
  236. }
  237. }
  238. }
  239. template
  240. <
  241. typename Turns,
  242. typename Clusters,
  243. typename ClusterPerSegment
  244. >
  245. inline void assign_cluster_to_turns(Turns& turns,
  246. Clusters& clusters,
  247. ClusterPerSegment const& cluster_per_segment)
  248. {
  249. typedef typename boost::range_value<Turns>::type turn_type;
  250. typedef typename turn_type::turn_operation_type turn_operation_type;
  251. typedef typename ClusterPerSegment::key_type segment_fraction_type;
  252. signed_size_type turn_index = 0;
  253. for (typename boost::range_iterator<Turns>::type it = turns.begin();
  254. it != turns.end(); ++it, ++turn_index)
  255. {
  256. turn_type& turn = *it;
  257. if (turn.discarded)
  258. {
  259. // They were processed (to create proper map) but will not be added
  260. // This might leave a cluster with only 1 turn, which will be fixed
  261. // afterwards
  262. continue;
  263. }
  264. for (int i = 0; i < 2; i++)
  265. {
  266. turn_operation_type const& op = turn.operations[i];
  267. segment_fraction_type seg_frac(op.seg_id, op.fraction);
  268. typename ClusterPerSegment::const_iterator cit = cluster_per_segment.find(seg_frac);
  269. if (cit != cluster_per_segment.end())
  270. {
  271. #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
  272. if (turn.is_clustered()
  273. && turn.cluster_id != cit->second)
  274. {
  275. std::cout << " CONFLICT " << std::endl;
  276. }
  277. #endif
  278. turn.cluster_id = cit->second;
  279. clusters[turn.cluster_id].turn_indices.insert(turn_index);
  280. }
  281. }
  282. }
  283. }
  284. template <typename Turns, typename Clusters>
  285. inline void remove_clusters(Turns& turns, Clusters& clusters)
  286. {
  287. typename Clusters::iterator it = clusters.begin();
  288. while (it != clusters.end())
  289. {
  290. // Hold iterator and increase. We can erase cit, this keeps the
  291. // iterator valid (cf The standard associative-container erase idiom)
  292. typename Clusters::iterator current_it = it;
  293. ++it;
  294. std::set<signed_size_type> const& turn_indices
  295. = current_it->second.turn_indices;
  296. if (turn_indices.size() == 1)
  297. {
  298. signed_size_type const turn_index = *turn_indices.begin();
  299. turns[turn_index].cluster_id = -1;
  300. clusters.erase(current_it);
  301. }
  302. }
  303. }
  304. template <typename Turns, typename Clusters>
  305. inline void cleanup_clusters(Turns& turns, Clusters& clusters)
  306. {
  307. // Removes discarded turns from clusters
  308. for (typename Clusters::iterator mit = clusters.begin();
  309. mit != clusters.end(); ++mit)
  310. {
  311. cluster_info& cinfo = mit->second;
  312. std::set<signed_size_type>& ids = cinfo.turn_indices;
  313. for (std::set<signed_size_type>::iterator sit = ids.begin();
  314. sit != ids.end(); /* no increment */)
  315. {
  316. std::set<signed_size_type>::iterator current_it = sit;
  317. ++sit;
  318. signed_size_type const turn_index = *current_it;
  319. if (turns[turn_index].discarded)
  320. {
  321. ids.erase(current_it);
  322. }
  323. }
  324. }
  325. remove_clusters(turns, clusters);
  326. }
  327. template <typename Turn, typename IdSet>
  328. inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id)
  329. {
  330. turn.discarded = true;
  331. // Set cluster id to -1, but don't clear colocated flags
  332. turn.cluster_id = -1;
  333. // To remove it later from clusters
  334. ids.insert(id);
  335. }
  336. template <bool Reverse>
  337. inline bool is_interior(segment_identifier const& seg_id)
  338. {
  339. return Reverse ? seg_id.ring_index == -1 : seg_id.ring_index >= 0;
  340. }
  341. template <bool Reverse0, bool Reverse1>
  342. inline bool is_ie_turn(segment_identifier const& ext_seg_0,
  343. segment_identifier const& ext_seg_1,
  344. segment_identifier const& int_seg_0,
  345. segment_identifier const& other_seg_1)
  346. {
  347. if (ext_seg_0.source_index == ext_seg_1.source_index)
  348. {
  349. // External turn is a self-turn, dont discard internal turn for this
  350. return false;
  351. }
  352. // Compares two segment identifiers from two turns (external / one internal)
  353. // From first turn [0], both are from same polygon (multi_index),
  354. // one is exterior (-1), the other is interior (>= 0),
  355. // and the second turn [1] handles the same ring
  356. // For difference, where the rings are processed in reversal, all interior
  357. // rings become exterior and vice versa. But also the multi property changes:
  358. // rings originally from the same multi should now be considered as from
  359. // different multi polygons.
  360. // But this is not always the case, and at this point hard to figure out
  361. // (not yet implemented, TODO)
  362. bool const same_multi0 = ! Reverse0
  363. && ext_seg_0.multi_index == int_seg_0.multi_index;
  364. bool const same_multi1 = ! Reverse1
  365. && ext_seg_1.multi_index == other_seg_1.multi_index;
  366. boost::ignore_unused(same_multi1);
  367. return same_multi0
  368. && same_multi1
  369. && ! is_interior<Reverse0>(ext_seg_0)
  370. && is_interior<Reverse0>(int_seg_0)
  371. && ext_seg_1.ring_index == other_seg_1.ring_index;
  372. // The other way round is tested in another call
  373. }
  374. template
  375. <
  376. bool Reverse0, bool Reverse1, // Reverse interpretation interior/exterior
  377. typename Turns,
  378. typename Clusters
  379. >
  380. inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
  381. {
  382. typedef std::set<signed_size_type>::const_iterator set_iterator;
  383. typedef typename boost::range_value<Turns>::type turn_type;
  384. std::set<signed_size_type> ids_to_remove;
  385. for (typename Clusters::iterator cit = clusters.begin();
  386. cit != clusters.end(); ++cit)
  387. {
  388. cluster_info& cinfo = cit->second;
  389. std::set<signed_size_type>& ids = cinfo.turn_indices;
  390. ids_to_remove.clear();
  391. for (set_iterator it = ids.begin(); it != ids.end(); ++it)
  392. {
  393. turn_type& turn = turns[*it];
  394. segment_identifier const& seg_0 = turn.operations[0].seg_id;
  395. segment_identifier const& seg_1 = turn.operations[1].seg_id;
  396. if (! (turn.both(operation_union)
  397. || turn.combination(operation_union, operation_blocked)))
  398. {
  399. // Not a uu/ux, so cannot be colocated with a iu turn
  400. continue;
  401. }
  402. for (set_iterator int_it = ids.begin(); int_it != ids.end(); ++int_it)
  403. {
  404. if (*it == *int_it)
  405. {
  406. continue;
  407. }
  408. // Turn with, possibly, an interior ring involved
  409. turn_type& int_turn = turns[*int_it];
  410. segment_identifier const& int_seg_0 = int_turn.operations[0].seg_id;
  411. segment_identifier const& int_seg_1 = int_turn.operations[1].seg_id;
  412. if (is_ie_turn<Reverse0, Reverse1>(seg_0, seg_1, int_seg_0, int_seg_1))
  413. {
  414. discard_ie_turn(int_turn, ids_to_remove, *int_it);
  415. }
  416. if (is_ie_turn<Reverse1, Reverse0>(seg_1, seg_0, int_seg_1, int_seg_0))
  417. {
  418. discard_ie_turn(int_turn, ids_to_remove, *int_it);
  419. }
  420. }
  421. }
  422. // Erase from the ids (which cannot be done above)
  423. for (set_iterator sit = ids_to_remove.begin();
  424. sit != ids_to_remove.end(); ++sit)
  425. {
  426. ids.erase(*sit);
  427. }
  428. }
  429. }
  430. template <typename Geometry0, typename Geometry1>
  431. inline segment_identifier get_preceding_segment_id(segment_identifier const& id,
  432. Geometry0 const& geometry0, Geometry1 const& geometry1)
  433. {
  434. segment_identifier result = id;
  435. if (result.segment_index == 0)
  436. {
  437. // Assign to segment_count before decrement
  438. result.segment_index
  439. = id.source_index == 0
  440. ? segment_count_on_ring(geometry0, id)
  441. : segment_count_on_ring(geometry1, id);
  442. }
  443. result.segment_index--;
  444. return result;
  445. }
  446. template
  447. <
  448. overlay_type OverlayType,
  449. typename Turns,
  450. typename Clusters
  451. >
  452. inline void set_colocation(Turns& turns, Clusters const& clusters)
  453. {
  454. typedef std::set<signed_size_type>::const_iterator set_iterator;
  455. typedef typename boost::range_value<Turns>::type turn_type;
  456. for (typename Clusters::const_iterator cit = clusters.begin();
  457. cit != clusters.end(); ++cit)
  458. {
  459. cluster_info const& cinfo = cit->second;
  460. std::set<signed_size_type> const& ids = cinfo.turn_indices;
  461. bool both_target = false;
  462. for (set_iterator it = ids.begin(); it != ids.end(); ++it)
  463. {
  464. turn_type const& turn = turns[*it];
  465. if (turn.both(operation_from_overlay<OverlayType>::value))
  466. {
  467. both_target = true;
  468. break;
  469. }
  470. }
  471. if (both_target)
  472. {
  473. for (set_iterator it = ids.begin(); it != ids.end(); ++it)
  474. {
  475. turn_type& turn = turns[*it];
  476. turn.has_colocated_both = true;
  477. }
  478. }
  479. }
  480. }
  481. template
  482. <
  483. typename Turns,
  484. typename Clusters
  485. >
  486. inline void check_colocation(bool& has_blocked,
  487. signed_size_type cluster_id, Turns const& turns, Clusters const& clusters)
  488. {
  489. typedef typename boost::range_value<Turns>::type turn_type;
  490. has_blocked = false;
  491. typename Clusters::const_iterator mit = clusters.find(cluster_id);
  492. if (mit == clusters.end())
  493. {
  494. return;
  495. }
  496. cluster_info const& cinfo = mit->second;
  497. for (std::set<signed_size_type>::const_iterator it
  498. = cinfo.turn_indices.begin();
  499. it != cinfo.turn_indices.end(); ++it)
  500. {
  501. turn_type const& turn = turns[*it];
  502. if (turn.any_blocked())
  503. {
  504. has_blocked = true;
  505. }
  506. }
  507. }
  508. // Checks colocated turns and flags combinations of uu/other, possibly a
  509. // combination of a ring touching another geometry's interior ring which is
  510. // tangential to the exterior ring
  511. // This function can be extended to replace handle_tangencies: at each
  512. // colocation incoming and outgoing vectors should be inspected
  513. template
  514. <
  515. bool Reverse1, bool Reverse2,
  516. overlay_type OverlayType,
  517. typename Turns,
  518. typename Clusters,
  519. typename Geometry1,
  520. typename Geometry2
  521. >
  522. inline bool handle_colocations(Turns& turns, Clusters& clusters,
  523. Geometry1 const& geometry1, Geometry2 const& geometry2)
  524. {
  525. static const detail::overlay::operation_type target_operation
  526. = detail::overlay::operation_from_overlay<OverlayType>::value;
  527. typedef std::map
  528. <
  529. segment_identifier,
  530. std::vector<turn_operation_index>
  531. > map_type;
  532. // Create and fill map on segment-identifier Map is sorted on seg_id,
  533. // meaning it is sorted on ring_identifier too. This means that exterior
  534. // rings are handled first. If there is a colocation on the exterior ring,
  535. // that information can be used for the interior ring too
  536. map_type map;
  537. signed_size_type index = 0;
  538. for (typename boost::range_iterator<Turns>::type
  539. it = boost::begin(turns);
  540. it != boost::end(turns);
  541. ++it, ++index)
  542. {
  543. map[it->operations[0].seg_id].push_back(turn_operation_index(index, 0));
  544. map[it->operations[1].seg_id].push_back(turn_operation_index(index, 1));
  545. }
  546. // Check if there are multiple turns on one or more segments,
  547. // if not then nothing is to be done
  548. bool colocations = 0;
  549. for (typename map_type::const_iterator it = map.begin();
  550. it != map.end();
  551. ++it)
  552. {
  553. if (it->second.size() > 1u)
  554. {
  555. colocations = true;
  556. break;
  557. }
  558. }
  559. if (! colocations)
  560. {
  561. return false;
  562. }
  563. // Sort all vectors, per same segment
  564. less_by_fraction_and_type<Turns> less(turns);
  565. for (typename map_type::iterator it = map.begin();
  566. it != map.end(); ++it)
  567. {
  568. std::sort(it->second.begin(), it->second.end(), less);
  569. }
  570. typedef typename boost::range_value<Turns>::type turn_type;
  571. typedef typename turn_type::segment_ratio_type segment_ratio_type;
  572. typedef std::map
  573. <
  574. segment_fraction<segment_ratio_type>,
  575. signed_size_type
  576. > cluster_per_segment_type;
  577. cluster_per_segment_type cluster_per_segment;
  578. // Assign to zero, because of pre-increment later the cluster_id
  579. // effectively starts with 1
  580. // (and can later be negated to use uniquely with turn_index)
  581. signed_size_type cluster_id = 0;
  582. for (typename map_type::const_iterator it = map.begin();
  583. it != map.end(); ++it)
  584. {
  585. if (it->second.size() > 1u)
  586. {
  587. handle_colocation_cluster(turns, cluster_id, cluster_per_segment,
  588. it->second, geometry1, geometry2);
  589. }
  590. }
  591. assign_cluster_to_turns(turns, clusters, cluster_per_segment);
  592. // Get colocated information here and not later, to keep information
  593. // on turns which are discarded afterwards
  594. set_colocation<OverlayType>(turns, clusters);
  595. if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection))
  596. {
  597. discard_interior_exterior_turns
  598. <
  599. do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse1,
  600. do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2
  601. >(turns, clusters);
  602. }
  603. #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
  604. std::cout << "*** Colocations " << map.size() << std::endl;
  605. for (typename map_type::const_iterator it = map.begin();
  606. it != map.end(); ++it)
  607. {
  608. std::cout << it->first << std::endl;
  609. for (std::vector<turn_operation_index>::const_iterator vit
  610. = it->second.begin(); vit != it->second.end(); ++vit)
  611. {
  612. turn_operation_index const& toi = *vit;
  613. std::cout << geometry::wkt(turns[toi.turn_index].point)
  614. << std::boolalpha
  615. << " discarded=" << turns[toi.turn_index].discarded
  616. << " colocated(uu)=" << turns[toi.turn_index].colocated_uu
  617. << " colocated(ii)=" << turns[toi.turn_index].colocated_ii
  618. << " " << operation_char(turns[toi.turn_index].operations[0].operation)
  619. << " " << turns[toi.turn_index].operations[0].seg_id
  620. << " " << turns[toi.turn_index].operations[0].fraction
  621. << " // " << operation_char(turns[toi.turn_index].operations[1].operation)
  622. << " " << turns[toi.turn_index].operations[1].seg_id
  623. << " " << turns[toi.turn_index].operations[1].fraction
  624. << std::endl;
  625. }
  626. }
  627. #endif // DEBUG
  628. return true;
  629. }
  630. struct is_turn_index
  631. {
  632. is_turn_index(signed_size_type index)
  633. : m_index(index)
  634. {}
  635. template <typename Indexed>
  636. inline bool operator()(Indexed const& indexed) const
  637. {
  638. // Indexed is a indexed_turn_operation<Operation>
  639. return indexed.turn_index == m_index;
  640. }
  641. signed_size_type m_index;
  642. };
  643. template
  644. <
  645. bool Reverse1, bool Reverse2,
  646. overlay_type OverlayType,
  647. typename Turns,
  648. typename Clusters,
  649. typename Geometry1,
  650. typename Geometry2,
  651. typename SideStrategy
  652. >
  653. inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
  654. operation_type for_operation,
  655. Geometry1 const& geometry1, Geometry2 const& geometry2,
  656. SideStrategy const& strategy)
  657. {
  658. typedef typename boost::range_value<Turns>::type turn_type;
  659. typedef typename turn_type::point_type point_type;
  660. typedef typename turn_type::turn_operation_type turn_operation_type;
  661. // Define sorter, sorting counter-clockwise such that polygons are on the
  662. // right side
  663. typedef sort_by_side::side_sorter
  664. <
  665. Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int>
  666. > sbs_type;
  667. for (typename Clusters::iterator mit = clusters.begin();
  668. mit != clusters.end(); ++mit)
  669. {
  670. cluster_info& cinfo = mit->second;
  671. std::set<signed_size_type> const& ids = cinfo.turn_indices;
  672. if (ids.empty())
  673. {
  674. continue;
  675. }
  676. sbs_type sbs(strategy);
  677. point_type turn_point; // should be all the same for all turns in cluster
  678. bool first = true;
  679. for (std::set<signed_size_type>::const_iterator sit = ids.begin();
  680. sit != ids.end(); ++sit)
  681. {
  682. signed_size_type turn_index = *sit;
  683. turn_type const& turn = turns[turn_index];
  684. if (first)
  685. {
  686. turn_point = turn.point;
  687. }
  688. for (int i = 0; i < 2; i++)
  689. {
  690. turn_operation_type const& op = turn.operations[i];
  691. sbs.add(op, turn_index, i, geometry1, geometry2, first);
  692. first = false;
  693. }
  694. }
  695. sbs.apply(turn_point);
  696. sbs.find_open();
  697. sbs.assign_zones(for_operation);
  698. cinfo.open_count = sbs.open_count(for_operation);
  699. bool const set_startable = OverlayType != overlay_dissolve;
  700. // Unset the startable flag for all 'closed' zones. This does not
  701. // apply for self-turns, because those counts are not from both
  702. // polygons
  703. for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
  704. {
  705. const typename sbs_type::rp& ranked = sbs.m_ranked_points[i];
  706. turn_type& turn = turns[ranked.turn_index];
  707. turn_operation_type& op = turn.operations[ranked.operation_index];
  708. if (set_startable
  709. && for_operation == operation_union && cinfo.open_count == 0)
  710. {
  711. op.enriched.startable = false;
  712. }
  713. if (ranked.direction != sort_by_side::dir_to)
  714. {
  715. continue;
  716. }
  717. op.enriched.count_left = ranked.count_left;
  718. op.enriched.count_right = ranked.count_right;
  719. op.enriched.rank = ranked.rank;
  720. op.enriched.zone = ranked.zone;
  721. if (! set_startable)
  722. {
  723. continue;
  724. }
  725. if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_difference)
  726. && is_self_turn<OverlayType>(turn))
  727. {
  728. // Difference needs the self-turns, TODO: investigate
  729. continue;
  730. }
  731. if ((for_operation == operation_union
  732. && ranked.count_left != 0)
  733. || (for_operation == operation_intersection
  734. && ranked.count_right != 2))
  735. {
  736. op.enriched.startable = false;
  737. }
  738. }
  739. }
  740. }
  741. }} // namespace detail::overlay
  742. #endif //DOXYGEN_NO_DETAIL
  743. }} // namespace boost::geometry
  744. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_COLOCATIONS_HPP