stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,54 @@
// Boost.Geometry Index
//
// R-tree queries range adaptors
//
// 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_ADAPTORS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP
#include <deque>
#include <boost/static_assert.hpp>
#include <boost/geometry/index/adaptors/query.hpp>
namespace boost { namespace geometry { namespace index {
template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator>
class rtree;
namespace adaptors { namespace detail {
template <typename Value, typename Options, typename IndexableGetter, typename EqualTo, typename Allocator>
class query_range< index::rtree<Value, Options, IndexableGetter, EqualTo, Allocator> >
{
public:
typedef std::vector<Value> result_type;
typedef typename result_type::iterator iterator;
typedef typename result_type::const_iterator const_iterator;
template <typename Predicates> inline
query_range(index::rtree<Value, Options, IndexableGetter, EqualTo, Allocator> const& rtree,
Predicates const& pred)
{
rtree.query(pred, std::back_inserter(m_result));
}
inline iterator begin() { return m_result.begin(); }
inline iterator end() { return m_result.end(); }
inline const_iterator begin() const { return m_result.begin(); }
inline const_iterator end() const { return m_result.end(); }
private:
result_type m_result;
};
}} // namespace adaptors::detail
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ADAPTORS_HPP
@@ -0,0 +1,122 @@
// Boost.Geometry Index
//
// R-tree iterators
//
// 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_ITERATORS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ITERATORS_HPP
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
template <typename Value, typename Allocators>
struct end_iterator
{
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
reference operator*() const
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable");
pointer p(0);
return *p;
}
const value_type * operator->() const
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable");
const value_type * p = 0;
return p;
}
end_iterator & operator++()
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable");
return *this;
}
end_iterator operator++(int)
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable");
return *this;
}
friend bool operator==(end_iterator const& /*l*/, end_iterator const& /*r*/)
{
return true;
}
};
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class iterator
{
typedef visitors::iterator<Value, Options, Translator, Box, Allocators> visitor_type;
typedef typename visitor_type::node_pointer node_pointer;
public:
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
inline iterator()
{}
inline iterator(node_pointer root)
{
m_visitor.initialize(root);
}
reference operator*() const
{
return m_visitor.dereference();
}
const value_type * operator->() const
{
return boost::addressof(m_visitor.dereference());
}
iterator & operator++()
{
m_visitor.increment();
return *this;
}
iterator operator++(int)
{
iterator temp = *this;
this->operator++();
return temp;
}
friend bool operator==(iterator const& l, iterator const& r)
{
return l.m_visitor == r.m_visitor;
}
friend bool operator==(iterator const& l, end_iterator<Value, Allocators> const& /*r*/)
{
return l.m_visitor.is_end();
}
friend bool operator==(end_iterator<Value, Allocators> const& /*l*/, iterator const& r)
{
return r.m_visitor.is_end();
}
private:
visitor_type m_visitor;
};
}}}}}} // namespace boost::geometry::index::detail::rtree::iterators
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_ITERATORS_HPP
@@ -0,0 +1,16 @@
// Boost.Geometry Index
//
// R-tree kmeans 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_KMEANS_KMEANS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP
#include <boost/geometry/index/rtree/kmeans/split.hpp>
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP
@@ -0,0 +1,87 @@
// Boost.Geometry Index
//
// R-tree kmeans split 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_KMEANS_SPLIT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP
#include <boost/geometry/index/rtree/node/node.hpp>
#include <boost/geometry/index/rtree/visitors/insert.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
namespace kmeans {
// some details
} // namespace kmeans
// split_kmeans_tag
// OR
// split_clusters_tag and redistribute_kmeans_tag - then redistribute will probably slightly different interface
// or some other than "redistribute"
// 1. for this algorithm one probably MUST USE NON-STATIC NODES with node_default_tag
// or the algorithm must be changed somehow - to not store additional nodes in the current node
// but return excessive element/elements container instead (possibly pushable_array<1> or std::vector)
// this would also cause building of smaller trees since +1 element in nodes wouldn't be needed in different redistributing algorithms
// 2. it is probably possible to add e.g. 2 levels of tree in one insert
// Edge case is that every node split generates M + 1 children, in parent containing M nodes
// result is 2M + 1 nodes in parent on this level
// On next level the same, next the same and so on.
// We have Depth*M+1 nodes in the root
// The tree may then gain some > 1 levels in one insert
// split::apply() manages this but special attention is required
// which algorithm should be used to choose current node in traversing while inserting?
// some of the currently used ones or some using mean values as well?
// TODO
// 1. Zmienic troche algorytm zeby przekazywal nadmiarowe elementy do split
// i pobieral ze split nadmiarowe elementy rodzica
// W zaleznosci od algorytmu w rozny sposob - l/q/r* powinny zwracac np pushable_array<1>
// wtedy tez is_overerflow (z R* insert?) bedzie nieportrzebne
// Dla kmeans zapewne std::vector, jednak w wezlach nadal moglaby byc pushable_array
// 2. Fajnie byloby tez uproscic te wszystkie parametry root,parent,index itd. Mozliwe ze okazalyby sie zbedne
// 3. Sprawdzyc czasy wykonywania i zajetosc pamieci
// 4. Pamietac o parametryzacji kontenera z nadmiarowymi elementami
// PS. Z R* reinsertami moze byc masakra
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class split<Value, Options, Translator, Box, Allocators, split_kmeans_tag>
{
protected:
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;
public:
template <typename Node>
static inline void apply(node* & root_node,
size_t & leafs_level,
Node & n,
internal_node *parent_node,
size_t current_child_index,
Translator const& tr,
Allocators & allocators)
{
}
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_SPLIT_HPP
@@ -0,0 +1,16 @@
// Boost.Geometry Index
//
// R-tree linear 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_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP
#include <boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp>
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP
@@ -0,0 +1,446 @@
// Boost.Geometry Index
//
// R-tree linear split algorithm implementation
//
// Copyright (c) 2008 Federico J. Fernandez.
// Copyright (c) 2011-2014 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_LINEAR_REDISTRIBUTE_ELEMENTS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP
#include <boost/type_traits/is_unsigned.hpp>
#include <boost/geometry/index/detail/algorithms/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 linear {
template <typename R, typename T>
inline R difference_dispatch(T const& from, T const& to, ::boost::mpl::bool_<false> const& /*is_unsigned*/)
{
return to - from;
}
template <typename R, typename T>
inline R difference_dispatch(T const& from, T const& to, ::boost::mpl::bool_<true> const& /*is_unsigned*/)
{
return from <= to ? R(to - from) : -R(from - to);
}
template <typename R, typename T>
inline R difference(T const& from, T const& to)
{
BOOST_MPL_ASSERT_MSG(!boost::is_unsigned<R>::value, RESULT_CANT_BE_UNSIGNED, (R));
typedef ::boost::mpl::bool_<
boost::is_unsigned<T>::value
> is_unsigned;
return difference_dispatch<R>(from, to, is_unsigned());
}
// TODO: awulkiew
// In general, all aerial Indexables in the tree with box-like nodes will be analyzed as boxes
// because they must fit into larger box. Therefore the algorithm could be the same for Bounds type.
// E.g. if Bounds type is sphere, Indexables probably should be analyzed as spheres.
// 1. View could be provided to 'see' all Indexables as Bounds type.
// Not ok in the case of big types like Ring, however it's possible that Rings won't be supported,
// only simple types. Even then if we consider storing Box inside the Sphere we must calculate
// the bounding sphere 2x for each box because there are 2 loops. For each calculation this means
// 4-2d or 8-3d expansions or -, / and sqrt().
// 2. Additional container could be used and reused if the Indexable type is other than the Bounds type.
// IMPORTANT!
// Still probably the best way would be providing specialized algorithms for each Indexable-Bounds pair!
// Probably on pick_seeds algorithm level - For Bounds=Sphere seeds would be choosen differently
// TODO: awulkiew
// there are loops inside find_greatest_normalized_separation::apply()
// iteration is done for each DimensionIndex.
// Separations and seeds for all DimensionIndex(es) could be calculated at once, stored, then the greatest would be choosen.
// The following struct/method was adapted for the preliminary version of the R-tree. Then it was called:
// void find_normalized_separations(std::vector<Box> const& boxes, T& separation, unsigned int& first, unsigned int& second) const
template <typename Elements, typename Parameters, typename Translator, typename Tag, size_t DimensionIndex>
struct find_greatest_normalized_separation
{
typedef typename Elements::value_type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef typename coordinate_type<indexable_type>::type coordinate_type;
typedef typename boost::mpl::if_c<
boost::is_integral<coordinate_type>::value,
double,
coordinate_type
>::type separation_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;
static inline void apply(Elements const& elements,
Parameters const& parameters,
Translator const& translator,
separation_type & separation,
size_t & seed1,
size_t & seed2)
{
const size_t elements_count = parameters.get_max_elements() + 1;
BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements");
BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
// find the lowest low, highest high
bounded_view_type bounded_indexable_0(rtree::element_indexable(elements[0], translator));
coordinate_type lowest_low = geometry::get<min_corner, DimensionIndex>(bounded_indexable_0);
coordinate_type highest_high = geometry::get<max_corner, DimensionIndex>(bounded_indexable_0);
// and the lowest high
coordinate_type lowest_high = highest_high;
size_t lowest_high_index = 0;
for ( size_t i = 1 ; i < elements_count ; ++i )
{
bounded_view_type bounded_indexable(rtree::element_indexable(elements[i], translator));
coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(bounded_indexable);
coordinate_type max_coord = geometry::get<max_corner, DimensionIndex>(bounded_indexable);
if ( max_coord < lowest_high )
{
lowest_high = max_coord;
lowest_high_index = i;
}
if ( min_coord < lowest_low )
lowest_low = min_coord;
if ( highest_high < max_coord )
highest_high = max_coord;
}
// find the highest low
size_t highest_low_index = lowest_high_index == 0 ? 1 : 0;
bounded_view_type bounded_indexable_hl(rtree::element_indexable(elements[highest_low_index], translator));
coordinate_type highest_low = geometry::get<min_corner, DimensionIndex>(bounded_indexable_hl);
for ( size_t i = highest_low_index ; i < elements_count ; ++i )
{
bounded_view_type bounded_indexable(rtree::element_indexable(elements[i], translator));
coordinate_type min_coord = geometry::get<min_corner, DimensionIndex>(bounded_indexable);
if ( highest_low < min_coord &&
i != lowest_high_index )
{
highest_low = min_coord;
highest_low_index = i;
}
}
coordinate_type const width = highest_high - lowest_low;
// highest_low - lowest_high
separation = difference<separation_type>(lowest_high, highest_low);
// BOOST_GEOMETRY_INDEX_ASSERT(0 <= width);
if ( std::numeric_limits<coordinate_type>::epsilon() < width )
separation /= width;
seed1 = highest_low_index;
seed2 = lowest_high_index;
::boost::ignore_unused_variable_warning(parameters);
}
};
// Version for points doesn't calculate normalized separation since it would always be equal to 1
// It returns two seeds most distant to each other, separation is equal to distance
template <typename Elements, typename Parameters, typename Translator, size_t DimensionIndex>
struct find_greatest_normalized_separation<Elements, Parameters, Translator, point_tag, DimensionIndex>
{
typedef typename Elements::value_type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef typename coordinate_type<indexable_type>::type coordinate_type;
typedef coordinate_type separation_type;
static inline void apply(Elements const& elements,
Parameters const& parameters,
Translator const& translator,
separation_type & separation,
size_t & seed1,
size_t & seed2)
{
const size_t elements_count = parameters.get_max_elements() + 1;
BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "unexpected number of elements");
BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
// find the lowest low, highest high
coordinate_type lowest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator));
coordinate_type highest = geometry::get<DimensionIndex>(rtree::element_indexable(elements[0], translator));
size_t lowest_index = 0;
size_t highest_index = 0;
for ( size_t i = 1 ; i < elements_count ; ++i )
{
coordinate_type coord = geometry::get<DimensionIndex>(rtree::element_indexable(elements[i], translator));
if ( coord < lowest )
{
lowest = coord;
lowest_index = i;
}
if ( highest < coord )
{
highest = coord;
highest_index = i;
}
}
separation = highest - lowest;
seed1 = lowest_index;
seed2 = highest_index;
if ( lowest_index == highest_index )
seed2 = (lowest_index + 1) % elements_count; // % is just in case since if this is true lowest_index is 0
::boost::ignore_unused_variable_warning(parameters);
}
};
template <typename Elements, typename Parameters, typename Translator, size_t Dimension>
struct pick_seeds_impl
{
BOOST_STATIC_ASSERT(0 < Dimension);
typedef typename Elements::value_type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef find_greatest_normalized_separation<
Elements, Parameters, Translator,
typename tag<indexable_type>::type, Dimension - 1
> find_norm_sep;
typedef typename find_norm_sep::separation_type separation_type;
static inline void apply(Elements const& elements,
Parameters const& parameters,
Translator const& tr,
separation_type & separation,
size_t & seed1,
size_t & seed2)
{
pick_seeds_impl<Elements, Parameters, Translator, Dimension - 1>::apply(elements, parameters, tr, separation, seed1, seed2);
separation_type current_separation;
size_t s1, s2;
find_norm_sep::apply(elements, parameters, tr, current_separation, s1, s2);
// in the old implementation different operator was used: <= (y axis prefered)
if ( separation < current_separation )
{
separation = current_separation;
seed1 = s1;
seed2 = s2;
}
}
};
template <typename Elements, typename Parameters, typename Translator>
struct pick_seeds_impl<Elements, Parameters, Translator, 1>
{
typedef typename Elements::value_type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef typename coordinate_type<indexable_type>::type coordinate_type;
typedef find_greatest_normalized_separation<
Elements, Parameters, Translator,
typename tag<indexable_type>::type, 0
> find_norm_sep;
typedef typename find_norm_sep::separation_type separation_type;
static inline void apply(Elements const& elements,
Parameters const& parameters,
Translator const& tr,
separation_type & separation,
size_t & seed1,
size_t & seed2)
{
find_norm_sep::apply(elements, parameters, tr, separation, seed1, seed2);
}
};
// from void linear_pick_seeds(node_pointer const& n, unsigned int &seed1, unsigned int &seed2) const
template <typename Elements, typename Parameters, typename Translator>
inline void pick_seeds(Elements const& elements,
Parameters const& parameters,
Translator const& tr,
size_t & seed1,
size_t & seed2)
{
typedef typename Elements::value_type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef pick_seeds_impl
<
Elements, Parameters, Translator,
geometry::dimension<indexable_type>::value
> impl;
typedef typename impl::separation_type separation_type;
separation_type separation = 0;
impl::apply(elements, parameters, tr, separation, seed1, seed2);
}
} // namespace linear
// from void split_node(node_pointer const& n, node_pointer& n1, node_pointer& n2) const
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear_tag>
{
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;
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;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef typename index::detail::default_content_result<Box>::type content_type;
elements_type & elements1 = rtree::elements(n);
elements_type & elements2 = rtree::elements(second_node);
const size_t elements1_count = parameters.get_max_elements() + 1;
BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected number of elements");
// 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 (alloc, copy)
// calculate initial seeds
size_t seed1 = 0;
size_t seed2 = 0;
linear::pick_seeds(elements_copy, parameters, translator, seed1, seed2);
// prepare nodes' elements containers
elements1.clear();
BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "unexpected container state");
BOOST_TRY
{
// add seeds
elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
// calculate boxes
detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1);
detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2);
// initialize areas
content_type content1 = index::detail::content(box1);
content_type content2 = index::detail::content(box2);
BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements1_count, "unexpected elements number");
size_t remaining = elements1_count - 2;
// redistribute the rest of the elements
for ( size_t i = 0 ; i < elements1_count ; ++i )
{
if (i != seed1 && i != seed2)
{
element_type const& elem = elements_copy[i];
indexable_type const& indexable = rtree::element_indexable(elem, translator);
// if there is small number of elements left and the number of elements in node is lesser than min_elems
// just insert them to this node
if ( elements1.size() + remaining <= parameters.get_min_elements() )
{
elements1.push_back(elem); // MAY THROW, STRONG (copy)
geometry::expand(box1, indexable);
content1 = index::detail::content(box1);
}
else if ( elements2.size() + remaining <= parameters.get_min_elements() )
{
elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
geometry::expand(box2, indexable);
content2 = index::detail::content(box2);
}
// choose better node and insert element
else
{
// calculate enlarged boxes and areas
Box enlarged_box1(box1);
Box enlarged_box2(box2);
geometry::expand(enlarged_box1, indexable);
geometry::expand(enlarged_box2, indexable);
content_type enlarged_content1 = index::detail::content(enlarged_box1);
content_type enlarged_content2 = index::detail::content(enlarged_box2);
content_type content_increase1 = enlarged_content1 - content1;
content_type content_increase2 = enlarged_content2 - content2;
// choose group which box content have to be enlarged least or has smaller content or has fewer elements
if ( content_increase1 < content_increase2 ||
( content_increase1 == content_increase2 &&
( content1 < content2 ||
( content1 == content2 && elements1.size() <= elements2.size() ) ) ) )
{
elements1.push_back(elem); // MAY THROW, STRONG (copy)
box1 = enlarged_box1;
content1 = enlarged_content1;
}
else
{
elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
box2 = enlarged_box2;
content2 = enlarged_content2;
}
}
BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "unexpected value");
--remaining;
}
}
}
BOOST_CATCH(...)
{
elements1.clear();
elements2.clear();
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
//elements_copy.clear();
BOOST_RETHROW // RETHROW, BASIC
}
BOOST_CATCH_END
}
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP
@@ -0,0 +1,85 @@
// Boost.Geometry Index
//
// R-tree node concept
//
// 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_NODE_CONCEPT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct node
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
(node));
};
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct internal_node
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
(internal_node));
};
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct leaf
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
(leaf));
};
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst>
struct visitor
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
(visitor));
};
template <typename Allocator, typename Value, typename Parameters, typename Box, typename Tag>
class allocators
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE,
(allocators));
};
template <typename Allocators, typename Node>
struct create_node
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE,
(create_node));
};
template <typename Allocators, typename Node>
struct destroy_node
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE,
(destroy_node));
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_CONCEPT_HPP
@@ -0,0 +1,212 @@
// Boost.Geometry Index
//
// R-tree nodes
//
// 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_NODE_NODE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP
#include <boost/container/vector.hpp>
#include <boost/geometry/index/detail/varray.hpp>
#include <boost/geometry/index/detail/rtree/node/concept.hpp>
#include <boost/geometry/index/detail/rtree/node/pairs.hpp>
#include <boost/geometry/index/detail/rtree/node/node_elements.hpp>
#include <boost/geometry/index/detail/rtree/node/scoped_deallocator.hpp>
//#include <boost/geometry/index/detail/rtree/node/weak_visitor.hpp>
//#include <boost/geometry/index/detail/rtree/node/weak_dynamic.hpp>
//#include <boost/geometry/index/detail/rtree/node/weak_static.hpp>
#include <boost/geometry/index/detail/rtree/node/variant_visitor.hpp>
#include <boost/geometry/index/detail/rtree/node/variant_dynamic.hpp>
#include <boost/geometry/index/detail/rtree/node/variant_static.hpp>
#include <boost/geometry/index/detail/rtree/node/subtree_destroyer.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
#include <boost/geometry/index/detail/algorithms/bounds.hpp>
#include <boost/geometry/index/detail/is_bounding_geometry.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// elements box
template <typename Box, typename FwdIter, typename Translator>
inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr)
{
Box result;
// Only here to suppress 'uninitialized local variable used' warning
// until the suggestion below is not implemented
geometry::assign_inverse(result);
//BOOST_GEOMETRY_INDEX_ASSERT(first != last, "non-empty range required");
// NOTE: this is not elegant temporary solution,
// reference to box could be passed as parameter and bool returned
if ( first == last )
return result;
detail::bounds(element_indexable(*first, tr), result);
++first;
for ( ; first != last ; ++first )
geometry::expand(result, element_indexable(*first, tr));
return result;
}
// Enlarge bounds of a leaf node WRT epsilon if needed.
// It's because Points and Segments are compared WRT machine epsilon.
// This ensures that leafs bounds correspond to the stored elements.
// NOTE: this is done only if the Indexable is not a Box
// in the future don't do it also for NSphere
template <typename Box, typename FwdIter, typename Translator>
inline Box values_box(FwdIter first, FwdIter last, Translator const& tr)
{
typedef typename std::iterator_traits<FwdIter>::value_type element_type;
BOOST_MPL_ASSERT_MSG((is_leaf_element<element_type>::value),
SHOULD_BE_CALLED_ONLY_FOR_LEAF_ELEMENTS,
(element_type));
Box result = elements_box<Box>(first, last, tr);
#ifdef BOOST_GEOMETRY_INDEX_EXPERIMENTAL_ENLARGE_BY_EPSILON
if (BOOST_GEOMETRY_CONDITION((
! is_bounding_geometry
<
typename indexable_type<Translator>::type
>::value)))
{
geometry::detail::expand_by_epsilon(result);
}
#endif
return result;
}
// destroys subtree if the element is internal node's element
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct destroy_element
{
typedef typename Options::parameters_type parameters_type;
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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
inline static void apply(typename internal_node::elements_type::value_type & element, Allocators & allocators)
{
subtree_destroyer dummy(element.second, allocators);
element.second = 0;
}
inline static void apply(typename leaf::elements_type::value_type &, Allocators &) {}
};
// destroys stored subtrees if internal node's elements are passed
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct destroy_elements
{
template <typename Range>
inline static void apply(Range & elements, Allocators & allocators)
{
apply(boost::begin(elements), boost::end(elements), allocators);
}
template <typename It>
inline static void apply(It first, It last, Allocators & allocators)
{
typedef boost::mpl::bool_<
boost::is_same<
Value, typename std::iterator_traits<It>::value_type
>::value
> is_range_of_values;
apply_dispatch(first, last, allocators, is_range_of_values());
}
private:
template <typename It>
inline static void apply_dispatch(It first, It last, Allocators & allocators,
boost::mpl::bool_<false> const& /*is_range_of_values*/)
{
typedef rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
for ( ; first != last ; ++first )
{
subtree_destroyer dummy(first->second, allocators);
first->second = 0;
}
}
template <typename It>
inline static void apply_dispatch(It /*first*/, It /*last*/, Allocators & /*allocators*/,
boost::mpl::bool_<true> const& /*is_range_of_values*/)
{}
};
// clears node, deletes all subtrees stored in node
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct clear_node
{
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;
inline static void apply(node & node, Allocators & allocators)
{
rtree::visitors::is_leaf<Value, Options, Box, Allocators> ilv;
rtree::apply_visitor(ilv, node);
if ( ilv.result )
{
apply(rtree::get<leaf>(node), allocators);
}
else
{
apply(rtree::get<internal_node>(node), allocators);
}
}
inline static void apply(internal_node & internal_node, Allocators & allocators)
{
destroy_elements<Value, Options, Translator, Box, Allocators>::apply(rtree::elements(internal_node), allocators);
rtree::elements(internal_node).clear();
}
inline static void apply(leaf & leaf, Allocators &)
{
rtree::elements(leaf).clear();
}
};
template <typename Container, typename Iterator>
void move_from_back(Container & container, Iterator it)
{
BOOST_GEOMETRY_INDEX_ASSERT(!container.empty(), "cannot copy from empty container");
Iterator back_it = container.end();
--back_it;
if ( it != back_it )
{
*it = boost::move(*back_it); // MAY THROW (copy)
}
}
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP
@@ -0,0 +1,110 @@
// Boost.Geometry Index
//
// R-tree node elements access
//
// 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_NODE_NODE_ELEMENTS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_HPP
#include <boost/container/vector.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
#include <boost/geometry/index/detail/varray.hpp>
#include <boost/geometry/index/detail/rtree/node/pairs.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// element's indexable type
template <typename Element, typename Translator>
struct element_indexable_type
{
typedef typename indexable_type<Translator>::type type;
};
template <typename First, typename Pointer, typename Translator>
struct element_indexable_type<
rtree::ptr_pair<First, Pointer>,
Translator
>
{
typedef First type;
};
// is leaf element
template <typename Element>
struct is_leaf_element
{
static const bool value = true;
};
template <typename First, typename Pointer>
struct is_leaf_element< rtree::ptr_pair<First, Pointer> >
{
static const bool value = false;
};
// element's indexable getter
template <typename Element, typename Translator>
typename result_type<Translator>::type
element_indexable(Element const& el, Translator const& tr)
{
return tr(el);
}
template <typename First, typename Pointer, typename Translator>
First const&
element_indexable(rtree::ptr_pair<First, Pointer> const& el, Translator const& /*tr*/)
{
return el.first;
}
// nodes elements
template <typename Node>
struct elements_type
{
typedef typename Node::elements_type type;
};
template <typename Node>
inline typename elements_type<Node>::type &
elements(Node & n)
{
return n.elements;
}
template <typename Node>
inline typename elements_type<Node>::type const&
elements(Node const& n)
{
return n.elements;
}
// elements derived type
template <typename Elements, typename NewValue>
struct container_from_elements_type
{
typedef boost::container::vector<NewValue> type;
};
template <typename OldValue, size_t N, typename NewValue>
struct container_from_elements_type<detail::varray<OldValue, N>, NewValue>
{
typedef detail::varray<NewValue, N> type;
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_ELEMENTS_HPP
@@ -0,0 +1,71 @@
// Boost.Geometry Index
//
// Pairs intended to be used internally in nodes.
//
// 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_NODE_PAIRS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP
#include <boost/move/move.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename First, typename Pointer>
class ptr_pair
{
public:
typedef First first_type;
typedef Pointer second_type;
ptr_pair(First const& f, Pointer s) : first(f), second(s) {}
//ptr_pair(ptr_pair const& p) : first(p.first), second(p.second) {}
//ptr_pair & operator=(ptr_pair const& p) { first = p.first; second = p.second; return *this; }
first_type first;
second_type second;
};
template <typename First, typename Pointer> inline
ptr_pair<First, Pointer>
make_ptr_pair(First const& f, Pointer s)
{
return ptr_pair<First, Pointer>(f, s);
}
// TODO: It this will be used, rename it to unique_ptr_pair and possibly use unique_ptr.
template <typename First, typename Pointer>
class exclusive_ptr_pair
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(exclusive_ptr_pair)
public:
typedef First first_type;
typedef Pointer second_type;
exclusive_ptr_pair(First const& f, Pointer s) : first(f), second(s) {}
// INFO - members aren't really moved!
exclusive_ptr_pair(BOOST_RV_REF(exclusive_ptr_pair) p) : first(p.first), second(p.second) { p.second = 0; }
exclusive_ptr_pair & operator=(BOOST_RV_REF(exclusive_ptr_pair) p) { first = p.first; second = p.second; p.second = 0; return *this; }
first_type first;
second_type second;
};
template <typename First, typename Pointer> inline
exclusive_ptr_pair<First, Pointer>
make_exclusive_ptr_pair(First const& f, Pointer s)
{
return exclusive_ptr_pair<First, Pointer>(f, s);
}
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP
@@ -0,0 +1,48 @@
// Boost.Geometry Index
//
// R-tree scoped deallocator
//
// 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_NODE_SCOPED_DEALLOCATOR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SCOPED_DEALLOCATOR_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename Alloc>
class scoped_deallocator
{
scoped_deallocator(scoped_deallocator const&);
scoped_deallocator & operator=(scoped_deallocator const&);
public:
typedef typename Alloc::pointer pointer;
inline scoped_deallocator(pointer p, Alloc & a)
: m_ptr(p), m_alloc(a)
{}
inline ~scoped_deallocator()
{
if ( m_ptr )
{
boost::container::allocator_traits<Alloc>::deallocate(m_alloc, m_ptr, 1);
}
}
inline void release()
{
m_ptr = 0;
}
private:
pointer m_ptr;
Alloc & m_alloc;
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SCOPED_DEALLOCATOR_HPP
@@ -0,0 +1,79 @@
// Boost.Geometry Index
//
// R-tree subtree scoped destroyer
//
// 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_NODE_SUBTREE_DESTROYED_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SUBTREE_DESTROYED_HPP
#include <boost/geometry/index/detail/rtree/visitors/destroy.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class subtree_destroyer
{
typedef typename rtree::node<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag>::type node;
typedef typename Allocators::node_pointer pointer;
subtree_destroyer(subtree_destroyer const&);
subtree_destroyer & operator=(subtree_destroyer const&);
public:
subtree_destroyer(pointer ptr, Allocators & allocators)
: m_ptr(ptr)
, m_allocators(allocators)
{}
~subtree_destroyer()
{
reset();
}
void reset(pointer ptr = 0)
{
if ( m_ptr && m_ptr != ptr )
{
detail::rtree::visitors::destroy<Value, Options, Translator, Box, Allocators> del_v(m_ptr, m_allocators);
detail::rtree::apply_visitor(del_v, *m_ptr);
}
m_ptr = ptr;
}
void release()
{
m_ptr = 0;
}
pointer get() const
{
return m_ptr;
}
node & operator*() const
{
return *m_ptr;
}
pointer operator->() const
{
return m_ptr;
}
private:
pointer m_ptr;
Allocators & m_allocators;
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_SUBTREE_DESTROYED_HPP
@@ -0,0 +1,276 @@
// Boost.Geometry Index
//
// R-tree nodes based on Boost.Variant, storing dynamic-size containers
//
// Copyright (c) 2011-2014 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_NODE_VARIANT_DYNAMIC_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// nodes default types
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct variant_internal_node
{
typedef boost::container::vector
<
rtree::ptr_pair<Box, typename Allocators::node_pointer>,
typename Allocators::node_allocator_type::template rebind
<
rtree::ptr_pair<Box, typename Allocators::node_pointer>
>::other
> elements_type;
template <typename Al>
inline variant_internal_node(Al const& al)
: elements(al)
{}
elements_type elements;
};
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct variant_leaf
{
typedef boost::container::vector
<
Value,
typename Allocators::node_allocator_type::template rebind
<
Value
>::other
> elements_type;
template <typename Al>
inline variant_leaf(Al const& al)
: elements(al)
{}
elements_type elements;
};
// nodes traits
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
{
typedef boost::variant<
variant_leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>,
variant_internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
{
typedef variant_internal_node<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag>
{
typedef variant_leaf<Value, Parameters, Box, Allocators, node_variant_dynamic_tag> type;
};
// visitor traits
template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
struct visitor<Value, Parameters, Box, Allocators, node_variant_dynamic_tag, IsVisitableConst>
{
typedef static_visitor<> type;
};
// allocators
template <typename Allocator, typename Value, typename Parameters, typename Box>
class allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag>
: public Allocator::template rebind<
typename node<
Value, Parameters, Box,
allocators<Allocator, Value, Parameters, Box, node_variant_dynamic_tag>,
node_variant_dynamic_tag
>::type
>::other
{
typedef typename Allocator::template rebind<
Value
>::other value_allocator_type;
public:
typedef Allocator allocator_type;
typedef Value value_type;
typedef typename value_allocator_type::reference reference;
typedef typename value_allocator_type::const_reference const_reference;
typedef typename value_allocator_type::size_type size_type;
typedef typename value_allocator_type::difference_type difference_type;
typedef typename value_allocator_type::pointer pointer;
typedef typename value_allocator_type::const_pointer const_pointer;
typedef typename Allocator::template rebind<
typename node<Value, Parameters, Box, allocators, node_variant_dynamic_tag>::type
>::other::pointer node_pointer;
typedef typename Allocator::template rebind<
typename node<Value, Parameters, Box, allocators, node_variant_dynamic_tag>::type
>::other node_allocator_type;
inline allocators()
: node_allocator_type()
{}
template <typename Alloc>
inline explicit allocators(Alloc const& alloc)
: node_allocator_type(alloc)
{}
inline allocators(BOOST_FWD_REF(allocators) a)
: node_allocator_type(boost::move(a.node_allocator()))
{}
inline allocators & operator=(BOOST_FWD_REF(allocators) a)
{
node_allocator() = boost::move(a.node_allocator());
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
inline allocators & operator=(allocators const& a)
{
node_allocator() = a.node_allocator();
return *this;
}
#endif
void swap(allocators & a)
{
boost::swap(node_allocator(), a.node_allocator());
}
bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); }
template <typename Alloc>
bool operator==(Alloc const& a) const { return node_allocator() == node_allocator_type(a); }
Allocator allocator() const { return Allocator(node_allocator()); }
node_allocator_type & node_allocator() { return *this; }
node_allocator_type const& node_allocator() const { return *this; }
};
// create_node_variant
template <typename VariantPtr, typename Node>
struct create_variant_node
{
template <typename AllocNode>
static inline VariantPtr apply(AllocNode & alloc_node)
{
typedef boost::container::allocator_traits<AllocNode> Al;
typedef typename Al::pointer P;
P p = Al::allocate(alloc_node, 1);
if ( 0 == p )
throw_runtime_error("boost::geometry::index::rtree node creation failed");
scoped_deallocator<AllocNode> deallocator(p, alloc_node);
Al::construct(alloc_node, boost::addressof(*p), Node(alloc_node)); // implicit cast to Variant
deallocator.release();
return p;
}
};
// destroy_node_variant
template <typename Node>
struct destroy_variant_node
{
template <typename AllocNode, typename VariantPtr>
static inline void apply(AllocNode & alloc_node, VariantPtr n)
{
typedef boost::container::allocator_traits<AllocNode> Al;
Al::destroy(alloc_node, boost::addressof(*n));
Al::deallocate(alloc_node, n, 1);
}
};
// create_node
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct create_node<
Allocators,
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
>
{
static inline typename Allocators::node_pointer
apply(Allocators & allocators)
{
return create_variant_node<
typename Allocators::node_pointer,
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.node_allocator());
}
};
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct create_node<
Allocators,
variant_leaf<Value, Parameters, Box, Allocators, Tag>
>
{
static inline typename Allocators::node_pointer
apply(Allocators & allocators)
{
return create_variant_node<
typename Allocators::node_pointer,
variant_leaf<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.node_allocator());
}
};
// destroy_node
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct destroy_node<
Allocators,
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
>
{
static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
{
destroy_variant_node<
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.node_allocator(), n);
}
};
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct destroy_node<
Allocators,
variant_leaf<Value, Parameters, Box, Allocators, Tag>
>
{
static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
{
destroy_variant_node<
variant_leaf<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.node_allocator(), n);
}
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_DYNAMIC_HPP
@@ -0,0 +1,160 @@
// Boost.Geometry Index
//
// R-tree nodes based on Boost.Variant, storing static-size containers
//
// Copyright (c) 2011-2014 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_NODE_VARIANT_STATIC_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// nodes default types
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
{
typedef detail::varray<
rtree::ptr_pair<Box, typename Allocators::node_pointer>,
Parameters::max_elements + 1
> elements_type;
template <typename Alloc>
inline variant_internal_node(Alloc const&) {}
elements_type elements;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>
{
typedef detail::varray<
Value,
Parameters::max_elements + 1
> elements_type;
template <typename Alloc>
inline variant_leaf(Alloc const&) {}
elements_type elements;
};
// nodes traits
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct node<Value, Parameters, Box, Allocators, node_variant_static_tag>
{
typedef boost::variant<
variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>,
variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag>
{
typedef variant_internal_node<Value, Parameters, Box, Allocators, node_variant_static_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct leaf<Value, Parameters, Box, Allocators, node_variant_static_tag>
{
typedef variant_leaf<Value, Parameters, Box, Allocators, node_variant_static_tag> type;
};
// visitor traits
template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
struct visitor<Value, Parameters, Box, Allocators, node_variant_static_tag, IsVisitableConst>
{
typedef static_visitor<> type;
};
// allocators
template <typename Allocator, typename Value, typename Parameters, typename Box>
class allocators<Allocator, Value, Parameters, Box, node_variant_static_tag>
: public Allocator::template rebind<
typename node<
Value, Parameters, Box,
allocators<Allocator, Value, Parameters, Box, node_variant_static_tag>,
node_variant_static_tag
>::type
>::other
{
typedef typename Allocator::template rebind<
Value
>::other value_allocator_type;
public:
typedef Allocator allocator_type;
typedef Value value_type;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef typename value_allocator_type::size_type size_type;
typedef typename value_allocator_type::difference_type difference_type;
typedef typename value_allocator_type::pointer pointer;
typedef typename value_allocator_type::const_pointer const_pointer;
typedef typename Allocator::template rebind<
typename node<Value, Parameters, Box, allocators, node_variant_static_tag>::type
>::other::pointer node_pointer;
typedef typename Allocator::template rebind<
typename node<Value, Parameters, Box, allocators, node_variant_static_tag>::type
>::other node_allocator_type;
inline allocators()
: node_allocator_type()
{}
template <typename Alloc>
inline explicit allocators(Alloc const& alloc)
: node_allocator_type(alloc)
{}
inline allocators(BOOST_FWD_REF(allocators) a)
: node_allocator_type(boost::move(a.node_allocator()))
{}
inline allocators & operator=(BOOST_FWD_REF(allocators) a)
{
node_allocator() = boost::move(a.node_allocator());
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
inline allocators & operator=(allocators const& a)
{
node_allocator() = a.node_allocator();
return *this;
}
#endif
void swap(allocators & a)
{
boost::swap(node_allocator(), a.node_allocator());
}
bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); }
template <typename Alloc>
bool operator==(Alloc const& a) const { return node_allocator() == node_allocator_type(a); }
Allocator allocator() const { return Allocator(node_allocator()); }
node_allocator_type & node_allocator() { return *this; }
node_allocator_type const& node_allocator() const { return *this; }
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_STATIC_HPP
@@ -0,0 +1,68 @@
// Boost.Geometry Index
//
// R-tree nodes static visitor related code
//
// Copyright (c) 2011-2014 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_NODE_VARIANT_VISITOR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/get.hpp>
#include <boost/variant/variant.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// nodes variants forward declarations
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct variant_internal_node;
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct variant_leaf;
// nodes conversion
template <typename V, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
inline V & get(
boost::variant<
variant_leaf<Value, Parameters, Box, Allocators, Tag>,
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
> & v)
{
return boost::get<V>(v);
}
// apply visitor
template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
inline void apply_visitor(Visitor & v,
boost::variant<
variant_leaf<Value, Parameters, Box, Allocators, Tag>,
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
> & n)
{
boost::apply_visitor(v, n);
}
template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
inline void apply_visitor(Visitor & v,
boost::variant<
variant_leaf<Value, Parameters, Box, Allocators, Tag>,
variant_internal_node<Value, Parameters, Box, Allocators, Tag>
> const& n)
{
boost::apply_visitor(v, n);
}
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_VARIANT_VISITOR_HPP
@@ -0,0 +1,294 @@
// Boost.Geometry Index
//
// R-tree nodes based on static conversion, storing dynamic-size containers
//
// Copyright (c) 2011-2014 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_NODE_WEAK_DYNAMIC_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct weak_internal_node
: public weak_node<Value, Parameters, Box, Allocators, Tag>
{
typedef boost::container::vector
<
rtree::ptr_pair<Box, typename Allocators::node_pointer>,
typename Allocators::internal_node_allocator_type::template rebind
<
rtree::ptr_pair<Box, typename Allocators::node_pointer>
>::other
> elements_type;
template <typename Al>
inline weak_internal_node(Al const& al)
: elements(al)
{}
elements_type elements;
};
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct weak_leaf
: public weak_node<Value, Parameters, Box, Allocators, Tag>
{
typedef boost::container::vector
<
Value,
typename Allocators::leaf_allocator_type::template rebind
<
Value
>::other
> elements_type;
template <typename Al>
inline weak_leaf(Al const& al)
: elements(al)
{}
elements_type elements;
};
// nodes traits
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag>
{
typedef weak_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct internal_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag>
{
typedef weak_internal_node<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct leaf<Value, Parameters, Box, Allocators, node_weak_dynamic_tag>
{
typedef weak_leaf<Value, Parameters, Box, Allocators, node_weak_dynamic_tag> type;
};
// visitor traits
template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
struct visitor<Value, Parameters, Box, Allocators, node_weak_dynamic_tag, IsVisitableConst>
{
typedef weak_visitor<Value, Parameters, Box, Allocators, node_weak_dynamic_tag, IsVisitableConst> type;
};
// allocators
template <typename Allocator, typename Value, typename Parameters, typename Box>
class allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>
: public Allocator::template rebind<
typename internal_node<
Value, Parameters, Box,
allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>,
node_weak_dynamic_tag
>::type
>::other
, public Allocator::template rebind<
typename leaf<
Value, Parameters, Box,
allocators<Allocator, Value, Parameters, Box, node_weak_dynamic_tag>,
node_weak_dynamic_tag
>::type
>::other
{
typedef typename Allocator::template rebind<
Value
>::other value_allocator_type;
public:
typedef Allocator allocator_type;
typedef Value value_type;
typedef typename value_allocator_type::reference reference;
typedef typename value_allocator_type::const_reference const_reference;
typedef typename value_allocator_type::size_type size_type;
typedef typename value_allocator_type::difference_type difference_type;
typedef typename value_allocator_type::pointer pointer;
typedef typename value_allocator_type::const_pointer const_pointer;
typedef typename Allocator::template rebind<
typename node<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type
>::other::pointer node_pointer;
typedef typename Allocator::template rebind<
typename internal_node<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type
>::other internal_node_allocator_type;
typedef typename Allocator::template rebind<
typename leaf<Value, Parameters, Box, allocators, node_weak_dynamic_tag>::type
>::other leaf_allocator_type;
inline allocators()
: internal_node_allocator_type()
, leaf_allocator_type()
{}
template <typename Alloc>
inline explicit allocators(Alloc const& alloc)
: internal_node_allocator_type(alloc)
, leaf_allocator_type(alloc)
{}
inline allocators(BOOST_FWD_REF(allocators) a)
: internal_node_allocator_type(boost::move(a.internal_node_allocator()))
, leaf_allocator_type(boost::move(a.leaf_allocator()))
{}
inline allocators & operator=(BOOST_FWD_REF(allocators) a)
{
internal_node_allocator() = ::boost::move(a.internal_node_allocator());
leaf_allocator() = ::boost::move(a.leaf_allocator());
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
inline allocators & operator=(allocators const& a)
{
internal_node_allocator() = a.internal_node_allocator();
leaf_allocator() = a.leaf_allocator();
return *this;
}
#endif
void swap(allocators & a)
{
boost::swap(internal_node_allocator(), a.internal_node_allocator());
boost::swap(leaf_allocator(), a.leaf_allocator());
}
bool operator==(allocators const& a) const { return leaf_allocator() == a.leaf_allocator(); }
template <typename Alloc>
bool operator==(Alloc const& a) const { return leaf_allocator() == leaf_allocator_type(a); }
Allocator allocator() const { return Allocator(leaf_allocator()); }
internal_node_allocator_type & internal_node_allocator() { return *this; }
internal_node_allocator_type const& internal_node_allocator() const { return *this; }
leaf_allocator_type & leaf_allocator() { return *this; }
leaf_allocator_type const& leaf_allocator() const { return *this; }
};
// create_node_impl
template <typename BaseNodePtr, typename Node>
struct create_weak_node
{
template <typename AllocNode>
static inline BaseNodePtr apply(AllocNode & alloc_node)
{
typedef boost::container::allocator_traits<AllocNode> Al;
typedef typename Al::pointer P;
P p = Al::allocate(alloc_node, 1);
if ( 0 == p )
throw_runtime_error("boost::geometry::index::rtree node creation failed");
scoped_deallocator<AllocNode> deallocator(p, alloc_node);
Al::construct(alloc_node, boost::addressof(*p), alloc_node);
deallocator.release();
return p;
}
};
// destroy_node_impl
template <typename Node>
struct destroy_weak_node
{
template <typename AllocNode, typename BaseNodePtr>
static inline void apply(AllocNode & alloc_node, BaseNodePtr n)
{
typedef boost::container::allocator_traits<AllocNode> Al;
typedef typename Al::pointer P;
P p(&static_cast<Node&>(rtree::get<Node>(*n)));
Al::destroy(alloc_node, boost::addressof(*p));
Al::deallocate(alloc_node, p, 1);
}
};
// create_node
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct create_node<
Allocators,
weak_internal_node<Value, Parameters, Box, Allocators, Tag>
>
{
static inline typename Allocators::node_pointer
apply(Allocators & allocators)
{
return create_weak_node<
typename Allocators::node_pointer,
weak_internal_node<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.internal_node_allocator());
}
};
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct create_node<
Allocators,
weak_leaf<Value, Parameters, Box, Allocators, Tag>
>
{
static inline typename Allocators::node_pointer
apply(Allocators & allocators)
{
return create_weak_node<
typename Allocators::node_pointer,
weak_leaf<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.leaf_allocator());
}
};
// destroy_node
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct destroy_node<
Allocators,
weak_internal_node<Value, Parameters, Box, Allocators, Tag>
>
{
static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
{
destroy_weak_node<
weak_internal_node<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.internal_node_allocator(), n);
}
};
template <typename Allocators, typename Value, typename Parameters, typename Box, typename Tag>
struct destroy_node<
Allocators,
weak_leaf<Value, Parameters, Box, Allocators, Tag>
>
{
static inline void apply(Allocators & allocators, typename Allocators::node_pointer n)
{
destroy_weak_node<
weak_leaf<Value, Parameters, Box, Allocators, Tag>
>::apply(allocators.leaf_allocator(), n);
}
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_DYNAMIC_HPP
@@ -0,0 +1,174 @@
// Boost.Geometry Index
//
// R-tree nodes based on static conversion, storing static-size containers
//
// Copyright (c) 2011-2014 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_NODE_WEAK_STATIC_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct weak_internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
: public weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
{
typedef detail::varray<
rtree::ptr_pair<Box, typename Allocators::node_pointer>,
Parameters::max_elements + 1
> elements_type;
template <typename Alloc>
inline weak_internal_node(Alloc const&) {}
elements_type elements;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct weak_leaf<Value, Parameters, Box, Allocators, node_weak_static_tag>
: public weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
{
typedef detail::varray<
Value,
Parameters::max_elements + 1
> elements_type;
template <typename Alloc>
inline weak_leaf(Alloc const&) {}
elements_type elements;
};
// nodes traits
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct node<Value, Parameters, Box, Allocators, node_weak_static_tag>
{
typedef weak_node<Value, Parameters, Box, Allocators, node_weak_static_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag>
{
typedef weak_internal_node<Value, Parameters, Box, Allocators, node_weak_static_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators>
struct leaf<Value, Parameters, Box, Allocators, node_weak_static_tag>
{
typedef weak_leaf<Value, Parameters, Box, Allocators, node_weak_static_tag> type;
};
template <typename Value, typename Parameters, typename Box, typename Allocators, bool IsVisitableConst>
struct visitor<Value, Parameters, Box, Allocators, node_weak_static_tag, IsVisitableConst>
{
typedef weak_visitor<Value, Parameters, Box, Allocators, node_weak_static_tag, IsVisitableConst> type;
};
// allocators
template <typename Allocator, typename Value, typename Parameters, typename Box>
class allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>
: public Allocator::template rebind<
typename internal_node<
Value, Parameters, Box,
allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>,
node_weak_static_tag
>::type
>::other
, public Allocator::template rebind<
typename leaf<
Value, Parameters, Box,
allocators<Allocator, Value, Parameters, Box, node_weak_static_tag>,
node_weak_static_tag
>::type
>::other
{
typedef typename Allocator::template rebind<
Value
>::other value_allocator_type;
public:
typedef Allocator allocator_type;
typedef Value value_type;
typedef value_type & reference;
typedef const value_type & const_reference;
typedef typename value_allocator_type::size_type size_type;
typedef typename value_allocator_type::difference_type difference_type;
typedef typename value_allocator_type::pointer pointer;
typedef typename value_allocator_type::const_pointer const_pointer;
typedef typename Allocator::template rebind<
typename node<Value, Parameters, Box, allocators, node_weak_static_tag>::type
>::other::pointer node_pointer;
typedef typename Allocator::template rebind<
typename internal_node<Value, Parameters, Box, allocators, node_weak_static_tag>::type
>::other internal_node_allocator_type;
typedef typename Allocator::template rebind<
typename leaf<Value, Parameters, Box, allocators, node_weak_static_tag>::type
>::other leaf_allocator_type;
inline allocators()
: internal_node_allocator_type()
, leaf_allocator_type()
{}
template <typename Alloc>
inline explicit allocators(Alloc const& alloc)
: internal_node_allocator_type(alloc)
, leaf_allocator_type(alloc)
{}
inline allocators(BOOST_FWD_REF(allocators) a)
: internal_node_allocator_type(boost::move(a.internal_node_allocator()))
, leaf_allocator_type(boost::move(a.leaf_allocator()))
{}
inline allocators & operator=(BOOST_FWD_REF(allocators) a)
{
internal_node_allocator() = ::boost::move(a.internal_node_allocator());
leaf_allocator() = ::boost::move(a.leaf_allocator());
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
inline allocators & operator=(allocators const& a)
{
internal_node_allocator() = a.internal_node_allocator();
leaf_allocator() = a.leaf_allocator();
return *this;
}
#endif
void swap(allocators & a)
{
boost::swap(internal_node_allocator(), a.internal_node_allocator());
boost::swap(leaf_allocator(), a.leaf_allocator());
}
bool operator==(allocators const& a) const { return leaf_allocator() == a.leaf_allocator(); }
template <typename Alloc>
bool operator==(Alloc const& a) const { return leaf_allocator() == leaf_allocator_type(a); }
Allocator allocator() const { return Allocator(leaf_allocator()); }
internal_node_allocator_type & internal_node_allocator() { return *this; }
internal_node_allocator_type const& internal_node_allocator() const { return *this; }
leaf_allocator_type & leaf_allocator() { return *this; }
leaf_allocator_type const& leaf_allocator() const{ return *this; }
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_STATIC_HPP
@@ -0,0 +1,67 @@
// Boost.Geometry Index
//
// R-tree nodes weak visitor and nodes base type
//
// Copyright (c) 2011-2014 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_NODE_WEAK_VISITOR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_WEAK_VISITOR_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// empty visitor
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag, bool IsVisitableConst>
struct weak_visitor {};
// node
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct weak_node {};
// nodes variants forward declarations
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct weak_internal_node;
template <typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
struct weak_leaf;
// nodes conversion
template <typename Derived, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
inline Derived & get(weak_node<Value, Parameters, Box, Allocators, Tag> & n)
{
return static_cast<Derived&>(n);
}
// apply visitor
template <typename Visitor, typename Value, typename Parameters, typename Box, typename Allocators, typename Tag>
inline void apply_visitor(Visitor & v,
weak_node<Value, Parameters, Box, Allocators, Tag> & n,
bool is_internal_node)
{
BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr");
if ( is_internal_node )
{
typedef weak_internal_node<Value, Parameters, Box, Allocators, Tag> internal_node;
v(get<internal_node>(n));
}
else
{
typedef weak_leaf<Value, Parameters, Box, Allocators, Tag> leaf;
v(get<leaf>(n));
}
}
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP
@@ -0,0 +1,155 @@
// Boost.Geometry Index
//
// R-tree options, algorithms, parameters
//
// Copyright (c) 2011-2014 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_OPTIONS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP
#include <boost/geometry/index/parameters.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// InsertTag
struct insert_default_tag {};
struct insert_reinsert_tag {};
// ChooseNextNodeTag
struct choose_by_content_diff_tag {};
struct choose_by_overlap_diff_tag {};
// SplitTag
struct split_default_tag {};
//struct split_kmeans_tag {};
// RedistributeTag
struct linear_tag {};
struct quadratic_tag {};
struct rstar_tag {};
// NodeTag
struct node_variant_dynamic_tag {};
struct node_variant_static_tag {};
//struct node_weak_dynamic_tag {};
//struct node_weak_static_tag {};
template <typename Parameters, typename InsertTag, typename ChooseNextNodeTag, typename SplitTag, typename RedistributeTag, typename NodeTag>
struct options
{
typedef Parameters parameters_type;
typedef InsertTag insert_tag;
typedef ChooseNextNodeTag choose_next_node_tag;
typedef SplitTag split_tag;
typedef RedistributeTag redistribute_tag;
typedef NodeTag node_tag;
};
template <typename Parameters>
struct options_type
{
// TODO: awulkiew - use static assert
};
template <size_t MaxElements, size_t MinElements>
struct options_type< index::linear<MaxElements, MinElements> >
{
typedef options<
index::linear<MaxElements, MinElements>,
insert_default_tag,
choose_by_content_diff_tag,
split_default_tag,
linear_tag,
node_variant_static_tag
> type;
};
template <size_t MaxElements, size_t MinElements>
struct options_type< index::quadratic<MaxElements, MinElements> >
{
typedef options<
index::quadratic<MaxElements, MinElements>,
insert_default_tag,
choose_by_content_diff_tag,
split_default_tag,
quadratic_tag,
node_variant_static_tag
> type;
};
template <size_t MaxElements, size_t MinElements, size_t OverlapCostThreshold, size_t ReinsertedElements>
struct options_type< index::rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements> >
{
typedef options<
index::rstar<MaxElements, MinElements, OverlapCostThreshold, ReinsertedElements>,
insert_reinsert_tag,
choose_by_overlap_diff_tag,
split_default_tag,
rstar_tag,
node_variant_static_tag
> type;
};
//template <size_t MaxElements, size_t MinElements>
//struct options_type< kmeans<MaxElements, MinElements> >
//{
// typedef options<
// kmeans<MaxElements, MinElements>,
// insert_default_tag,
// choose_by_content_diff_tag, // change it?
// split_kmeans_tag,
// int, // dummy tag - not used for now
// node_variant_static_tag
// > type;
//};
template <>
struct options_type< index::dynamic_linear >
{
typedef options<
index::dynamic_linear,
insert_default_tag,
choose_by_content_diff_tag,
split_default_tag,
linear_tag,
node_variant_dynamic_tag
> type;
};
template <>
struct options_type< index::dynamic_quadratic >
{
typedef options<
index::dynamic_quadratic,
insert_default_tag,
choose_by_content_diff_tag,
split_default_tag,
quadratic_tag,
node_variant_dynamic_tag
> type;
};
template <>
struct options_type< index::dynamic_rstar >
{
typedef options<
index::dynamic_rstar,
insert_reinsert_tag,
choose_by_overlap_diff_tag,
split_default_tag,
rstar_tag,
node_variant_dynamic_tag
> type;
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP
@@ -0,0 +1,465 @@
// Boost.Geometry Index
//
// R-tree initial packing
//
// 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_PACK_CREATE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/index/detail/algorithms/bounds.hpp>
#include <boost/geometry/index/detail/algorithms/nth_element.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
namespace pack_utils {
template <std::size_t Dimension>
struct biggest_edge
{
BOOST_STATIC_ASSERT(0 < Dimension);
template <typename Box>
static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index)
{
biggest_edge<Dimension-1>::apply(box, length, dim_index);
typename coordinate_type<Box>::type curr
= geometry::get<max_corner, Dimension-1>(box) - geometry::get<min_corner, Dimension-1>(box);
if ( length < curr )
{
dim_index = Dimension - 1;
length = curr;
}
}
};
template <>
struct biggest_edge<1>
{
template <typename Box>
static inline void apply(Box const& box, typename coordinate_type<Box>::type & length, std::size_t & dim_index)
{
dim_index = 0;
length = geometry::get<max_corner, 0>(box) - geometry::get<min_corner, 0>(box);
}
};
template <std::size_t I>
struct point_entries_comparer
{
template <typename PointEntry>
bool operator()(PointEntry const& e1, PointEntry const& e2) const
{
return geometry::get<I>(e1.first) < geometry::get<I>(e2.first);
}
};
template <std::size_t I, std::size_t Dimension>
struct nth_element_and_half_boxes
{
template <typename EIt, typename Box>
static inline void apply(EIt first, EIt median, EIt last, Box const& box, Box & left, Box & right, std::size_t dim_index)
{
if ( I == dim_index )
{
index::detail::nth_element(first, median, last, point_entries_comparer<I>());
geometry::convert(box, left);
geometry::convert(box, right);
typename coordinate_type<Box>::type edge_len
= geometry::get<max_corner, I>(box) - geometry::get<min_corner, I>(box);
typename coordinate_type<Box>::type median
= geometry::get<min_corner, I>(box) + edge_len / 2;
geometry::set<max_corner, I>(left, median);
geometry::set<min_corner, I>(right, median);
}
else
nth_element_and_half_boxes<I+1, Dimension>::apply(first, median, last, box, left, right, dim_index);
}
};
template <std::size_t Dimension>
struct nth_element_and_half_boxes<Dimension, Dimension>
{
template <typename EIt, typename Box>
static inline void apply(EIt , EIt , EIt , Box const& , Box & , Box & , std::size_t ) {}
};
} // namespace pack_utils
// STR leafs number are calculated as rcount/max
// and the number of splitting planes for each dimension as (count/max)^(1/dimension)
// <-> for dimension==2 -> sqrt(count/max)
//
// The main flaw of this algorithm is that the resulting tree will have bad structure for:
// 1. non-uniformly distributed elements
// Statistic check could be performed, e.g. based on variance of lengths of elements edges for each dimension
// 2. elements distributed mainly along one axis
// Calculate bounding box of all elements and then number of dividing planes for a dimension
// from the length of BB edge for this dimension (more or less assuming that elements are uniformly-distributed squares)
//
// Another thing is that the last node may have less elements than Max or even Min.
// The number of splitting planes must be chosen more carefully than count/max
//
// This algorithm is something between STR and TGS
// it is more similar to the top-down recursive kd-tree creation algorithm
// using object median split and split axis of greatest BB edge
// BB is only used as a hint (assuming objects are distributed uniformly)
//
// Implemented algorithm guarantees that the number of elements in nodes will be between Min and Max
// and that nodes are packed as tightly as possible
// e.g. for 177 values Max = 5 and Min = 2 it will construct the following tree:
// ROOT 177
// L1 125 52
// L2 25 25 25 25 25 25 17 10
// L3 5x5 5x5 5x5 5x5 5x5 5x5 3x5+2 2x5
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class pack
{
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 Allocators::node_pointer node_pointer;
typedef rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
typedef typename Allocators::size_type size_type;
typedef typename geometry::point_type<Box>::type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
typedef typename detail::default_content_result<Box>::type content_type;
typedef typename Options::parameters_type parameters_type;
static const std::size_t dimension = geometry::dimension<point_type>::value;
typedef typename rtree::container_from_elements_type<
typename rtree::elements_type<leaf>::type,
std::size_t
>::type values_counts_container;
typedef typename rtree::elements_type<internal_node>::type internal_elements;
typedef typename internal_elements::value_type internal_element;
public:
// Arbitrary iterators
template <typename InIt> inline static
node_pointer apply(InIt first, InIt last, size_type & values_count, size_type & leafs_level,
parameters_type const& parameters, Translator const& translator, Allocators & allocators)
{
typedef typename std::iterator_traits<InIt>::difference_type diff_type;
diff_type diff = std::distance(first, last);
if ( diff <= 0 )
return node_pointer(0);
typedef std::pair<point_type, InIt> entry_type;
std::vector<entry_type> entries;
values_count = static_cast<size_type>(diff);
entries.reserve(values_count);
expandable_box<Box> hint_box;
for ( ; first != last ; ++first )
{
// NOTE: support for iterators not returning true references adapted
// to Geometry concept and default translator returning true reference
// An alternative would be to dereference the iterator and translate
// in one expression each time the indexable was needed.
typename std::iterator_traits<InIt>::reference in_ref = *first;
typename Translator::result_type indexable = translator(in_ref);
// NOTE: added for consistency with insert()
// CONSIDER: alternative - ignore invalid indexable or throw an exception
BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(indexable), "Indexable is invalid");
hint_box.expand(indexable);
point_type pt;
geometry::centroid(indexable, pt);
entries.push_back(std::make_pair(pt, first));
}
subtree_elements_counts subtree_counts = calculate_subtree_elements_counts(values_count, parameters, leafs_level);
internal_element el = per_level(entries.begin(), entries.end(), hint_box.get(), values_count, subtree_counts,
parameters, translator, allocators);
return el.second;
}
private:
template <typename BoxType>
class expandable_box
{
public:
expandable_box()
: m_initialized(false)
{}
template <typename Indexable>
explicit expandable_box(Indexable const& indexable)
: m_initialized(true)
{
detail::bounds(indexable, m_box);
}
template <typename Indexable>
void expand(Indexable const& indexable)
{
if ( !m_initialized )
{
// it's guaranteed that the Box will be initialized
// only for Points, Boxes and Segments but that's ok
// since only those Geometries can be stored
detail::bounds(indexable, m_box);
m_initialized = true;
}
else
{
geometry::expand(m_box, indexable);
}
}
void expand_by_epsilon()
{
geometry::detail::expand_by_epsilon(m_box);
}
BoxType const& get() const
{
BOOST_GEOMETRY_INDEX_ASSERT(m_initialized, "uninitialized envelope accessed");
return m_box;
}
private:
bool m_initialized;
BoxType m_box;
};
struct subtree_elements_counts
{
subtree_elements_counts(std::size_t ma, std::size_t mi) : maxc(ma), minc(mi) {}
std::size_t maxc;
std::size_t minc;
};
template <typename EIt> inline static
internal_element per_level(EIt first, EIt last, Box const& hint_box, std::size_t values_count, subtree_elements_counts const& subtree_counts,
parameters_type const& parameters, Translator const& translator, Allocators & allocators)
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count,
"unexpected parameters");
if ( subtree_counts.maxc <= 1 )
{
// ROOT or LEAF
BOOST_GEOMETRY_INDEX_ASSERT(values_count <= parameters.get_max_elements(),
"too big number of elements");
// if !root check m_parameters.get_min_elements() <= count
// create new leaf node
node_pointer n = rtree::create_node<Allocators, leaf>::apply(allocators); // MAY THROW (A)
subtree_destroyer auto_remover(n, allocators);
leaf & l = rtree::get<leaf>(*n);
// reserve space for values
rtree::elements(l).reserve(values_count); // MAY THROW (A)
// calculate values box and copy values
// initialize the box explicitly to avoid GCC-4.4 uninitialized variable warnings with O2
expandable_box<Box> elements_box(translator(*(first->second)));
rtree::elements(l).push_back(*(first->second)); // MAY THROW (A?,C)
for ( ++first ; first != last ; ++first )
{
// NOTE: push_back() must be called at the end in order to support move_iterator.
// The iterator is dereferenced 2x (no temporary reference) to support
// non-true reference types and move_iterator without boost::forward<>.
elements_box.expand(translator(*(first->second)));
rtree::elements(l).push_back(*(first->second)); // MAY THROW (A?,C)
}
#ifdef BOOST_GEOMETRY_INDEX_EXPERIMENTAL_ENLARGE_BY_EPSILON
// Enlarge bounds of a leaf node.
// It's because Points and Segments are compared WRT machine epsilon
// This ensures that leafs bounds correspond to the stored elements
// NOTE: this is done only if the Indexable is a different kind of Geometry
// than the bounds (only Box for now). Spatial predicates are checked
// the same way for Geometry of the same kind.
if ( BOOST_GEOMETRY_CONDITION((
! index::detail::is_bounding_geometry
<
typename indexable_type<Translator>::type
>::value )) )
{
elements_box.expand_by_epsilon();
}
#endif
auto_remover.release();
return internal_element(elements_box.get(), n);
}
// calculate next max and min subtree counts
subtree_elements_counts next_subtree_counts = subtree_counts;
next_subtree_counts.maxc /= parameters.get_max_elements();
next_subtree_counts.minc /= parameters.get_max_elements();
// create new internal node
node_pointer n = rtree::create_node<Allocators, internal_node>::apply(allocators); // MAY THROW (A)
subtree_destroyer auto_remover(n, allocators);
internal_node & in = rtree::get<internal_node>(*n);
// reserve space for values
std::size_t nodes_count = calculate_nodes_count(values_count, subtree_counts);
rtree::elements(in).reserve(nodes_count); // MAY THROW (A)
// calculate values box and copy values
expandable_box<Box> elements_box;
per_level_packets(first, last, hint_box, values_count, subtree_counts, next_subtree_counts,
rtree::elements(in), elements_box,
parameters, translator, allocators);
auto_remover.release();
return internal_element(elements_box.get(), n);
}
template <typename EIt, typename ExpandableBox> inline static
void per_level_packets(EIt first, EIt last, Box const& hint_box,
std::size_t values_count,
subtree_elements_counts const& subtree_counts,
subtree_elements_counts const& next_subtree_counts,
internal_elements & elements, ExpandableBox & elements_box,
parameters_type const& parameters, Translator const& translator, Allocators & allocators)
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < std::distance(first, last) && static_cast<std::size_t>(std::distance(first, last)) == values_count,
"unexpected parameters");
BOOST_GEOMETRY_INDEX_ASSERT(subtree_counts.minc <= values_count,
"too small number of elements");
// only one packet
if ( values_count <= subtree_counts.maxc )
{
// the end, move to the next level
internal_element el = per_level(first, last, hint_box, values_count, next_subtree_counts,
parameters, translator, allocators);
// in case if push_back() do throw here
// and even if this is not probable (previously reserved memory, nonthrowing pairs copy)
// this case is also tested by exceptions test.
subtree_destroyer auto_remover(el.second, allocators);
// this container should have memory allocated, reserve() called outside
elements.push_back(el); // MAY THROW (A?,C) - however in normal conditions shouldn't
auto_remover.release();
elements_box.expand(el.first);
return;
}
std::size_t median_count = calculate_median_count(values_count, subtree_counts);
EIt median = first + median_count;
coordinate_type greatest_length;
std::size_t greatest_dim_index = 0;
pack_utils::biggest_edge<dimension>::apply(hint_box, greatest_length, greatest_dim_index);
Box left, right;
pack_utils::nth_element_and_half_boxes<0, dimension>
::apply(first, median, last, hint_box, left, right, greatest_dim_index);
per_level_packets(first, median, left,
median_count, subtree_counts, next_subtree_counts,
elements, elements_box,
parameters, translator, allocators);
per_level_packets(median, last, right,
values_count - median_count, subtree_counts, next_subtree_counts,
elements, elements_box,
parameters, translator, allocators);
}
inline static
subtree_elements_counts calculate_subtree_elements_counts(std::size_t elements_count, parameters_type const& parameters, size_type & leafs_level)
{
boost::ignore_unused_variable_warning(parameters);
subtree_elements_counts res(1, 1);
leafs_level = 0;
std::size_t smax = parameters.get_max_elements();
for ( ; smax < elements_count ; smax *= parameters.get_max_elements(), ++leafs_level )
res.maxc = smax;
res.minc = parameters.get_min_elements() * (res.maxc / parameters.get_max_elements());
return res;
}
inline static
std::size_t calculate_nodes_count(std::size_t count,
subtree_elements_counts const& subtree_counts)
{
std::size_t n = count / subtree_counts.maxc;
std::size_t r = count % subtree_counts.maxc;
if ( 0 < r && r < subtree_counts.minc )
{
std::size_t count_minus_min = count - subtree_counts.minc;
n = count_minus_min / subtree_counts.maxc;
r = count_minus_min % subtree_counts.maxc;
++n;
}
if ( 0 < r )
++n;
return n;
}
inline static
std::size_t calculate_median_count(std::size_t count,
subtree_elements_counts const& subtree_counts)
{
// e.g. for max = 5, min = 2, count = 52, subtree_max = 25, subtree_min = 10
std::size_t n = count / subtree_counts.maxc; // e.g. 52 / 25 = 2
std::size_t r = count % subtree_counts.maxc; // e.g. 52 % 25 = 2
std::size_t median_count = (n / 2) * subtree_counts.maxc; // e.g. 2 / 2 * 25 = 25
if ( 0 != r ) // e.g. 0 != 2
{
if ( subtree_counts.minc <= r ) // e.g. 10 <= 2 == false
{
//BOOST_GEOMETRY_INDEX_ASSERT(0 < n, "unexpected value");
median_count = ((n+1)/2) * subtree_counts.maxc; // if calculated ((2+1)/2) * 25 which would be ok, but not in all cases
}
else // r < subtree_counts.second // e.g. 2 < 10 == true
{
std::size_t count_minus_min = count - subtree_counts.minc; // e.g. 52 - 10 = 42
n = count_minus_min / subtree_counts.maxc; // e.g. 42 / 25 = 1
r = count_minus_min % subtree_counts.maxc; // e.g. 42 % 25 = 17
if ( r == 0 ) // e.g. false
{
// n can't be equal to 0 because then there wouldn't be any element in the other node
//BOOST_GEOMETRY_INDEX_ASSERT(0 < n, "unexpected value");
median_count = ((n+1)/2) * subtree_counts.maxc; // if calculated ((1+1)/2) * 25 which would be ok, but not in all cases
}
else
{
if ( n == 0 ) // e.g. false
median_count = r; // if calculated -> 17 which is wrong!
else
median_count = ((n+2)/2) * subtree_counts.maxc; // e.g. ((1+2)/2) * 25 = 25
}
}
}
return median_count;
}
};
}}}}} // namespace boost::geometry::index::detail::rtree
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_PACK_CREATE_HPP
@@ -0,0 +1,16 @@
// Boost.Geometry Index
//
// R-tree quadratic 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_QUADRATIC_QUADRATIC_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP
#include <boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp>
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP
@@ -0,0 +1,295 @@
// Boost.Geometry Index
//
// R-tree quadratic split 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_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
#include <algorithm>
#include <boost/geometry/index/detail/algorithms/content.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 quadratic {
template <typename Box, typename Elements, typename Parameters, typename Translator>
inline void pick_seeds(Elements const& elements,
Parameters const& parameters,
Translator const& tr,
size_t & seed1,
size_t & seed2)
{
typedef typename Elements::value_type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
typedef Box box_type;
typedef typename index::detail::default_content_result<box_type>::type content_type;
typedef index::detail::bounded_view<indexable_type, box_type> bounded_indexable_view;
const size_t elements_count = parameters.get_max_elements() + 1;
BOOST_GEOMETRY_INDEX_ASSERT(elements.size() == elements_count, "wrong number of elements");
BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements_count, "unexpected number of elements");
content_type greatest_free_content = 0;
seed1 = 0;
seed2 = 1;
for ( size_t i = 0 ; i < elements_count - 1 ; ++i )
{
for ( size_t j = i + 1 ; j < elements_count ; ++j )
{
indexable_type const& ind1 = rtree::element_indexable(elements[i], tr);
indexable_type const& ind2 = rtree::element_indexable(elements[j], tr);
box_type enlarged_box;
detail::bounds(ind1, enlarged_box);
geometry::expand(enlarged_box, ind2);
bounded_indexable_view bounded_ind1(ind1);
bounded_indexable_view bounded_ind2(ind2);
content_type free_content = ( index::detail::content(enlarged_box)
- index::detail::content(bounded_ind1) )
- index::detail::content(bounded_ind2);
if ( greatest_free_content < free_content )
{
greatest_free_content = free_content;
seed1 = i;
seed2 = j;
}
}
}
::boost::ignore_unused_variable_warning(parameters);
}
} // namespace quadratic
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadratic_tag>
{
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 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;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
elements_type & elements1 = rtree::elements(n);
elements_type & elements2 = rtree::elements(second_node);
BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == parameters.get_max_elements() + 1, "unexpected elements number");
// 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 (alloc, copy)
container_type elements_backup(elements1.begin(), elements1.end()); // MAY THROW, STRONG (alloc, copy)
// calculate initial seeds
size_t seed1 = 0;
size_t seed2 = 0;
quadratic::pick_seeds<Box>(elements_copy, parameters, translator, seed1, seed2);
// prepare nodes' elements containers
elements1.clear();
BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "second node's elements container should be empty");
BOOST_TRY
{
// add seeds
elements1.push_back(elements_copy[seed1]); // MAY THROW, STRONG (copy)
elements2.push_back(elements_copy[seed2]); // MAY THROW, STRONG (alloc, copy)
// calculate boxes
detail::bounds(rtree::element_indexable(elements_copy[seed1], translator), box1);
detail::bounds(rtree::element_indexable(elements_copy[seed2], translator), box2);
// remove seeds
if (seed1 < seed2)
{
rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
elements_copy.pop_back();
rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
elements_copy.pop_back();
}
else
{
rtree::move_from_back(elements_copy, elements_copy.begin() + seed1); // MAY THROW, STRONG (copy)
elements_copy.pop_back();
rtree::move_from_back(elements_copy, elements_copy.begin() + seed2); // MAY THROW, STRONG (copy)
elements_copy.pop_back();
}
// initialize areas
content_type content1 = index::detail::content(box1);
content_type content2 = index::detail::content(box2);
size_t remaining = elements_copy.size();
// redistribute the rest of the elements
while ( !elements_copy.empty() )
{
typename container_type::reverse_iterator el_it = elements_copy.rbegin();
bool insert_into_group1 = false;
size_t elements1_count = elements1.size();
size_t elements2_count = elements2.size();
// if there is small number of elements left and the number of elements in node is lesser than min_elems
// just insert them to this node
if ( elements1_count + remaining <= parameters.get_min_elements() )
{
insert_into_group1 = true;
}
else if ( elements2_count + remaining <= parameters.get_min_elements() )
{
insert_into_group1 = false;
}
// insert the best element
else
{
// find element with minimum groups areas increses differences
content_type content_increase1 = 0;
content_type content_increase2 = 0;
el_it = pick_next(elements_copy.rbegin(), elements_copy.rend(),
box1, box2, content1, content2, translator,
content_increase1, content_increase2);
if ( content_increase1 < content_increase2 ||
( content_increase1 == content_increase2 && ( content1 < content2 ||
( content1 == content2 && elements1_count <= elements2_count ) )
) )
{
insert_into_group1 = true;
}
else
{
insert_into_group1 = false;
}
}
// move element to the choosen group
element_type const& elem = *el_it;
indexable_type const& indexable = rtree::element_indexable(elem, translator);
if ( insert_into_group1 )
{
elements1.push_back(elem); // MAY THROW, STRONG (copy)
geometry::expand(box1, indexable);
content1 = index::detail::content(box1);
}
else
{
elements2.push_back(elem); // MAY THROW, STRONG (alloc, copy)
geometry::expand(box2, indexable);
content2 = index::detail::content(box2);
}
BOOST_GEOMETRY_INDEX_ASSERT(!elements_copy.empty(), "expected more elements");
typename container_type::iterator el_it_base = el_it.base();
rtree::move_from_back(elements_copy, --el_it_base); // MAY THROW, STRONG (copy)
elements_copy.pop_back();
BOOST_GEOMETRY_INDEX_ASSERT(0 < remaining, "expected more remaining elements");
--remaining;
}
}
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
}
// TODO: awulkiew - change following function to static member of the pick_next class?
template <typename It>
static inline It pick_next(It first, It last,
Box const& box1, Box const& box2,
content_type const& content1, content_type const& content2,
Translator const& translator,
content_type & out_content_increase1, content_type & out_content_increase2)
{
typedef typename boost::iterator_value<It>::type element_type;
typedef typename rtree::element_indexable_type<element_type, Translator>::type indexable_type;
content_type greatest_content_incrase_diff = 0;
It out_it = first;
out_content_increase1 = 0;
out_content_increase2 = 0;
// find element with greatest difference between increased group's boxes areas
for ( It el_it = first ; el_it != last ; ++el_it )
{
indexable_type const& indexable = rtree::element_indexable(*el_it, translator);
// calculate enlarged boxes and areas
Box enlarged_box1(box1);
Box enlarged_box2(box2);
geometry::expand(enlarged_box1, indexable);
geometry::expand(enlarged_box2, indexable);
content_type enlarged_content1 = index::detail::content(enlarged_box1);
content_type enlarged_content2 = index::detail::content(enlarged_box2);
content_type content_incrase1 = (enlarged_content1 - content1);
content_type content_incrase2 = (enlarged_content2 - content2);
content_type content_incrase_diff = content_incrase1 < content_incrase2 ?
content_incrase2 - content_incrase1 : content_incrase1 - content_incrase2;
if ( greatest_content_incrase_diff < content_incrase_diff )
{
greatest_content_incrase_diff = content_incrase_diff;
out_it = el_it;
out_content_increase1 = content_incrase1;
out_content_increase2 = content_incrase2;
}
}
return out_it;
}
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP
@@ -0,0 +1,387 @@
// Boost.Geometry Index
//
// R-tree query iterators
//
// 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_QUERY_ITERATORS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP
#include <boost/scoped_ptr.hpp>
//#define BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace iterators {
template <typename Value, typename Allocators>
struct end_query_iterator
{
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
reference operator*() const
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable");
pointer p(0);
return *p;
}
const value_type * operator->() const
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not dereferencable");
const value_type * p = 0;
return p;
}
end_query_iterator & operator++()
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable");
return *this;
}
end_query_iterator operator++(int)
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "iterator not incrementable");
return *this;
}
friend bool operator==(end_query_iterator const& /*l*/, end_query_iterator const& /*r*/)
{
return true;
}
};
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates>
class spatial_query_iterator
{
typedef visitors::spatial_query_incremental<Value, Options, Translator, Box, Allocators, Predicates> visitor_type;
typedef typename visitor_type::node_pointer node_pointer;
public:
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
inline spatial_query_iterator()
{}
inline spatial_query_iterator(Translator const& t, Predicates const& p)
: m_visitor(t, p)
{}
inline spatial_query_iterator(node_pointer root, Translator const& t, Predicates const& p)
: m_visitor(t, p)
{
m_visitor.initialize(root);
}
reference operator*() const
{
return m_visitor.dereference();
}
const value_type * operator->() const
{
return boost::addressof(m_visitor.dereference());
}
spatial_query_iterator & operator++()
{
m_visitor.increment();
return *this;
}
spatial_query_iterator operator++(int)
{
spatial_query_iterator temp = *this;
this->operator++();
return temp;
}
friend bool operator==(spatial_query_iterator const& l, spatial_query_iterator const& r)
{
return l.m_visitor == r.m_visitor;
}
friend bool operator==(spatial_query_iterator const& l, end_query_iterator<Value, Allocators> const& /*r*/)
{
return l.m_visitor.is_end();
}
friend bool operator==(end_query_iterator<Value, Allocators> const& /*l*/, spatial_query_iterator const& r)
{
return r.m_visitor.is_end();
}
private:
visitor_type m_visitor;
};
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates, unsigned NearestPredicateIndex>
class distance_query_iterator
{
typedef visitors::distance_query_incremental<Value, Options, Translator, Box, Allocators, Predicates, NearestPredicateIndex> visitor_type;
typedef typename visitor_type::node_pointer node_pointer;
public:
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
inline distance_query_iterator()
{}
inline distance_query_iterator(Translator const& t, Predicates const& p)
: m_visitor(t, p)
{}
inline distance_query_iterator(node_pointer root, Translator const& t, Predicates const& p)
: m_visitor(t, p)
{
m_visitor.initialize(root);
}
reference operator*() const
{
return m_visitor.dereference();
}
const value_type * operator->() const
{
return boost::addressof(m_visitor.dereference());
}
distance_query_iterator & operator++()
{
m_visitor.increment();
return *this;
}
distance_query_iterator operator++(int)
{
distance_query_iterator temp = *this;
this->operator++();
return temp;
}
friend bool operator==(distance_query_iterator const& l, distance_query_iterator const& r)
{
return l.m_visitor == r.m_visitor;
}
friend bool operator==(distance_query_iterator const& l, end_query_iterator<Value, Allocators> const& /*r*/)
{
return l.m_visitor.is_end();
}
friend bool operator==(end_query_iterator<Value, Allocators> const& /*l*/, distance_query_iterator const& r)
{
return r.m_visitor.is_end();
}
private:
visitor_type m_visitor;
};
template <typename L, typename R>
inline bool operator!=(L const& l, R const& r)
{
return !(l == r);
}
template <typename Value, typename Allocators>
class query_iterator_base
{
public:
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
virtual ~query_iterator_base() {}
virtual query_iterator_base * clone() const = 0;
virtual bool is_end() const = 0;
virtual reference dereference() const = 0;
virtual void increment() = 0;
virtual bool equals(query_iterator_base const&) const = 0;
};
template <typename Value, typename Allocators, typename Iterator>
class query_iterator_wrapper
: public query_iterator_base<Value, Allocators>
{
typedef query_iterator_base<Value, Allocators> base_t;
public:
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
query_iterator_wrapper() : m_iterator() {}
explicit query_iterator_wrapper(Iterator const& it) : m_iterator(it) {}
virtual base_t * clone() const { return new query_iterator_wrapper(m_iterator); }
virtual bool is_end() const { return m_iterator == end_query_iterator<Value, Allocators>(); }
virtual reference dereference() const { return *m_iterator; }
virtual void increment() { ++m_iterator; }
virtual bool equals(base_t const& r) const
{
const query_iterator_wrapper * p = dynamic_cast<const query_iterator_wrapper *>(boost::addressof(r));
BOOST_GEOMETRY_INDEX_ASSERT(p, "iterators can't be compared");
return m_iterator == p->m_iterator;
}
private:
Iterator m_iterator;
};
template <typename Value, typename Allocators>
class query_iterator
{
typedef query_iterator_base<Value, Allocators> iterator_base;
typedef boost::scoped_ptr<iterator_base> iterator_ptr;
public:
typedef std::forward_iterator_tag iterator_category;
typedef Value value_type;
typedef typename Allocators::const_reference reference;
typedef typename Allocators::difference_type difference_type;
typedef typename Allocators::const_pointer pointer;
query_iterator()
{}
template <typename It>
query_iterator(It const& it)
: m_ptr(static_cast<iterator_base*>(
new query_iterator_wrapper<Value, Allocators, It>(it) ))
{}
query_iterator(end_query_iterator<Value, Allocators> const& /*it*/)
{}
query_iterator(query_iterator const& o)
: m_ptr(o.m_ptr.get() ? o.m_ptr->clone() : 0)
{}
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
query_iterator & operator=(query_iterator const& o)
{
if ( this != boost::addressof(o) )
{
m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0);
}
return *this;
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
query_iterator(query_iterator && o)
: m_ptr(0)
{
m_ptr.swap(o.m_ptr);
}
query_iterator & operator=(query_iterator && o)
{
if ( this != boost::addressof(o) )
{
m_ptr.swap(o.m_ptr);
o.m_ptr.reset();
}
return *this;
}
#endif
#else // !BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
private:
BOOST_COPYABLE_AND_MOVABLE(query_iterator)
public:
query_iterator & operator=(BOOST_COPY_ASSIGN_REF(query_iterator) o)
{
if ( this != boost::addressof(o) )
{
m_ptr.reset(o.m_ptr.get() ? o.m_ptr->clone() : 0);
}
return *this;
}
query_iterator(BOOST_RV_REF(query_iterator) o)
: m_ptr(0)
{
m_ptr.swap(o.m_ptr);
}
query_iterator & operator=(BOOST_RV_REF(query_iterator) o)
{
if ( this != boost::addressof(o) )
{
m_ptr.swap(o.m_ptr);
o.m_ptr.reset();
}
return *this;
}
#endif // BOOST_GEOMETRY_INDEX_DETAIL_QUERY_ITERATORS_USE_MOVE
reference operator*() const
{
return m_ptr->dereference();
}
const value_type * operator->() const
{
return boost::addressof(m_ptr->dereference());
}
query_iterator & operator++()
{
m_ptr->increment();
return *this;
}
query_iterator operator++(int)
{
query_iterator temp = *this;
this->operator++();
return temp;
}
friend bool operator==(query_iterator const& l, query_iterator const& r)
{
if ( l.m_ptr.get() )
{
if ( r.m_ptr.get() )
return l.m_ptr->equals(*r.m_ptr);
else
return l.m_ptr->is_end();
}
else
{
if ( r.m_ptr.get() )
return r.m_ptr->is_end();
else
return true;
}
}
private:
iterator_ptr m_ptr;
};
}}}}}} // namespace boost::geometry::index::detail::rtree::iterators
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUERY_ITERATORS_HPP
@@ -0,0 +1,234 @@
// Boost.Geometry Index
//
// R-tree R*-tree next node choosing 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_CHOOSE_NEXT_NODE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
#include <algorithm>
#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_variable_warning(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:
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
typedef boost::tuple<size_t, content_type, content_type> child_contents;
typename rtree::container_from_elements_type<children_type, child_contents>::type children_contents;
children_contents.resize(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] = boost::make_tuple(i, content_diff, content);
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(boost::tuple<size_t, content_type, content_type> const& p1, boost::tuple<size_t, content_type, content_type> const& p2)
{
return boost::get<1>(p1) < boost::get<1>(p2) ||
(boost::get<1>(p1) == boost::get<1>(p2) && boost::get<2>(p1) < boost::get<2>(p2));
}
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 i = 0 ; i < first_n_children_count ; ++i )
{
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);
}
}
}
content_type content = boost::get<2>(children_contents[i]);
content_type content_diff = boost::get<1>(children_contents[i]);
// 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
@@ -0,0 +1,591 @@
// 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/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_variable_warning(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
@@ -0,0 +1,470 @@
// 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/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_variable_warning(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
@@ -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
@@ -0,0 +1,128 @@
// Boost.Geometry Index
//
// R-tree boxes validating visitor 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_UTILITIES_ARE_BOXES_OK_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/index/detail/rtree/node/node.hpp>
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class are_boxes_ok
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
public:
are_boxes_ok(Translator const& tr, bool exact_match)
: result(false), m_tr(tr), m_is_root(true), m_exact_match(exact_match)
{}
void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
if (elements.empty())
{
result = false;
return;
}
Box box_bckup = m_box;
bool is_root_bckup = m_is_root;
m_is_root = false;
for ( typename elements_type::const_iterator it = elements.begin();
it != elements.end() ; ++it)
{
m_box = it->first;
rtree::apply_visitor(*this, *it->second);
if ( result == false )
return;
}
m_box = box_bckup;
m_is_root = is_root_bckup;
Box box_exp = rtree::elements_box<Box>(elements.begin(), elements.end(), m_tr);
if ( m_exact_match )
result = m_is_root || geometry::equals(box_exp, m_box);
else
result = m_is_root || geometry::covered_by(box_exp, m_box);
}
void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// non-root node
if (!m_is_root)
{
if ( elements.empty() )
{
result = false;
return;
}
Box box_exp = rtree::values_box<Box>(elements.begin(), elements.end(), m_tr);
if ( m_exact_match )
result = geometry::equals(box_exp, m_box);
else
result = geometry::covered_by(box_exp, m_box);
}
else
result = true;
}
bool result;
private:
Translator const& m_tr;
Box m_box;
bool m_is_root;
bool m_exact_match;
};
} // namespace visitors
template <typename Rtree> inline
bool are_boxes_ok(Rtree const& tree, bool exact_match = true)
{
typedef utilities::view<Rtree> RTV;
RTV rtv(tree);
visitors::are_boxes_ok<
typename RTV::value_type,
typename RTV::options_type,
typename RTV::translator_type,
typename RTV::box_type,
typename RTV::allocators_type
> v(rtv.translator(), exact_match);
rtv.apply_visitor(v);
return v.result;
}
}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_BOXES_OK_HPP
@@ -0,0 +1,110 @@
// Boost.Geometry Index
//
// R-tree nodes elements numbers validating visitor 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_UTILITIES_ARE_COUNTS_OK_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_COUNTS_OK_HPP
#include <boost/geometry/index/detail/rtree/node/node.hpp>
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
namespace visitors {
template <typename Value, typename Options, typename Box, typename Allocators>
class are_counts_ok
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
public:
inline are_counts_ok(parameters_type const& parameters)
: result(true), m_current_level(0), m_parameters(parameters)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// root internal node shouldn't contain 0 elements
if ( elements.empty()
|| !check_count(elements) )
{
result = false;
return;
}
size_t current_level_backup = m_current_level;
++m_current_level;
for ( typename elements_type::const_iterator it = elements.begin();
it != elements.end() && result == true ;
++it)
{
rtree::apply_visitor(*this, *it->second);
}
m_current_level = current_level_backup;
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// empty leaf in non-root node
if ( ( m_current_level > 0 && elements.empty() )
|| !check_count(elements) )
{
result = false;
}
}
bool result;
private:
template <typename Elements>
bool check_count(Elements const& elements)
{
// root may contain count < min but should never contain count > max
return elements.size() <= m_parameters.get_max_elements()
&& ( elements.size() >= m_parameters.get_min_elements()
|| m_current_level == 0 );
}
size_t m_current_level;
parameters_type const& m_parameters;
};
} // namespace visitors
template <typename Rtree> inline
bool are_counts_ok(Rtree const& tree)
{
typedef utilities::view<Rtree> RTV;
RTV rtv(tree);
visitors::are_counts_ok<
typename RTV::value_type,
typename RTV::options_type,
typename RTV::box_type,
typename RTV::allocators_type
> v(tree.parameters());
rtv.apply_visitor(v);
return v.result;
}
}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_COUNTS_OK_HPP
@@ -0,0 +1,109 @@
// Boost.Geometry Index
//
// R-tree levels validating visitor 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_UTILITIES_ARE_LEVELS_OK_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP
#include <boost/geometry/index/detail/rtree/node/node.hpp>
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
namespace visitors {
template <typename Value, typename Options, typename Box, typename Allocators>
class are_levels_ok
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
public:
inline are_levels_ok()
: result(true), m_leafs_level((std::numeric_limits<size_t>::max)()), m_current_level(0)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
if (elements.empty())
{
result = false;
return;
}
size_t current_level_backup = m_current_level;
++m_current_level;
for ( typename elements_type::const_iterator it = elements.begin();
it != elements.end() ; ++it)
{
rtree::apply_visitor(*this, *it->second);
if ( result == false )
return;
}
m_current_level = current_level_backup;
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// empty leaf in non-root node
if (0 < m_current_level && elements.empty())
{
result = false;
return;
}
if ( m_leafs_level == (std::numeric_limits<size_t>::max)() )
{
m_leafs_level = m_current_level;
}
else if ( m_leafs_level != m_current_level )
{
result = false;
}
}
bool result;
private:
size_t m_leafs_level;
size_t m_current_level;
};
} // namespace visitors
template <typename Rtree> inline
bool are_levels_ok(Rtree const& tree)
{
typedef utilities::view<Rtree> RTV;
RTV rtv(tree);
visitors::are_levels_ok<
typename RTV::value_type,
typename RTV::options_type,
typename RTV::box_type,
typename RTV::allocators_type
> v;
rtv.apply_visitor(v);
return v.result;
}
}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_ARE_LEVELS_OK_HPP
@@ -0,0 +1,243 @@
// Boost.Geometry Index
//
// R-tree OpenGL drawing visitor 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_UTILITIES_GL_DRAW_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
namespace utilities {
namespace dispatch {
template <typename Point, size_t Dimension>
struct gl_draw_point
{};
template <typename Point>
struct gl_draw_point<Point, 2>
{
static inline void apply(Point const& p, typename coordinate_type<Point>::type z)
{
typename coordinate_type<Point>::type const& x = geometry::get<0>(p);
typename coordinate_type<Point>::type const& y = geometry::get<1>(p);
/*glBegin(GL_POINT);
glVertex3f(x, y, z);
glEnd();*/
glBegin(GL_QUADS);
glVertex3f(x+1, y, z);
glVertex3f(x, y+1, z);
glVertex3f(x-1, y, z);
glVertex3f(x, y-1, z);
glEnd();
}
};
template <typename Box, size_t Dimension>
struct gl_draw_box
{};
template <typename Box>
struct gl_draw_box<Box, 2>
{
static inline void apply(Box const& b, typename coordinate_type<Box>::type z)
{
glBegin(GL_LINE_LOOP);
glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<min_corner, 1>(b), z);
glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<min_corner, 1>(b), z);
glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<max_corner, 1>(b), z);
glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<max_corner, 1>(b), z);
glEnd();
}
};
template <typename Segment, size_t Dimension>
struct gl_draw_segment
{};
template <typename Segment>
struct gl_draw_segment<Segment, 2>
{
static inline void apply(Segment const& s, typename coordinate_type<Segment>::type z)
{
glBegin(GL_LINES);
glVertex3f(geometry::get<0, 0>(s), geometry::get<0, 1>(s), z);
glVertex3f(geometry::get<1, 0>(s), geometry::get<1, 1>(s), z);
glEnd();
}
};
template <typename Indexable, typename Tag>
struct gl_draw_indexable
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag));
};
template <typename Box>
struct gl_draw_indexable<Box, box_tag>
: gl_draw_box<Box, geometry::dimension<Box>::value>
{};
template <typename Point>
struct gl_draw_indexable<Point, point_tag>
: gl_draw_point<Point, geometry::dimension<Point>::value>
{};
template <typename Segment>
struct gl_draw_indexable<Segment, segment_tag>
: gl_draw_segment<Segment, geometry::dimension<Segment>::value>
{};
} // namespace dispatch
template <typename Indexable> inline
void gl_draw_indexable(Indexable const& i, typename coordinate_type<Indexable>::type z)
{
dispatch::gl_draw_indexable<
Indexable,
typename tag<Indexable>::type
>::apply(i, z);
}
} // namespace utilities
namespace rtree { namespace utilities {
namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct gl_draw : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
inline gl_draw(Translator const& t,
size_t level_first = 0,
size_t level_last = (std::numeric_limits<size_t>::max)(),
typename coordinate_type<Box>::type z_coord_level_multiplier = 1
)
: tr(t)
, level_f(level_first)
, level_l(level_last)
, z_mul(z_coord_level_multiplier)
, level(0)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
if ( level_f <= level )
{
size_t level_rel = level - level_f;
if ( level_rel == 0 )
glColor3f(0.75f, 0.0f, 0.0f);
else if ( level_rel == 1 )
glColor3f(0.0f, 0.75f, 0.0f);
else if ( level_rel == 2 )
glColor3f(0.0f, 0.0f, 0.75f);
else if ( level_rel == 3 )
glColor3f(0.75f, 0.75f, 0.0f);
else if ( level_rel == 4 )
glColor3f(0.75f, 0.0f, 0.75f);
else if ( level_rel == 5 )
glColor3f(0.0f, 0.75f, 0.75f);
else
glColor3f(0.5f, 0.5f, 0.5f);
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
detail::utilities::gl_draw_indexable(it->first, level_rel * z_mul);
}
}
size_t level_backup = level;
++level;
if ( level < level_l )
{
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
rtree::apply_visitor(*this, *it->second);
}
}
level = level_backup;
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
if ( level_f <= level )
{
size_t level_rel = level - level_f;
glColor3f(0.25f, 0.25f, 0.25f);
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
detail::utilities::gl_draw_indexable(tr(*it), level_rel * z_mul);
}
}
}
Translator const& tr;
size_t level_f;
size_t level_l;
typename coordinate_type<Box>::type z_mul;
size_t level;
};
} // namespace visitors
template <typename Rtree> inline
void gl_draw(Rtree const& tree,
size_t level_first = 0,
size_t level_last = (std::numeric_limits<size_t>::max)(),
typename coordinate_type<
typename Rtree::bounds_type
>::type z_coord_level_multiplier = 1
)
{
typedef utilities::view<Rtree> RTV;
RTV rtv(tree);
if ( !tree.empty() )
{
glColor3f(0.75f, 0.75f, 0.75f);
detail::utilities::gl_draw_indexable(tree.bounds(), 0);
}
visitors::gl_draw<
typename RTV::value_type,
typename RTV::options_type,
typename RTV::translator_type,
typename RTV::box_type,
typename RTV::allocators_type
> gl_draw_v(rtv.translator(), level_first, level_last, z_coord_level_multiplier);
rtv.apply_visitor(gl_draw_v);
}
}} // namespace rtree::utilities
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_GL_DRAW_HPP
@@ -0,0 +1,219 @@
// Boost.Geometry Index
//
// R-tree ostreaming visitor 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_UTILITIES_PRINT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP
#include <iostream>
namespace boost { namespace geometry { namespace index { namespace detail {
namespace utilities {
namespace dispatch {
template <typename Point, size_t Dimension>
struct print_point
{
BOOST_STATIC_ASSERT(0 < Dimension);
static inline void apply(std::ostream & os, Point const& p)
{
print_point<Point, Dimension - 1>::apply(os, p);
os << ", " << geometry::get<Dimension - 1>(p);
}
};
template <typename Point>
struct print_point<Point, 1>
{
static inline void apply(std::ostream & os, Point const& p)
{
os << geometry::get<0>(p);
}
};
template <typename Box, size_t Corner, size_t Dimension>
struct print_corner
{
BOOST_STATIC_ASSERT(0 < Dimension);
static inline void apply(std::ostream & os, Box const& b)
{
print_corner<Box, Corner, Dimension - 1>::apply(os, b);
os << ", " << geometry::get<Corner, Dimension - 1>(b);
}
};
template <typename Box, size_t Corner>
struct print_corner<Box, Corner, 1>
{
static inline void apply(std::ostream & os, Box const& b)
{
os << geometry::get<Corner, 0>(b);
}
};
template <typename Indexable, typename Tag>
struct print_indexable
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag));
};
template <typename Indexable>
struct print_indexable<Indexable, box_tag>
{
static const size_t dimension = geometry::dimension<Indexable>::value;
static inline void apply(std::ostream &os, Indexable const& i)
{
os << '(';
print_corner<Indexable, min_corner, dimension>::apply(os, i);
os << ")x(";
print_corner<Indexable, max_corner, dimension>::apply(os, i);
os << ')';
}
};
template <typename Indexable>
struct print_indexable<Indexable, point_tag>
{
static const size_t dimension = geometry::dimension<Indexable>::value;
static inline void apply(std::ostream &os, Indexable const& i)
{
os << '(';
print_point<Indexable, dimension>::apply(os, i);
os << ')';
}
};
template <typename Indexable>
struct print_indexable<Indexable, segment_tag>
{
static const size_t dimension = geometry::dimension<Indexable>::value;
static inline void apply(std::ostream &os, Indexable const& i)
{
os << '(';
print_corner<Indexable, 0, dimension>::apply(os, i);
os << ")-(";
print_corner<Indexable, 1, dimension>::apply(os, i);
os << ')';
}
};
} // namespace dispatch
template <typename Indexable> inline
void print_indexable(std::ostream & os, Indexable const& i)
{
dispatch::print_indexable<
Indexable,
typename tag<Indexable>::type
>::apply(os, i);
}
} // namespace utilities
namespace rtree { namespace utilities {
namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct print : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
inline print(std::ostream & o, Translator const& t)
: os(o), tr(t), level(0)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
spaces(level) << "INTERNAL NODE - L:" << level << " Ch:" << elements.size() << " @:" << &n << '\n';
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
spaces(level);
detail::utilities::print_indexable(os, it->first);
os << " ->" << it->second << '\n';
}
size_t level_backup = level;
++level;
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
rtree::apply_visitor(*this, *it->second);
}
level = level_backup;
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
spaces(level) << "LEAF - L:" << level << " V:" << elements.size() << " @:" << &n << '\n';
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
spaces(level);
detail::utilities::print_indexable(os, tr(*it));
os << '\n';
}
}
inline std::ostream & spaces(size_t level)
{
for ( size_t i = 0 ; i < 2 * level ; ++i )
os << ' ';
return os;
}
std::ostream & os;
Translator const& tr;
size_t level;
};
} // namespace visitors
template <typename Rtree> inline
void print(std::ostream & os, Rtree const& tree)
{
typedef utilities::view<Rtree> RTV;
RTV rtv(tree);
visitors::print<
typename RTV::value_type,
typename RTV::options_type,
typename RTV::translator_type,
typename RTV::box_type,
typename RTV::allocators_type
> print_v(os, rtv.translator());
rtv.apply_visitor(print_v);
}
}} // namespace rtree::utilities
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_PRINT_HPP
@@ -0,0 +1,105 @@
// Boost.Geometry Index
//
// R-tree visitor collecting basic statistics
//
// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2013 Mateusz Loskot, London, UK.
//
// 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_UTILITIES_STATISTICS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP
#include <algorithm>
#include <boost/tuple/tuple.hpp>
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace utilities {
namespace visitors {
template <typename Value, typename Options, typename Box, typename Allocators>
struct statistics : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
inline statistics()
: level(0)
, levels(1) // count root
, nodes(0)
, leaves(0)
, values(0)
, values_min(0)
, values_max(0)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
++nodes; // count node
size_t const level_backup = level;
++level;
levels += level++ > levels ? 1 : 0; // count level (root already counted)
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
rtree::apply_visitor(*this, *it->second);
}
level = level_backup;
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
++leaves; // count leaves
std::size_t const v = elements.size();
// count values spread per node and total
values_min = (std::min)(values_min == 0 ? v : values_min, v);
values_max = (std::max)(values_max, v);
values += v;
}
std::size_t level;
std::size_t levels;
std::size_t nodes;
std::size_t leaves;
std::size_t values;
std::size_t values_min;
std::size_t values_max;
};
} // namespace visitors
template <typename Rtree> inline
boost::tuple<std::size_t, std::size_t, std::size_t, std::size_t, std::size_t, std::size_t>
statistics(Rtree const& tree)
{
typedef utilities::view<Rtree> RTV;
RTV rtv(tree);
visitors::statistics<
typename RTV::value_type,
typename RTV::options_type,
typename RTV::box_type,
typename RTV::allocators_type
> stats_v;
rtv.apply_visitor(stats_v);
return boost::make_tuple(stats_v.levels, stats_v.nodes, stats_v.leaves, stats_v.values, stats_v.values_min, stats_v.values_max);
}
}}}}}} // namespace boost::geometry::index::detail::rtree::utilities
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_STATISTICS_HPP
@@ -0,0 +1,61 @@
// Boost.Geometry Index
//
// Rtree utilities view
//
// 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_UTILITIES_VIEW_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace utilities {
template <typename Rtree>
class view
{
public:
typedef typename Rtree::size_type size_type;
typedef typename Rtree::translator_type translator_type;
typedef typename Rtree::value_type value_type;
typedef typename Rtree::options_type options_type;
typedef typename Rtree::box_type box_type;
typedef typename Rtree::allocators_type allocators_type;
view(Rtree const& rt) : m_rtree(rt) {}
template <typename Visitor>
void apply_visitor(Visitor & vis) const
{
m_rtree.apply_visitor(vis);
}
// This will most certainly be removed in the future
translator_type translator() const
{
return m_rtree.translator();
}
// This will probably be removed in the future
size_type depth() const
{
return m_rtree.depth();
}
private:
view(view const&);
view & operator=(view const&);
Rtree const& m_rtree;
};
}}} // namespace detail::rtree::utilities
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_UTILITIES_VIEW_HPP
@@ -0,0 +1,55 @@
// Boost.Geometry Index
//
// R-tree node children box calculating visitor 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_VISITORS_CHILDREN_BOX_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class children_box
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
public:
inline children_box(Box & result, Translator const& tr)
: m_result(result), m_tr(tr)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
m_result = rtree::elements_box<Box>(elements.begin(), elements.end(), m_tr);
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
m_result = rtree::values_box<Box>(elements.begin(), elements.end(), m_tr);
}
private:
Box & m_result;
Translator const& m_tr;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_CHILDREN_BOX_HPP
@@ -0,0 +1,92 @@
// Boost.Geometry Index
//
// R-tree deep copying visitor 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_VISITORS_COPY_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class copy
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
{
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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
typedef typename Allocators::node_pointer node_pointer;
explicit inline copy(Allocators & allocators)
: result(0)
, m_allocators(allocators)
{}
inline void operator()(internal_node & n)
{
node_pointer raw_new_node = rtree::create_node<Allocators, internal_node>::apply(m_allocators); // MAY THROW, STRONG (N: alloc)
subtree_destroyer new_node(raw_new_node, m_allocators);
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type & elements = rtree::elements(n);
elements_type & elements_dst = rtree::elements(rtree::get<internal_node>(*new_node));
for (typename elements_type::iterator it = elements.begin();
it != elements.end(); ++it)
{
rtree::apply_visitor(*this, *it->second); // MAY THROW (V, E: alloc, copy, N: alloc)
// for exception safety
subtree_destroyer auto_result(result, m_allocators);
elements_dst.push_back( rtree::make_ptr_pair(it->first, result) ); // MAY THROW, STRONG (E: alloc, copy)
auto_result.release();
}
result = new_node.get();
new_node.release();
}
inline void operator()(leaf & l)
{
node_pointer raw_new_node = rtree::create_node<Allocators, leaf>::apply(m_allocators); // MAY THROW, STRONG (N: alloc)
subtree_destroyer new_node(raw_new_node, m_allocators);
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type & elements = rtree::elements(l);
elements_type & elements_dst = rtree::elements(rtree::get<leaf>(*new_node));
for (typename elements_type::iterator it = elements.begin();
it != elements.end(); ++it)
{
elements_dst.push_back(*it); // MAY THROW, STRONG (V: alloc, copy)
}
result = new_node.get();
new_node.release();
}
node_pointer result;
private:
Allocators & m_allocators;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COPY_HPP
@@ -0,0 +1,107 @@
// Boost.Geometry Index
//
// R-tree count visitor implementation
//
// Copyright (c) 2011-2014 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_VISITORS_COUNT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Indexable, typename Value>
struct count_helper
{
template <typename Translator>
static inline typename Translator::result_type indexable(Indexable const& i, Translator const&)
{
return i;
}
template <typename Translator>
static inline bool equals(Indexable const& i, Value const& v, Translator const& tr)
{
return geometry::equals(i, tr(v));
}
};
template <typename Value>
struct count_helper<Value, Value>
{
template <typename Translator>
static inline typename Translator::result_type indexable(Value const& v, Translator const& tr)
{
return tr(v);
}
template <typename Translator>
static inline bool equals(Value const& v1, Value const& v2, Translator const& tr)
{
return tr.equals(v1, v2);
}
};
template <typename ValueOrIndexable, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct count
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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 count_helper<ValueOrIndexable, Value> count_help;
inline count(ValueOrIndexable const& vori, Translator const& t)
: value_or_indexable(vori), tr(t), found_count(0)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// traverse nodes meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
if ( geometry::covered_by(
return_ref_or_bounds(
count_help::indexable(value_or_indexable, tr)),
it->first) )
{
rtree::apply_visitor(*this, *it->second);
}
}
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// get all values meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if value meets predicates
if ( count_help::equals(value_or_indexable, *it, tr) )
{
++found_count;
}
}
}
ValueOrIndexable const& value_or_indexable;
Translator const& tr;
typename Allocators::size_type found_count;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_COUNT_HPP
@@ -0,0 +1,71 @@
// Boost.Geometry Index
//
// R-tree destroying visitor implementation
//
// Copyright (c) 2011-2014 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_VISITORS_DELETE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class destroy
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
{
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 Allocators::node_pointer node_pointer;
inline destroy(node_pointer root_node, Allocators & allocators)
: m_current_node(root_node)
, m_allocators(allocators)
{}
inline void operator()(internal_node & n)
{
BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_current_node), "invalid pointers");
node_pointer node_to_destroy = m_current_node;
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type & elements = rtree::elements(n);
for (typename elements_type::iterator it = elements.begin();
it != elements.end(); ++it)
{
m_current_node = it->second;
rtree::apply_visitor(*this, *m_current_node);
it->second = 0;
}
rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, node_to_destroy);
}
inline void operator()(leaf & l)
{
boost::ignore_unused(l);
BOOST_GEOMETRY_INDEX_ASSERT(&l == &rtree::get<leaf>(*m_current_node), "invalid pointers");
rtree::destroy_node<Allocators, leaf>::apply(m_allocators, m_current_node);
}
private:
node_pointer m_current_node;
Allocators & m_allocators;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DELETE_HPP
@@ -0,0 +1,588 @@
// Boost.Geometry Index
//
// R-tree distance (knn, path, etc. ) query visitor implementation
//
// Copyright (c) 2011-2014 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_VISITORS_DISTANCE_QUERY_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Translator, typename DistanceType, typename OutIt>
class distance_query_result
{
public:
typedef DistanceType distance_type;
inline explicit distance_query_result(size_t k, OutIt out_it)
: m_count(k), m_out_it(out_it)
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < m_count, "Number of neighbors should be greater than 0");
m_neighbors.reserve(m_count);
}
inline void store(Value const& val, distance_type const& curr_comp_dist)
{
if ( m_neighbors.size() < m_count )
{
m_neighbors.push_back(std::make_pair(curr_comp_dist, val));
if ( m_neighbors.size() == m_count )
std::make_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
}
else
{
if ( curr_comp_dist < m_neighbors.front().first )
{
std::pop_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
m_neighbors.back().first = curr_comp_dist;
m_neighbors.back().second = val;
std::push_heap(m_neighbors.begin(), m_neighbors.end(), neighbors_less);
}
}
}
inline bool has_enough_neighbors() const
{
return m_count <= m_neighbors.size();
}
inline distance_type greatest_comparable_distance() const
{
// greatest distance is in the first neighbor only
// if there is at least m_count values found
// this is just for safety reasons since is_comparable_distance_valid() is checked earlier
// TODO - may be replaced by ASSERT
return m_neighbors.size() < m_count
? (std::numeric_limits<distance_type>::max)()
: m_neighbors.front().first;
}
inline size_t finish()
{
typedef typename std::vector< std::pair<distance_type, Value> >::const_iterator neighbors_iterator;
for ( neighbors_iterator it = m_neighbors.begin() ; it != m_neighbors.end() ; ++it, ++m_out_it )
*m_out_it = it->second;
return m_neighbors.size();
}
private:
inline static bool neighbors_less(
std::pair<distance_type, Value> const& p1,
std::pair<distance_type, Value> const& p2)
{
return p1.first < p2.first;
}
size_t m_count;
OutIt m_out_it;
std::vector< std::pair<distance_type, Value> > m_neighbors;
};
template <
typename Value,
typename Options,
typename Translator,
typename Box,
typename Allocators,
typename Predicates,
unsigned DistancePredicateIndex,
typename OutIter
>
class distance_query
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
public:
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 index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
typedef typename nearest_predicate_access::type nearest_predicate_type;
typedef typename indexable_type<Translator>::type indexable_type;
typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, value_tag> calculate_value_distance;
typedef index::detail::calculate_distance<nearest_predicate_type, Box, bounds_tag> calculate_node_distance;
typedef typename calculate_value_distance::result_type value_distance_type;
typedef typename calculate_node_distance::result_type node_distance_type;
static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
inline distance_query(parameters_type const& parameters, Translator const& translator, Predicates const& pred, OutIter out_it)
: m_parameters(parameters), m_translator(translator)
, m_pred(pred)
, m_result(nearest_predicate_access::get(m_pred).count, out_it)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
// array of active nodes
typedef typename index::detail::rtree::container_from_elements_type<
elements_type,
std::pair<node_distance_type, typename Allocators::node_pointer>
>::type active_branch_list_type;
active_branch_list_type active_branch_list;
active_branch_list.reserve(m_parameters.get_max_elements());
elements_type const& elements = rtree::elements(n);
// fill array of nodes meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if current node meets predicates
// 0 - dummy value
if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) )
{
// calculate node's distance(s) for distance predicate
node_distance_type node_distance;
// if distance isn't ok - move to the next node
if ( !calculate_node_distance::apply(predicate(), it->first, node_distance) )
{
continue;
}
// if current node is further than found neighbors - don't analyze it
if ( m_result.has_enough_neighbors() &&
is_node_prunable(m_result.greatest_comparable_distance(), node_distance) )
{
continue;
}
// add current node's data into the list
active_branch_list.push_back( std::make_pair(node_distance, it->second) );
}
}
// if there aren't any nodes in ABL - return
if ( active_branch_list.empty() )
return;
// sort array
std::sort(active_branch_list.begin(), active_branch_list.end(), abl_less);
// recursively visit nodes
for ( typename active_branch_list_type::const_iterator it = active_branch_list.begin();
it != active_branch_list.end() ; ++it )
{
// if current node is further than furthest neighbor, the rest of nodes also will be further
if ( m_result.has_enough_neighbors() &&
is_node_prunable(m_result.greatest_comparable_distance(), it->first) )
break;
rtree::apply_visitor(*this, *(it->second));
}
// ALTERNATIVE VERSION - use heap instead of sorted container
// It seems to be faster for greater MaxElements and slower otherwise
// CONSIDER: using one global container/heap for active branches
// instead of a sorted container per level
// This would also change the way how branches are traversed!
// The same may be applied to the iterative version which btw suffers
// from the copying of the whole containers on resize of the ABLs container
//// make a heap
//std::make_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater);
//// recursively visit nodes
//while ( !active_branch_list.empty() )
//{
// //if current node is further than furthest neighbor, the rest of nodes also will be further
// if ( m_result.has_enough_neighbors()
// && is_node_prunable(m_result.greatest_comparable_distance(), active_branch_list.front().first) )
// {
// break;
// }
// rtree::apply_visitor(*this, *(active_branch_list.front().second));
// std::pop_heap(active_branch_list.begin(), active_branch_list.end(), abl_greater);
// active_branch_list.pop_back();
//}
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// search leaf for closest value meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if value meets predicates
if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, *it, m_translator(*it)) )
{
// calculate values distance for distance predicate
value_distance_type value_distance;
// if distance is ok
if ( calculate_value_distance::apply(predicate(), m_translator(*it), value_distance) )
{
// store value
m_result.store(*it, value_distance);
}
}
}
}
inline size_t finish()
{
return m_result.finish();
}
private:
static inline bool abl_less(
std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
{
return p1.first < p2.first;
}
//static inline bool abl_greater(
// std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
// std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
//{
// return p1.first > p2.first;
//}
template <typename Distance>
static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
{
return greatest_dist <= d;
}
nearest_predicate_type const& predicate() const
{
return nearest_predicate_access::get(m_pred);
}
parameters_type const& m_parameters;
Translator const& m_translator;
Predicates m_pred;
distance_query_result<Value, Translator, value_distance_type, OutIter> m_result;
};
template <
typename Value,
typename Options,
typename Translator,
typename Box,
typename Allocators,
typename Predicates,
unsigned DistancePredicateIndex
>
class distance_query_incremental
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
public:
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 index::detail::predicates_element<DistancePredicateIndex, Predicates> nearest_predicate_access;
typedef typename nearest_predicate_access::type nearest_predicate_type;
typedef typename indexable_type<Translator>::type indexable_type;
typedef index::detail::calculate_distance<nearest_predicate_type, indexable_type, value_tag> calculate_value_distance;
typedef index::detail::calculate_distance<nearest_predicate_type, Box, bounds_tag> calculate_node_distance;
typedef typename calculate_value_distance::result_type value_distance_type;
typedef typename calculate_node_distance::result_type node_distance_type;
typedef typename Allocators::size_type size_type;
typedef typename Allocators::const_reference const_reference;
typedef typename Allocators::node_pointer node_pointer;
static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
typedef typename rtree::elements_type<internal_node>::type internal_elements;
typedef typename internal_elements::const_iterator internal_iterator;
typedef typename rtree::elements_type<leaf>::type leaf_elements;
typedef std::pair<node_distance_type, node_pointer> branch_data;
typedef typename index::detail::rtree::container_from_elements_type<
internal_elements, branch_data
>::type active_branch_list_type;
struct internal_stack_element
{
internal_stack_element() : current_branch(0) {}
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
// Required in c++03 for containers using Boost.Move
internal_stack_element & operator=(internal_stack_element const& o)
{
branches = o.branches;
current_branch = o.current_branch;
return *this;
}
#endif
active_branch_list_type branches;
typename active_branch_list_type::size_type current_branch;
};
typedef std::vector<internal_stack_element> internal_stack_type;
inline distance_query_incremental()
: m_translator(NULL)
// , m_pred()
, current_neighbor((std::numeric_limits<size_type>::max)())
// , next_closest_node_distance((std::numeric_limits<node_distance_type>::max)())
{}
inline distance_query_incremental(Translator const& translator, Predicates const& pred)
: m_translator(::boost::addressof(translator))
, m_pred(pred)
, current_neighbor((std::numeric_limits<size_type>::max)())
, next_closest_node_distance((std::numeric_limits<node_distance_type>::max)())
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < max_count(), "k must be greather than 0");
}
const_reference dereference() const
{
return *(neighbors[current_neighbor].second);
}
void initialize(node_pointer root)
{
rtree::apply_visitor(*this, *root);
increment();
}
void increment()
{
for (;;)
{
size_type new_neighbor = current_neighbor == (std::numeric_limits<size_type>::max)() ? 0 : current_neighbor + 1;
if ( internal_stack.empty() )
{
if ( new_neighbor < neighbors.size() )
current_neighbor = new_neighbor;
else
{
current_neighbor = (std::numeric_limits<size_type>::max)();
// clear() is used to disable the condition above
neighbors.clear();
}
return;
}
else
{
active_branch_list_type & branches = internal_stack.back().branches;
typename active_branch_list_type::size_type & current_branch = internal_stack.back().current_branch;
if ( branches.size() <= current_branch )
{
internal_stack.pop_back();
continue;
}
// if there are no nodes which can have closer values, set new value
if ( new_neighbor < neighbors.size() &&
// here must be < because otherwise neighbours may be sorted in different order
// if there is another value with equal distance
neighbors[new_neighbor].first < next_closest_node_distance )
{
current_neighbor = new_neighbor;
return;
}
// if node is further than the furthest neighbour, following nodes also will be further
BOOST_GEOMETRY_INDEX_ASSERT(neighbors.size() <= max_count(), "unexpected neighbours count");
if ( max_count() <= neighbors.size() &&
is_node_prunable(neighbors.back().first, branches[current_branch].first) )
{
// stop traversing current level
internal_stack.pop_back();
continue;
}
else
{
// new level - must increment current_branch before traversing of another level (mem reallocation)
++current_branch;
rtree::apply_visitor(*this, *(branches[current_branch - 1].second));
next_closest_node_distance = calc_closest_node_distance(internal_stack.begin(), internal_stack.end());
}
}
}
}
bool is_end() const
{
return (std::numeric_limits<size_type>::max)() == current_neighbor;
}
friend bool operator==(distance_query_incremental const& l, distance_query_incremental const& r)
{
BOOST_GEOMETRY_INDEX_ASSERT(l.current_neighbor != r.current_neighbor ||
(std::numeric_limits<size_type>::max)() == l.current_neighbor ||
(std::numeric_limits<size_type>::max)() == r.current_neighbor ||
l.neighbors[l.current_neighbor].second == r.neighbors[r.current_neighbor].second,
"not corresponding iterators");
return l.current_neighbor == r.current_neighbor;
}
// Put node's elements into the list of active branches if those elements meets predicates
// and distance predicates(currently not used)
// and aren't further than found neighbours (if there is enough neighbours)
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// add new element
internal_stack.resize(internal_stack.size()+1);
// fill active branch list array of nodes meeting predicates
for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it )
{
// if current node meets predicates
// 0 - dummy value
if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) )
{
// calculate node's distance(s) for distance predicate
node_distance_type node_distance;
// if distance isn't ok - move to the next node
if ( !calculate_node_distance::apply(predicate(), it->first, node_distance) )
{
continue;
}
// if current node is further than found neighbors - don't analyze it
if ( max_count() <= neighbors.size() &&
is_node_prunable(neighbors.back().first, node_distance) )
{
continue;
}
// add current node's data into the list
internal_stack.back().branches.push_back( std::make_pair(node_distance, it->second) );
}
}
if ( internal_stack.back().branches.empty() )
internal_stack.pop_back();
else
// sort array
std::sort(internal_stack.back().branches.begin(), internal_stack.back().branches.end(), abl_less);
}
// Put values into the list of neighbours if those values meets predicates
// and distance predicates(currently not used)
// and aren't further than already found neighbours (if there is enough neighbours)
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// store distance to the furthest neighbour
bool not_enough_neighbors = neighbors.size() < max_count();
value_distance_type greatest_distance = !not_enough_neighbors ? neighbors.back().first : (std::numeric_limits<value_distance_type>::max)();
// search leaf for closest value meeting predicates
for ( typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
{
// if value meets predicates
if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, *it, (*m_translator)(*it)) )
{
// calculate values distance for distance predicate
value_distance_type value_distance;
// if distance is ok
if ( calculate_value_distance::apply(predicate(), (*m_translator)(*it), value_distance) )
{
// if there is not enough values or current value is closer than furthest neighbour
if ( not_enough_neighbors || value_distance < greatest_distance )
{
neighbors.push_back(std::make_pair(value_distance, boost::addressof(*it)));
}
}
}
}
// sort array
std::sort(neighbors.begin(), neighbors.end(), neighbors_less);
// remove furthest values
if ( max_count() < neighbors.size() )
neighbors.resize(max_count());
}
private:
static inline bool abl_less(std::pair<node_distance_type, typename Allocators::node_pointer> const& p1,
std::pair<node_distance_type, typename Allocators::node_pointer> const& p2)
{
return p1.first < p2.first;
}
static inline bool neighbors_less(std::pair<value_distance_type, const Value *> const& p1,
std::pair<value_distance_type, const Value *> const& p2)
{
return p1.first < p2.first;
}
node_distance_type
calc_closest_node_distance(typename internal_stack_type::const_iterator first,
typename internal_stack_type::const_iterator last)
{
node_distance_type result = (std::numeric_limits<node_distance_type>::max)();
for ( ; first != last ; ++first )
{
if ( first->branches.size() <= first->current_branch )
continue;
node_distance_type curr_dist = first->branches[first->current_branch].first;
if ( curr_dist < result )
result = curr_dist;
}
return result;
}
template <typename Distance>
static inline bool is_node_prunable(Distance const& greatest_dist, node_distance_type const& d)
{
return greatest_dist <= d;
}
inline unsigned max_count() const
{
return nearest_predicate_access::get(m_pred).count;
}
nearest_predicate_type const& predicate() const
{
return nearest_predicate_access::get(m_pred);
}
const Translator * m_translator;
Predicates m_pred;
internal_stack_type internal_stack;
std::vector< std::pair<value_distance_type, const Value *> > neighbors;
size_type current_neighbor;
node_distance_type next_closest_node_distance;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_DISTANCE_QUERY_HPP
@@ -0,0 +1,573 @@
// Boost.Geometry Index
//
// R-tree inserting visitor 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_VISITORS_INSERT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP
#include <boost/type_traits/is_same.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/index/detail/algorithms/content.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree {
// Default choose_next_node
template <typename Value, typename Options, typename Box, typename Allocators, typename ChooseNextNodeTag>
class choose_next_node;
template <typename Value, typename Options, typename Box, typename Allocators>
class choose_next_node<Value, Options, Box, Allocators, choose_by_content_diff_tag>
{
public:
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 rtree::elements_type<internal_node>::type children_type;
typedef typename index::detail::default_content_result<Box>::type content_type;
template <typename Indexable>
static inline size_t apply(internal_node & n,
Indexable const& indexable,
parameters_type const& /*parameters*/,
size_t /*node_relative_level*/)
{
children_type & children = rtree::elements(n);
BOOST_GEOMETRY_INDEX_ASSERT(!children.empty(), "can't choose the next node if children are empty");
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)();
// caculate areas and areas of all nodes' boxes
for ( size_t i = 0 ; i < children_count ; ++i )
{
typedef typename children_type::value_type child_type;
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;
}
};
// ----------------------------------------------------------------------- //
// Not implemented here
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename RedistributeTag>
struct redistribute_elements
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_REDISTRIBUTE_TAG_TYPE,
(redistribute_elements));
};
// ----------------------------------------------------------------------- //
// Split algorithm
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename SplitTag>
class split
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_SPLIT_TAG_TYPE,
(split));
};
// Default split algorithm
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class split<Value, Options, Translator, Box, Allocators, split_default_tag>
{
protected:
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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
public:
typedef index::detail::varray<
typename rtree::elements_type<internal_node>::type::value_type,
1
> nodes_container_type;
template <typename Node>
static inline void apply(nodes_container_type & additional_nodes,
Node & n,
Box & n_box,
parameters_type const& parameters,
Translator const& translator,
Allocators & allocators)
{
// TODO - consider creating nodes always with sufficient memory allocated
// create additional node, use auto destroyer for automatic destruction on exception
subtree_destroyer second_node(rtree::create_node<Allocators, Node>::apply(allocators), allocators); // MAY THROW, STRONG (N: alloc)
// create reference to the newly created node
Node & n2 = rtree::get<Node>(*second_node);
// NOTE: thread-safety
// After throwing an exception by redistribute_elements the original node may be not changed or
// both nodes may be empty. In both cases the tree won't be valid r-tree.
// The alternative is to create 2 (or more) additional nodes here and store backup info
// in the original node, then, if exception was thrown, the node would always have more than max
// elements.
// The alternative is to use moving semantics in the implementations of redistribute_elements,
// it will be possible to throw from boost::move() in the case of e.g. static size nodes.
// redistribute elements
Box box2;
redistribute_elements<
Value,
Options,
Translator,
Box,
Allocators,
typename Options::redistribute_tag
>::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW (V, E: alloc, copy, copy)
// check numbers of elements
BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n).size() &&
rtree::elements(n).size() <= parameters.get_max_elements(),
"unexpected number of elements");
BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n2).size() &&
rtree::elements(n2).size() <= parameters.get_max_elements(),
"unexpected number of elements");
// return the list of newly created nodes (this algorithm returns one)
additional_nodes.push_back(rtree::make_ptr_pair(box2, second_node.get())); // MAY THROW, STRONG (alloc, copy)
// release the ptr
second_node.release();
}
};
// ----------------------------------------------------------------------- //
namespace visitors { namespace detail {
template <typename InternalNode, typename InternalNodePtr, typename SizeType>
struct insert_traverse_data
{
typedef typename rtree::elements_type<InternalNode>::type elements_type;
typedef typename elements_type::value_type element_type;
typedef typename elements_type::size_type elements_size_type;
typedef SizeType size_type;
insert_traverse_data()
: parent(0), current_child_index(0), current_level(0)
{}
void move_to_next_level(InternalNodePtr new_parent,
elements_size_type new_child_index)
{
parent = new_parent;
current_child_index = new_child_index;
++current_level;
}
bool current_is_root() const
{
return 0 == parent;
}
elements_type & parent_elements() const
{
BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer");
return rtree::elements(*parent);
}
element_type & current_element() const
{
BOOST_GEOMETRY_INDEX_ASSERT(parent, "null pointer");
return rtree::elements(*parent)[current_child_index];
}
InternalNodePtr parent;
elements_size_type current_child_index;
size_type current_level;
};
// Default insert visitor
template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class insert
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, false>::type
{
protected:
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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
//typedef typename Allocators::internal_node_pointer internal_node_pointer;
typedef internal_node * internal_node_pointer;
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_element(element)
, m_parameters(parameters)
, m_translator(translator)
, m_relative_level(relative_level)
, m_level(leafs_level - relative_level)
, m_root_node(root)
, m_leafs_level(leafs_level)
, m_traverse_data()
, m_allocators(allocators)
{
BOOST_GEOMETRY_INDEX_ASSERT(m_relative_level <= leafs_level, "unexpected level value");
BOOST_GEOMETRY_INDEX_ASSERT(m_level <= m_leafs_level, "unexpected level value");
BOOST_GEOMETRY_INDEX_ASSERT(0 != m_root_node, "there is no root node");
// TODO
// assert - check if Box is correct
// When a value is inserted, during the tree traversal bounds of nodes
// on a path from the root to a leaf must be expanded. So prepare
// a bounding object at the beginning to not do it later for each node.
// NOTE: This is actually only needed because conditionally the bounding
// object may be expanded below. Otherwise the indexable could be
// directly used instead
index::detail::bounds(rtree::element_indexable(m_element, m_translator), m_element_bounds);
#ifdef BOOST_GEOMETRY_INDEX_EXPERIMENTAL_ENLARGE_BY_EPSILON
// Enlarge it in case if it's not bounding geometry type.
// It's because Points and Segments are compared WRT machine epsilon
// This ensures that leafs bounds correspond to the stored elements
if (BOOST_GEOMETRY_CONDITION((
boost::is_same<Element, Value>::value
&& ! index::detail::is_bounding_geometry
<
typename indexable_type<Translator>::type
>::value )) )
{
geometry::detail::expand_by_epsilon(m_element_bounds);
}
#endif
}
template <typename Visitor>
inline void traverse(Visitor & visitor, internal_node & n)
{
// choose next node
size_t choosen_node_index = rtree::choose_next_node<Value, Options, Box, Allocators, typename Options::choose_next_node_tag>::
apply(n, rtree::element_indexable(m_element, m_translator), m_parameters, m_leafs_level - m_traverse_data.current_level);
// expand the node to contain value
geometry::expand(
rtree::elements(n)[choosen_node_index].first,
m_element_bounds
/*rtree::element_indexable(m_element, m_translator)*/);
// next traversing step
traverse_apply_visitor(visitor, n, choosen_node_index); // MAY THROW (V, E: alloc, copy, N:alloc)
}
// TODO: awulkiew - change post_traverse name to handle_overflow or overflow_treatment?
template <typename Node>
inline void post_traverse(Node &n)
{
BOOST_GEOMETRY_INDEX_ASSERT(m_traverse_data.current_is_root() ||
&n == &rtree::get<Node>(*m_traverse_data.current_element().second),
"if node isn't the root current_child_index should be valid");
// handle overflow
if ( m_parameters.get_max_elements() < rtree::elements(n).size() )
{
// NOTE: If the exception is thrown current node may contain more than MAX elements or be empty.
// Furthermore it may be empty root - internal node.
split(n); // MAY THROW (V, E: alloc, copy, N:alloc)
}
}
template <typename Visitor>
inline void traverse_apply_visitor(Visitor & visitor, internal_node &n, size_t choosen_node_index)
{
// save previous traverse inputs and set new ones
insert_traverse_data<internal_node, internal_node_pointer, size_type>
backup_traverse_data = m_traverse_data;
// calculate new traverse inputs
m_traverse_data.move_to_next_level(&n, choosen_node_index);
// next traversing step
rtree::apply_visitor(visitor, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V, E: alloc, copy, N:alloc)
// restore previous traverse inputs
m_traverse_data = backup_traverse_data;
}
// TODO: consider - split result returned as OutIter is faster than reference to the container. Why?
template <typename Node>
inline void split(Node & n) const
{
typedef rtree::split<Value, Options, Translator, Box, Allocators, typename Options::split_tag> split_algo;
typename split_algo::nodes_container_type additional_nodes;
Box n_box;
split_algo::apply(additional_nodes, n, n_box, m_parameters, m_translator, m_allocators); // MAY THROW (V, E: alloc, copy, N:alloc)
BOOST_GEOMETRY_INDEX_ASSERT(additional_nodes.size() == 1, "unexpected number of additional nodes");
// TODO add all additional nodes
// For kmeans algorithm:
// elements number may be greater than node max elements count
// split and reinsert must take node with some elements count
// and container of additional elements (std::pair<Box, node*>s or Values)
// and translator + allocators
// where node_elements_count + additional_elements > node_max_elements_count
// What with elements other than std::pair<Box, node*> ?
// Implement template <node_tag> struct node_element_type or something like that
// for exception safety
subtree_destroyer additional_node_ptr(additional_nodes[0].second, m_allocators);
#ifdef BOOST_GEOMETRY_INDEX_EXPERIMENTAL_ENLARGE_BY_EPSILON
// Enlarge bounds of a leaf node.
// It's because Points and Segments are compared WRT machine epsilon
// This ensures that leafs' bounds correspond to the stored elements.
if (BOOST_GEOMETRY_CONDITION((
boost::is_same<Node, leaf>::value
&& ! index::detail::is_bounding_geometry
<
typename indexable_type<Translator>::type
>::value )))
{
geometry::detail::expand_by_epsilon(n_box);
geometry::detail::expand_by_epsilon(additional_nodes[0].first);
}
#endif
// node is not the root - just add the new node
if ( !m_traverse_data.current_is_root() )
{
// update old node's box
m_traverse_data.current_element().first = n_box;
// add new node to parent's children
m_traverse_data.parent_elements().push_back(additional_nodes[0]); // MAY THROW, STRONG (V, E: alloc, copy)
}
// node is the root - add level
else
{
BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<Node>(*m_root_node), "node should be the root");
// create new root and add nodes
subtree_destroyer new_root(rtree::create_node<Allocators, internal_node>::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc)
BOOST_TRY
{
rtree::elements(rtree::get<internal_node>(*new_root)).push_back(rtree::make_ptr_pair(n_box, m_root_node)); // MAY THROW, STRONG (E:alloc, copy)
rtree::elements(rtree::get<internal_node>(*new_root)).push_back(additional_nodes[0]); // MAY THROW, STRONG (E:alloc, copy)
}
BOOST_CATCH(...)
{
// clear new root to not delete in the ~subtree_destroyer() potentially stored old root node
rtree::elements(rtree::get<internal_node>(*new_root)).clear();
BOOST_RETHROW // RETHROW
}
BOOST_CATCH_END
m_root_node = new_root.get();
++m_leafs_level;
new_root.release();
}
additional_node_ptr.release();
}
// TODO: awulkiew - implement dispatchable split::apply to enable additional nodes creation
Element const& m_element;
Box m_element_bounds;
parameters_type const& m_parameters;
Translator const& m_translator;
size_type const m_relative_level;
size_type const m_level;
node_pointer & m_root_node;
size_type & m_leafs_level;
// traversing input parameters
insert_traverse_data<internal_node, internal_node_pointer, size_type> m_traverse_data;
Allocators & m_allocators;
};
} // namespace detail
// Insert visitor forward declaration
template <typename Element, typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename InsertTag>
class insert;
// Default insert visitor used for nodes elements
// 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_default_tag>
: public detail::insert<Element, Value, Options, Translator, Box, Allocators>
{
public:
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 Options::parameters_type parameters_type;
typedef typename base::node_pointer node_pointer;
typedef typename base::size_type size_type;
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
)
: 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)
}
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(...)
{
// if the insert fails above, the element won't be stored in the tree
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
}
base::post_traverse(n); // MAY THROW (E: alloc, copy, N: alloc)
}
inline void operator()(leaf &)
{
BOOST_GEOMETRY_INDEX_ASSERT(false, "this visitor can't be used for a leaf");
}
};
// Default insert visitor specialized for Values elements
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class insert<Value, Value, Options, Translator, Box, Allocators, insert_default_tag>
: public detail::insert<Value, Value, Options, Translator, Box, Allocators>
{
public:
typedef detail::insert<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 base::node_pointer node_pointer;
typedef typename base::size_type size_type;
inline insert(node_pointer & root,
size_type & leafs_level,
Value const& value,
parameters_type const& parameters,
Translator const& translator,
Allocators & allocators,
size_type relative_level = 0
)
: base(root, leafs_level, value, 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)
base::post_traverse(n); // MAY THROW (E: alloc, copy, N: alloc)
}
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::post_traverse(n); // MAY THROW (V: alloc, copy, N: alloc)
}
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP
@@ -0,0 +1,45 @@
// Boost.Geometry Index
//
// R-tree leaf node checking visitor 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_VISITORS_IS_LEAF_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Options, typename Box, typename Allocators>
struct is_leaf : public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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;
is_leaf()
: result(false)
{}
inline void operator()(internal_node const&)
{
// result = false;
}
inline void operator()(leaf const&)
{
result = true;
}
bool result;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_IS_LEAF_HPP
@@ -0,0 +1,134 @@
// Boost.Geometry Index
//
// R-tree iterator visitor 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_VISITORS_ITERATOR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ITERATOR_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class iterator
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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 Allocators::size_type size_type;
typedef typename Allocators::const_reference const_reference;
typedef typename Allocators::node_pointer node_pointer;
typedef typename rtree::elements_type<internal_node>::type::const_iterator internal_iterator;
typedef typename rtree::elements_type<leaf>::type leaf_elements;
typedef typename rtree::elements_type<leaf>::type::const_iterator leaf_iterator;
inline iterator()
: m_values(NULL)
, m_current()
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
m_internal_stack.push_back(std::make_pair(elements.begin(), elements.end()));
}
inline void operator()(leaf const& n)
{
m_values = ::boost::addressof(rtree::elements(n));
m_current = rtree::elements(n).begin();
}
const_reference dereference() const
{
BOOST_GEOMETRY_INDEX_ASSERT(m_values, "not dereferencable");
return *m_current;
}
void initialize(node_pointer root)
{
rtree::apply_visitor(*this, *root);
search_value();
}
void increment()
{
++m_current;
search_value();
}
void search_value()
{
for (;;)
{
// if leaf is choosen, move to the next value in leaf
if ( m_values )
{
// there are more values in the current leaf
if ( m_current != m_values->end() )
{
return;
}
// no more values, clear current leaf
else
{
m_values = 0;
}
}
// if leaf isn't choosen, move to the next leaf
else
{
// return if there is no more nodes to traverse
if ( m_internal_stack.empty() )
return;
// no more children in current node, remove it from stack
if ( m_internal_stack.back().first == m_internal_stack.back().second )
{
m_internal_stack.pop_back();
continue;
}
internal_iterator it = m_internal_stack.back().first;
++m_internal_stack.back().first;
// push the next node to the stack
rtree::apply_visitor(*this, *(it->second));
}
}
}
bool is_end() const
{
return 0 == m_values;
}
friend bool operator==(iterator const& l, iterator const& r)
{
return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current );
}
private:
std::vector< std::pair<internal_iterator, internal_iterator> > m_internal_stack;
const leaf_elements * m_values;
leaf_iterator m_current;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ITERATOR_HPP
@@ -0,0 +1,344 @@
// Boost.Geometry Index
//
// R-tree removing visitor 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_VISITORS_REMOVE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP
#include <boost/geometry/index/detail/rtree/visitors/is_leaf.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
// Default remove algorithm
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class remove
: 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 rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
typedef typename Allocators::node_pointer node_pointer;
typedef typename Allocators::size_type size_type;
typedef typename rtree::elements_type<internal_node>::type::size_type internal_size_type;
//typedef typename Allocators::internal_node_pointer internal_node_pointer;
typedef internal_node * internal_node_pointer;
public:
inline remove(node_pointer & root,
size_type & leafs_level,
Value const& value,
parameters_type const& parameters,
Translator const& translator,
Allocators & allocators)
: m_value(value)
, m_parameters(parameters)
, m_translator(translator)
, m_allocators(allocators)
, m_root_node(root)
, m_leafs_level(leafs_level)
, m_is_value_removed(false)
, m_parent(0)
, m_current_child_index(0)
, m_current_level(0)
, m_is_underflow(false)
{
// TODO
// assert - check if Value/Box is correct
}
inline void operator()(internal_node & n)
{
typedef typename rtree::elements_type<internal_node>::type children_type;
children_type & children = rtree::elements(n);
// traverse children which boxes intersects value's box
internal_size_type child_node_index = 0;
for ( ; child_node_index < children.size() ; ++child_node_index )
{
if ( geometry::covered_by(
return_ref_or_bounds(m_translator(m_value)),
children[child_node_index].first) )
{
// next traversing step
traverse_apply_visitor(n, child_node_index); // MAY THROW
if ( m_is_value_removed )
break;
}
}
// value was found and removed
if ( m_is_value_removed )
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
typedef typename elements_type::iterator element_iterator;
elements_type & elements = rtree::elements(n);
// underflow occured - child node should be removed
if ( m_is_underflow )
{
element_iterator underfl_el_it = elements.begin() + child_node_index;
size_type relative_level = m_leafs_level - m_current_level;
// move node to the container - store node's relative level as well and return new underflow state
// NOTE: if the min elements number is 1, then after an underflow
// here the child elements count is 0, so it's not required to store this node,
// it could just be destroyed
m_is_underflow = store_underflowed_node(elements, underfl_el_it, relative_level); // MAY THROW (E: alloc, copy)
}
// n is not root - adjust aabb
if ( 0 != m_parent )
{
// underflow state should be ok here
// note that there may be less than min_elems elements in root
// so this condition should be checked only here
BOOST_GEOMETRY_INDEX_ASSERT((elements.size() < m_parameters.get_min_elements()) == m_is_underflow, "unexpected state");
rtree::elements(*m_parent)[m_current_child_index].first
= rtree::elements_box<Box>(elements.begin(), elements.end(), m_translator);
}
// n is root node
else
{
BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get<internal_node>(*m_root_node), "node must be the root");
// reinsert elements from removed nodes (underflows)
reinsert_removed_nodes_elements(); // MAY THROW (V, E: alloc, copy, N: alloc)
// shorten the tree
// NOTE: if the min elements number is 1, then after underflow
// here the number of elements may be equal to 0
// this can occur only for the last removed element
if ( rtree::elements(n).size() <= 1 )
{
node_pointer root_to_destroy = m_root_node;
if ( rtree::elements(n).size() == 0 )
m_root_node = 0;
else
m_root_node = rtree::elements(n)[0].second;
--m_leafs_level;
rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, root_to_destroy);
}
}
}
}
inline void operator()(leaf & n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type & elements = rtree::elements(n);
// find value and remove it
for ( typename elements_type::iterator it = elements.begin() ; it != elements.end() ; ++it )
{
if ( m_translator.equals(*it, m_value) )
{
rtree::move_from_back(elements, it); // MAY THROW (V: copy)
elements.pop_back();
m_is_value_removed = true;
break;
}
}
// if value was removed
if ( m_is_value_removed )
{
BOOST_GEOMETRY_INDEX_ASSERT(0 < m_parameters.get_min_elements(), "min number of elements is too small");
// calc underflow
m_is_underflow = elements.size() < m_parameters.get_min_elements();
// n is not root - adjust aabb
if ( 0 != m_parent )
{
rtree::elements(*m_parent)[m_current_child_index].first
= rtree::values_box<Box>(elements.begin(), elements.end(), m_translator);
}
}
}
bool is_value_removed() const
{
return m_is_value_removed;
}
private:
typedef std::vector< std::pair<size_type, node_pointer> > UnderflowNodes;
void traverse_apply_visitor(internal_node &n, internal_size_type choosen_node_index)
{
// save previous traverse inputs and set new ones
internal_node_pointer parent_bckup = m_parent;
internal_size_type current_child_index_bckup = m_current_child_index;
size_type current_level_bckup = m_current_level;
m_parent = &n;
m_current_child_index = choosen_node_index;
++m_current_level;
// next traversing step
rtree::apply_visitor(*this, *rtree::elements(n)[choosen_node_index].second); // MAY THROW (V, E: alloc, copy, N: alloc)
// restore previous traverse inputs
m_parent = parent_bckup;
m_current_child_index = current_child_index_bckup;
m_current_level = current_level_bckup;
}
bool store_underflowed_node(
typename rtree::elements_type<internal_node>::type & elements,
typename rtree::elements_type<internal_node>::type::iterator underfl_el_it,
size_type relative_level)
{
// move node to the container - store node's relative level as well
m_underflowed_nodes.push_back(std::make_pair(relative_level, underfl_el_it->second)); // MAY THROW (E: alloc, copy)
BOOST_TRY
{
// NOTE: those are elements of the internal node which means that copy/move shouldn't throw
// Though it's safer in case if the pointer type could throw in copy ctor.
// In the future this try-catch block could be removed.
rtree::move_from_back(elements, underfl_el_it); // MAY THROW (E: copy)
elements.pop_back();
}
BOOST_CATCH(...)
{
m_underflowed_nodes.pop_back();
BOOST_RETHROW // RETHROW
}
BOOST_CATCH_END
// calc underflow
return elements.size() < m_parameters.get_min_elements();
}
static inline bool is_leaf(node const& n)
{
visitors::is_leaf<Value, Options, Box, Allocators> ilv;
rtree::apply_visitor(ilv, n);
return ilv.result;
}
void reinsert_removed_nodes_elements()
{
typename UnderflowNodes::reverse_iterator it = m_underflowed_nodes.rbegin();
BOOST_TRY
{
// reinsert elements from removed nodes
// begin with levels closer to the root
for ( ; it != m_underflowed_nodes.rend() ; ++it )
{
// it->first is an index of a level of a node, not children
// counted from the leafs level
bool const node_is_leaf = it->first == 1;
BOOST_GEOMETRY_INDEX_ASSERT(node_is_leaf == is_leaf(*it->second), "unexpected condition");
if ( node_is_leaf )
{
reinsert_node_elements(rtree::get<leaf>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc)
rtree::destroy_node<Allocators, leaf>::apply(m_allocators, it->second);
}
else
{
reinsert_node_elements(rtree::get<internal_node>(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc)
rtree::destroy_node<Allocators, internal_node>::apply(m_allocators, it->second);
}
}
//m_underflowed_nodes.clear();
}
BOOST_CATCH(...)
{
// destroy current and remaining nodes
for ( ; it != m_underflowed_nodes.rend() ; ++it )
{
subtree_destroyer dummy(it->second, m_allocators);
}
//m_underflowed_nodes.clear();
BOOST_RETHROW // RETHROW
}
BOOST_CATCH_END
}
template <typename Node>
void reinsert_node_elements(Node &n, size_type node_relative_level)
{
typedef typename rtree::elements_type<Node>::type elements_type;
elements_type & elements = rtree::elements(n);
typename elements_type::iterator it = elements.begin();
BOOST_TRY
{
for ( ; it != elements.end() ; ++it )
{
visitors::insert<
typename elements_type::value_type,
Value, Options, Translator, Box, Allocators,
typename Options::insert_tag
> insert_v(
m_root_node, m_leafs_level, *it,
m_parameters, m_translator, m_allocators,
node_relative_level - 1);
rtree::apply_visitor(insert_v, *m_root_node); // MAY THROW (V, E: alloc, copy, N: alloc)
}
}
BOOST_CATCH(...)
{
++it;
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>
::apply(it, elements.end(), m_allocators);
elements.clear();
BOOST_RETHROW // RETHROW
}
BOOST_CATCH_END
}
Value const& m_value;
parameters_type const& m_parameters;
Translator const& m_translator;
Allocators & m_allocators;
node_pointer & m_root_node;
size_type & m_leafs_level;
bool m_is_value_removed;
UnderflowNodes m_underflowed_nodes;
// traversing input parameters
internal_node_pointer m_parent;
internal_size_type m_current_child_index;
size_type m_current_level;
// traversing output parameters
bool m_is_underflow;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP
@@ -0,0 +1,214 @@
// Boost.Geometry Index
//
// R-tree spatial query visitor implementation
//
// Copyright (c) 2011-2014 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_VISITORS_SPATIAL_QUERY_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP
namespace boost { namespace geometry { namespace index {
namespace detail { namespace rtree { namespace visitors {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates, typename OutIter>
struct spatial_query
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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 Allocators::size_type size_type;
static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
inline spatial_query(Translator const& t, Predicates const& p, OutIter out_it)
: tr(t), pred(p), out_iter(out_it), found_count(0)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// traverse nodes meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if node meets predicates
// 0 - dummy value
if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(pred, 0, it->first) )
rtree::apply_visitor(*this, *it->second);
}
}
inline void operator()(leaf const& n)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
elements_type const& elements = rtree::elements(n);
// get all values meeting predicates
for (typename elements_type::const_iterator it = elements.begin();
it != elements.end(); ++it)
{
// if value meets predicates
if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(pred, *it, tr(*it)) )
{
*out_iter = *it;
++out_iter;
++found_count;
}
}
}
Translator const& tr;
Predicates pred;
OutIter out_iter;
size_type found_count;
};
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators, typename Predicates>
class spatial_query_incremental
: public rtree::visitor<Value, typename Options::parameters_type, Box, Allocators, typename Options::node_tag, true>::type
{
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 Allocators::size_type size_type;
typedef typename Allocators::const_reference const_reference;
typedef typename Allocators::node_pointer node_pointer;
typedef typename rtree::elements_type<internal_node>::type::const_iterator internal_iterator;
typedef typename rtree::elements_type<leaf>::type leaf_elements;
typedef typename rtree::elements_type<leaf>::type::const_iterator leaf_iterator;
static const unsigned predicates_len = index::detail::predicates_length<Predicates>::value;
inline spatial_query_incremental()
: m_translator(NULL)
// , m_pred()
, m_values(NULL)
, m_current()
{}
inline spatial_query_incremental(Translator const& t, Predicates const& p)
: m_translator(::boost::addressof(t))
, m_pred(p)
, m_values(NULL)
, m_current()
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
m_internal_stack.push_back(std::make_pair(elements.begin(), elements.end()));
}
inline void operator()(leaf const& n)
{
m_values = ::boost::addressof(rtree::elements(n));
m_current = rtree::elements(n).begin();
}
const_reference dereference() const
{
BOOST_GEOMETRY_INDEX_ASSERT(m_values, "not dereferencable");
return *m_current;
}
void initialize(node_pointer root)
{
rtree::apply_visitor(*this, *root);
search_value();
}
void increment()
{
++m_current;
search_value();
}
void search_value()
{
for (;;)
{
// if leaf is choosen, move to the next value in leaf
if ( m_values )
{
if ( m_current != m_values->end() )
{
// return if next value is found
Value const& v = *m_current;
if ( index::detail::predicates_check<index::detail::value_tag, 0, predicates_len>(m_pred, v, (*m_translator)(v)) )
return;
++m_current;
}
// no more values, clear current leaf
else
{
m_values = 0;
}
}
// if leaf isn't choosen, move to the next leaf
else
{
// return if there is no more nodes to traverse
if ( m_internal_stack.empty() )
return;
// no more children in current node, remove it from stack
if ( m_internal_stack.back().first == m_internal_stack.back().second )
{
m_internal_stack.pop_back();
continue;
}
internal_iterator it = m_internal_stack.back().first;
++m_internal_stack.back().first;
// next node is found, push it to the stack
if ( index::detail::predicates_check<index::detail::bounds_tag, 0, predicates_len>(m_pred, 0, it->first) )
rtree::apply_visitor(*this, *(it->second));
}
}
}
bool is_end() const
{
return 0 == m_values;
}
friend bool operator==(spatial_query_incremental const& l, spatial_query_incremental const& r)
{
return (l.m_values == r.m_values) && (0 == l.m_values || l.m_current == r.m_current );
}
private:
const Translator * m_translator;
Predicates m_pred;
std::vector< std::pair<internal_iterator, internal_iterator> > m_internal_stack;
const leaf_elements * m_values;
leaf_iterator m_current;
};
}}} // namespace detail::rtree::visitors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP