// Boost.Geometry // Copyright (c) 2022, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { struct gc_element_id { gc_element_id(unsigned int source_id_, std::size_t gc_id_) : source_id(source_id_), gc_id(gc_id_) {} unsigned int source_id; std::size_t gc_id; friend bool operator<(gc_element_id const& left, gc_element_id const& right) { return left.source_id < right.source_id || (left.source_id == right.source_id && left.gc_id < right.gc_id); } }; template inline void gc_group_elements(GC1View const& gc1_view, GC2View const& gc2_view, Strategy const& strategy, IntersectingFun&& intersecting_fun, DisjointFun&& disjoint_fun, bool const group_self = false) { // NOTE: gc_make_rtree_indexes() already checks for random-access, // non-recursive geometry collections. // NOTE: could be replaced with unordered_map and unordered_set std::map> adjacent; // Create adjacency list based on intersecting envelopes of GC elements auto const rtree2 = gc_make_rtree_indexes(gc2_view, strategy); if (! group_self) // group only elements from the other GC? { for (std::size_t i = 0; i < boost::size(gc1_view); ++i) { traits::iter_visit::apply([&](auto const& g1) { using g1_t = util::remove_cref_t; using box1_t = gc_make_rtree_box_t; box1_t b1 = geometry::return_envelope(g1, strategy); detail::expand_by_epsilon(b1); gc_element_id id1 = {0, i}; for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit) { gc_element_id id2 = {1, qit->second}; adjacent[id1].insert(id2); adjacent[id2].insert(id1); } }, boost::begin(gc1_view) + i); } } else // group elements from the same GCs and the other GC { auto const rtree1 = gc_make_rtree_indexes(gc1_view, strategy); for (auto it1 = rtree1.begin() ; it1 != rtree1.end() ; ++it1) { auto const b1 = it1->first; gc_element_id id1 = {0, it1->second}; for (auto qit2 = rtree2.qbegin(index::intersects(b1)); qit2 != rtree2.qend(); ++qit2) { gc_element_id id2 = {1, qit2->second}; adjacent[id1].insert(id2); adjacent[id2].insert(id1); } for (auto qit1 = rtree1.qbegin(index::intersects(b1)); qit1 != rtree1.qend(); ++qit1) { if (id1.gc_id != qit1->second) { gc_element_id id11 = {0, qit1->second}; adjacent[id1].insert(id11); adjacent[id11].insert(id1); } } } for (auto it2 = rtree2.begin(); it2 != rtree2.end(); ++it2) { auto const b2 = it2->first; gc_element_id id2 = {1, it2->second}; for (auto qit2 = rtree2.qbegin(index::intersects(b2)); qit2 != rtree2.qend(); ++qit2) { if (id2.gc_id != qit2->second) { gc_element_id id22 = {1, qit2->second}; adjacent[id2].insert(id22); adjacent[id22].insert(id2); } } } } // Traverse the graph and build connected groups i.e. groups of intersecting envelopes std::deque queue; std::array, 2> visited = { std::vector(boost::size(gc1_view), false), std::vector(boost::size(gc2_view), false) }; for (auto const& elem : adjacent) { std::vector group; if (! visited[elem.first.source_id][elem.first.gc_id]) { queue.push_back(elem.first); visited[elem.first.source_id][elem.first.gc_id] = true; group.push_back(elem.first); while (! queue.empty()) { gc_element_id e = queue.front(); queue.pop_front(); for (auto const& n : adjacent[e]) { if (! visited[n.source_id][n.gc_id]) { queue.push_back(n); visited[n.source_id][n.gc_id] = true; group.push_back(n); } } } } if (! group.empty()) { if (! intersecting_fun(group)) { return; } } } { std::vector group; for (std::size_t i = 0; i < visited[0].size(); ++i) { if (! visited[0][i]) { group.emplace_back(0, i); } } for (std::size_t i = 0; i < visited[1].size(); ++i) { if (! visited[1][i]) { group.emplace_back(1, i); } } if (! group.empty()) { disjoint_fun(group); } } } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GC_GROUP_ELEMENTS_HPP