mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-15 01:02:09 +00:00
other version of split algorithm + a lot of minor changes
[SVN r70607]
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
//
|
||||
// Boost.Index - R*-tree ChooseNextNode algorithm
|
||||
//
|
||||
// Copyright 2011 Adam Wulkiewicz.
|
||||
// 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_EXTENSIONS_INDEX_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/geometry/extensions/index/algorithms/area.hpp>
|
||||
#include <boost/geometry/extensions/index/algorithms/overlap.hpp>
|
||||
#include <boost/geometry/extensions/index/algorithms/union_area.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/rtree_node.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/rtree_is_leaf.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace visitors {
|
||||
|
||||
struct rtree_rstar_chnn_min_overlap_cost {};
|
||||
struct rtree_rstar_chnn_nearly_min_overlap_cost {};
|
||||
|
||||
// TODO: awulkiew - it's possible that goodness values may be used to choose next node
|
||||
// on this step some of the goodness values would be calculated (not all)
|
||||
// and only for some nodes (goodness values should be calculated only if there is an overflow)
|
||||
|
||||
template <typename Value, typename Box, typename Tag>
|
||||
class rtree_rstar_choose_next_node
|
||||
{};
|
||||
|
||||
// TODO: awulkiew finish this version
|
||||
// use min_element instead of searching by myself
|
||||
|
||||
//template <typename Value, typename Box>
|
||||
//class rtree_rstar_choose_next_node<Value, Box, rtree_rstar_chnn_nearly_min_overlap_cost>
|
||||
//{
|
||||
// typedef typename index::detail::rtree_node<Value, Box, rtree_rstar_tag>::type node;
|
||||
// typedef typename index::detail::rtree_internal_node<Value, Box, rtree_rstar_tag>::type internal_node;
|
||||
// typedef typename index::detail::rtree_leaf<Value, Box, rtree_rstar_tag>::type leaf;
|
||||
//
|
||||
// typedef typename internal_node::children_type children_type;
|
||||
//
|
||||
//public:
|
||||
// template <typename Indexable>
|
||||
// static inline size_t apply(internal_node & n, Indexable const& indexable)
|
||||
// {
|
||||
// assert(!n.children.empty());
|
||||
//
|
||||
// bool has_leaves = boost::apply_visitor(
|
||||
// visitors::rtree_is_leaf<Value, Box, rtree_rstar_tag>(),
|
||||
// *n.children.front().second);
|
||||
//
|
||||
// if ( !has_leaves )
|
||||
// return impl<internal_node_areas>(n, indexable);
|
||||
// else
|
||||
// return impl<branch_areas>(n, indexable);
|
||||
// }
|
||||
//
|
||||
//private:
|
||||
// template <typename Areas, typename Indexable>
|
||||
// static inline size_t impl(internal_node & n, Indexable const& indexable)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
//};
|
||||
|
||||
// TODO: awulkiew - wrong algorithm? Should branch check be applied to Leafs?
|
||||
// TODO: awulkiew - further optimization: don't calculate area with the overlap, calculate it only if
|
||||
// overlap < smallest_overlap (and current area must be stored) OR
|
||||
// overlap == smallest_overlap (and area must be compared)
|
||||
|
||||
template <typename Value, typename Box>
|
||||
class rtree_rstar_choose_next_node<Value, Box, rtree_rstar_chnn_min_overlap_cost>
|
||||
{
|
||||
typedef typename index::detail::rtree_node<Value, Box, rtree_rstar_tag>::type node;
|
||||
typedef typename index::detail::rtree_internal_node<Value, Box, rtree_rstar_tag>::type internal_node;
|
||||
typedef typename index::detail::rtree_leaf<Value, Box, rtree_rstar_tag>::type leaf;
|
||||
|
||||
typedef typename internal_node::children_type children_type;
|
||||
|
||||
public:
|
||||
template <typename Indexable>
|
||||
static inline size_t apply(internal_node & n, Indexable const& indexable)
|
||||
{
|
||||
assert(!n.children.empty());
|
||||
|
||||
bool has_leaves = boost::apply_visitor(
|
||||
visitors::rtree_is_leaf<Value, Box, rtree_rstar_tag>(),
|
||||
*n.children.front().second);
|
||||
|
||||
if ( !has_leaves )
|
||||
return impl<internal_node_areas>(n, indexable);
|
||||
else
|
||||
return impl<branch_areas>(n, indexable);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Areas, typename Indexable>
|
||||
static inline size_t impl(internal_node & n, Indexable const& indexable)
|
||||
{
|
||||
typedef typename children_type::iterator children_iterator;
|
||||
|
||||
//assert(!n.children.empty());
|
||||
|
||||
children_iterator temp_it = n.children.begin();
|
||||
children_iterator child_it = temp_it;
|
||||
Areas min_areas(n.children, child_it, indexable);
|
||||
|
||||
for (children_iterator it = ++temp_it;
|
||||
it != n.children.end(); ++it)
|
||||
{
|
||||
Areas areas(n.children, it, indexable);
|
||||
|
||||
if ( areas < min_areas )
|
||||
{
|
||||
child_it = it;
|
||||
min_areas = areas;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: awulkiew - switch to indexes in the whole class?
|
||||
return child_it - n.children.begin();
|
||||
}
|
||||
|
||||
struct branch_areas
|
||||
{
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
|
||||
template <typename Indexable>
|
||||
inline branch_areas(children_type const& ch, typename children_type::iterator const& k_it, Indexable const& indexable)
|
||||
{
|
||||
overlap_area = 0;
|
||||
for (typename children_type::const_iterator it = ch.begin(); it != ch.end(); ++it)
|
||||
if ( it != k_it )
|
||||
overlap_area += index::overlap(k_it->first, it->first);
|
||||
|
||||
area = index::area(k_it->first);
|
||||
|
||||
diff_area = index::union_area(k_it->first, indexable) - area;
|
||||
}
|
||||
|
||||
inline bool operator<(branch_areas &a) const
|
||||
{
|
||||
return overlap_area < a.overlap_area ||
|
||||
( overlap_area == a.overlap_area && diff_area < a.diff_area ) ||
|
||||
( diff_area == a.diff_area && area < a.area );
|
||||
}
|
||||
|
||||
area_type overlap_area;
|
||||
area_type diff_area;
|
||||
area_type area;
|
||||
};
|
||||
|
||||
struct internal_node_areas
|
||||
{
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
|
||||
template <typename Indexable>
|
||||
inline internal_node_areas(children_type const&, typename children_type::iterator const& k_it, Indexable const& indexable)
|
||||
{
|
||||
area = index::area(k_it->first);
|
||||
diff_area = index::union_area(k_it->first, indexable) - area;
|
||||
}
|
||||
|
||||
inline bool operator<(internal_node_areas &a) const
|
||||
{
|
||||
return diff_area < a.diff_area ||
|
||||
( diff_area == a.diff_area && area < a.area );
|
||||
}
|
||||
|
||||
area_type diff_area;
|
||||
area_type area;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace visitors
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP
|
||||
@@ -23,578 +23,13 @@
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/rtree_insert.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/rtree_is_leaf.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/rstar/choose_next_node.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/rstar/split.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace visitors {
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// rstar/choose_next_node
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
// TODO: awulkiew - it's possible that goodness values may be used to choose next node
|
||||
|
||||
// rtree choose_next_node algorithm for rstar variant
|
||||
|
||||
template <typename Value, typename Box>
|
||||
class rtree_rstar_choose_next_node
|
||||
{
|
||||
typedef typename index::detail::rtree_node<Value, Box, rtree_rstar_tag>::type node;
|
||||
typedef typename index::detail::rtree_internal_node<Value, Box, rtree_rstar_tag>::type internal_node;
|
||||
typedef typename index::detail::rtree_leaf<Value, Box, rtree_rstar_tag>::type leaf;
|
||||
|
||||
typedef typename internal_node::children_type children_type;
|
||||
|
||||
public:
|
||||
// TODO: awulkiew - alternative lower-cost version of overlap calculation may be used (branch_areas)
|
||||
// TODO: awulkiew - further optimization: don't calculate area with the overlap, calculate it only if
|
||||
// overlap < smallest_overlap (and current area must be stored) OR
|
||||
// overlap == smallest_overlap (and area must be compared)
|
||||
template <typename Indexable>
|
||||
static inline size_t apply(internal_node & n, Indexable const& indexable)
|
||||
{
|
||||
assert(!n.children.empty());
|
||||
|
||||
bool has_leaves = boost::apply_visitor(
|
||||
visitors::rtree_is_leaf<Value, Box, rtree_rstar_tag>(),
|
||||
*n.children.front().second);
|
||||
|
||||
if ( !has_leaves )
|
||||
return impl<internal_node_areas>(n, indexable);
|
||||
else
|
||||
return impl<branch_areas>(n, indexable);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Areas, typename Indexable>
|
||||
static inline size_t impl(internal_node & n, Indexable const& indexable)
|
||||
{
|
||||
typedef typename children_type::iterator children_iterator;
|
||||
|
||||
//assert(!n.children.empty());
|
||||
|
||||
children_iterator temp_it = n.children.begin();
|
||||
children_iterator child_it = temp_it;
|
||||
Areas min_areas(n.children, child_it, indexable);
|
||||
|
||||
for (children_iterator it = ++temp_it;
|
||||
it != n.children.end(); ++it)
|
||||
{
|
||||
Areas areas(n.children, it, indexable);
|
||||
|
||||
if ( areas < min_areas )
|
||||
{
|
||||
child_it = it;
|
||||
min_areas = areas;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: awulkiew - switch to indexes in the whole class?
|
||||
return child_it - n.children.begin();
|
||||
}
|
||||
|
||||
struct branch_areas
|
||||
{
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
|
||||
template <typename Indexable>
|
||||
inline branch_areas(children_type const& ch, typename children_type::iterator const& k_it, Indexable const& indexable)
|
||||
{
|
||||
overlap_area = 0;
|
||||
for (typename children_type::const_iterator it = ch.begin(); it != ch.end(); ++it)
|
||||
if ( it != k_it )
|
||||
overlap_area += index::overlap(k_it->first, it->first);
|
||||
|
||||
area = index::area(k_it->first);
|
||||
|
||||
diff_area = index::union_area(k_it->first, indexable) - area;
|
||||
}
|
||||
|
||||
inline bool operator<(branch_areas &a) const
|
||||
{
|
||||
return overlap_area < a.overlap_area ||
|
||||
( overlap_area == a.overlap_area && diff_area < a.diff_area ) ||
|
||||
( diff_area == a.diff_area && area < a.area );
|
||||
}
|
||||
|
||||
area_type overlap_area;
|
||||
area_type diff_area;
|
||||
area_type area;
|
||||
};
|
||||
|
||||
struct internal_node_areas
|
||||
{
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
|
||||
template <typename Indexable>
|
||||
inline internal_node_areas(children_type const&, typename children_type::iterator const& k_it, Indexable const& indexable)
|
||||
{
|
||||
area = index::area(k_it->first);
|
||||
diff_area = index::union_area(k_it->first, indexable) - area;
|
||||
}
|
||||
|
||||
inline bool operator<(internal_node_areas &a) const
|
||||
{
|
||||
return diff_area < a.diff_area ||
|
||||
( diff_area == a.diff_area && area < a.area );
|
||||
}
|
||||
|
||||
area_type diff_area;
|
||||
area_type area;
|
||||
};
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// rstar/sorts
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
// elements ids less comparator
|
||||
|
||||
template <typename Elements, typename Translator, size_t Corner, size_t AxisIndex>
|
||||
class rtree_rstar_elements_indexes_less
|
||||
{
|
||||
public:
|
||||
rtree_rstar_elements_indexes_less(Elements const& elements, Translator const& tr)
|
||||
: m_elements(elements), m_tr(tr)
|
||||
{}
|
||||
|
||||
bool operator()(size_t e1_index, size_t e2_index)
|
||||
{
|
||||
return
|
||||
index::detail::get<Corner, AxisIndex>(
|
||||
index::detail::rtree_element_indexable(m_elements[e1_index], m_tr)
|
||||
)
|
||||
<
|
||||
index::detail::get<Corner, AxisIndex>(
|
||||
index::detail::rtree_element_indexable(m_elements[e2_index], m_tr)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
Elements const& m_elements;
|
||||
Translator const& m_tr;
|
||||
};
|
||||
|
||||
template <typename T, size_t Dimension>
|
||||
class rtree_rstar_vectors
|
||||
{
|
||||
public:
|
||||
inline rtree_rstar_vectors(size_t count)
|
||||
: m_count(count), m_ids(Dimension * 2 * count)
|
||||
{}
|
||||
|
||||
template <size_t AxisIndex, size_t Corner>
|
||||
inline typename std::vector<T>::iterator begin()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(AxisIndex < Dimension);
|
||||
BOOST_STATIC_ASSERT(Corner < 2);
|
||||
return m_ids.begin() + ( AxisIndex * 2 + Corner ) * m_count;
|
||||
}
|
||||
|
||||
template <size_t AxisIndex, size_t Corner>
|
||||
inline typename std::vector<T>::iterator end()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(AxisIndex < Dimension);
|
||||
BOOST_STATIC_ASSERT(Corner < 2);
|
||||
return m_ids.begin() + ( AxisIndex * 2 + Corner + 1) * m_count;
|
||||
}
|
||||
|
||||
template <size_t AxisIndex, size_t Corner>
|
||||
inline T const& get(size_t index) const
|
||||
{
|
||||
BOOST_STATIC_ASSERT(AxisIndex < Dimension);
|
||||
BOOST_STATIC_ASSERT(Corner < 2);
|
||||
assert(index < m_count);
|
||||
return m_ids[( AxisIndex * 2 + Corner ) * m_count + index];
|
||||
}
|
||||
|
||||
template <size_t AxisIndex, size_t Corner>
|
||||
inline void set(size_t index, T const& v)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(AxisIndex < Dimension);
|
||||
BOOST_STATIC_ASSERT(Corner < 2);
|
||||
assert(index < m_count);
|
||||
m_ids[( AxisIndex * 2 + Corner ) * m_count + index] = v;
|
||||
}
|
||||
|
||||
inline T const& get(size_t axis, size_t corner, size_t index) const
|
||||
{
|
||||
assert(axis < Dimension);
|
||||
assert(corner < 2);
|
||||
assert(index < m_count);
|
||||
return m_ids[( axis * 2 + corner ) * m_count + index];
|
||||
}
|
||||
|
||||
inline size_t vector_size() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_count;
|
||||
std::vector<T> m_ids;
|
||||
};
|
||||
|
||||
// init indexes of elements and sort them
|
||||
|
||||
template <typename Elements, typename Translator, size_t Dimension>
|
||||
class rtree_rstar_sorts_fill_ids
|
||||
{
|
||||
BOOST_STATIC_ASSERT(0 < Dimension);
|
||||
|
||||
public:
|
||||
template <size_t D>
|
||||
static inline void apply(rtree_rstar_vectors<size_t, D> & ids, Elements const& elements, Translator const& tr)
|
||||
{
|
||||
rtree_rstar_sorts_fill_ids<Elements, Translator, Dimension - 1>::apply(ids, elements, tr);
|
||||
|
||||
fill<min_corner>(ids, elements, tr);
|
||||
fill<max_corner>(ids, elements, tr);
|
||||
}
|
||||
|
||||
private:
|
||||
template <size_t Corner, size_t D>
|
||||
static inline void fill(rtree_rstar_vectors<size_t, D> & ids, Elements const& elements, Translator const& tr)
|
||||
{
|
||||
for ( size_t i = 0 ; i < elements.size() ; ++i )
|
||||
ids.set<Dimension - 1, Corner>(i, i);
|
||||
|
||||
rtree_rstar_elements_indexes_less<Elements, Translator, Corner, Dimension - 1> less(elements, tr);
|
||||
std::sort(ids.begin<Dimension - 1, Corner>(), ids.end<Dimension - 1, Corner>(), less);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Elements, typename Translator>
|
||||
class rtree_rstar_sorts_fill_ids<Elements, Translator, 1>
|
||||
{
|
||||
public:
|
||||
template <size_t D>
|
||||
static inline void apply(rtree_rstar_vectors<size_t, D> & ids, Elements const& elements, Translator const& tr)
|
||||
{
|
||||
fill<min_corner>(ids, elements, tr);
|
||||
fill<max_corner>(ids, elements, tr);
|
||||
}
|
||||
|
||||
private:
|
||||
template <size_t Corner, size_t D>
|
||||
static inline void fill(rtree_rstar_vectors<size_t, D> & ids, Elements const& elements, Translator const& tr)
|
||||
{
|
||||
for ( size_t i = 0 ; i < elements.size() ; ++i )
|
||||
ids.set<0, Corner>(i, i);
|
||||
|
||||
rtree_rstar_elements_indexes_less<Elements, Translator, Corner, 0> less(elements, tr);
|
||||
std::sort(ids.begin<0, Corner>(), ids.end<0, Corner>(), less);
|
||||
}
|
||||
};
|
||||
|
||||
// sorts for each axis for min and max
|
||||
|
||||
template <typename Elements, typename Translator, size_t Dimension>
|
||||
class rtree_rstar_sorts
|
||||
{
|
||||
public:
|
||||
inline rtree_rstar_sorts(Elements const& elements, Translator const& tr)
|
||||
: m_elems(elements), m_tr(tr), m_ids(m_elems.size())
|
||||
{
|
||||
rtree_rstar_sorts_fill_ids<Elements, Translator, Dimension>::apply(m_ids, elements, tr);
|
||||
}
|
||||
|
||||
// TODO: awulkiew - should those methods be here? Just leave get_element?
|
||||
|
||||
template <size_t AxisIndex, size_t Corner>
|
||||
inline typename index::detail::rtree_element_indexable_type<typename Elements::value_type, Translator>::type const&
|
||||
get_indexable(size_t index) const
|
||||
{
|
||||
size_t id = m_ids.get<AxisIndex, Corner>(index);
|
||||
return index::detail::rtree_element_indexable(m_elems[id], m_tr);
|
||||
}
|
||||
|
||||
inline typename index::detail::rtree_element_indexable_type<typename Elements::value_type, Translator>::type const&
|
||||
get_indexable(size_t axis, size_t corner, size_t index) const
|
||||
{
|
||||
size_t id = m_ids.get(axis, corner, index);
|
||||
return index::detail::rtree_element_indexable(m_elems[id], m_tr);
|
||||
}
|
||||
|
||||
template <size_t AxisIndex, size_t Corner>
|
||||
inline typename Elements::value_type const& get_element(size_t index) const
|
||||
{
|
||||
size_t id = m_ids.get<AxisIndex, Corner>(index);
|
||||
return m_elems[id];
|
||||
}
|
||||
|
||||
inline typename Elements::value_type const& get_element(size_t axis, size_t corner, size_t index) const
|
||||
{
|
||||
size_t id = m_ids.get(axis, corner, index);
|
||||
return m_elems[id];
|
||||
}
|
||||
|
||||
inline size_t sort_size() const
|
||||
{
|
||||
return m_ids.vector_size();
|
||||
}
|
||||
|
||||
private:
|
||||
Elements const& m_elems;
|
||||
Translator const& m_tr;
|
||||
|
||||
rtree_rstar_vectors<size_t, Dimension> m_ids;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- //
|
||||
// rstar/goodness_values
|
||||
// ----------------------------------------------------------------------------- //
|
||||
|
||||
// calculate margins, areas and overlaps
|
||||
|
||||
template <typename Box, size_t AxisIndex, size_t Corner>
|
||||
class rtree_rstar_calculate_goodness_values_for_axis
|
||||
{
|
||||
typedef typename geometry::traits::coordinate_type<
|
||||
typename geometry::traits::point_type<Box>::type
|
||||
>::type coordinate_type;
|
||||
|
||||
static const size_t dimension = geometry::traits::dimension<
|
||||
typename geometry::traits::point_type<Box>::type
|
||||
>::value;
|
||||
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
typedef boost::tuple<Box, Box, margin_type, overlap_type, area_type> goodness_type;
|
||||
|
||||
public:
|
||||
template <typename Elements, typename Translator>
|
||||
static inline void apply(
|
||||
rtree_rstar_vectors<goodness_type, dimension> & goodness_vectors,
|
||||
rtree_rstar_sorts<Elements, Translator, dimension> const& sorts,
|
||||
size_t min_elems,
|
||||
size_t max_elems)
|
||||
{
|
||||
assert(sorts.sort_size() == max_elems + 1);
|
||||
assert(goodness_vectors.vector_size() == max_elems - 2 * min_elems + 2);
|
||||
|
||||
size_t median_index_last = max_elems - min_elems + 2;
|
||||
size_t i = 0;
|
||||
for ( size_t median_index = min_elems ; median_index < median_index_last ; ++median_index, ++i )
|
||||
{
|
||||
Box left_box = calculate_box(sorts, 0, median_index);
|
||||
Box right_box = calculate_box(sorts, median_index, sorts.sort_size());
|
||||
|
||||
margin_type margin = index::margin(left_box) + index::margin(right_box);
|
||||
area_type area = index::area(left_box) + index::area(right_box);
|
||||
overlap_type overlap = index::overlap(left_box, right_box);
|
||||
|
||||
goodness_vectors.set<AxisIndex, Corner>(
|
||||
i,
|
||||
boost::make_tuple(left_box, right_box, margin, overlap, area));
|
||||
}
|
||||
}
|
||||
private:
|
||||
template <typename Elements, typename Translator>
|
||||
static inline Box calculate_box(
|
||||
rtree_rstar_sorts<Elements, Translator, dimension> const& sorts,
|
||||
size_t index_first,
|
||||
size_t index_last)
|
||||
{
|
||||
assert(index_first < index_last);
|
||||
|
||||
Box result;
|
||||
geometry::convert(sorts.template get_indexable<AxisIndex, Corner>(index_first), result);
|
||||
++index_first;
|
||||
for ( ; index_first < index_last ; ++index_first )
|
||||
geometry::expand(result, sorts.template get_indexable<AxisIndex, Corner>(index_first));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// calculate goodness values for all axis
|
||||
|
||||
template <typename Box, size_t Dimension>
|
||||
struct rtree_rstar_calculate_goodness_values
|
||||
{
|
||||
BOOST_STATIC_ASSERT(0 < Dimension);
|
||||
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
typedef boost::tuple<Box, Box, margin_type, overlap_type, area_type> goodness_type;
|
||||
|
||||
template <typename Elements, typename Translator, size_t D>
|
||||
static inline void apply(
|
||||
rtree_rstar_vectors<goodness_type, D> & goodness_vectors,
|
||||
rtree_rstar_sorts<Elements, Translator, D> const& sorts,
|
||||
size_t min_elems,
|
||||
size_t max_elems)
|
||||
{
|
||||
rtree_rstar_calculate_goodness_values<Box, Dimension - 1>
|
||||
::apply(goodness_vectors, sorts, min_elems, max_elems);
|
||||
|
||||
rtree_rstar_calculate_goodness_values_for_axis<Box, Dimension - 1, min_corner>
|
||||
::apply(goodness_vectors, sorts, min_elems, max_elems);
|
||||
rtree_rstar_calculate_goodness_values_for_axis<Box, Dimension - 1, max_corner>
|
||||
::apply(goodness_vectors, sorts, min_elems, max_elems);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box>
|
||||
struct rtree_rstar_calculate_goodness_values<Box, 1>
|
||||
{
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
typedef boost::tuple<Box, Box, margin_type, overlap_type, area_type> goodness_type;
|
||||
|
||||
template <typename Elements, typename Translator, size_t D>
|
||||
static inline void apply(
|
||||
rtree_rstar_vectors<goodness_type, D> & goodness_vectors,
|
||||
rtree_rstar_sorts<Elements, Translator, D> const& sorts,
|
||||
size_t min_elems,
|
||||
size_t max_elems)
|
||||
{
|
||||
rtree_rstar_calculate_goodness_values_for_axis<Box, 0, min_corner>
|
||||
::apply(goodness_vectors, sorts, min_elems, max_elems);
|
||||
rtree_rstar_calculate_goodness_values_for_axis<Box, 0, max_corner>
|
||||
::apply(goodness_vectors, sorts, min_elems, max_elems);
|
||||
}
|
||||
};
|
||||
|
||||
// goodness values
|
||||
|
||||
template <typename Elements, typename Translator, typename Box>
|
||||
class rtree_rstar_goodness_values
|
||||
{
|
||||
typedef typename geometry::traits::coordinate_type<
|
||||
typename geometry::traits::point_type<Box>::type
|
||||
>::type coordinate_type;
|
||||
|
||||
static const size_t dimension = geometry::traits::dimension<
|
||||
typename geometry::traits::point_type<Box>::type
|
||||
>::value;
|
||||
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
typedef boost::tuple<Box, Box, margin_type, overlap_type, area_type> goodness_type;
|
||||
|
||||
public:
|
||||
inline rtree_rstar_goodness_values(
|
||||
Elements const& elements,
|
||||
Translator const& tr,
|
||||
size_t min_elems,
|
||||
size_t max_elems)
|
||||
: m_sorts(elements, tr)
|
||||
, m_goodness_vectors(max_elems - 2 * min_elems + 2)
|
||||
{
|
||||
rtree_rstar_calculate_goodness_values<Box, dimension>::apply(
|
||||
m_goodness_vectors, m_sorts, min_elems, max_elems);
|
||||
}
|
||||
|
||||
inline size_t elements_size() const
|
||||
{
|
||||
return m_sorts.sort_size();
|
||||
}
|
||||
|
||||
inline size_t goodnesses_size() const
|
||||
{
|
||||
return m_goodness_vectors.vector_size();
|
||||
}
|
||||
|
||||
inline goodness_type const& get_goodness(size_t axis, size_t corner, size_t index) const
|
||||
{
|
||||
return m_goodness_vectors.get(axis, corner, index);
|
||||
}
|
||||
|
||||
inline typename Elements::value_type const& get_element(size_t axis, size_t corner, size_t index) const
|
||||
{
|
||||
return m_sorts.get_element(axis, corner, index);
|
||||
}
|
||||
|
||||
private:
|
||||
rtree_rstar_sorts<Elements, Translator, dimension> m_sorts;
|
||||
rtree_rstar_vectors<goodness_type, dimension> m_goodness_vectors;
|
||||
};
|
||||
|
||||
template <typename Elements, typename Translator, typename Box>
|
||||
class rtree_rstar_choose_split_axis
|
||||
{
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
public:
|
||||
static inline std::pair<size_t, size_t> apply(rtree_rstar_goodness_values<Elements, Translator, Box> const& gv)
|
||||
{
|
||||
std::pair<size_t, size_t> smallest_distr = std::make_pair(0, 0);
|
||||
margin_type smallest_margins_sum = calculate_margins_sum(0, 0, gv);
|
||||
|
||||
margin_type margins_sum = calculate_margins_sum(0, 1, gv);
|
||||
if ( margins_sum < smallest_margins_sum )
|
||||
{
|
||||
smallest_distr.second = 1;
|
||||
smallest_margins_sum = margins_sum;
|
||||
}
|
||||
|
||||
for ( size_t a = 1 ; a < traits::dimension<Box>::value ; ++a )
|
||||
{
|
||||
for ( size_t c = 0 ; c < 2 ; ++c )
|
||||
{
|
||||
margins_sum = calculate_margins_sum(a, c, gv);
|
||||
if ( margins_sum < smallest_margins_sum )
|
||||
{
|
||||
smallest_distr.first = a;
|
||||
smallest_distr.second = c;
|
||||
smallest_margins_sum = margins_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
return smallest_distr;
|
||||
}
|
||||
private:
|
||||
static inline typename margin_result<Box>::type
|
||||
calculate_margins_sum(size_t axis, size_t corner, rtree_rstar_goodness_values<Elements, Translator, Box> const& gv)
|
||||
{
|
||||
typename margin_result<Box>::type margins_sum = 0;
|
||||
for ( size_t i = 0 ; i < gv.goodnesses_size() ; ++i )
|
||||
margins_sum += boost::get<2>(gv.get_goodness(axis, corner, i));
|
||||
return margins_sum;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Elements, typename Translator, typename Box>
|
||||
class rtree_rstar_choose_split_index
|
||||
{
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
public:
|
||||
static inline size_t apply(rtree_rstar_goodness_values<Elements, Translator, Box> const& gv, size_t axis, size_t corner)
|
||||
{
|
||||
size_t smallest_index = 0;
|
||||
overlap_type smallest_overlap = boost::get<3>(gv.get_goodness(axis, corner, 0));
|
||||
overlap_type smallest_area = boost::get<4>(gv.get_goodness(axis, corner, 0));
|
||||
|
||||
for ( size_t i = 1 ; i < gv.goodnesses_size() ; ++i )
|
||||
{
|
||||
overlap_type overlap = boost::get<3>(gv.get_goodness(axis, corner, i));
|
||||
if ( overlap < smallest_overlap )
|
||||
{
|
||||
smallest_overlap = overlap;
|
||||
smallest_area = boost::get<4>(gv.get_goodness(axis, corner, i));
|
||||
smallest_index = i;
|
||||
}
|
||||
else if ( overlap == smallest_overlap )
|
||||
{
|
||||
area_type area = boost::get<4>(gv.get_goodness(axis, corner, i));
|
||||
if ( area < smallest_area )
|
||||
{
|
||||
smallest_area = area;
|
||||
smallest_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return smallest_index;
|
||||
}
|
||||
};
|
||||
|
||||
// rtree insert routine for rstar variant
|
||||
|
||||
template <typename Value, typename Translator, typename Box>
|
||||
class rtree_insert<Value, Translator, Box, rtree_rstar_tag> : public boost::static_visitor<>
|
||||
{
|
||||
@@ -617,7 +52,9 @@ public:
|
||||
size_t current_child_index_bckup = m_current_child_index;
|
||||
|
||||
// choose next node, where value insert traversing should go
|
||||
m_current_child_index = rtree_rstar_choose_next_node<Value, Box>::apply(n, m_tr(m_value));
|
||||
m_current_child_index =
|
||||
rtree_rstar_choose_next_node<Value, Box, rtree_rstar_chnn_min_overlap_cost>::
|
||||
apply(n, m_tr(m_value));
|
||||
|
||||
// TODO: awulkiew - if reinsert is implemented this must be changed
|
||||
geometry::expand(n.children[m_current_child_index].first, m_tr(m_value));
|
||||
@@ -631,7 +68,8 @@ public:
|
||||
|
||||
if ( m_max_elems_per_node < n.children.size() )
|
||||
{
|
||||
split(n);
|
||||
rtree_rstar_split<Value, Translator, Box>::
|
||||
apply(n, m_parent, m_current_child_index, m_root_node, m_min_elems_per_node, m_max_elems_per_node, m_tr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,75 +79,12 @@ public:
|
||||
|
||||
if ( m_max_elems_per_node < n.values.size() )
|
||||
{
|
||||
split(n);
|
||||
rtree_rstar_split<Value, Translator, Box>::
|
||||
apply(n, m_parent, m_current_child_index, m_root_node, m_min_elems_per_node, m_max_elems_per_node, m_tr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Node>
|
||||
inline void split(Node & n)
|
||||
{
|
||||
typedef typename index::detail::rtree_elements_type<Node>::type elements_type;
|
||||
typedef typename elements_type::value_type element_type;
|
||||
|
||||
elements_type & elems = index::detail::get_elements(n);
|
||||
|
||||
rtree_rstar_goodness_values<elements_type, Translator, Box> gv(elems, m_tr, m_min_elems_per_node, m_max_elems_per_node);
|
||||
|
||||
std::pair<size_t, size_t> axis_and_corner =
|
||||
rtree_rstar_choose_split_axis<elements_type, Translator, Box>::apply(gv);
|
||||
size_t axis = axis_and_corner.first;
|
||||
size_t corner = axis_and_corner.second;
|
||||
|
||||
size_t choosen_index =
|
||||
rtree_rstar_choose_split_index<elements_type, Translator, Box>::apply(gv, axis, corner);
|
||||
|
||||
size_t median_index = m_min_elems_per_node + choosen_index;
|
||||
assert(median_index <= m_max_elems_per_node + 1 - m_min_elems_per_node);
|
||||
|
||||
// create new node
|
||||
node * right_node = rtree_create_node(Node());
|
||||
elements_type & new_elems = index::detail::get_elements(boost::get<Node>(*right_node));
|
||||
|
||||
// update new node's elements
|
||||
new_elems.reserve(m_max_elems_per_node + 1 - median_index);
|
||||
for ( size_t i = median_index ; i < m_max_elems_per_node + 1 ; ++i)
|
||||
new_elems.push_back(gv.get_element(axis, corner, i));
|
||||
|
||||
// fill temporary container with left node's elements
|
||||
elements_type left_elems;
|
||||
left_elems.reserve(median_index);
|
||||
for ( size_t i = 0 ; i < median_index ; ++i )
|
||||
left_elems.push_back(gv.get_element(axis, corner, i));
|
||||
// update old node's elements
|
||||
elems = left_elems;
|
||||
|
||||
if ( m_parent != 0 )
|
||||
{
|
||||
// update old node's box
|
||||
m_parent->children[m_current_child_index].first = boost::get<0>(gv.get_goodness(axis, corner, choosen_index));
|
||||
// add new node to the parent's children
|
||||
m_parent->children.push_back( std::make_pair(
|
||||
boost::get<1>(gv.get_goodness(axis, corner, choosen_index)), right_node ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(&n == boost::get<Node>(m_root_node));
|
||||
|
||||
// create new root and add nodes
|
||||
node * new_root = rtree_create_node(internal_node());
|
||||
|
||||
boost::get<internal_node>(*new_root).children.push_back(
|
||||
std::make_pair(boost::get<0>(gv.get_goodness(axis, corner, choosen_index)), m_root_node)
|
||||
);
|
||||
boost::get<internal_node>(*new_root).children.push_back(
|
||||
std::make_pair(boost::get<1>(gv.get_goodness(axis, corner, choosen_index)), right_node)
|
||||
);
|
||||
|
||||
m_root_node = new_root;
|
||||
}
|
||||
}
|
||||
|
||||
Value const& m_value;
|
||||
Translator const& m_tr;
|
||||
size_t m_min_elems_per_node;
|
||||
|
||||
338
include/boost/geometry/extensions/index/rtree/rstar/split.hpp
Normal file
338
include/boost/geometry/extensions/index/rtree/rstar/split.hpp
Normal file
@@ -0,0 +1,338 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
//
|
||||
// Boost.Index - R*-tree split algorithm implementation
|
||||
//
|
||||
// Copyright 2011 Adam Wulkiewicz.
|
||||
// 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_EXTENSIONS_INDEX_RTREE_RSTAR_SPLIT_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RSTAR_SPLIT_HPP
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/algorithms/area.hpp>
|
||||
#include <boost/geometry/extensions/index/algorithms/margin.hpp>
|
||||
#include <boost/geometry/extensions/index/algorithms/overlap.hpp>
|
||||
#include <boost/geometry/extensions/index/algorithms/union_area.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/rtree_node.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/rtree_insert.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/rtree_is_leaf.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace visitors {
|
||||
|
||||
// elements less
|
||||
|
||||
template <typename Elements, typename Translator, size_t AxisIndex, size_t Corner>
|
||||
class rtree_rstar_elements_less
|
||||
{
|
||||
typedef typename Elements::value_type element_type;
|
||||
public:
|
||||
inline rtree_rstar_elements_less(Translator const& tr)
|
||||
: m_tr(tr)
|
||||
{}
|
||||
|
||||
inline bool operator()(element_type const& e1, element_type const e2) const
|
||||
{
|
||||
return
|
||||
index::detail::get<Corner, AxisIndex>(
|
||||
index::detail::rtree_element_indexable(e1, m_tr)
|
||||
)
|
||||
<
|
||||
index::detail::get<Corner, AxisIndex>(
|
||||
index::detail::rtree_element_indexable(e2, m_tr)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
Translator const& m_tr;
|
||||
};
|
||||
|
||||
// rstar split axis data
|
||||
|
||||
template <typename Box>
|
||||
struct rtree_rstar_split_axis_data
|
||||
{
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
|
||||
inline rtree_rstar_split_axis_data()
|
||||
: margins_sum(0)
|
||||
, smallest_overlap(std::numeric_limits<overlap_type>::max())
|
||||
, smallest_area(std::numeric_limits<area_type>::max())
|
||||
{}
|
||||
|
||||
inline void update(
|
||||
size_t corner,
|
||||
size_t median_index,
|
||||
Box const& left_box,
|
||||
Box const& right_box,
|
||||
margin_type const& margin,
|
||||
overlap_type const& overlap,
|
||||
area_type const& area)
|
||||
{
|
||||
margins_sum += margin;
|
||||
|
||||
if ( overlap < smallest_overlap ||
|
||||
( overlap == smallest_overlap && area < smallest_area ) )
|
||||
{
|
||||
choosen_corner = corner;
|
||||
choosen_median_index = median_index;
|
||||
choosen_left_box = left_box;
|
||||
choosen_right_box = right_box;
|
||||
smallest_overlap = overlap;
|
||||
smallest_area = area;
|
||||
}
|
||||
}
|
||||
|
||||
size_t choosen_corner;
|
||||
size_t choosen_median_index;
|
||||
Box choosen_left_box;
|
||||
Box choosen_right_box;
|
||||
margin_type margins_sum;
|
||||
overlap_type smallest_overlap;
|
||||
area_type smallest_area;
|
||||
};
|
||||
|
||||
// update axis data for given axis and corner
|
||||
|
||||
template <typename Value, typename Translator, typename Box, size_t Corner>
|
||||
class rtree_rstar_split_update_axis_data_for_corner
|
||||
{
|
||||
typedef typename rtree_rstar_split_axis_data<Box>::margin_type margin_type;
|
||||
typedef typename rtree_rstar_split_axis_data<Box>::overlap_type overlap_type;
|
||||
typedef typename rtree_rstar_split_axis_data<Box>::area_type area_type;
|
||||
|
||||
BOOST_STATIC_ASSERT(Corner < 2);
|
||||
|
||||
public:
|
||||
template <typename Elements>
|
||||
static inline void apply(
|
||||
rtree_rstar_split_axis_data<Box> & split_axis_data,
|
||||
Elements const& sorted_elements,
|
||||
size_t min_elems,
|
||||
size_t max_elems,
|
||||
Translator const& tr)
|
||||
{
|
||||
size_t median_index_last = max_elems - min_elems + 2;
|
||||
for ( size_t median_index = min_elems ; median_index < median_index_last ; ++median_index )
|
||||
{
|
||||
Box left_box = index::detail::elements_box<Box>(sorted_elements.begin(), sorted_elements.begin() + median_index, tr);
|
||||
Box right_box = index::detail::elements_box<Box>(sorted_elements.begin() + median_index, sorted_elements.end(), tr);
|
||||
|
||||
margin_type margin = index::margin(left_box) + index::margin(right_box);
|
||||
overlap_type overlap = index::overlap(left_box, right_box);
|
||||
area_type area = index::area(left_box) + index::area(right_box);
|
||||
|
||||
split_axis_data.update(Corner, median_index, left_box, right_box, margin, overlap, area);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// split data
|
||||
|
||||
template <typename Elements, typename Box>
|
||||
struct rtree_rstar_split_data
|
||||
{
|
||||
typedef typename margin_result<Box>::type margin_type;
|
||||
typedef typename overlap_result<Box>::type overlap_type;
|
||||
typedef typename area_result<Box>::type area_type;
|
||||
|
||||
inline rtree_rstar_split_data()
|
||||
: smallest_margins_sum(std::numeric_limits<margin_type>::max())
|
||||
{}
|
||||
|
||||
inline void update(
|
||||
size_t axis,
|
||||
size_t corner,
|
||||
size_t median_index,
|
||||
Box const& left_box,
|
||||
Box const& right_box,
|
||||
margin_type const& margins_sum,
|
||||
Elements const& distribution)
|
||||
{
|
||||
if ( margins_sum < smallest_margins_sum )
|
||||
{
|
||||
choosen_axis = axis;
|
||||
choosen_corner = corner;
|
||||
choosen_median_index = median_index;
|
||||
choosen_left_box = left_box;
|
||||
choosen_right_box = right_box;
|
||||
smallest_margins_sum = margins_sum;
|
||||
choosen_distribution = distribution;
|
||||
}
|
||||
}
|
||||
|
||||
size_t choosen_axis;
|
||||
size_t choosen_corner;
|
||||
size_t choosen_median_index;
|
||||
Box choosen_left_box;
|
||||
Box choosen_right_box;
|
||||
margin_type smallest_margins_sum;
|
||||
Elements choosen_distribution;
|
||||
};
|
||||
|
||||
// update split data for given axis and corner
|
||||
|
||||
template <typename Value, typename Translator, typename Box, size_t AxisIndex, size_t Corner>
|
||||
class rtree_rstar_split_update_data_for_axis_and_corner
|
||||
{
|
||||
typedef typename rtree_rstar_split_axis_data<Box>::margin_type margin_type;
|
||||
typedef typename rtree_rstar_split_axis_data<Box>::overlap_type overlap_type;
|
||||
typedef typename rtree_rstar_split_axis_data<Box>::area_type area_type;
|
||||
|
||||
public:
|
||||
template <typename Elements>
|
||||
static inline void apply(
|
||||
rtree_rstar_split_data<Elements, Box> & split_data,
|
||||
Elements & elements,
|
||||
size_t min_elems,
|
||||
size_t max_elems,
|
||||
Translator const& tr)
|
||||
{
|
||||
rtree_rstar_split_axis_data<Box> split_axis_data;
|
||||
|
||||
rtree_rstar_elements_less<Elements, Translator, AxisIndex, Corner> less_min(tr);
|
||||
std::sort(elements.begin(), elements.end(), less_min);
|
||||
|
||||
rtree_rstar_split_update_axis_data_for_corner<Value, Translator, Box, Corner>::
|
||||
apply(split_axis_data, elements, min_elems, max_elems, tr);
|
||||
|
||||
split_data.update(
|
||||
AxisIndex,
|
||||
split_axis_data.choosen_corner,
|
||||
split_axis_data.choosen_median_index,
|
||||
split_axis_data.choosen_left_box,
|
||||
split_axis_data.choosen_right_box,
|
||||
split_axis_data.margins_sum,
|
||||
elements);
|
||||
}
|
||||
};
|
||||
|
||||
// for each dimension and corner update split data
|
||||
|
||||
template <typename Value, typename Translator, typename Box, size_t Dimension>
|
||||
struct rtree_rstar_split_update_data
|
||||
{
|
||||
BOOST_STATIC_ASSERT(0 < Dimension);
|
||||
|
||||
template <typename Elements>
|
||||
static inline void apply(
|
||||
rtree_rstar_split_data<Elements, Box> & split_data,
|
||||
Elements & elements,
|
||||
size_t min_elems,
|
||||
size_t max_elems,
|
||||
Translator const& tr)
|
||||
{
|
||||
rtree_rstar_split_update_data<Value, Translator, Box, Dimension - 1>::
|
||||
apply(split_data, elements, min_elems, max_elems, tr);
|
||||
|
||||
rtree_rstar_split_update_data_for_axis_and_corner<Value, Translator, Box, Dimension - 1, min_corner>::
|
||||
apply(split_data, elements, min_elems, max_elems, tr);
|
||||
rtree_rstar_split_update_data_for_axis_and_corner<Value, Translator, Box, Dimension - 1, max_corner>::
|
||||
apply(split_data, elements, min_elems, max_elems, tr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Value, typename Translator, typename Box>
|
||||
struct rtree_rstar_split_update_data<Value, Translator, Box, 1>
|
||||
{
|
||||
template <typename Elements>
|
||||
static inline void apply(
|
||||
rtree_rstar_split_data<Elements, Box> & split_data,
|
||||
Elements & elements,
|
||||
size_t min_elems,
|
||||
size_t max_elems,
|
||||
Translator const& tr)
|
||||
{
|
||||
rtree_rstar_split_update_data_for_axis_and_corner<Value, Translator, Box, 0, min_corner>::
|
||||
apply(split_data, elements, min_elems, max_elems, tr);
|
||||
rtree_rstar_split_update_data_for_axis_and_corner<Value, Translator, Box, 0, max_corner>::
|
||||
apply(split_data, elements, min_elems, max_elems, tr);
|
||||
}
|
||||
};
|
||||
|
||||
// split
|
||||
|
||||
template <typename Value, typename Translator, typename Box>
|
||||
class rtree_rstar_split
|
||||
{
|
||||
typedef typename index::detail::rtree_node<Value, Box, rtree_rstar_tag>::type node;
|
||||
typedef typename index::detail::rtree_internal_node<Value, Box, rtree_rstar_tag>::type internal_node;
|
||||
typedef typename index::detail::rtree_leaf<Value, Box, rtree_rstar_tag>::type leaf;
|
||||
|
||||
static const size_t dimension = index::traits::dimension<Box>::value;
|
||||
|
||||
public:
|
||||
template <typename Node>
|
||||
static inline void apply(
|
||||
Node & n,
|
||||
internal_node *parent,
|
||||
size_t current_child_index,
|
||||
node *& root,
|
||||
size_t min_elems,
|
||||
size_t max_elems,
|
||||
Translator const& tr)
|
||||
{
|
||||
typedef typename index::detail::rtree_elements_type<Node>::type elements_type;
|
||||
typedef typename elements_type::value_type element_type;
|
||||
|
||||
elements_type & elements = index::detail::get_elements(n);
|
||||
|
||||
// get split data
|
||||
rtree_rstar_split_data<elements_type, Box> split_data;
|
||||
rtree_rstar_split_update_data<Value, Translator, Box, dimension>::
|
||||
apply(split_data, elements, min_elems, max_elems, tr);
|
||||
|
||||
// create new node
|
||||
node * right_node = rtree_create_node(Node());
|
||||
elements_type & new_elems = index::detail::get_elements(boost::get<Node>(*right_node));
|
||||
|
||||
// update new node's elements
|
||||
new_elems.resize(max_elems + 1 - split_data.choosen_median_index);
|
||||
std::copy(
|
||||
split_data.choosen_distribution.begin() + split_data.choosen_median_index,
|
||||
split_data.choosen_distribution.end(),
|
||||
new_elems.begin());
|
||||
|
||||
// update elements of the current node
|
||||
elements.resize(split_data.choosen_median_index);
|
||||
std::copy(
|
||||
split_data.choosen_distribution.begin(),
|
||||
split_data.choosen_distribution.begin() + split_data.choosen_median_index,
|
||||
elements.begin());
|
||||
|
||||
if ( parent != 0 )
|
||||
{
|
||||
// update old node's box
|
||||
parent->children[current_child_index].first = split_data.choosen_left_box;
|
||||
// add new node to the parent's children
|
||||
parent->children.push_back(std::make_pair(split_data.choosen_right_box, right_node));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(&n == boost::get<Node>(root));
|
||||
|
||||
// create new root and add nodes
|
||||
node * new_root = rtree_create_node(internal_node());
|
||||
|
||||
boost::get<internal_node>(*new_root).children.push_back(std::make_pair(split_data.choosen_left_box, root));
|
||||
boost::get<internal_node>(*new_root).children.push_back(std::make_pair(split_data.choosen_right_box, right_node));
|
||||
|
||||
root = new_root;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace visitors
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RSTAR_SPLIT_HPP
|
||||
@@ -41,18 +41,17 @@ public:
|
||||
typedef typename detail::rtree_internal_node<Value, box_type, rtree_rstar_tag>::type internal_node;
|
||||
typedef typename detail::rtree_leaf<Value, box_type, rtree_rstar_tag>::type leaf;
|
||||
|
||||
inline explicit rtree(size_t max_elems_per_node = 4, size_t min_elems_per_node = 2, translator_type const& translator = translator_type())
|
||||
inline explicit rtree(size_t max_elems_per_node = 2, size_t min_elems_per_node = 1, translator_type const& translator = translator_type())
|
||||
: m_values_count(0)
|
||||
, m_max_elems_per_node(max_elems_per_node)
|
||||
, m_min_elems_per_node(min_elems_per_node)
|
||||
, m_root(0)
|
||||
, m_translator(translator)
|
||||
{
|
||||
if ( min_elems_per_node < 2 )
|
||||
min_elems_per_node = 2;
|
||||
|
||||
// TODO: awulkiew - reconsider following assert
|
||||
assert(2 * m_min_elems_per_node <= m_max_elems_per_node);
|
||||
if ( m_min_elems_per_node < 1 )
|
||||
m_min_elems_per_node = 1;
|
||||
if ( m_max_elems_per_node < 2 )
|
||||
m_max_elems_per_node = 2;
|
||||
|
||||
m_root = detail::rtree_create_node(leaf());
|
||||
}
|
||||
@@ -82,9 +81,9 @@ public:
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
void apply_visitor(Visitor & visitor) const
|
||||
typename Visitor::result_type apply_visitor(Visitor & visitor) const
|
||||
{
|
||||
boost::apply_visitor(visitor, *m_root);
|
||||
return boost::apply_visitor(visitor, *m_root);
|
||||
}
|
||||
|
||||
translator_type const& get_translator() const
|
||||
|
||||
@@ -153,6 +153,24 @@ rtree_element_indexable(Value const& el, Translator const& tr)
|
||||
return tr(el);
|
||||
};
|
||||
|
||||
// elements box
|
||||
|
||||
template <typename Box, typename FwdIter, typename Translator>
|
||||
inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr)
|
||||
{
|
||||
assert(first != last);
|
||||
|
||||
Box result;
|
||||
|
||||
geometry::convert(index::detail::rtree_element_indexable(*first, tr), result);
|
||||
++first;
|
||||
|
||||
for ( ; first != last ; ++first )
|
||||
geometry::expand(result, index::detail::rtree_element_indexable(*first, tr));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// create leaf node
|
||||
|
||||
template <typename Value, typename Box, typename Tag>
|
||||
|
||||
@@ -27,10 +27,10 @@ struct rtree_gl_draw_point
|
||||
template <typename Point>
|
||||
struct rtree_gl_draw_point<Point, 2>
|
||||
{
|
||||
static inline void apply(Point const& p)
|
||||
static inline void apply(Point const& p, size_t level)
|
||||
{
|
||||
glBegin(GL_POINT);
|
||||
glVertex2f(geometry::get<0>(p), geometry::get<1>(p));
|
||||
glVertex2f(geometry::get<0>(p), geometry::get<1>(p), level);
|
||||
glEnd();
|
||||
}
|
||||
};
|
||||
@@ -42,13 +42,13 @@ struct rtree_gl_draw_box
|
||||
template <typename Box>
|
||||
struct rtree_gl_draw_box<Box, 2>
|
||||
{
|
||||
static inline void apply(Box const& b)
|
||||
static inline void apply(Box const& b, size_t level)
|
||||
{
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(geometry::get<min_corner, 0>(b), geometry::get<min_corner, 1>(b));
|
||||
glVertex2f(geometry::get<max_corner, 0>(b), geometry::get<min_corner, 1>(b));
|
||||
glVertex2f(geometry::get<max_corner, 0>(b), geometry::get<max_corner, 1>(b));
|
||||
glVertex2f(geometry::get<min_corner, 0>(b), geometry::get<max_corner, 1>(b));
|
||||
glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<min_corner, 1>(b), level);
|
||||
glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<min_corner, 1>(b), level);
|
||||
glVertex3f(geometry::get<max_corner, 0>(b), geometry::get<max_corner, 1>(b), level);
|
||||
glVertex3f(geometry::get<min_corner, 0>(b), geometry::get<max_corner, 1>(b), level);
|
||||
glEnd();
|
||||
}
|
||||
};
|
||||
@@ -64,9 +64,9 @@ struct rtree_gl_draw_indexable<Indexable, box_tag>
|
||||
typedef typename geometry::traits::point_type<Indexable>::type point_type;
|
||||
static const size_t dimension = geometry::traits::dimension<point_type>::value;
|
||||
|
||||
static inline void apply(Indexable const& i)
|
||||
static inline void apply(Indexable const& i, size_t level)
|
||||
{
|
||||
rtree_gl_draw_box<Indexable, dimension>::apply(i);
|
||||
rtree_gl_draw_box<Indexable, dimension>::apply(i, level);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,9 +75,9 @@ struct rtree_gl_draw_indexable<Indexable, point_tag>
|
||||
{
|
||||
static const size_t dimension = geometry::traits::dimension<Indexable>::value;
|
||||
|
||||
static inline void apply(std::ostream &os, Indexable const& i)
|
||||
static inline void apply(Indexable const& i, size_t level)
|
||||
{
|
||||
rtree_gl_draw_point<Indexable, dimension>::apply(i);
|
||||
rtree_gl_draw_point<Indexable, dimension>::apply(i, level);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -86,12 +86,12 @@ struct rtree_gl_draw_indexable<Indexable, point_tag>
|
||||
namespace detail {
|
||||
|
||||
template <typename Indexable>
|
||||
inline void rtree_gl_draw_indexable(Indexable const& i)
|
||||
inline void rtree_gl_draw_indexable(Indexable const& i, size_t level)
|
||||
{
|
||||
dispatch::rtree_gl_draw_indexable<
|
||||
Indexable,
|
||||
typename geometry::traits::tag<Indexable>::type
|
||||
>::apply(i);
|
||||
>::apply(i, level);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@@ -128,7 +128,7 @@ struct rtree_gl_draw : public boost::static_visitor<>
|
||||
for (typename children_type::const_iterator it = n.children.begin();
|
||||
it != n.children.end(); ++it)
|
||||
{
|
||||
detail::rtree_gl_draw_indexable(it->first);
|
||||
detail::rtree_gl_draw_indexable(it->first, level);
|
||||
}
|
||||
|
||||
size_t level_backup = level;
|
||||
@@ -152,7 +152,7 @@ struct rtree_gl_draw : public boost::static_visitor<>
|
||||
for (typename values_type::const_iterator it = n.values.begin();
|
||||
it != n.values.end(); ++it)
|
||||
{
|
||||
detail::rtree_gl_draw_indexable(tr(*it));
|
||||
detail::rtree_gl_draw_indexable(tr(*it), level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,22 +128,15 @@ struct rtree_print : public boost::static_visitor<>
|
||||
{
|
||||
typedef typename internal_node::children_type children_type;
|
||||
|
||||
os << " --> Node --------" << std::endl;
|
||||
os << " Address: " << this << std::endl;
|
||||
os << " Level: " << level << std::endl;
|
||||
os << " Children: " << n.children.size() << std::endl;
|
||||
os << " | ";
|
||||
|
||||
spaces(level) << "INTERNAL NODE - L:" << level << " Ch:" << n.children.size() << " @:" << &n << '\n';
|
||||
|
||||
for (typename children_type::const_iterator it = n.children.begin();
|
||||
it != n.children.end(); ++it)
|
||||
{
|
||||
spaces(level);
|
||||
detail::rtree_print_indexable(os, it->first);
|
||||
os << " | ";
|
||||
os << " ->" << it->second << '\n';
|
||||
}
|
||||
os << std::endl;
|
||||
os << " --< Node --------" << std::endl;
|
||||
|
||||
os << " Children: " << std::endl;
|
||||
|
||||
size_t level_backup = level;
|
||||
++level;
|
||||
@@ -161,17 +154,21 @@ struct rtree_print : public boost::static_visitor<>
|
||||
{
|
||||
typedef typename leaf::values_type values_type;
|
||||
|
||||
os << "\t" << " --> Leaf --------" << std::endl;
|
||||
os << "\t" << " Values: " << n.values.size() << std::endl;
|
||||
spaces(level) << "LEAF - L:" << level << " V:" << n.values.size() << " @:" << &n << '\n';
|
||||
for (typename values_type::const_iterator it = n.values.begin();
|
||||
it != n.values.end(); ++it)
|
||||
{
|
||||
os << "\t" << " | ";
|
||||
spaces(level);
|
||||
detail::rtree_print_indexable(os, tr(*it));
|
||||
os << " | " << std::endl;;
|
||||
os << '\n';
|
||||
}
|
||||
os << "\t" << " --< Leaf --------" << std::endl;
|
||||
}
|
||||
|
||||
inline std::ostream & spaces(size_t level)
|
||||
{
|
||||
for ( size_t i = 0 ; i < 2 * level ; ++i )
|
||||
os << ' ';
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream & os;
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
//
|
||||
// Boost.Index - R-tree boxes checking visitor
|
||||
//
|
||||
// Copyright 2011 Adam Wulkiewicz.
|
||||
// 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_EXTENSIONS_INDEX_RTREE_VISITORS_RTREE_ARE_BOXES_OK_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_VISITORS_RTREE_ARE_BOXES_OK_HPP
|
||||
|
||||
#include <boost/geometry/algorithms//equals.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/rtree_node.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
namespace visitors {
|
||||
|
||||
template <typename Value, typename Translator, typename Box, typename Tag>
|
||||
class rtree_are_boxes_ok : public boost::static_visitor<bool>
|
||||
{
|
||||
typedef typename index::detail::rtree_internal_node<Value, Box, Tag>::type internal_node;
|
||||
typedef typename index::detail::rtree_leaf<Value, Box, Tag>::type leaf;
|
||||
|
||||
public:
|
||||
inline rtree_are_boxes_ok(Translator const& tr)
|
||||
: m_tr(tr), m_is_root(true)
|
||||
{}
|
||||
|
||||
inline bool operator()(internal_node const& n)
|
||||
{
|
||||
if (n.children.empty())
|
||||
return false;
|
||||
|
||||
Box box_bckup = m_box;
|
||||
bool is_root_bckup = m_is_root;
|
||||
|
||||
m_is_root = false;
|
||||
|
||||
for ( internal_node::children_type::const_iterator it = n.children.begin();
|
||||
it != n.children.end() ; ++it)
|
||||
{
|
||||
m_box = it->first;
|
||||
|
||||
if ( false == boost::apply_visitor(*this, *it->second) )
|
||||
return false;
|
||||
}
|
||||
|
||||
m_box = box_bckup;
|
||||
m_is_root = is_root_bckup;
|
||||
|
||||
Box result;
|
||||
geometry::convert(n.children.front().first, result);
|
||||
for(internal_node::children_type::const_iterator it = n.children.begin() + 1;
|
||||
it != n.children.end() ; ++it)
|
||||
{
|
||||
geometry::expand(result, it->first);
|
||||
}
|
||||
|
||||
return m_is_root || geometry::equals(result, m_box);
|
||||
}
|
||||
|
||||
inline bool operator()(leaf const& n)
|
||||
{
|
||||
if (n.values.empty())
|
||||
return false;
|
||||
|
||||
Box result;
|
||||
geometry::convert(m_tr(n.values.front()), result);
|
||||
for(leaf::values_type::const_iterator it = n.values.begin() + 1;
|
||||
it != n.values.end() ; ++it)
|
||||
{
|
||||
geometry::expand(result, m_tr(*it));
|
||||
}
|
||||
|
||||
return m_is_root || geometry::equals(result, m_box);
|
||||
}
|
||||
|
||||
private:
|
||||
Translator const& m_tr;
|
||||
Box m_box;
|
||||
bool m_is_root;
|
||||
};
|
||||
|
||||
} // namespace visitors
|
||||
|
||||
template <typename Value, typename Translator, typename Box, typename Tag>
|
||||
bool rtree_are_boxes_ok(rtree<Value, Translator, Box, Tag> const& tree)
|
||||
{
|
||||
typedef rtree<Value, Translator, Box, Tag> rt;
|
||||
visitors::rtree_are_boxes_ok<
|
||||
typename rt::value_type,
|
||||
typename rt::translator_type,
|
||||
typename rt::box_type,
|
||||
Tag> v(tree.get_translator());
|
||||
|
||||
return tree.apply_visitor(v);
|
||||
}
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_VISITORS_RTREE_ARE_BOXES_OK_HPP
|
||||
@@ -4,10 +4,12 @@
|
||||
#include <boost/geometry/extensions/index/rtree/rtree.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/gl_draw.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/print.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/visitors/rtree_are_boxes_ok.hpp>
|
||||
|
||||
typedef boost::geometry::model::point<float, 2, boost::geometry::cs::cartesian> P;
|
||||
typedef boost::geometry::model::box<P> B;
|
||||
boost::geometry::index::rtree<B> t;
|
||||
boost::geometry::index::rtree<B> t(2, 1);
|
||||
|
||||
void render_scene(void)
|
||||
{
|
||||
@@ -30,8 +32,8 @@ void resize(int w, int h)
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(
|
||||
5.0f, 5.0f, 15.0f,
|
||||
5.0f, 5.0f, -1.0f,
|
||||
150.0f, 150.0f, 150.0f,
|
||||
50.0f, 50.0f, -1.0f,
|
||||
0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
@@ -39,12 +41,21 @@ void mouse(int button, int state, int x, int y)
|
||||
{
|
||||
if ( state == GLUT_DOWN )
|
||||
{
|
||||
float x = ( rand() % 10000 ) / 1000.0f;
|
||||
float y = ( rand() % 10000 ) / 1000.0f;
|
||||
float w = ( rand() % 10000 ) / 100000.0f;
|
||||
float h = ( rand() % 10000 ) / 100000.0f;
|
||||
float x = ( rand() % 100 );
|
||||
float y = ( rand() % 100 );
|
||||
float w = ( rand() % 2 ) + 1;
|
||||
float h = ( rand() % 2 ) + 1;
|
||||
|
||||
boost::geometry::index::insert(t, B(P(x - w, y - h),P(x + w, y + h)));
|
||||
B b(P(x - w, y - h),P(x + w, y + h));
|
||||
|
||||
boost::geometry::index::insert(t, b);
|
||||
|
||||
std::cout << "\n\n\n" << t << "\n\n";
|
||||
|
||||
std::cout << "inserted: ";
|
||||
boost::geometry::index::visitors::detail::rtree_print_indexable(std::cout, b);
|
||||
std::cout << '\n';
|
||||
std::cout << ( boost::geometry::index::rtree_are_boxes_ok(t) ? "boxes OK" : "WRONG BOXES!" );
|
||||
|
||||
glutPostRedisplay();
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@ int main()
|
||||
std::vector<B> v(n);
|
||||
for ( size_t i = 0 ; i < n ; ++i )
|
||||
{
|
||||
float x = ( rand() % 10000 ) / 1000.0f;
|
||||
float y = ( rand() % 10000 ) / 1000.0f;
|
||||
float w = ( rand() % 10000 ) / 100000.0f;
|
||||
float h = ( rand() % 10000 ) / 100000.0f;
|
||||
float x = float( rand() % 1000 );
|
||||
float y = float( rand() % 1000 );
|
||||
float w = float( rand() % 10 ) / 10.0f;
|
||||
float h = float( rand() % 10 ) / 10.0f;
|
||||
v[i] = B(P(x - w, y - h),P(x + w, y + h));
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,19 @@ int main()
|
||||
tests_rtree_native_hpp();
|
||||
tests_rtree_filters_hpp();
|
||||
|
||||
/*namespace g = boost::geometry;
|
||||
typedef g::model::point<float, 2, g::cs::cartesian> P;
|
||||
typedef g::model::box<P> B;
|
||||
|
||||
g::index::rtree<B> tree(4, 2);
|
||||
g::index::insert(tree, B(P(1, 6),P(6, 19)));
|
||||
g::index::insert(tree, B(P(10, 1),P(18, 18)));
|
||||
g::index::insert(tree, B(P(22, 6),P(27, 20)));
|
||||
g::index::insert(tree, B(P(29, 2),P(34, 18)));
|
||||
g::index::insert(tree, B(P(35, 3),P(39, 19)));
|
||||
|
||||
std::cout << tree;*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
std::cin.get();
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,24 @@ void tests_rtree_native_hpp()
|
||||
{
|
||||
std::cout << "tests/rtree_native.hpp\n";
|
||||
|
||||
std::cout << "Boxes\n";
|
||||
std::cout << "Boxes3d\n";
|
||||
{
|
||||
typedef boost::geometry::model::point<float, 3, boost::geometry::cs::cartesian> P;
|
||||
typedef boost::geometry::model::box<P> B;
|
||||
|
||||
boost::geometry::index::rtree<B> t(4, 2);
|
||||
boost::geometry::index::insert(t, B(P(0, 0, 0), P(1, 1, 1)));
|
||||
boost::geometry::index::insert(t, B(P(2, 2, 2), P(3, 3, 3)));
|
||||
boost::geometry::index::insert(t, B(P(4, 4, 4), P(5, 5, 5)));
|
||||
boost::geometry::index::insert(t, B(P(6, 6, 6), P(7, 7, 7)));
|
||||
boost::geometry::index::insert(t, B(P(8, 8, 8), P(9, 9, 9)));
|
||||
std::cerr << t;
|
||||
}
|
||||
|
||||
std::cout << "-------------------------------------------------\n";
|
||||
std::cout << "-------------------------------------------------\n";
|
||||
|
||||
std::cout << "Boxes2d\n";
|
||||
{
|
||||
typedef boost::geometry::model::point<float, 2, boost::geometry::cs::cartesian> P;
|
||||
typedef boost::geometry::model::box<P> B;
|
||||
|
||||
Reference in New Issue
Block a user