gc_group_elements.hpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Boost.Geometry
  2. // Copyright (c) 2022, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  4. // Licensed under the Boost Software License version 1.0.
  5. // http://www.boost.org/users/license.html
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP
  8. #include <array>
  9. #include <deque>
  10. #include <map>
  11. #include <set>
  12. #include <vector>
  13. #include <boost/range/begin.hpp>
  14. #include <boost/range/size.hpp>
  15. #include <boost/geometry/algorithms/detail/gc_make_rtree.hpp>
  16. #include <boost/geometry/algorithms/detail/visit.hpp>
  17. #include <boost/geometry/algorithms/is_empty.hpp>
  18. #include <boost/geometry/core/topological_dimension.hpp>
  19. #include <boost/geometry/views/detail/random_access_view.hpp>
  20. namespace boost { namespace geometry
  21. {
  22. #ifndef DOXYGEN_NO_DETAIL
  23. namespace detail
  24. {
  25. struct gc_element_id
  26. {
  27. gc_element_id(unsigned int source_id_, std::size_t gc_id_)
  28. : source_id(source_id_), gc_id(gc_id_)
  29. {}
  30. unsigned int source_id;
  31. std::size_t gc_id;
  32. friend bool operator<(gc_element_id const& left, gc_element_id const& right)
  33. {
  34. return left.source_id < right.source_id
  35. || (left.source_id == right.source_id && left.gc_id < right.gc_id);
  36. }
  37. };
  38. template <typename GC1View, typename GC2View, typename Strategy, typename IntersectingFun, typename DisjointFun>
  39. inline void gc_group_elements(GC1View const& gc1_view, GC2View const& gc2_view, Strategy const& strategy,
  40. IntersectingFun&& intersecting_fun,
  41. DisjointFun&& disjoint_fun,
  42. bool const group_self = false)
  43. {
  44. // NOTE: gc_make_rtree_indexes() already checks for random-access,
  45. // non-recursive geometry collections.
  46. // NOTE: could be replaced with unordered_map and unordered_set
  47. std::map<gc_element_id, std::set<gc_element_id>> adjacent;
  48. // Create adjacency list based on intersecting envelopes of GC elements
  49. auto const rtree2 = gc_make_rtree_indexes(gc2_view, strategy);
  50. if (! group_self) // group only elements from the other GC?
  51. {
  52. for (std::size_t i = 0; i < boost::size(gc1_view); ++i)
  53. {
  54. traits::iter_visit<GC1View>::apply([&](auto const& g1)
  55. {
  56. using g1_t = util::remove_cref_t<decltype(g1)>;
  57. using box1_t = gc_make_rtree_box_t<g1_t>;
  58. box1_t b1 = geometry::return_envelope<box1_t>(g1, strategy);
  59. detail::expand_by_epsilon(b1);
  60. gc_element_id id1 = {0, i};
  61. for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit)
  62. {
  63. gc_element_id id2 = {1, qit->second};
  64. adjacent[id1].insert(id2);
  65. adjacent[id2].insert(id1);
  66. }
  67. }, boost::begin(gc1_view) + i);
  68. }
  69. }
  70. else // group elements from the same GCs and the other GC
  71. {
  72. auto const rtree1 = gc_make_rtree_indexes(gc1_view, strategy);
  73. for (auto it1 = rtree1.begin() ; it1 != rtree1.end() ; ++it1)
  74. {
  75. auto const b1 = it1->first;
  76. gc_element_id id1 = {0, it1->second};
  77. for (auto qit2 = rtree2.qbegin(index::intersects(b1)); qit2 != rtree2.qend(); ++qit2)
  78. {
  79. gc_element_id id2 = {1, qit2->second};
  80. adjacent[id1].insert(id2);
  81. adjacent[id2].insert(id1);
  82. }
  83. for (auto qit1 = rtree1.qbegin(index::intersects(b1)); qit1 != rtree1.qend(); ++qit1)
  84. {
  85. if (id1.gc_id != qit1->second)
  86. {
  87. gc_element_id id11 = {0, qit1->second};
  88. adjacent[id1].insert(id11);
  89. adjacent[id11].insert(id1);
  90. }
  91. }
  92. }
  93. for (auto it2 = rtree2.begin(); it2 != rtree2.end(); ++it2)
  94. {
  95. auto const b2 = it2->first;
  96. gc_element_id id2 = {1, it2->second};
  97. for (auto qit2 = rtree2.qbegin(index::intersects(b2)); qit2 != rtree2.qend(); ++qit2)
  98. {
  99. if (id2.gc_id != qit2->second)
  100. {
  101. gc_element_id id22 = {1, qit2->second};
  102. adjacent[id2].insert(id22);
  103. adjacent[id22].insert(id2);
  104. }
  105. }
  106. }
  107. }
  108. // Traverse the graph and build connected groups i.e. groups of intersecting envelopes
  109. std::deque<gc_element_id> queue;
  110. std::array<std::vector<bool>, 2> visited = {
  111. std::vector<bool>(boost::size(gc1_view), false),
  112. std::vector<bool>(boost::size(gc2_view), false)
  113. };
  114. for (auto const& elem : adjacent)
  115. {
  116. std::vector<gc_element_id> group;
  117. if (! visited[elem.first.source_id][elem.first.gc_id])
  118. {
  119. queue.push_back(elem.first);
  120. visited[elem.first.source_id][elem.first.gc_id] = true;
  121. group.push_back(elem.first);
  122. while (! queue.empty())
  123. {
  124. gc_element_id e = queue.front();
  125. queue.pop_front();
  126. for (auto const& n : adjacent[e])
  127. {
  128. if (! visited[n.source_id][n.gc_id])
  129. {
  130. queue.push_back(n);
  131. visited[n.source_id][n.gc_id] = true;
  132. group.push_back(n);
  133. }
  134. }
  135. }
  136. }
  137. if (! group.empty())
  138. {
  139. if (! intersecting_fun(group))
  140. {
  141. return;
  142. }
  143. }
  144. }
  145. {
  146. std::vector<gc_element_id> group;
  147. for (std::size_t i = 0; i < visited[0].size(); ++i)
  148. {
  149. if (! visited[0][i])
  150. {
  151. group.emplace_back(0, i);
  152. }
  153. }
  154. for (std::size_t i = 0; i < visited[1].size(); ++i)
  155. {
  156. if (! visited[1][i])
  157. {
  158. group.emplace_back(1, i);
  159. }
  160. }
  161. if (! group.empty())
  162. {
  163. disjoint_fun(group);
  164. }
  165. }
  166. }
  167. } // namespace detail
  168. #endif // DOXYGEN_NO_DETAIL
  169. }} // namespace boost::geometry
  170. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP