mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-17 12:48:11 +00:00
Added thirdparty: boost library
This commit is contained in:
+269
@@ -0,0 +1,269 @@
|
||||
// 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 <algorithm>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
|
||||
#include <boost/geometry/index/detail/algorithms/content.hpp>
|
||||
#include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
|
||||
#include <boost/geometry/index/detail/algorithms/nth_element.hpp>
|
||||
#include <boost/geometry/index/detail/algorithms/union_content.hpp>
|
||||
|
||||
#include <boost/geometry/index/detail/rtree/node/node.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/options.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace detail { namespace rtree {
|
||||
|
||||
template <typename MembersHolder>
|
||||
class choose_next_node<MembersHolder, choose_by_overlap_diff_tag>
|
||||
{
|
||||
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<internal_node>::type children_type;
|
||||
typedef typename children_type::value_type child_type;
|
||||
|
||||
typedef typename index::detail::default_content_result<box_type>::type content_type;
|
||||
|
||||
public:
|
||||
template <typename Indexable>
|
||||
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 <typename Indexable, typename Strategy>
|
||||
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<content_type>::max)();
|
||||
content_type min_content = (std::numeric_limits<content_type>::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<children_type, child_contents>::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<double>::epsilon() || std::numeric_limits<double>::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 <typename Indexable, typename ChildrenContents, typename Strategy>
|
||||
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<content_type>::max)();
|
||||
content_type smallest_content_diff = (std::numeric_limits<content_type>::max)();
|
||||
content_type smallest_content = (std::numeric_limits<content_type>::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<content_type>::epsilon() || std::numeric_limits<content_type>::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 <typename Indexable, typename Strategy>
|
||||
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<content_type>::max)();
|
||||
content_type smallest_content = (std::numeric_limits<content_type>::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
|
||||
+685
@@ -0,0 +1,685 @@
|
||||
// Boost.Geometry Index
|
||||
//
|
||||
// R-tree R*-tree insert algorithm implementation
|
||||
//
|
||||
// Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
|
||||
//
|
||||
// This file was modified by Oracle on 2019-2023.
|
||||
// Modifications copyright (c) 2019-2023 Oracle and/or its affiliates.
|
||||
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
|
||||
// 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_INSERT_HPP
|
||||
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/centroid.hpp>
|
||||
#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp>
|
||||
|
||||
#include <boost/geometry/index/detail/algorithms/content.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/node/concept.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/node/node_elements.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace detail { namespace rtree { namespace visitors {
|
||||
|
||||
namespace rstar {
|
||||
|
||||
// Utility to distinguish between default and non-default index strategy
|
||||
template <typename Point1, typename Point2, typename Strategy>
|
||||
struct comparable_distance
|
||||
{
|
||||
typedef typename geometry::comparable_distance_result
|
||||
<
|
||||
Point1, Point2, Strategy
|
||||
>::type result_type;
|
||||
|
||||
static inline result_type call(Point1 const& p1, Point2 const& p2, Strategy const& s)
|
||||
{
|
||||
return geometry::comparable_distance(p1, p2, s);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Point1, typename Point2>
|
||||
struct comparable_distance<Point1, Point2, default_strategy>
|
||||
{
|
||||
typedef typename geometry::default_comparable_distance_result
|
||||
<
|
||||
Point1, Point2
|
||||
>::type result_type;
|
||||
|
||||
static inline result_type call(Point1 const& p1, Point2 const& p2, default_strategy const& )
|
||||
{
|
||||
return geometry::comparable_distance(p1, p2);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MembersHolder>
|
||||
class remove_elements_to_reinsert
|
||||
{
|
||||
public:
|
||||
typedef typename MembersHolder::box_type box_type;
|
||||
typedef typename MembersHolder::parameters_type parameters_type;
|
||||
typedef typename MembersHolder::translator_type translator_type;
|
||||
typedef typename MembersHolder::allocators_type allocators_type;
|
||||
|
||||
typedef typename MembersHolder::node node;
|
||||
typedef typename MembersHolder::internal_node internal_node;
|
||||
typedef typename MembersHolder::leaf leaf;
|
||||
|
||||
//typedef typename Allocators::internal_node_pointer internal_node_pointer;
|
||||
typedef internal_node * internal_node_pointer;
|
||||
|
||||
template <typename ResultElements, typename Node>
|
||||
static inline void apply(ResultElements & result_elements,
|
||||
Node & n,
|
||||
internal_node_pointer parent,
|
||||
size_t current_child_index,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators)
|
||||
{
|
||||
typedef typename rtree::elements_type<Node>::type elements_type;
|
||||
typedef typename elements_type::value_type element_type;
|
||||
typedef typename geometry::point_type<box_type>::type point_type;
|
||||
typedef typename index::detail::strategy_type<parameters_type>::type strategy_type;
|
||||
// TODO: awulkiew - change second point_type to the point type of the Indexable?
|
||||
typedef rstar::comparable_distance
|
||||
<
|
||||
point_type, point_type, strategy_type
|
||||
> comparable_distance_pp;
|
||||
typedef typename comparable_distance_pp::result_type comparable_distance_type;
|
||||
|
||||
elements_type & elements = rtree::elements(n);
|
||||
|
||||
const size_t elements_count = parameters.get_max_elements() + 1;
|
||||
const size_t reinserted_elements_count = (::std::min)(parameters.get_reinserted_elements(), elements_count - parameters.get_min_elements());
|
||||
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(parent, "node shouldn't be the root node");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected elements number");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(0 < reinserted_elements_count, "wrong value of elements to reinsert");
|
||||
|
||||
auto const& strategy = index::detail::get_strategy(parameters);
|
||||
|
||||
// calculate current node's center
|
||||
point_type node_center;
|
||||
geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center,
|
||||
strategy);
|
||||
|
||||
// fill the container of centers' distances of children from current node's center
|
||||
typedef typename index::detail::rtree::container_from_elements_type<
|
||||
elements_type,
|
||||
std::pair<comparable_distance_type, element_type>
|
||||
>::type sorted_elements_type;
|
||||
|
||||
sorted_elements_type sorted_elements;
|
||||
// If constructor is used instead of resize() MS implementation leaks here
|
||||
sorted_elements.reserve(elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
|
||||
|
||||
for ( typename elements_type::const_iterator it = elements.begin() ;
|
||||
it != elements.end() ; ++it )
|
||||
{
|
||||
point_type element_center;
|
||||
geometry::centroid(rtree::element_indexable(*it, translator), element_center,
|
||||
strategy);
|
||||
sorted_elements.push_back(std::make_pair(
|
||||
comparable_distance_pp::call(node_center, element_center, strategy),
|
||||
*it)); // MAY THROW (V, E: copy)
|
||||
}
|
||||
|
||||
// sort elements by distances from center
|
||||
std::partial_sort(
|
||||
sorted_elements.begin(),
|
||||
sorted_elements.begin() + reinserted_elements_count,
|
||||
sorted_elements.end(),
|
||||
distances_dsc<comparable_distance_type, element_type>); // MAY THROW, BASIC (V, E: copy)
|
||||
|
||||
// copy elements which will be reinserted
|
||||
result_elements.clear();
|
||||
result_elements.reserve(reinserted_elements_count); // MAY THROW, STRONG (V, E: alloc, copy)
|
||||
for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() ;
|
||||
it != sorted_elements.begin() + reinserted_elements_count ; ++it )
|
||||
{
|
||||
result_elements.push_back(it->second); // MAY THROW (V, E: copy)
|
||||
}
|
||||
|
||||
BOOST_TRY
|
||||
{
|
||||
// copy remaining elements to the current node
|
||||
elements.clear();
|
||||
elements.reserve(elements_count - reinserted_elements_count); // SHOULDN'T THROW (new_size <= old size)
|
||||
for ( typename sorted_elements_type::const_iterator it = sorted_elements.begin() + reinserted_elements_count;
|
||||
it != sorted_elements.end() ; ++it )
|
||||
{
|
||||
elements.push_back(it->second); // MAY THROW (V, E: copy)
|
||||
}
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
elements.clear();
|
||||
|
||||
for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ;
|
||||
it != sorted_elements.end() ; ++it )
|
||||
{
|
||||
destroy_element<MembersHolder>::apply(it->second, allocators);
|
||||
}
|
||||
|
||||
BOOST_RETHROW // RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
::boost::ignore_unused(parameters);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Distance, typename El>
|
||||
static inline bool distances_asc(
|
||||
std::pair<Distance, El> const& d1,
|
||||
std::pair<Distance, El> const& d2)
|
||||
{
|
||||
return d1.first < d2.first;
|
||||
}
|
||||
|
||||
template <typename Distance, typename El>
|
||||
static inline bool distances_dsc(
|
||||
std::pair<Distance, El> const& d1,
|
||||
std::pair<Distance, El> const& d2)
|
||||
{
|
||||
return d1.first > d2.first;
|
||||
}
|
||||
};
|
||||
|
||||
template
|
||||
<
|
||||
size_t InsertIndex,
|
||||
typename Element,
|
||||
typename MembersHolder,
|
||||
bool IsValue = std::is_same<Element, typename MembersHolder::value_type>::value
|
||||
>
|
||||
struct level_insert_elements_type
|
||||
{
|
||||
typedef typename rtree::elements_type<
|
||||
typename rtree::internal_node<
|
||||
typename MembersHolder::value_type,
|
||||
typename MembersHolder::parameters_type,
|
||||
typename MembersHolder::box_type,
|
||||
typename MembersHolder::allocators_type,
|
||||
typename MembersHolder::node_tag
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <typename Value, typename MembersHolder>
|
||||
struct level_insert_elements_type<0, Value, MembersHolder, true>
|
||||
{
|
||||
typedef typename rtree::elements_type<
|
||||
typename rtree::leaf<
|
||||
typename MembersHolder::value_type,
|
||||
typename MembersHolder::parameters_type,
|
||||
typename MembersHolder::box_type,
|
||||
typename MembersHolder::allocators_type,
|
||||
typename MembersHolder::node_tag
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <size_t InsertIndex, typename Element, typename MembersHolder>
|
||||
struct level_insert_base
|
||||
: public detail::insert<Element, MembersHolder>
|
||||
{
|
||||
typedef detail::insert<Element, MembersHolder> base;
|
||||
typedef typename base::node node;
|
||||
typedef typename base::internal_node internal_node;
|
||||
typedef typename base::leaf leaf;
|
||||
|
||||
typedef typename level_insert_elements_type<InsertIndex, Element, MembersHolder>::type elements_type;
|
||||
typedef typename index::detail::rtree::container_from_elements_type<
|
||||
elements_type,
|
||||
typename elements_type::value_type
|
||||
>::type result_elements_type;
|
||||
|
||||
typedef typename MembersHolder::box_type box_type;
|
||||
typedef typename MembersHolder::parameters_type parameters_type;
|
||||
typedef typename MembersHolder::translator_type translator_type;
|
||||
typedef typename MembersHolder::allocators_type allocators_type;
|
||||
|
||||
typedef typename allocators_type::node_pointer node_pointer;
|
||||
typedef typename allocators_type::size_type size_type;
|
||||
|
||||
inline level_insert_base(node_pointer & root,
|
||||
size_type & leafs_level,
|
||||
Element const& element,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators,
|
||||
size_type relative_level)
|
||||
: base(root, leafs_level, element, parameters, translator, allocators, relative_level)
|
||||
, result_relative_level(0)
|
||||
{}
|
||||
|
||||
template <typename Node>
|
||||
inline void handle_possible_reinsert_or_split_of_root(Node &n)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(result_elements.empty(), "reinsert should be handled only once for level");
|
||||
|
||||
result_relative_level = base::m_leafs_level - base::m_traverse_data.current_level;
|
||||
|
||||
// overflow
|
||||
if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
|
||||
{
|
||||
// node isn't root node
|
||||
if ( !base::m_traverse_data.current_is_root() )
|
||||
{
|
||||
// NOTE: exception-safety
|
||||
// After an exception result_elements may contain garbage, don't use it
|
||||
rstar::remove_elements_to_reinsert<MembersHolder>::apply(
|
||||
result_elements, n,
|
||||
base::m_traverse_data.parent, base::m_traverse_data.current_child_index,
|
||||
base::m_parameters, base::m_translator, base::m_allocators); // MAY THROW, BASIC (V, E: alloc, copy)
|
||||
}
|
||||
// node is root node
|
||||
else
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*base::m_root_node), "node should be the root node");
|
||||
base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
inline void handle_possible_split(Node &n) const
|
||||
{
|
||||
// overflow
|
||||
if ( base::m_parameters.get_max_elements() < rtree::elements(n).size() )
|
||||
{
|
||||
base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
inline void recalculate_aabb_if_necessary(Node const& n) const
|
||||
{
|
||||
if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() )
|
||||
{
|
||||
// calulate node's new box
|
||||
recalculate_aabb(n);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
inline void recalculate_aabb(Node const& n) const
|
||||
{
|
||||
base::m_traverse_data.current_element().first =
|
||||
elements_box<box_type>(rtree::elements(n).begin(), rtree::elements(n).end(),
|
||||
base::m_translator,
|
||||
index::detail::get_strategy(base::m_parameters));
|
||||
}
|
||||
|
||||
inline void recalculate_aabb(leaf const& n) const
|
||||
{
|
||||
base::m_traverse_data.current_element().first =
|
||||
values_box<box_type>(rtree::elements(n).begin(), rtree::elements(n).end(),
|
||||
base::m_translator,
|
||||
index::detail::get_strategy(base::m_parameters));
|
||||
}
|
||||
|
||||
size_type result_relative_level;
|
||||
result_elements_type result_elements;
|
||||
};
|
||||
|
||||
template
|
||||
<
|
||||
size_t InsertIndex,
|
||||
typename Element,
|
||||
typename MembersHolder,
|
||||
bool IsValue = std::is_same<Element, typename MembersHolder::value_type>::value
|
||||
>
|
||||
struct level_insert
|
||||
: public level_insert_base<InsertIndex, Element, MembersHolder>
|
||||
{
|
||||
typedef level_insert_base<InsertIndex, Element, MembersHolder> base;
|
||||
typedef typename base::node node;
|
||||
typedef typename base::internal_node internal_node;
|
||||
typedef typename base::leaf leaf;
|
||||
|
||||
typedef typename base::parameters_type parameters_type;
|
||||
typedef typename base::translator_type translator_type;
|
||||
typedef typename base::allocators_type allocators_type;
|
||||
|
||||
typedef typename base::node_pointer node_pointer;
|
||||
typedef typename base::size_type size_type;
|
||||
|
||||
inline level_insert(node_pointer & root,
|
||||
size_type & leafs_level,
|
||||
Element const& element,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators,
|
||||
size_type relative_level)
|
||||
: base(root, leafs_level, element, parameters, translator, allocators, relative_level)
|
||||
{}
|
||||
|
||||
inline void operator()(internal_node & n)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
|
||||
|
||||
if ( base::m_traverse_data.current_level < base::m_level )
|
||||
{
|
||||
// next traversing step
|
||||
base::traverse(*this, n); // MAY THROW (E: alloc, copy, N: alloc)
|
||||
|
||||
// further insert
|
||||
if ( 0 < InsertIndex )
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
|
||||
|
||||
if ( base::m_traverse_data.current_level == base::m_level - 1 )
|
||||
{
|
||||
base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level, "unexpected level");
|
||||
|
||||
BOOST_TRY
|
||||
{
|
||||
// push new child node
|
||||
rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy)
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
// NOTE: exception-safety
|
||||
// if the insert fails above, the element won't be stored in the tree, so delete it
|
||||
|
||||
rtree::visitors::destroy<MembersHolder>::apply(base::m_element.second, base::m_allocators);
|
||||
|
||||
BOOST_RETHROW // RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
// first insert
|
||||
if ( 0 == InsertIndex )
|
||||
{
|
||||
base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
|
||||
}
|
||||
// not the first insert
|
||||
else
|
||||
{
|
||||
base::handle_possible_split(n); // MAY THROW (E: alloc, N: alloc)
|
||||
}
|
||||
}
|
||||
|
||||
base::recalculate_aabb_if_necessary(n);
|
||||
}
|
||||
|
||||
inline void operator()(leaf &)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t InsertIndex, typename Value, typename MembersHolder>
|
||||
struct level_insert<InsertIndex, Value, MembersHolder, true>
|
||||
: public level_insert_base<InsertIndex, typename MembersHolder::value_type, MembersHolder>
|
||||
{
|
||||
typedef level_insert_base<InsertIndex, typename MembersHolder::value_type, MembersHolder> base;
|
||||
typedef typename base::node node;
|
||||
typedef typename base::internal_node internal_node;
|
||||
typedef typename base::leaf leaf;
|
||||
|
||||
typedef typename MembersHolder::value_type value_type;
|
||||
typedef typename base::parameters_type parameters_type;
|
||||
typedef typename base::translator_type translator_type;
|
||||
typedef typename base::allocators_type allocators_type;
|
||||
|
||||
typedef typename base::node_pointer node_pointer;
|
||||
typedef typename base::size_type size_type;
|
||||
|
||||
inline level_insert(node_pointer & root,
|
||||
size_type & leafs_level,
|
||||
value_type const& v,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators,
|
||||
size_type relative_level)
|
||||
: base(root, leafs_level, v, parameters, translator, allocators, relative_level)
|
||||
{}
|
||||
|
||||
inline void operator()(internal_node & n)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level, "unexpected level");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level, "unexpected level");
|
||||
|
||||
// next traversing step
|
||||
base::traverse(*this, n); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(0 < base::m_level, "illegal level value, level shouldn't be the root level for 0 < InsertIndex");
|
||||
|
||||
if ( base::m_traverse_data.current_level == base::m_level - 1 )
|
||||
{
|
||||
base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (E: alloc, copy, N: alloc)
|
||||
}
|
||||
|
||||
base::recalculate_aabb_if_necessary(n);
|
||||
}
|
||||
|
||||
inline void operator()(leaf & n)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
|
||||
"unexpected level");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
|
||||
base::m_level == (std::numeric_limits<size_t>::max)(),
|
||||
"unexpected level");
|
||||
|
||||
rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
|
||||
|
||||
base::handle_possible_split(n); // MAY THROW (V: alloc, copy, N: alloc)
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Value, typename MembersHolder>
|
||||
struct level_insert<0, Value, MembersHolder, true>
|
||||
: public level_insert_base<0, typename MembersHolder::value_type, MembersHolder>
|
||||
{
|
||||
typedef level_insert_base<0, typename MembersHolder::value_type, MembersHolder> base;
|
||||
typedef typename base::node node;
|
||||
typedef typename base::internal_node internal_node;
|
||||
typedef typename base::leaf leaf;
|
||||
|
||||
typedef typename MembersHolder::value_type value_type;
|
||||
typedef typename base::parameters_type parameters_type;
|
||||
typedef typename base::translator_type translator_type;
|
||||
typedef typename base::allocators_type allocators_type;
|
||||
|
||||
typedef typename base::node_pointer node_pointer;
|
||||
typedef typename base::size_type size_type;
|
||||
|
||||
inline level_insert(node_pointer & root,
|
||||
size_type & leafs_level,
|
||||
value_type const& v,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators,
|
||||
size_type relative_level)
|
||||
: base(root, leafs_level, v, parameters, translator, allocators, relative_level)
|
||||
{}
|
||||
|
||||
inline void operator()(internal_node & n)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_leafs_level,
|
||||
"unexpected level");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level < base::m_level,
|
||||
"unexpected level");
|
||||
|
||||
// next traversing step
|
||||
base::traverse(*this, n); // MAY THROW (V: alloc, copy, N: alloc)
|
||||
|
||||
base::recalculate_aabb_if_necessary(n);
|
||||
}
|
||||
|
||||
inline void operator()(leaf & n)
|
||||
{
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_traverse_data.current_level == base::m_leafs_level,
|
||||
"unexpected level");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(base::m_level == base::m_traverse_data.current_level ||
|
||||
base::m_level == (std::numeric_limits<size_t>::max)(),
|
||||
"unexpected level");
|
||||
|
||||
rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (V: alloc, copy)
|
||||
|
||||
base::handle_possible_reinsert_or_split_of_root(n); // MAY THROW (V: alloc, copy, N: alloc)
|
||||
|
||||
base::recalculate_aabb_if_necessary(n);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rstar
|
||||
|
||||
// R*-tree insert visitor
|
||||
// After passing the Element to insert visitor the Element is managed by the tree
|
||||
// I.e. one should not delete the node passed to the insert visitor after exception is thrown
|
||||
// because this visitor may delete it
|
||||
template <typename Element, typename MembersHolder>
|
||||
class insert<Element, MembersHolder, insert_reinsert_tag>
|
||||
: public MembersHolder::visitor
|
||||
{
|
||||
typedef typename MembersHolder::parameters_type parameters_type;
|
||||
typedef typename MembersHolder::translator_type translator_type;
|
||||
typedef typename MembersHolder::allocators_type allocators_type;
|
||||
|
||||
typedef typename MembersHolder::node node;
|
||||
typedef typename MembersHolder::internal_node internal_node;
|
||||
typedef typename MembersHolder::leaf leaf;
|
||||
|
||||
typedef typename allocators_type::node_pointer node_pointer;
|
||||
typedef typename allocators_type::size_type size_type;
|
||||
|
||||
public:
|
||||
inline insert(node_pointer & root,
|
||||
size_type & leafs_level,
|
||||
Element const& element,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators,
|
||||
size_type relative_level = 0)
|
||||
: m_root(root), m_leafs_level(leafs_level), m_element(element)
|
||||
, m_parameters(parameters), m_translator(translator)
|
||||
, m_relative_level(relative_level), m_allocators(allocators)
|
||||
{}
|
||||
|
||||
inline void operator()(internal_node & n)
|
||||
{
|
||||
boost::ignore_unused(n);
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root), "current node should be the root");
|
||||
|
||||
// Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
|
||||
if ( m_parameters.get_reinserted_elements() > 0 )
|
||||
{
|
||||
rstar::level_insert<0, Element, MembersHolder> lins_v(
|
||||
m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
||||
|
||||
rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
|
||||
if ( !lins_v.result_elements.empty() )
|
||||
{
|
||||
recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
visitors::insert<Element, MembersHolder, insert_default_tag> ins_v(
|
||||
m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
||||
|
||||
rtree::apply_visitor(ins_v, *m_root);
|
||||
}
|
||||
}
|
||||
|
||||
inline void operator()(leaf & n)
|
||||
{
|
||||
boost::ignore_unused(n);
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<leaf>(*m_root), "current node should be the root");
|
||||
|
||||
// Distinguish between situation when reinserts are required and use adequate visitor, otherwise use default one
|
||||
if ( m_parameters.get_reinserted_elements() > 0 )
|
||||
{
|
||||
rstar::level_insert<0, Element, MembersHolder> lins_v(
|
||||
m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
||||
|
||||
rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
|
||||
// we're in the root, so root should be split and there should be no elements to reinsert
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(lins_v.result_elements.empty(), "unexpected state");
|
||||
}
|
||||
else
|
||||
{
|
||||
visitors::insert<Element, MembersHolder, insert_default_tag> ins_v(
|
||||
m_root, m_leafs_level, m_element, m_parameters, m_translator, m_allocators, m_relative_level);
|
||||
|
||||
rtree::apply_visitor(ins_v, *m_root);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Elements>
|
||||
inline void recursive_reinsert(Elements & elements, size_t relative_level)
|
||||
{
|
||||
typedef typename Elements::value_type element_type;
|
||||
|
||||
// reinsert children starting from the minimum distance
|
||||
typename Elements::reverse_iterator it = elements.rbegin();
|
||||
for ( ; it != elements.rend() ; ++it)
|
||||
{
|
||||
rstar::level_insert<1, element_type, MembersHolder> lins_v(
|
||||
m_root, m_leafs_level, *it, m_parameters, m_translator, m_allocators, relative_level);
|
||||
|
||||
BOOST_TRY
|
||||
{
|
||||
rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
++it;
|
||||
for ( ; it != elements.rend() ; ++it)
|
||||
rtree::destroy_element<MembersHolder>::apply(*it, m_allocators);
|
||||
BOOST_RETHROW // RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(relative_level + 1 == lins_v.result_relative_level, "unexpected level");
|
||||
|
||||
// non-root relative level
|
||||
if ( lins_v.result_relative_level < m_leafs_level && !lins_v.result_elements.empty())
|
||||
{
|
||||
recursive_reinsert(lins_v.result_elements, lins_v.result_relative_level); // MAY THROW (V, E: alloc, copy, N: alloc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node_pointer & m_root;
|
||||
size_type & m_leafs_level;
|
||||
Element const& m_element;
|
||||
|
||||
parameters_type const& m_parameters;
|
||||
translator_type const& m_translator;
|
||||
|
||||
size_type m_relative_level;
|
||||
|
||||
allocators_type & m_allocators;
|
||||
};
|
||||
|
||||
}}} // namespace detail::rtree::visitors
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
|
||||
Vendored
Executable
+510
@@ -0,0 +1,510 @@
|
||||
// Boost.Geometry Index
|
||||
//
|
||||
// R-tree R*-tree split algorithm implementation
|
||||
//
|
||||
// Copyright (c) 2011-2022 Adam Wulkiewicz, Lodz, Poland.
|
||||
//
|
||||
// This file was modified by Oracle on 2019-2020.
|
||||
// Modifications copyright (c) 2019-2020 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_REDISTRIBUTE_ELEMENTS_HPP
|
||||
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
#include <boost/geometry/core/static_assert.hpp>
|
||||
|
||||
#include <boost/geometry/index/detail/algorithms/intersection_content.hpp>
|
||||
#include <boost/geometry/index/detail/algorithms/margin.hpp>
|
||||
#include <boost/geometry/index/detail/algorithms/nth_element.hpp>
|
||||
#include <boost/geometry/index/detail/algorithms/union_content.hpp>
|
||||
|
||||
#include <boost/geometry/index/detail/bounded_view.hpp>
|
||||
|
||||
#include <boost/geometry/index/detail/rtree/node/node.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/visitors/insert.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace detail { namespace rtree {
|
||||
|
||||
namespace rstar {
|
||||
|
||||
template <typename Element, typename Parameters, typename Translator, typename Tag, size_t Corner, size_t AxisIndex>
|
||||
class element_axis_corner_less
|
||||
{
|
||||
typedef typename rtree::element_indexable_type<Element, Translator>::type indexable_type;
|
||||
typedef typename geometry::point_type<indexable_type>::type point_type;
|
||||
typedef geometry::model::box<point_type> bounds_type;
|
||||
typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
|
||||
typedef index::detail::bounded_view
|
||||
<
|
||||
indexable_type, bounds_type, strategy_type
|
||||
> bounded_view_type;
|
||||
|
||||
public:
|
||||
element_axis_corner_less(Translator const& tr, strategy_type const& strategy)
|
||||
: m_tr(tr), m_strategy(strategy)
|
||||
{}
|
||||
|
||||
bool operator()(Element const& e1, Element const& e2) const
|
||||
{
|
||||
indexable_type const& ind1 = rtree::element_indexable(e1, m_tr);
|
||||
indexable_type const& ind2 = rtree::element_indexable(e2, m_tr);
|
||||
return geometry::get<Corner, AxisIndex>(bounded_view_type(ind1, m_strategy))
|
||||
< geometry::get<Corner, AxisIndex>(bounded_view_type(ind2, m_strategy));
|
||||
}
|
||||
|
||||
private:
|
||||
Translator const& m_tr;
|
||||
strategy_type const& m_strategy;
|
||||
};
|
||||
|
||||
template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
|
||||
class element_axis_corner_less<Element, Parameters, Translator, box_tag, Corner, AxisIndex>
|
||||
{
|
||||
typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
|
||||
|
||||
public:
|
||||
element_axis_corner_less(Translator const& tr, strategy_type const&)
|
||||
: m_tr(tr)
|
||||
{}
|
||||
|
||||
bool operator()(Element const& e1, Element const& e2) const
|
||||
{
|
||||
return geometry::get<Corner, AxisIndex>(rtree::element_indexable(e1, m_tr))
|
||||
< geometry::get<Corner, AxisIndex>(rtree::element_indexable(e2, m_tr));
|
||||
}
|
||||
|
||||
private:
|
||||
Translator const& m_tr;
|
||||
};
|
||||
|
||||
template <typename Element, typename Parameters, typename Translator, size_t Corner, size_t AxisIndex>
|
||||
class element_axis_corner_less<Element, Parameters, Translator, point_tag, Corner, AxisIndex>
|
||||
{
|
||||
typedef typename index::detail::strategy_type<Parameters>::type strategy_type;
|
||||
|
||||
public:
|
||||
element_axis_corner_less(Translator const& tr, strategy_type const& )
|
||||
: m_tr(tr)
|
||||
{}
|
||||
|
||||
bool operator()(Element const& e1, Element const& e2) const
|
||||
{
|
||||
return geometry::get<AxisIndex>(rtree::element_indexable(e1, m_tr))
|
||||
< geometry::get<AxisIndex>(rtree::element_indexable(e2, m_tr));
|
||||
}
|
||||
|
||||
private:
|
||||
Translator const& m_tr;
|
||||
};
|
||||
|
||||
template <typename Box, size_t Corner, size_t AxisIndex>
|
||||
struct choose_split_axis_and_index_for_corner
|
||||
{
|
||||
typedef typename index::detail::default_margin_result<Box>::type margin_type;
|
||||
typedef typename index::detail::default_content_result<Box>::type content_type;
|
||||
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements const& elements,
|
||||
size_t & choosen_index,
|
||||
margin_type & sum_of_margins,
|
||||
content_type & smallest_overlap,
|
||||
content_type & smallest_content,
|
||||
Parameters const& parameters,
|
||||
Translator const& translator)
|
||||
{
|
||||
typedef typename Elements::value_type element_type;
|
||||
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
|
||||
typedef typename tag<indexable_type>::type indexable_tag;
|
||||
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == parameters.get_max_elements() + 1, "wrong number of elements");
|
||||
|
||||
typename index::detail::strategy_type<Parameters>::type const&
|
||||
strategy = index::detail::get_strategy(parameters);
|
||||
|
||||
// copy elements
|
||||
Elements elements_copy(elements); // MAY THROW, STRONG (alloc, copy)
|
||||
|
||||
size_t const index_first = parameters.get_min_elements();
|
||||
size_t const index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2;
|
||||
|
||||
// sort elements
|
||||
element_axis_corner_less
|
||||
<
|
||||
element_type, Parameters, Translator, indexable_tag, Corner, AxisIndex
|
||||
> elements_less(translator, strategy);
|
||||
std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
|
||||
// {
|
||||
// typename Elements::iterator f = elements_copy.begin() + index_first;
|
||||
// typename Elements::iterator l = elements_copy.begin() + index_last;
|
||||
// // NOTE: for stdlibc++ shipped with gcc 4.8.2 std::nth_element is replaced with std::sort anyway
|
||||
// index::detail::nth_element(elements_copy.begin(), f, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
|
||||
// index::detail::nth_element(f, l, elements_copy.end(), elements_less); // MAY THROW, BASIC (copy)
|
||||
// std::sort(f, l, elements_less); // MAY THROW, BASIC (copy)
|
||||
// }
|
||||
|
||||
// init outputs
|
||||
choosen_index = index_first;
|
||||
sum_of_margins = 0;
|
||||
smallest_overlap = (std::numeric_limits<content_type>::max)();
|
||||
smallest_content = (std::numeric_limits<content_type>::max)();
|
||||
|
||||
// calculate sum of margins for all distributions
|
||||
for ( size_t i = index_first ; i < index_last ; ++i )
|
||||
{
|
||||
// TODO - awulkiew: may be optimized - box of group 1 may be initialized with
|
||||
// box of min_elems number of elements and expanded for each iteration by another element
|
||||
|
||||
Box box1 = rtree::elements_box<Box>(elements_copy.begin(), elements_copy.begin() + i,
|
||||
translator, strategy);
|
||||
Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(),
|
||||
translator, strategy);
|
||||
|
||||
sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2);
|
||||
|
||||
content_type ovl = index::detail::intersection_content(box1, box2, strategy);
|
||||
content_type con = index::detail::content(box1) + index::detail::content(box2);
|
||||
|
||||
// TODO - shouldn't here be < instead of <= ?
|
||||
if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) )
|
||||
{
|
||||
choosen_index = i;
|
||||
smallest_overlap = ovl;
|
||||
smallest_content = con;
|
||||
}
|
||||
}
|
||||
|
||||
::boost::ignore_unused(parameters);
|
||||
}
|
||||
};
|
||||
|
||||
//template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
|
||||
//struct choose_split_axis_and_index_for_axis
|
||||
//{
|
||||
// BOOST_GEOMETRY_STATIC_ASSERT_FALSE("Not implemented for this Tag type.", ElementIndexableTag);
|
||||
//};
|
||||
|
||||
template <typename Box, size_t AxisIndex, typename ElementIndexableTag>
|
||||
struct choose_split_axis_and_index_for_axis
|
||||
{
|
||||
typedef typename index::detail::default_margin_result<Box>::type margin_type;
|
||||
typedef typename index::detail::default_content_result<Box>::type content_type;
|
||||
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements const& elements,
|
||||
size_t & choosen_corner,
|
||||
size_t & choosen_index,
|
||||
margin_type & sum_of_margins,
|
||||
content_type & smallest_overlap,
|
||||
content_type & smallest_content,
|
||||
Parameters const& parameters,
|
||||
Translator const& translator)
|
||||
{
|
||||
size_t index1 = 0;
|
||||
margin_type som1 = 0;
|
||||
content_type ovl1 = (std::numeric_limits<content_type>::max)();
|
||||
content_type con1 = (std::numeric_limits<content_type>::max)();
|
||||
|
||||
choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
|
||||
::apply(elements, index1,
|
||||
som1, ovl1, con1,
|
||||
parameters, translator); // MAY THROW, STRONG
|
||||
|
||||
size_t index2 = 0;
|
||||
margin_type som2 = 0;
|
||||
content_type ovl2 = (std::numeric_limits<content_type>::max)();
|
||||
content_type con2 = (std::numeric_limits<content_type>::max)();
|
||||
|
||||
choose_split_axis_and_index_for_corner<Box, max_corner, AxisIndex>
|
||||
::apply(elements, index2,
|
||||
som2, ovl2, con2,
|
||||
parameters, translator); // MAY THROW, STRONG
|
||||
|
||||
sum_of_margins = som1 + som2;
|
||||
|
||||
if ( ovl1 < ovl2 || (ovl1 == ovl2 && con1 <= con2) )
|
||||
{
|
||||
choosen_corner = min_corner;
|
||||
choosen_index = index1;
|
||||
smallest_overlap = ovl1;
|
||||
smallest_content = con1;
|
||||
}
|
||||
else
|
||||
{
|
||||
choosen_corner = max_corner;
|
||||
choosen_index = index2;
|
||||
smallest_overlap = ovl2;
|
||||
smallest_content = con2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box, size_t AxisIndex>
|
||||
struct choose_split_axis_and_index_for_axis<Box, AxisIndex, point_tag>
|
||||
{
|
||||
typedef typename index::detail::default_margin_result<Box>::type margin_type;
|
||||
typedef typename index::detail::default_content_result<Box>::type content_type;
|
||||
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements const& elements,
|
||||
size_t & choosen_corner,
|
||||
size_t & choosen_index,
|
||||
margin_type & sum_of_margins,
|
||||
content_type & smallest_overlap,
|
||||
content_type & smallest_content,
|
||||
Parameters const& parameters,
|
||||
Translator const& translator)
|
||||
{
|
||||
choose_split_axis_and_index_for_corner<Box, min_corner, AxisIndex>
|
||||
::apply(elements, choosen_index,
|
||||
sum_of_margins, smallest_overlap, smallest_content,
|
||||
parameters, translator); // MAY THROW, STRONG
|
||||
|
||||
choosen_corner = min_corner;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box, size_t Dimension>
|
||||
struct choose_split_axis_and_index
|
||||
{
|
||||
BOOST_STATIC_ASSERT(0 < Dimension);
|
||||
|
||||
typedef typename index::detail::default_margin_result<Box>::type margin_type;
|
||||
typedef typename index::detail::default_content_result<Box>::type content_type;
|
||||
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements const& elements,
|
||||
size_t & choosen_axis,
|
||||
size_t & choosen_corner,
|
||||
size_t & choosen_index,
|
||||
margin_type & smallest_sum_of_margins,
|
||||
content_type & smallest_overlap,
|
||||
content_type & smallest_content,
|
||||
Parameters const& parameters,
|
||||
Translator const& translator)
|
||||
{
|
||||
typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
|
||||
|
||||
choose_split_axis_and_index<Box, Dimension - 1>
|
||||
::apply(elements, choosen_axis, choosen_corner, choosen_index,
|
||||
smallest_sum_of_margins, smallest_overlap, smallest_content,
|
||||
parameters, translator); // MAY THROW, STRONG
|
||||
|
||||
margin_type sum_of_margins = 0;
|
||||
|
||||
size_t corner = min_corner;
|
||||
size_t index = 0;
|
||||
|
||||
content_type overlap_val = (std::numeric_limits<content_type>::max)();
|
||||
content_type content_val = (std::numeric_limits<content_type>::max)();
|
||||
|
||||
choose_split_axis_and_index_for_axis<
|
||||
Box,
|
||||
Dimension - 1,
|
||||
typename tag<element_indexable_type>::type
|
||||
>::apply(elements, corner, index, sum_of_margins, overlap_val, content_val, parameters, translator); // MAY THROW, STRONG
|
||||
|
||||
if ( sum_of_margins < smallest_sum_of_margins )
|
||||
{
|
||||
choosen_axis = Dimension - 1;
|
||||
choosen_corner = corner;
|
||||
choosen_index = index;
|
||||
smallest_sum_of_margins = sum_of_margins;
|
||||
smallest_overlap = overlap_val;
|
||||
smallest_content = content_val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box>
|
||||
struct choose_split_axis_and_index<Box, 1>
|
||||
{
|
||||
typedef typename index::detail::default_margin_result<Box>::type margin_type;
|
||||
typedef typename index::detail::default_content_result<Box>::type content_type;
|
||||
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements const& elements,
|
||||
size_t & choosen_axis,
|
||||
size_t & choosen_corner,
|
||||
size_t & choosen_index,
|
||||
margin_type & smallest_sum_of_margins,
|
||||
content_type & smallest_overlap,
|
||||
content_type & smallest_content,
|
||||
Parameters const& parameters,
|
||||
Translator const& translator)
|
||||
{
|
||||
typedef typename rtree::element_indexable_type<typename Elements::value_type, Translator>::type element_indexable_type;
|
||||
|
||||
choosen_axis = 0;
|
||||
|
||||
choose_split_axis_and_index_for_axis<
|
||||
Box,
|
||||
0,
|
||||
typename tag<element_indexable_type>::type
|
||||
>::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Corner, size_t Dimension, size_t I = 0>
|
||||
struct nth_element
|
||||
{
|
||||
BOOST_STATIC_ASSERT(0 < Dimension);
|
||||
BOOST_STATIC_ASSERT(I < Dimension);
|
||||
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements & elements, Parameters const& parameters,
|
||||
const size_t axis, const size_t index, Translator const& tr)
|
||||
{
|
||||
//BOOST_GEOMETRY_INDEX_ASSERT(axis < Dimension, "unexpected axis value");
|
||||
|
||||
if ( axis != I )
|
||||
{
|
||||
nth_element<Corner, Dimension, I + 1>::apply(elements, parameters, axis, index, tr); // MAY THROW, BASIC (copy)
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef typename Elements::value_type element_type;
|
||||
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
|
||||
typedef typename tag<indexable_type>::type indexable_tag;
|
||||
|
||||
typename index::detail::strategy_type<Parameters>::type
|
||||
strategy = index::detail::get_strategy(parameters);
|
||||
|
||||
element_axis_corner_less
|
||||
<
|
||||
element_type, Parameters, Translator, indexable_tag, Corner, I
|
||||
> less(tr, strategy);
|
||||
index::detail::nth_element(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Corner, size_t Dimension>
|
||||
struct nth_element<Corner, Dimension, Dimension>
|
||||
{
|
||||
template <typename Elements, typename Parameters, typename Translator>
|
||||
static inline void apply(Elements & /*elements*/, Parameters const& /*parameters*/,
|
||||
const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/)
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace rstar
|
||||
|
||||
template <typename MembersHolder>
|
||||
struct redistribute_elements<MembersHolder, rstar_tag>
|
||||
{
|
||||
typedef typename MembersHolder::box_type box_type;
|
||||
typedef typename MembersHolder::parameters_type parameters_type;
|
||||
typedef typename MembersHolder::translator_type translator_type;
|
||||
typedef typename MembersHolder::allocators_type allocators_type;
|
||||
|
||||
typedef typename MembersHolder::node node;
|
||||
typedef typename MembersHolder::internal_node internal_node;
|
||||
typedef typename MembersHolder::leaf leaf;
|
||||
|
||||
static const size_t dimension = geometry::dimension<box_type>::value;
|
||||
|
||||
typedef typename index::detail::default_margin_result<box_type>::type margin_type;
|
||||
typedef typename index::detail::default_content_result<box_type>::type content_type;
|
||||
|
||||
template <typename Node>
|
||||
static inline void apply(
|
||||
Node & n,
|
||||
Node & second_node,
|
||||
box_type & box1,
|
||||
box_type & box2,
|
||||
parameters_type const& parameters,
|
||||
translator_type const& translator,
|
||||
allocators_type & allocators)
|
||||
{
|
||||
typedef typename rtree::elements_type<Node>::type elements_type;
|
||||
typedef typename elements_type::value_type element_type;
|
||||
|
||||
elements_type & elements1 = rtree::elements(n);
|
||||
elements_type & elements2 = rtree::elements(second_node);
|
||||
|
||||
// copy original elements - use in-memory storage (std::allocator)
|
||||
// TODO: move if noexcept
|
||||
typedef typename rtree::container_from_elements_type<elements_type, element_type>::type
|
||||
container_type;
|
||||
container_type elements_copy(elements1.begin(), elements1.end()); // MAY THROW, STRONG
|
||||
container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG
|
||||
|
||||
size_t split_axis = 0;
|
||||
size_t split_corner = 0;
|
||||
size_t split_index = parameters.get_min_elements();
|
||||
margin_type smallest_sum_of_margins = (std::numeric_limits<margin_type>::max)();
|
||||
content_type smallest_overlap = (std::numeric_limits<content_type>::max)();
|
||||
content_type smallest_content = (std::numeric_limits<content_type>::max)();
|
||||
|
||||
// NOTE: this function internally copies passed elements
|
||||
// why not pass mutable elements and use the same container for all axes/corners
|
||||
// and again, the same below calling partial_sort/nth_element
|
||||
// It would be even possible to not re-sort/find nth_element if the axis/corner
|
||||
// was found for the last sorting - last combination of axis/corner
|
||||
rstar::choose_split_axis_and_index<box_type, dimension>
|
||||
::apply(elements_copy,
|
||||
split_axis, split_corner, split_index,
|
||||
smallest_sum_of_margins, smallest_overlap, smallest_content,
|
||||
parameters, translator); // MAY THROW, STRONG
|
||||
|
||||
// TODO: awulkiew - get rid of following static_casts?
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(split_axis < dimension, "unexpected value");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast<size_t>(min_corner) || split_corner == static_cast<size_t>(max_corner), "unexpected value");
|
||||
BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= split_index && split_index <= parameters.get_max_elements() - parameters.get_min_elements() + 1, "unexpected value");
|
||||
|
||||
// TODO: consider using nth_element
|
||||
if ( split_corner == static_cast<size_t>(min_corner) )
|
||||
{
|
||||
rstar::nth_element<min_corner, dimension>
|
||||
::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
|
||||
}
|
||||
else
|
||||
{
|
||||
rstar::nth_element<max_corner, dimension>
|
||||
::apply(elements_copy, parameters, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
|
||||
}
|
||||
|
||||
BOOST_TRY
|
||||
{
|
||||
typename index::detail::strategy_type<parameters_type>::type const&
|
||||
strategy = index::detail::get_strategy(parameters);
|
||||
|
||||
// copy elements to nodes
|
||||
elements1.assign(elements_copy.begin(), elements_copy.begin() + split_index); // MAY THROW, BASIC
|
||||
elements2.assign(elements_copy.begin() + split_index, elements_copy.end()); // MAY THROW, BASIC
|
||||
|
||||
// calculate boxes
|
||||
box1 = rtree::elements_box<box_type>(elements1.begin(), elements1.end(),
|
||||
translator, strategy);
|
||||
box2 = rtree::elements_box<box_type>(elements2.begin(), elements2.end(),
|
||||
translator, strategy);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
//elements_copy.clear();
|
||||
elements1.clear();
|
||||
elements2.clear();
|
||||
|
||||
rtree::destroy_elements<MembersHolder>::apply(elements_backup, allocators);
|
||||
//elements_backup.clear();
|
||||
|
||||
BOOST_RETHROW // RETHROW, BASIC
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail::rtree
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// Boost.Geometry Index
|
||||
//
|
||||
// R-tree R*-tree algorithm implementation
|
||||
//
|
||||
// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
|
||||
//
|
||||
// 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_RSTAR_HPP
|
||||
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP
|
||||
|
||||
#include <boost/geometry/index/detail/rtree/rstar/insert.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp>
|
||||
#include <boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp>
|
||||
|
||||
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP
|
||||
Reference in New Issue
Block a user