add boost on mac

This commit is contained in:
Bassem Girgis
2019-08-10 16:38:17 -05:00
parent 861b918727
commit be945cb63b
14105 changed files with 2714968 additions and 0 deletions

View File

@@ -0,0 +1,249 @@
// Boost.Geometry Index
//
// R-tree R*-tree next node choosing algorithm implementation
//
// Copyright (c) 2011-2019 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_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/visitors/is_leaf.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename Value, typename Options, typename Box, typename Allocators>
class choose_next_node<Value, Options, Box, Allocators, choose_by_overlap_diff_tag>
{
typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
typedef typename rtree::elements_type<internal_node>::type children_type;
typedef typename children_type::value_type child_type;
typedef typename Options::parameters_type parameters_type;
typedef typename index::detail::default_content_result<Box>::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());
}
// children are internal nodes
else
return choose_by_minimum_content_cost(children, indexable);
}
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>
static inline size_t choose_by_minimum_overlap_cost(children_type const& children,
Indexable const& indexable,
size_t overlap_cost_threshold)
{
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 box_exp(ch_i.first);
geometry::expand(box_exp, indexable);
// 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);
}
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>
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)
{
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 box_exp(ch_i.first);
// calculate expanded box of child node ch_i
geometry::expand(box_exp, indexable);
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);
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);
}
}
}
// 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>
static inline size_t choose_by_minimum_content_cost(children_type const& children, Indexable const& indexable)
{
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 box_exp(ch_i.first);
geometry::expand(box_exp, indexable);
// 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

View File

@@ -0,0 +1,593 @@
// Boost.Geometry Index
//
// R-tree R*-tree insert algorithm implementation
//
// Copyright (c) 2011-2015 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_INSERT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/index/detail/algorithms/content.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
namespace rstar {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class remove_elements_to_reinsert
{
public:
typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
typedef typename Options::parameters_type parameters_type;
//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 const& translator,
Allocators & 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 point_type;
// TODO: awulkiew - change second point_type to the point type of the Indexable?
typedef typename
geometry::default_comparable_distance_result<point_type>::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");
// calculate current node's center
point_type node_center;
geometry::centroid(rtree::elements(*parent)[current_child_index].first, node_center);
// 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);
sorted_elements.push_back(std::make_pair(
geometry::comparable_distance(node_center, element_center),
*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<Value, Options, Translator, Box, Allocators>::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 Value, typename Options, typename Box, typename Allocators>
struct level_insert_elements_type
{
typedef typename rtree::elements_type<
typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type
>::type type;
};
template <typename Value, typename Options, typename Box, typename Allocators>
struct level_insert_elements_type<0, Value, Value, Options, Box, Allocators>
{
typedef typename rtree::elements_type<
typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type
>::type type;
};
template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct level_insert_base
: public detail::insert<Element, Value, Options, Translator, Box, Allocators>
{
typedef detail::insert<Element, Value, Options, Translator, Box, Allocators> 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, Value, Options, Box, Allocators>::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 Options::parameters_type parameters_type;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
inline level_insert_base(node_pointer & root,
size_type & leafs_level,
Element const& element,
parameters_type const& parameters,
Translator const& translator,
Allocators & 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<Value, Options, Translator, Box, Allocators>::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>(rtree::elements(n).begin(), rtree::elements(n).end(), base::m_translator);
}
inline void recalculate_aabb(leaf const& n) const
{
base::m_traverse_data.current_element().first =
values_box<Box>(rtree::elements(n).begin(), rtree::elements(n).end(), base::m_translator);
}
size_type result_relative_level;
result_elements_type result_elements;
};
template <size_t InsertIndex, typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct level_insert
: public level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators>
{
typedef level_insert_base<InsertIndex, Element, Value, Options, Translator, Box, Allocators> base;
typedef typename base::node node;
typedef typename base::internal_node internal_node;
typedef typename base::leaf leaf;
typedef typename Options::parameters_type parameters_type;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
inline level_insert(node_pointer & root,
size_type & leafs_level,
Element const& element,
parameters_type const& parameters,
Translator const& translator,
Allocators & 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<Value, Options, Translator, Box, Allocators> del_v(base::m_element.second, base::m_allocators);
rtree::apply_visitor(del_v, *base::m_element.second);
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 Options, typename Translator, typename Box, typename Allocators>
struct level_insert<InsertIndex, Value, Value, Options, Translator, Box, Allocators>
: public level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators>
{
typedef level_insert_base<InsertIndex, Value, Value, Options, Translator, Box, Allocators> base;
typedef typename base::node node;
typedef typename base::internal_node internal_node;
typedef typename base::leaf leaf;
typedef typename Options::parameters_type parameters_type;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
inline level_insert(node_pointer & root,
size_type & leafs_level,
Value const& v,
parameters_type const& parameters,
Translator const& translator,
Allocators & 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 Options, typename Translator, typename Box, typename Allocators>
struct level_insert<0, Value, Value, Options, Translator, Box, Allocators>
: public level_insert_base<0, Value, Value, Options, Translator, Box, Allocators>
{
typedef level_insert_base<0, Value, Value, Options, Translator, Box, Allocators> base;
typedef typename base::node node;
typedef typename base::internal_node internal_node;
typedef typename base::leaf leaf;
typedef typename Options::parameters_type parameters_type;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
inline level_insert(node_pointer & root,
size_type & leafs_level,
Value const& v,
parameters_type const& parameters,
Translator const& translator,
Allocators & 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 Value, typename Options, typename Translator, typename Box, typename Allocators>
class insert<Element, Value, Options, Translator, Box, Allocators, insert_reinsert_tag>
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
{
typedef typename Options::parameters_type parameters_type;
typedef typename rtree::node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type node;
typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
public:
inline insert(node_pointer & root,
size_type & leafs_level,
Element const& element,
parameters_type const& parameters,
Translator const& translator,
Allocators & 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, Value, Options, Translator, Box, Allocators> 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, Value, Options, Translator, Box, Allocators, 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, Value, Options, Translator, Box, Allocators> 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, Value, Options, Translator, Box, Allocators, 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, Value, Options, Translator, Box, Allocators> 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<Value, Options, Translator, Box, Allocators>::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 const& m_translator;
size_type m_relative_level;
Allocators & m_allocators;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP

View File

@@ -0,0 +1,472 @@
// Boost.Geometry Index
//
// R-tree R*-tree split algorithm implementation
//
// Copyright (c) 2011-2017 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_REDISTRIBUTE_ELEMENTS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP
#include <boost/core/ignore_unused.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 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 index::detail::bounded_view<indexable_type, bounds_type> bounded_view_type;
public:
element_axis_corner_less(Translator const& tr)
: m_tr(tr)
{}
bool operator()(Element const& e1, Element const& e2) const
{
bounded_view_type bounded_ind1(rtree::element_indexable(e1, m_tr));
bounded_view_type bounded_ind2(rtree::element_indexable(e2, m_tr));
return geometry::get<Corner, AxisIndex>(bounded_ind1)
< geometry::get<Corner, AxisIndex>(bounded_ind2);
}
private:
Translator const& m_tr;
};
template <typename Element, typename Translator, size_t Corner, size_t AxisIndex>
class element_axis_corner_less<Element, Translator, box_tag, Corner, AxisIndex>
{
public:
element_axis_corner_less(Translator const& tr)
: 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 Translator, size_t Corner, size_t AxisIndex>
class element_axis_corner_less<Element, Translator, point_tag, Corner, AxisIndex>
{
public:
element_axis_corner_less(Translator const& tr)
: 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");
// 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, Translator, indexable_tag, Corner, AxisIndex> elements_less(translator);
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);
Box box2 = rtree::elements_box<Box>(elements_copy.begin() + i, elements_copy.end(), translator);
sum_of_margins += index::detail::comparable_margin(box1) + index::detail::comparable_margin(box2);
content_type ovl = index::detail::intersection_content(box1, box2);
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_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (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 Translator>
static inline void apply(Elements & elements, 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, 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;
element_axis_corner_less<element_type, Translator, indexable_tag, Corner, I> less(tr);
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 Translator>
static inline void apply(Elements & /*elements*/, const size_t /*axis*/, const size_t /*index*/, Translator const& /*tr*/)
{}
};
} // namespace rstar
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_tag>
{
typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
typedef typename rtree::internal_node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
typedef typename rtree::leaf<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
typedef typename Options::parameters_type parameters_type;
static const size_t dimension = geometry::dimension<Box>::value;
typedef typename index::detail::default_margin_result<Box>::type margin_type;
typedef typename index::detail::default_content_result<Box>::type content_type;
template <typename Node>
static inline void apply(
Node & n,
Node & second_node,
Box & box1,
Box & box2,
parameters_type const& parameters,
Translator const& translator,
Allocators & 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, 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, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
}
else
{
rstar::nth_element<max_corner, dimension>
::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy)
}
BOOST_TRY
{
// 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>(elements1.begin(), elements1.end(), translator);
box2 = rtree::elements_box<Box>(elements2.begin(), elements2.end(), translator);
}
BOOST_CATCH(...)
{
//elements_copy.clear();
elements1.clear();
elements2.clear();
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::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

View File

@@ -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