// Boost.Geometry Index // // R-tree R*-tree next node choosing algorithm implementation // // Copyright (c) 2011-2019 Adam Wulkiewicz, Lodz, Poland. // // This file was modified by Oracle on 2019-2021. // Modifications copyright (c) 2019-2021 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP #define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { template class choose_next_node { typedef typename MembersHolder::box_type box_type; typedef typename MembersHolder::parameters_type parameters_type; typedef typename MembersHolder::node node; typedef typename MembersHolder::internal_node internal_node; typedef typename MembersHolder::leaf leaf; typedef typename rtree::elements_type::type children_type; typedef typename children_type::value_type child_type; typedef typename index::detail::default_content_result::type content_type; public: template static inline size_t apply(internal_node & n, Indexable const& indexable, parameters_type const& parameters, size_t node_relative_level) { ::boost::ignore_unused(parameters); children_type & children = rtree::elements(n); // children are leafs if ( node_relative_level <= 1 ) { return choose_by_minimum_overlap_cost(children, indexable, parameters.get_overlap_cost_threshold(), index::detail::get_strategy(parameters)); } // children are internal nodes else { return choose_by_minimum_content_cost(children, indexable, index::detail::get_strategy(parameters)); } } private: struct child_contents { content_type content_diff; content_type content; size_t i; void set(size_t i_, content_type const& content_, content_type const& content_diff_) { i = i_; content = content_; content_diff = content_diff_; } }; template static inline size_t choose_by_minimum_overlap_cost(children_type const& children, Indexable const& indexable, size_t overlap_cost_threshold, Strategy const& strategy) { const size_t children_count = children.size(); content_type min_content_diff = (std::numeric_limits::max)(); content_type min_content = (std::numeric_limits::max)(); size_t choosen_index = 0; // create container of children sorted by content enlargement needed to include the new value typename rtree::container_from_elements_type::type children_contents(children_count); for ( size_t i = 0 ; i < children_count ; ++i ) { child_type const& ch_i = children[i]; // expanded child node's box box_type box_exp(ch_i.first); index::detail::expand(box_exp, indexable, strategy); // areas difference content_type content = index::detail::content(box_exp); content_type content_diff = content - index::detail::content(ch_i.first); children_contents[i].set(i, content, content_diff); if ( content_diff < min_content_diff || (content_diff == min_content_diff && content < min_content) ) { min_content_diff = content_diff; min_content = content; choosen_index = i; } } // is this assumption ok? if min_content_diff == 0 there is no overlap increase? if ( min_content_diff < -std::numeric_limits::epsilon() || std::numeric_limits::epsilon() < min_content_diff ) { size_t first_n_children_count = children_count; if ( 0 < overlap_cost_threshold && overlap_cost_threshold < children.size() ) { first_n_children_count = overlap_cost_threshold; // rearrange by content_diff // in order to calculate nearly minimum overlap cost index::detail::nth_element(children_contents.begin(), children_contents.begin() + first_n_children_count, children_contents.end(), content_diff_less); } // calculate minimum or nearly minimum overlap cost choosen_index = choose_by_minimum_overlap_cost_first_n(children, indexable, first_n_children_count, children_count, children_contents, strategy); } return choosen_index; } static inline bool content_diff_less(child_contents const& p1, child_contents const& p2) { return p1.content_diff < p2.content_diff || (p1.content_diff == p2.content_diff && (p1.content) < (p2.content)); } template static inline size_t choose_by_minimum_overlap_cost_first_n(children_type const& children, Indexable const& indexable, size_t const first_n_children_count, size_t const children_count, ChildrenContents const& children_contents, Strategy const& strategy) { BOOST_GEOMETRY_INDEX_ASSERT(first_n_children_count <= children_count, "unexpected value"); BOOST_GEOMETRY_INDEX_ASSERT(children_contents.size() == children_count, "unexpected number of elements"); // choose index with smallest overlap change value, or content change or smallest content size_t choosen_index = 0; content_type smallest_overlap_diff = (std::numeric_limits::max)(); content_type smallest_content_diff = (std::numeric_limits::max)(); content_type smallest_content = (std::numeric_limits::max)(); // for each child node for (size_t first_i = 0 ; first_i < first_n_children_count ; ++first_i) { size_t i = children_contents[first_i].i; content_type const& content = children_contents[first_i].content; content_type const& content_diff = children_contents[first_i].content_diff; child_type const& ch_i = children[i]; box_type box_exp(ch_i.first); // calculate expanded box of child node ch_i index::detail::expand(box_exp, indexable, strategy); content_type overlap_diff = 0; // calculate overlap for ( size_t j = 0 ; j < children_count ; ++j ) { if ( i != j ) { child_type const& ch_j = children[j]; content_type overlap_exp = index::detail::intersection_content(box_exp, ch_j.first, strategy); if ( overlap_exp < -std::numeric_limits::epsilon() || std::numeric_limits::epsilon() < overlap_exp ) { overlap_diff += overlap_exp - index::detail::intersection_content(ch_i.first, ch_j.first, strategy); } } } // update result if ( overlap_diff < smallest_overlap_diff || ( overlap_diff == smallest_overlap_diff && ( content_diff < smallest_content_diff || ( content_diff == smallest_content_diff && content < smallest_content ) ) ) ) { smallest_overlap_diff = overlap_diff; smallest_content_diff = content_diff; smallest_content = content; choosen_index = i; } } return choosen_index; } template static inline size_t choose_by_minimum_content_cost(children_type const& children, Indexable const& indexable, Strategy const& strategy) { size_t children_count = children.size(); // choose index with smallest content change or smallest content size_t choosen_index = 0; content_type smallest_content_diff = (std::numeric_limits::max)(); content_type smallest_content = (std::numeric_limits::max)(); // choose the child which requires smallest box expansion to store the indexable for ( size_t i = 0 ; i < children_count ; ++i ) { child_type const& ch_i = children[i]; // expanded child node's box box_type box_exp(ch_i.first); index::detail::expand(box_exp, indexable, strategy); // areas difference content_type content = index::detail::content(box_exp); content_type content_diff = content - index::detail::content(ch_i.first); // update the result if ( content_diff < smallest_content_diff || ( content_diff == smallest_content_diff && content < smallest_content ) ) { smallest_content_diff = content_diff; smallest_content = content; choosen_index = i; } } return choosen_index; } }; }} // namespace detail::rtree }}} // namespace boost::geometry::index #endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP