handle_colocations.hpp 28 KB

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