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,88 @@
// Boost.Geometry Index
//
// Query range adaptor
//
// 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_ADAPTORS_QUERY_HPP
#define BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP
/*!
\defgroup adaptors Adaptors (boost::geometry::index::adaptors::)
*/
namespace boost { namespace geometry { namespace index {
namespace adaptors {
namespace detail {
template <typename Index>
class query_range
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_INDEX,
(query_range));
typedef int* iterator;
typedef const int* const_iterator;
template <typename Predicates>
inline query_range(
Index const&,
Predicates const&)
{}
inline iterator begin() { return 0; }
inline iterator end() { return 0; }
inline const_iterator begin() const { return 0; }
inline const_iterator end() const { return 0; }
};
// TODO: awulkiew - consider removing reference from predicates
template<typename Predicates>
struct query
{
inline explicit query(Predicates const& pred)
: predicates(pred)
{}
Predicates const& predicates;
};
template<typename Index, typename Predicates>
index::adaptors::detail::query_range<Index>
operator|(
Index const& si,
index::adaptors::detail::query<Predicates> const& f)
{
return index::adaptors::detail::query_range<Index>(si, f.predicates);
}
} // namespace detail
/*!
\brief The query index adaptor generator.
\ingroup adaptors
\param pred Predicates.
*/
template <typename Predicates>
detail::query<Predicates>
queried(Predicates const& pred)
{
return detail::query<Predicates>(pred);
}
} // namespace adaptors
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP
@@ -0,0 +1,90 @@
// Boost.Geometry Index
//
// n-dimensional bounds
//
// 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_ALGORITHMS_BOUNDS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP
#include <boost/geometry/index/detail/bounded_view.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
namespace dispatch {
template <typename Geometry,
typename Bounds,
typename TagGeometry = typename geometry::tag<Geometry>::type,
typename TagBounds = typename geometry::tag<Bounds>::type>
struct bounds
{
static inline void apply(Geometry const& g, Bounds & b)
{
geometry::convert(g, b);
}
};
template <typename Geometry, typename Bounds>
struct bounds<Geometry, Bounds, segment_tag, box_tag>
{
static inline void apply(Geometry const& g, Bounds & b)
{
index::detail::bounded_view<Geometry, Bounds> v(g);
geometry::convert(v, b);
}
};
} // namespace dispatch
template <typename Geometry, typename Bounds>
inline void bounds(Geometry const& g, Bounds & b)
{
concepts::check_concepts_and_equal_dimensions<Geometry const, Bounds>();
dispatch::bounds<Geometry, Bounds>::apply(g, b);
}
namespace dispatch {
template <typename Geometry,
typename TagGeometry = typename geometry::tag<Geometry>::type>
struct return_ref_or_bounds
{
typedef Geometry const& result_type;
static inline result_type apply(Geometry const& g)
{
return g;
}
};
template <typename Geometry>
struct return_ref_or_bounds<Geometry, segment_tag>
{
typedef typename point_type<Geometry>::type point_type;
typedef geometry::model::box<point_type> bounds_type;
typedef index::detail::bounded_view<Geometry, bounds_type> result_type;
static inline result_type apply(Geometry const& g)
{
return result_type(g);
}
};
} // namespace dispatch
template <typename Geometry>
inline
typename dispatch::return_ref_or_bounds<Geometry>::result_type
return_ref_or_bounds(Geometry const& g)
{
return dispatch::return_ref_or_bounds<Geometry>::apply(g);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP
@@ -0,0 +1,77 @@
// Boost.Geometry Index
//
// squared distance between point and centroid of the box or point
//
// 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_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP
#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
#include <boost/geometry/index/detail/algorithms/diff_abs.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
struct comparable_distance_centroid_tag {};
template <
typename Point,
typename PointIndexable,
size_t N>
struct sum_for_indexable<Point, PointIndexable, point_tag, comparable_distance_centroid_tag, N>
{
typedef typename geometry::default_comparable_distance_result<Point, PointIndexable>::type result_type;
inline static result_type apply(Point const& pt, PointIndexable const& i)
{
return geometry::comparable_distance(pt, i);
}
};
template <
typename Point,
typename BoxIndexable,
size_t DimensionIndex>
struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_centroid_tag, DimensionIndex>
{
typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
inline static result_type apply(Point const& pt, BoxIndexable const& i)
{
typedef typename coordinate_type<Point>::type point_coord_t;
typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
indexable_coord_t ind_c_avg = ind_c_min + (ind_c_max - ind_c_min) / 2;
// TODO: awulkiew - is (ind_c_min + ind_c_max) / 2 safe?
result_type diff = detail::diff_abs(ind_c_avg, pt_c);
return diff * diff;
}
};
template <typename Point, typename Indexable>
typename geometry::default_comparable_distance_result<Point, Indexable>::type
comparable_distance_centroid(Point const& pt, Indexable const& i)
{
return detail::sum_for_indexable<
Point,
Indexable,
typename tag<Indexable>::type,
detail::comparable_distance_centroid_tag,
dimension<Indexable>::value
>::apply(pt, i);
}
}}}} // namespace boost::geometry::index::detail
#endif // #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP
@@ -0,0 +1,66 @@
// Boost.Geometry Index
//
// squared distance between point and furthest point of the box or point
//
// 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_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP
#include <boost/geometry/index/detail/algorithms/diff_abs.hpp>
#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
// minmaxdist component
struct comparable_distance_far_tag {};
template <
typename Point,
typename BoxIndexable,
size_t DimensionIndex>
struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_far_tag, DimensionIndex>
{
typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
inline static result_type apply(Point const& pt, BoxIndexable const& i)
{
typedef typename coordinate_type<Point>::type point_coord_t;
typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
result_type further_diff = 0;
if ( (ind_c_min + ind_c_max) / 2 <= pt_c )
further_diff = pt_c - ind_c_min;
else
further_diff = detail::diff_abs(pt_c, ind_c_max); // unsigned values protection
return further_diff * further_diff;
}
};
template <typename Point, typename Indexable>
typename geometry::default_comparable_distance_result<Point, Indexable>::type
comparable_distance_far(Point const& pt, Indexable const& i)
{
return detail::sum_for_indexable<
Point,
Indexable,
typename tag<Indexable>::type,
detail::comparable_distance_far_tag,
dimension<Indexable>::value
>::apply(pt, i);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP
@@ -0,0 +1,77 @@
// Boost.Geometry Index
//
// squared distance between point and nearest point of the box or point
//
// 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_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP
#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
struct comparable_distance_near_tag {};
template <
typename Point,
typename PointIndexable,
size_t N>
struct sum_for_indexable<Point, PointIndexable, point_tag, comparable_distance_near_tag, N>
{
typedef typename geometry::default_comparable_distance_result<Point, PointIndexable>::type result_type;
inline static result_type apply(Point const& pt, PointIndexable const& i)
{
return geometry::comparable_distance(pt, i);
}
};
template <
typename Point,
typename BoxIndexable,
size_t DimensionIndex>
struct sum_for_indexable_dimension<Point, BoxIndexable, box_tag, comparable_distance_near_tag, DimensionIndex>
{
typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
inline static result_type apply(Point const& pt, BoxIndexable const& i)
{
typedef typename coordinate_type<Point>::type point_coord_t;
typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
result_type diff = 0;
if ( pt_c < ind_c_min )
diff = ind_c_min - pt_c;
else if ( ind_c_max < pt_c )
diff = pt_c - ind_c_max;
return diff * diff;
}
};
template <typename Point, typename Indexable>
typename geometry::default_comparable_distance_result<Point, Indexable>::type
comparable_distance_near(Point const& pt, Indexable const& i)
{
return detail::sum_for_indexable<
Point,
Indexable,
typename tag<Indexable>::type,
detail::comparable_distance_near_tag,
dimension<Indexable>::value
>::apply(pt, i);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP
@@ -0,0 +1,87 @@
// Boost.Geometry Index
//
// n-dimensional content (hypervolume) - 2d area, 3d volume, ...
//
// 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_ALGORITHMS_CONTENT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename Indexable>
struct default_content_result
{
typedef typename select_most_precise<
typename coordinate_type<Indexable>::type,
long double
>::type type;
};
namespace dispatch {
template <typename Box,
std::size_t CurrentDimension = dimension<Box>::value>
struct content_box
{
BOOST_STATIC_ASSERT(0 < CurrentDimension);
static inline typename detail::default_content_result<Box>::type apply(Box const& b)
{
return content_box<Box, CurrentDimension - 1>::apply(b) *
( get<max_corner, CurrentDimension - 1>(b) - get<min_corner, CurrentDimension - 1>(b) );
}
};
template <typename Box>
struct content_box<Box, 1>
{
static inline typename detail::default_content_result<Box>::type apply(Box const& b)
{
return get<max_corner, 0>(b) - get<min_corner, 0>(b);
}
};
template <typename Indexable, typename Tag>
struct content
{
BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_AND_TAG, (Indexable, Tag));
};
template <typename Indexable>
struct content<Indexable, point_tag>
{
static typename detail::default_content_result<Indexable>::type apply(Indexable const&)
{
return 0;
}
};
template <typename Indexable>
struct content<Indexable, box_tag>
{
static typename default_content_result<Indexable>::type apply(Indexable const& b)
{
return dispatch::content_box<Indexable>::apply(b);
}
};
} // namespace dispatch
template <typename Indexable>
typename default_content_result<Indexable>::type content(Indexable const& b)
{
return dispatch::content
<
Indexable,
typename tag<Indexable>::type
>::apply(b);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP
@@ -0,0 +1,39 @@
// Boost.Geometry Index
//
// Abs of difference
//
// 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_ALGORITHMS_DIFF_ABS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename T>
inline T diff_abs_dispatch(T const& v1, T const& v2, boost::mpl::bool_<true> const& /*is_integral*/)
{
return v1 < v2 ? v2 - v1 : v1 - v2;
}
template <typename T>
inline T diff_abs_dispatch(T const& v1, T const& v2, boost::mpl::bool_<false> const& /*is_integral*/)
{
return ::fabs(v1 - v2);
}
template <typename T>
inline T diff_abs(T const& v1, T const& v2)
{
typedef boost::mpl::bool_<
boost::is_integral<T>::value
> is_integral;
return diff_abs_dispatch(v1, v2, is_integral());
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP
@@ -0,0 +1,37 @@
// Boost.Geometry Index
//
// boxes union/intersection area/volume
//
// Copyright (c) 2011-2016 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_ALGORITHMS_INTERSECTION_CONTENT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/strategies/intersection_strategies.hpp>
#include <boost/geometry/index/detail/algorithms/content.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
/**
* \brief Compute the area of the intersection of b1 and b2
*/
template <typename Box>
inline typename default_content_result<Box>::type intersection_content(Box const& box1, Box const& box2)
{
if ( geometry::intersects(box1, box2) )
{
Box box_intersection;
if ( geometry::intersection(box1, box2, box_intersection) )
return detail::content(box_intersection);
}
return 0;
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP
@@ -0,0 +1,91 @@
// Boost.Geometry Index
//
// n-dimensional Indexable validity check
//
// 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_ALGORITHMS_IS_VALID_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_IS_VALID_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
namespace dispatch {
template <typename Box,
std::size_t Dimension = geometry::dimension<Box>::value>
struct is_valid_box
{
static inline bool apply(Box const& b)
{
return is_valid_box<Box, Dimension - 1>::apply(b) &&
( get<min_corner, Dimension - 1>(b) <= get<max_corner, Dimension - 1>(b) );
}
};
template <typename Box>
struct is_valid_box<Box, 1>
{
static inline bool apply(Box const& b)
{
return get<min_corner, 0>(b) <= get<max_corner, 0>(b);
}
};
template <typename Indexable,
typename Tag = typename geometry::tag<Indexable>::type>
struct is_valid
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_INDEXABLE,
(is_valid));
};
template <typename Indexable>
struct is_valid<Indexable, point_tag>
{
static inline bool apply(Indexable const&)
{
return true;
}
};
template <typename Indexable>
struct is_valid<Indexable, box_tag>
{
static inline bool apply(Indexable const& b)
{
return dispatch::is_valid_box<Indexable>::apply(b);
}
};
template <typename Indexable>
struct is_valid<Indexable, segment_tag>
{
static inline bool apply(Indexable const&)
{
return true;
}
};
} // namespace dispatch
template <typename Indexable>
inline bool is_valid(Indexable const& b)
{
// CONSIDER: detection of NaNs
// e.g. by comparison of b with copy of b
return dispatch::is_valid<Indexable>::apply(b);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_DETAIL_INDEX_ALGORITHMS_IS_VALID_HPP
@@ -0,0 +1,169 @@
// Boost.Geometry Index
//
// n-dimensional box's margin value (hypersurface), 2d perimeter, 3d surface, etc...
//
// 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_ALGORITHMS_MARGIN_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
// WARNING! comparable_margin() will work only if the same Geometries are compared
// so it shouldn't be used in the case of Variants!
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename Box>
struct default_margin_result
{
typedef typename select_most_precise<
typename coordinate_type<Box>::type,
long double
>::type type;
};
//template <typename Box,
// std::size_t CurrentDimension,
// std::size_t EdgeDimension = dimension<Box>::value>
//struct margin_for_each_edge
//{
// BOOST_STATIC_ASSERT(0 < CurrentDimension);
// BOOST_STATIC_ASSERT(0 < EdgeDimension);
//
// static inline typename default_margin_result<Box>::type apply(Box const& b)
// {
// return margin_for_each_edge<Box, CurrentDimension, EdgeDimension - 1>::apply(b) *
// ( geometry::get<max_corner, EdgeDimension - 1>(b) - geometry::get<min_corner, EdgeDimension - 1>(b) );
// }
//};
//
//template <typename Box, std::size_t CurrentDimension>
//struct margin_for_each_edge<Box, CurrentDimension, CurrentDimension>
//{
// BOOST_STATIC_ASSERT(0 < CurrentDimension);
//
// static inline typename default_margin_result<Box>::type apply(Box const& b)
// {
// return margin_for_each_edge<Box, CurrentDimension, CurrentDimension - 1>::apply(b);
// }
//};
//
//template <typename Box, std::size_t CurrentDimension>
//struct margin_for_each_edge<Box, CurrentDimension, 1>
//{
// BOOST_STATIC_ASSERT(0 < CurrentDimension);
//
// static inline typename default_margin_result<Box>::type apply(Box const& b)
// {
// return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b);
// }
//};
//
//template <typename Box>
//struct margin_for_each_edge<Box, 1, 1>
//{
// static inline typename default_margin_result<Box>::type apply(Box const& /*b*/)
// {
// return 1;
// }
//};
//
//template <typename Box,
// std::size_t CurrentDimension = dimension<Box>::value>
//struct margin_for_each_dimension
//{
// BOOST_STATIC_ASSERT(0 < CurrentDimension);
//
// static inline typename default_margin_result<Box>::type apply(Box const& b)
// {
// return margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) +
// margin_for_each_edge<Box, CurrentDimension>::apply(b);
// }
//};
//
//template <typename Box>
//struct margin_for_each_dimension<Box, 1>
//{
// static inline typename default_margin_result<Box>::type apply(Box const& b)
// {
// return margin_for_each_edge<Box, 1>::apply(b);
// }
//};
// TODO - test if this definition of margin is ok for Dimension > 2
// Now it's sum of edges lengths
// maybe margin_for_each_dimension should be used to get more or less hypersurface?
template <typename Box,
std::size_t CurrentDimension = dimension<Box>::value>
struct simple_margin_for_each_dimension
{
BOOST_STATIC_ASSERT(0 < CurrentDimension);
static inline typename default_margin_result<Box>::type apply(Box const& b)
{
return simple_margin_for_each_dimension<Box, CurrentDimension - 1>::apply(b) +
geometry::get<max_corner, CurrentDimension - 1>(b) - geometry::get<min_corner, CurrentDimension - 1>(b);
}
};
template <typename Box>
struct simple_margin_for_each_dimension<Box, 1>
{
static inline typename default_margin_result<Box>::type apply(Box const& b)
{
return geometry::get<max_corner, 0>(b) - geometry::get<min_corner, 0>(b);
}
};
namespace dispatch {
template <typename Geometry, typename Tag>
struct comparable_margin
{
BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (Geometry, Tag));
};
template <typename Geometry>
struct comparable_margin<Geometry, point_tag>
{
typedef typename default_margin_result<Geometry>::type result_type;
static inline result_type apply(Geometry const& ) { return 0; }
};
template <typename Box>
struct comparable_margin<Box, box_tag>
{
typedef typename default_margin_result<Box>::type result_type;
static inline result_type apply(Box const& g)
{
//return detail::margin_for_each_dimension<Box>::apply(g);
return detail::simple_margin_for_each_dimension<Box>::apply(g);
}
};
} // namespace dispatch
template <typename Geometry>
typename default_margin_result<Geometry>::type comparable_margin(Geometry const& g)
{
return dispatch::comparable_margin<
Geometry,
typename tag<Geometry>::type
>::apply(g);
}
//template <typename Box>
//typename default_margin_result<Box>::type margin(Box const& b)
//{
// return 2 * detail::margin_for_each_dimension<Box>::apply(b);
//}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP
@@ -0,0 +1,119 @@
// Boost.Geometry Index
//
// minmaxdist used in R-tree k nearest neighbors query
//
// 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_ALGORITHMS_MINMAXDIST_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/algorithms/comparable_distance.hpp>
#include <boost/geometry/index/detail/algorithms/diff_abs.hpp>
#include <boost/geometry/index/detail/algorithms/sum_for_indexable.hpp>
#include <boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
struct minmaxdist_tag {};
template <
typename Point,
typename BoxIndexable,
size_t DimensionIndex>
struct smallest_for_indexable_dimension<Point, BoxIndexable, box_tag, minmaxdist_tag, DimensionIndex>
{
typedef typename geometry::default_comparable_distance_result<Point, BoxIndexable>::type result_type;
inline static result_type apply(Point const& pt, BoxIndexable const& i, result_type const& maxd)
{
typedef typename coordinate_type<Point>::type point_coord_t;
typedef typename coordinate_type<BoxIndexable>::type indexable_coord_t;
point_coord_t pt_c = geometry::get<DimensionIndex>(pt);
indexable_coord_t ind_c_min = geometry::get<geometry::min_corner, DimensionIndex>(i);
indexable_coord_t ind_c_max = geometry::get<geometry::max_corner, DimensionIndex>(i);
indexable_coord_t ind_c_avg = ind_c_min + (ind_c_max - ind_c_min) / 2;
// TODO: awulkiew - is (ind_c_min + ind_c_max) / 2 safe?
// TODO: awulkiew - optimize! don't calculate 2x pt_c <= ind_c_avg
// take particular case pt_c == ind_c_avg into account
result_type closer_comp = 0;
if ( pt_c <= ind_c_avg )
closer_comp = detail::diff_abs(pt_c, ind_c_min); // unsigned values protection
else
closer_comp = ind_c_max - pt_c;
result_type further_comp = 0;
if ( ind_c_avg <= pt_c )
further_comp = pt_c - ind_c_min;
else
further_comp = detail::diff_abs(pt_c, ind_c_max); // unsigned values protection
return (maxd + closer_comp * closer_comp) - further_comp * further_comp;
}
};
template <typename Point, typename Indexable, typename IndexableTag>
struct minmaxdist_impl
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE,
(minmaxdist_impl));
};
template <typename Point, typename Indexable>
struct minmaxdist_impl<Point, Indexable, point_tag>
{
typedef typename geometry::default_comparable_distance_result<Point, Indexable>::type result_type;
inline static result_type apply(Point const& pt, Indexable const& i)
{
return geometry::comparable_distance(pt, i);
}
};
template <typename Point, typename Indexable>
struct minmaxdist_impl<Point, Indexable, box_tag>
{
typedef typename geometry::default_comparable_distance_result<Point, Indexable>::type result_type;
inline static result_type apply(Point const& pt, Indexable const& i)
{
result_type maxd = geometry::comparable_distance(pt, i);
return smallest_for_indexable<
Point,
Indexable,
box_tag,
minmaxdist_tag,
dimension<Indexable>::value
>::apply(pt, i, maxd);
}
};
/**
* This is comparable distace.
*/
template <typename Point, typename Indexable>
typename geometry::default_comparable_distance_result<Point, Indexable>::type
minmaxdist(Point const& pt, Indexable const& i)
{
return detail::minmaxdist_impl<
Point,
Indexable,
typename tag<Indexable>::type
>::apply(pt, i);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP
@@ -0,0 +1,62 @@
// Boost.Geometry Index
//
// Copyright (c) 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_ALGORITHMS_NTH_ELEMENT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP
#include <algorithm>
namespace boost { namespace geometry { namespace index { namespace detail {
// See https://svn.boost.org/trac/boost/ticket/12861
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58800
// https://gcc.gnu.org/develop.html#timeline
// 20120920 4.7.2 - no bug
// 20130322 4.8.0 - no bug
// 20130411 4.7.3 - no bug
// 20130531 4.8.1 - no bug
// 20131016 4.8.2 - bug
// 20140422 4.9.0 - fixed
// 20140522 4.8.3 - fixed
// 20140612 4.7.4 - fixed
// 20140716 4.9.1 - fixed
#if defined(__GLIBCXX__) && (__GLIBCXX__ == 20131016)
#warning "std::nth_element replaced with std::sort, libstdc++ bug workaround.";
template <typename RandomIt>
void nth_element(RandomIt first, RandomIt , RandomIt last)
{
std::sort(first, last);
}
template <typename RandomIt, typename Compare>
void nth_element(RandomIt first, RandomIt , RandomIt last, Compare comp)
{
std::sort(first, last, comp);
}
#else
template <typename RandomIt>
void nth_element(RandomIt first, RandomIt nth, RandomIt last)
{
std::nth_element(first, nth, last);
}
template <typename RandomIt, typename Compare>
void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp)
{
std::nth_element(first, nth, last, comp);
}
#endif
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_NTH_ELEMENT_HPP
@@ -0,0 +1,119 @@
// Boost.Geometry Index
//
// n-dimensional box-linestring intersection
//
// 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_ALGORITHMS_PATH_INTERSECTION_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP
#include <boost/geometry/index/detail/algorithms/segment_intersection.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
namespace dispatch {
template <typename Indexable, typename Geometry, typename IndexableTag, typename GeometryTag>
struct path_intersection
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_OR_INDEXABLE, (path_intersection));
};
// TODO: FP type must be used as a relative distance type!
// and default_distance_result can be some user-defined int type
// BUT! This code is experimental and probably won't be released at all
// since more flexible user-defined-nearest predicate should be added instead
template <typename Indexable, typename Segment>
struct path_intersection<Indexable, Segment, box_tag, segment_tag>
{
typedef typename default_distance_result<typename point_type<Segment>::type>::type comparable_distance_type;
static inline bool apply(Indexable const& b, Segment const& segment, comparable_distance_type & comparable_distance)
{
typedef typename point_type<Segment>::type point_type;
point_type p1, p2;
geometry::detail::assign_point_from_index<0>(segment, p1);
geometry::detail::assign_point_from_index<1>(segment, p2);
return index::detail::segment_intersection(b, p1, p2, comparable_distance);
}
};
template <typename Indexable, typename Linestring>
struct path_intersection<Indexable, Linestring, box_tag, linestring_tag>
{
typedef typename default_length_result<Linestring>::type comparable_distance_type;
static inline bool apply(Indexable const& b, Linestring const& path, comparable_distance_type & comparable_distance)
{
typedef typename ::boost::range_value<Linestring>::type point_type;
typedef typename ::boost::range_const_iterator<Linestring>::type const_iterator;
typedef typename ::boost::range_size<Linestring>::type size_type;
const size_type count = ::boost::size(path);
if ( count == 2 )
{
return index::detail::segment_intersection(b, *::boost::begin(path), *(::boost::begin(path)+1), comparable_distance);
}
else if ( 2 < count )
{
const_iterator it0 = ::boost::begin(path);
const_iterator it1 = ::boost::begin(path) + 1;
const_iterator last = ::boost::end(path);
comparable_distance = 0;
for ( ; it1 != last ; ++it0, ++it1 )
{
typename default_distance_result<point_type, point_type>::type
dist = geometry::distance(*it0, *it1);
comparable_distance_type rel_dist;
if ( index::detail::segment_intersection(b, *it0, *it1, rel_dist) )
{
comparable_distance += dist * rel_dist;
return true;
}
else
comparable_distance += dist;
}
}
return false;
}
};
} // namespace dispatch
template <typename Indexable, typename SegmentOrLinestring>
struct default_path_intersection_distance_type
{
typedef typename dispatch::path_intersection<
Indexable, SegmentOrLinestring,
typename tag<Indexable>::type,
typename tag<SegmentOrLinestring>::type
>::comparable_distance_type type;
};
template <typename Indexable, typename SegmentOrLinestring> inline
bool path_intersection(Indexable const& b,
SegmentOrLinestring const& path,
typename default_path_intersection_distance_type<Indexable, SegmentOrLinestring>::type & comparable_distance)
{
// TODO check Indexable and Linestring concepts
return dispatch::path_intersection<
Indexable, SegmentOrLinestring,
typename tag<Indexable>::type,
typename tag<SegmentOrLinestring>::type
>::apply(b, path, comparable_distance);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_PATH_INTERSECTION_HPP
@@ -0,0 +1,146 @@
// Boost.Geometry Index
//
// n-dimensional box-segment intersection
//
// 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_ALGORITHMS_SEGMENT_INTERSECTION_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
//template <typename Indexable, typename Point>
//struct default_relative_distance_type
//{
// typedef typename select_most_precise<
// typename select_most_precise<
// typename coordinate_type<Indexable>::type,
// typename coordinate_type<Point>::type
// >::type,
// float // TODO - use bigger type, calculated from the size of coordinate types
// >::type type;
//
//
// BOOST_MPL_ASSERT_MSG((!::boost::is_unsigned<type>::value),
// THIS_TYPE_SHOULDNT_BE_UNSIGNED, (type));
//};
namespace dispatch {
template <typename Box, typename Point, size_t I>
struct box_segment_intersection_dim
{
BOOST_STATIC_ASSERT(0 <= dimension<Box>::value);
BOOST_STATIC_ASSERT(0 <= dimension<Point>::value);
BOOST_STATIC_ASSERT(I < size_t(dimension<Box>::value));
BOOST_STATIC_ASSERT(I < size_t(dimension<Point>::value));
BOOST_STATIC_ASSERT(dimension<Point>::value == dimension<Box>::value);
// WARNING! - RelativeDistance must be IEEE float for this to work
template <typename RelativeDistance>
static inline bool apply(Box const& b, Point const& p0, Point const& p1,
RelativeDistance & t_near, RelativeDistance & t_far)
{
RelativeDistance ray_d = geometry::get<I>(p1) - geometry::get<I>(p0);
RelativeDistance tn = ( geometry::get<min_corner, I>(b) - geometry::get<I>(p0) ) / ray_d;
RelativeDistance tf = ( geometry::get<max_corner, I>(b) - geometry::get<I>(p0) ) / ray_d;
if ( tf < tn )
::std::swap(tn, tf);
if ( t_near < tn )
t_near = tn;
if ( tf < t_far )
t_far = tf;
return 0 <= t_far && t_near <= t_far;
}
};
template <typename Box, typename Point, size_t CurrentDimension>
struct box_segment_intersection
{
BOOST_STATIC_ASSERT(0 < CurrentDimension);
typedef box_segment_intersection_dim<Box, Point, CurrentDimension - 1> for_dim;
template <typename RelativeDistance>
static inline bool apply(Box const& b, Point const& p0, Point const& p1,
RelativeDistance & t_near, RelativeDistance & t_far)
{
return box_segment_intersection<Box, Point, CurrentDimension - 1>::apply(b, p0, p1, t_near, t_far)
&& for_dim::apply(b, p0, p1, t_near, t_far);
}
};
template <typename Box, typename Point>
struct box_segment_intersection<Box, Point, 1>
{
typedef box_segment_intersection_dim<Box, Point, 0> for_dim;
template <typename RelativeDistance>
static inline bool apply(Box const& b, Point const& p0, Point const& p1,
RelativeDistance & t_near, RelativeDistance & t_far)
{
return for_dim::apply(b, p0, p1, t_near, t_far);
}
};
template <typename Indexable, typename Point, typename Tag>
struct segment_intersection
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_GEOMETRY, (segment_intersection));
};
template <typename Indexable, typename Point>
struct segment_intersection<Indexable, Point, point_tag>
{
BOOST_MPL_ASSERT_MSG((false), SEGMENT_POINT_INTERSECTION_UNAVAILABLE, (segment_intersection));
};
template <typename Indexable, typename Point>
struct segment_intersection<Indexable, Point, box_tag>
{
typedef dispatch::box_segment_intersection<Indexable, Point, dimension<Indexable>::value> impl;
template <typename RelativeDistance>
static inline bool apply(Indexable const& b, Point const& p0, Point const& p1, RelativeDistance & relative_distance)
{
// TODO: this ASSERT CHECK is wrong for user-defined CoordinateTypes!
static const bool check = !::boost::is_integral<RelativeDistance>::value;
BOOST_MPL_ASSERT_MSG(check, RELATIVE_DISTANCE_MUST_BE_FLOATING_POINT_TYPE, (RelativeDistance));
RelativeDistance t_near = -(::std::numeric_limits<RelativeDistance>::max)();
RelativeDistance t_far = (::std::numeric_limits<RelativeDistance>::max)();
return impl::apply(b, p0, p1, t_near, t_far) &&
(t_near <= 1) &&
( relative_distance = 0 < t_near ? t_near : 0, true );
}
};
} // namespace dispatch
template <typename Indexable, typename Point, typename RelativeDistance> inline
bool segment_intersection(Indexable const& b,
Point const& p0,
Point const& p1,
RelativeDistance & relative_distance)
{
// TODO check Indexable and Point concepts
return dispatch::segment_intersection<
Indexable, Point,
typename tag<Indexable>::type
>::apply(b, p0, p1, relative_distance);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SEGMENT_INTERSECTION_HPP
@@ -0,0 +1,80 @@
// Boost.Geometry Index
//
// Get smallest value calculated for indexable's dimensions, used in R-tree k nearest neighbors query
//
// 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_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
template <
typename Geometry,
typename Indexable,
typename IndexableTag,
typename AlgoTag,
size_t DimensionIndex>
struct smallest_for_indexable_dimension
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE,
(smallest_for_indexable_dimension));
};
template <
typename Geometry,
typename Indexable,
typename IndexableTag,
typename AlgoTag,
size_t N>
struct smallest_for_indexable
{
typedef typename smallest_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, N - 1
>::result_type result_type;
template <typename Data>
inline static result_type apply(Geometry const& g, Indexable const& i, Data const& data)
{
result_type r1 = smallest_for_indexable<
Geometry, Indexable, IndexableTag, AlgoTag, N - 1
>::apply(g, i, data);
result_type r2 = smallest_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, N - 1
>::apply(g, i, data);
return r1 < r2 ? r1 : r2;
}
};
template <
typename Geometry,
typename Indexable,
typename IndexableTag,
typename AlgoTag>
struct smallest_for_indexable<Geometry, Indexable, IndexableTag, AlgoTag, 1>
{
typedef typename smallest_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, 0
>::result_type result_type;
template <typename Data>
inline static result_type apply(Geometry const& g, Indexable const& i, Data const& data)
{
return
smallest_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, 0
>::apply(g, i, data);
}
};
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SMALLEST_FOR_INDEXABLE_HPP
@@ -0,0 +1,76 @@
// Boost.Geometry Index
//
// Sum values calculated for indexable's dimensions, used e.g. in R-tree k nearest neighbors query
//
// 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_ALGORITHMS_SUM_FOR_INDEXABLE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
template <
typename Geometry,
typename Indexable,
typename IndexableTag,
typename AlgoTag,
size_t DimensionIndex>
struct sum_for_indexable_dimension
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE,
(sum_for_indexable_dimension));
};
template <
typename Geometry,
typename Indexable,
typename IndexableTag,
typename AlgoTag,
size_t N>
struct sum_for_indexable
{
typedef typename sum_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, N - 1
>::result_type result_type;
inline static result_type apply(Geometry const& g, Indexable const& i)
{
return
sum_for_indexable<
Geometry, Indexable, IndexableTag, AlgoTag, N - 1
>::apply(g, i) +
sum_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, N - 1
>::apply(g, i);
}
};
template <
typename Geometry,
typename Indexable,
typename IndexableTag,
typename AlgoTag>
struct sum_for_indexable<Geometry, Indexable, IndexableTag, AlgoTag, 1>
{
typedef typename sum_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, 0
>::result_type result_type;
inline static result_type apply(Geometry const& g, Indexable const& i)
{
return
sum_for_indexable_dimension<
Geometry, Indexable, IndexableTag, AlgoTag, 0
>::apply(g, i);
}
};
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_SUM_FOR_INDEXABLE_HPP
@@ -0,0 +1,33 @@
// Boost.Geometry Index
//
// boxes union/sum area/volume
//
// Copyright (c) 2008 Federico J. Fernandez.
// 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_ALGORITHMS_UNION_CONTENT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/index/detail/algorithms/content.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
/**
* \brief Compute the area of the union of b1 and b2
*/
template <typename Box, typename Geometry>
inline typename default_content_result<Box>::type union_content(Box const& b, Geometry const& g)
{
Box expanded_box(b);
geometry::expand(expanded_box, g);
return detail::content(expanded_box);
}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_UNION_CONTENT_HPP
@@ -0,0 +1,19 @@
// Boost.Geometry Index
//
// 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_ASSERT_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP
#include <boost/geometry/core/assert.hpp>
#undef BOOST_GEOMETRY_INDEX_ASSERT
#define BOOST_GEOMETRY_INDEX_ASSERT(CONDITION, TEXT_MSG) \
BOOST_GEOMETRY_ASSERT_MSG(CONDITION, TEXT_MSG)
#endif // BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP
@@ -0,0 +1,215 @@
// Boost.Geometry Index
//
// This view makes possible to treat some simple primitives as its bounding geometry
// e.g. box, nsphere, etc.
//
// Copyright (c) 2014-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_BOUNDED_VIEW_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP
#include <boost/geometry/algorithms/envelope.hpp>
namespace boost { namespace geometry {
namespace index { namespace detail {
template <typename Geometry,
typename BoundingGeometry,
typename Tag = typename geometry::tag<Geometry>::type,
typename BoundingTag = typename geometry::tag<BoundingGeometry>::type,
typename CSystem = typename geometry::coordinate_system<Geometry>::type>
struct bounded_view
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THOSE_GEOMETRIES,
(BoundingTag, Tag));
};
// Segment -> Box
template <typename Segment, typename Box>
struct bounded_view<Segment, Box, segment_tag, box_tag, cs::cartesian>
{
public:
typedef typename geometry::coordinate_type<Box>::type coordinate_type;
explicit bounded_view(Segment const& segment)
: m_segment(segment)
{}
template <std::size_t Dimension>
inline coordinate_type get_min() const
{
return boost::numeric_cast<coordinate_type>(
(std::min)( geometry::get<0, Dimension>(m_segment),
geometry::get<1, Dimension>(m_segment) ) );
}
template <std::size_t Dimension>
inline coordinate_type get_max() const
{
return boost::numeric_cast<coordinate_type>(
(std::max)( geometry::get<0, Dimension>(m_segment),
geometry::get<1, Dimension>(m_segment) ) );
}
private:
Segment const& m_segment;
};
template <typename Segment, typename Box, typename CSystem>
struct bounded_view<Segment, Box, segment_tag, box_tag, CSystem>
{
public:
typedef typename geometry::coordinate_type<Box>::type coordinate_type;
explicit bounded_view(Segment const& segment)
{
geometry::envelope(segment, m_box);
}
template <std::size_t Dimension>
inline coordinate_type get_min() const
{
return geometry::get<min_corner, Dimension>(m_box);
}
template <std::size_t Dimension>
inline coordinate_type get_max() const
{
return geometry::get<max_corner, Dimension>(m_box);
}
private:
Box m_box;
};
// Box -> Box
template <typename BoxIn, typename Box, typename CSystem>
struct bounded_view<BoxIn, Box, box_tag, box_tag, CSystem>
{
public:
typedef typename geometry::coordinate_type<Box>::type coordinate_type;
explicit bounded_view(BoxIn const& box)
: m_box(box)
{}
template <std::size_t Dimension>
inline coordinate_type get_min() const
{
return boost::numeric_cast<coordinate_type>(
geometry::get<min_corner, Dimension>(m_box) );
}
template <std::size_t Dimension>
inline coordinate_type get_max() const
{
return boost::numeric_cast<coordinate_type>(
geometry::get<max_corner, Dimension>(m_box) );
}
private:
BoxIn const& m_box;
};
// Point -> Box
template <typename Point, typename Box, typename CSystem>
struct bounded_view<Point, Box, point_tag, box_tag, CSystem>
{
public:
typedef typename geometry::coordinate_type<Box>::type coordinate_type;
explicit bounded_view(Point const& point)
: m_point(point)
{}
template <std::size_t Dimension>
inline coordinate_type get_min() const
{
return boost::numeric_cast<coordinate_type>(
geometry::get<Dimension>(m_point) );
}
template <std::size_t Dimension>
inline coordinate_type get_max() const
{
return boost::numeric_cast<coordinate_type>(
geometry::get<Dimension>(m_point) );
}
private:
Point const& m_point;
};
}} // namespace index::detail
// XXX -> Box
#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
namespace traits
{
template <typename Geometry, typename Box, typename Tag, typename CSystem>
struct tag< index::detail::bounded_view<Geometry, Box, Tag, box_tag, CSystem> >
{
typedef box_tag type;
};
template <typename Geometry, typename Box, typename Tag, typename CSystem>
struct point_type< index::detail::bounded_view<Geometry, Box, Tag, box_tag, CSystem> >
{
typedef typename point_type<Box>::type type;
};
template <typename Geometry, typename Box, typename Tag, typename CSystem, std::size_t Dimension>
struct indexed_access<index::detail::bounded_view<Geometry, Box, Tag, box_tag, CSystem>,
min_corner, Dimension>
{
typedef index::detail::bounded_view<Geometry, Box, Tag, box_tag, CSystem> box_type;
typedef typename geometry::coordinate_type<Box>::type coordinate_type;
static inline coordinate_type get(box_type const& b)
{
return b.template get_min<Dimension>();
}
//static inline void set(box_type & b, coordinate_type const& value)
//{
// BOOST_GEOMETRY_INDEX_ASSERT(false, "unable to modify a box through view");
//}
};
template <typename Geometry, typename Box, typename Tag, typename CSystem, std::size_t Dimension>
struct indexed_access<index::detail::bounded_view<Geometry, Box, Tag, box_tag, CSystem>,
max_corner, Dimension>
{
typedef index::detail::bounded_view<Geometry, Box, Tag, box_tag, CSystem> box_type;
typedef typename geometry::coordinate_type<Box>::type coordinate_type;
static inline coordinate_type get(box_type const& b)
{
return b.template get_max<Dimension>();
}
//static inline void set(box_type & b, coordinate_type const& value)
//{
// BOOST_GEOMETRY_INDEX_ASSERT(false, "unable to modify a box through view");
//}
};
} // namespace traits
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_INDEX_DETAIL_BOUNDED_VIEW_HPP
@@ -0,0 +1,21 @@
// Boost.Geometry Index
//
// 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)
#include <boost/config.hpp>
#ifdef BOOST_MSVC
#pragma warning (push)
#pragma warning (disable : 4512) // assignment operator could not be generated
#pragma warning (disable : 4127) // conditional expression is constant
// temporary?
#pragma warning (disable : 4180) // qualifier applied to function type has no meaning
#endif //BOOST_MSVC
@@ -0,0 +1,12 @@
// Boost.Geometry Index
//
// 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)
#if defined BOOST_MSVC
#pragma warning (pop)
#endif
@@ -0,0 +1,161 @@
// Boost.Geometry Index
//
// Spatial index distance predicates, calculators and checkers
// used in nearest query - specialized for envelopes
//
// 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_DISTANCE_PREDICATES_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_DISTANCE_PREDICATES_HPP
#include <boost/geometry/index/detail/algorithms/comparable_distance_near.hpp>
#include <boost/geometry/index/detail/algorithms/comparable_distance_far.hpp>
#include <boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp>
#include <boost/geometry/index/detail/algorithms/path_intersection.hpp>
#include <boost/geometry/index/detail/tags.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
// ------------------------------------------------------------------ //
// relations
// ------------------------------------------------------------------ //
template <typename T>
struct to_nearest
{
to_nearest(T const& v) : value(v) {}
T value;
};
template <typename T>
struct to_centroid
{
to_centroid(T const& v) : value(v) {}
T value;
};
template <typename T>
struct to_furthest
{
to_furthest(T const& v) : value(v) {}
T value;
};
// tags
struct to_nearest_tag {};
struct to_centroid_tag {};
struct to_furthest_tag {};
// ------------------------------------------------------------------ //
// relation traits and access
// ------------------------------------------------------------------ //
template <typename T>
struct relation
{
typedef T value_type;
typedef to_nearest_tag tag;
static inline T const& value(T const& v) { return v; }
static inline T & value(T & v) { return v; }
};
template <typename T>
struct relation< to_nearest<T> >
{
typedef T value_type;
typedef to_nearest_tag tag;
static inline T const& value(to_nearest<T> const& r) { return r.value; }
static inline T & value(to_nearest<T> & r) { return r.value; }
};
template <typename T>
struct relation< to_centroid<T> >
{
typedef T value_type;
typedef to_centroid_tag tag;
static inline T const& value(to_centroid<T> const& r) { return r.value; }
static inline T & value(to_centroid<T> & r) { return r.value; }
};
template <typename T>
struct relation< to_furthest<T> >
{
typedef T value_type;
typedef to_furthest_tag tag;
static inline T const& value(to_furthest<T> const& r) { return r.value; }
static inline T & value(to_furthest<T> & r) { return r.value; }
};
// ------------------------------------------------------------------ //
// calculate_distance
// ------------------------------------------------------------------ //
template <typename Predicate, typename Indexable, typename Tag>
struct calculate_distance
{
BOOST_MPL_ASSERT_MSG((false), INVALID_PREDICATE_OR_TAG, (calculate_distance));
};
// this handles nearest() with default Point parameter, to_nearest() and bounds
template <typename PointRelation, typename Indexable, typename Tag>
struct calculate_distance< predicates::nearest<PointRelation>, Indexable, Tag >
{
typedef detail::relation<PointRelation> relation;
typedef typename relation::value_type point_type;
typedef typename geometry::default_comparable_distance_result<point_type, Indexable>::type result_type;
static inline bool apply(predicates::nearest<PointRelation> const& p, Indexable const& i, result_type & result)
{
result = geometry::comparable_distance(relation::value(p.point_or_relation), i);
return true;
}
};
template <typename Point, typename Indexable>
struct calculate_distance< predicates::nearest< to_centroid<Point> >, Indexable, value_tag>
{
typedef Point point_type;
typedef typename geometry::default_comparable_distance_result<point_type, Indexable>::type result_type;
static inline bool apply(predicates::nearest< to_centroid<Point> > const& p, Indexable const& i, result_type & result)
{
result = index::detail::comparable_distance_centroid(p.point_or_relation.value, i);
return true;
}
};
template <typename Point, typename Indexable>
struct calculate_distance< predicates::nearest< to_furthest<Point> >, Indexable, value_tag>
{
typedef Point point_type;
typedef typename geometry::default_comparable_distance_result<point_type, Indexable>::type result_type;
static inline bool apply(predicates::nearest< to_furthest<Point> > const& p, Indexable const& i, result_type & result)
{
result = index::detail::comparable_distance_far(p.point_or_relation.value, i);
return true;
}
};
template <typename SegmentOrLinestring, typename Indexable, typename Tag>
struct calculate_distance< predicates::path<SegmentOrLinestring>, Indexable, Tag>
{
typedef typename index::detail::default_path_intersection_distance_type<
Indexable, SegmentOrLinestring
>::type result_type;
static inline bool apply(predicates::path<SegmentOrLinestring> const& p, Indexable const& i, result_type & result)
{
return index::detail::path_intersection(i, p.geometry, result);
}
};
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_RTREE_DISTANCE_PREDICATES_HPP
@@ -0,0 +1,87 @@
// Boost.Geometry Index
//
// 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_EXCEPTION_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP
#include <boost/core/no_exceptions_support.hpp>
#ifndef BOOST_NO_EXCEPTIONS
#include <stdexcept>
#include <boost/throw_exception.hpp>
#else
#include <cstdlib>
#include <boost/geometry/index/detail/assert.hpp>
#endif
namespace boost { namespace geometry { namespace index { namespace detail {
#ifndef BOOST_NO_EXCEPTIONS
inline void throw_runtime_error(const char * str)
{
BOOST_THROW_EXCEPTION(std::runtime_error(str));
}
inline void throw_logic_error(const char * str)
{
BOOST_THROW_EXCEPTION(std::logic_error(str));
}
inline void throw_invalid_argument(const char * str)
{
BOOST_THROW_EXCEPTION(std::invalid_argument(str));
}
inline void throw_length_error(const char * str)
{
BOOST_THROW_EXCEPTION(std::length_error(str));
}
inline void throw_out_of_range(const char * str)
{
BOOST_THROW_EXCEPTION(std::out_of_range(str));
}
#else
inline void throw_runtime_error(const char * str)
{
BOOST_GEOMETRY_INDEX_ASSERT(!"runtime_error thrown", str);
std::abort();
}
inline void throw_logic_error(const char * str)
{
BOOST_GEOMETRY_INDEX_ASSERT(!"logic_error thrown", str);
std::abort();
}
inline void throw_invalid_argument(const char * str)
{
BOOST_GEOMETRY_INDEX_ASSERT(!"invalid_argument thrown", str);
std::abort();
}
inline void throw_length_error(const char * str)
{
BOOST_GEOMETRY_INDEX_ASSERT(!"length_error thrown", str);
std::abort();
}
inline void throw_out_of_range(const char * str)
{
BOOST_GEOMETRY_INDEX_ASSERT(!"out_of_range thrown", str);
std::abort();
}
#endif
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXCEPTION_HPP
@@ -0,0 +1,35 @@
// Boost.Geometry Index
//
// 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_IS_BOUNDING_GEOMETRY_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_IS_BOUNDING_GEOMETRY_HPP
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
template
<
typename Geometry,
typename Tag = typename geometry::tag<Geometry>::type
>
struct is_bounding_geometry
{
static const bool value = false;
};
template <typename Box>
struct is_bounding_geometry<Box, box_tag>
{
static const bool value = true;
};
}}}} // namespave boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_IS_BOUNDING_GEOMETRY_HPP
@@ -0,0 +1,47 @@
// Boost.Geometry Index
//
// 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_IS_INDEXABLE_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_IS_INDEXABLE_HPP
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
template
<
typename Geometry,
typename Tag = typename geometry::tag<Geometry>::type
>
struct is_indexable
{
static const bool value = false;
};
template <typename Point>
struct is_indexable<Point, geometry::point_tag>
{
static const bool value = true;
};
template <typename Box>
struct is_indexable<Box, geometry::box_tag>
{
static const bool value = true;
};
template <typename Segment>
struct is_indexable<Segment, geometry::segment_tag>
{
static const bool value = true;
};
}}}} // namespave boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_IS_INDEXABLE_HPP
@@ -0,0 +1,42 @@
// Boost.Geometry Index
//
// 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)
#include <boost/range.hpp>
#include <boost/mpl/aux_/has_type.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
//#include <boost/type_traits/is_convertible.hpp>
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_META_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_META_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename T>
struct is_range
: ::boost::mpl::aux::has_type< ::boost::range_iterator<T> >
{};
//template <typename T, typename V, bool IsRange>
//struct is_range_of_convertible_values_impl
// : ::boost::is_convertible<typename ::boost::range_value<T>::type, V>
//{};
//
//template <typename T, typename V>
//struct is_range_of_convertible_values_impl<T, V, false>
// : ::boost::mpl::bool_<false>
//{};
//
//template <typename T, typename V>
//struct is_range_of_convertible_values
// : is_range_of_convertible_values_impl<T, V, is_range<T>::value>
//{};
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_META_HPP
@@ -0,0 +1,831 @@
// Boost.Geometry Index
//
// Spatial query predicates definition and checks.
//
// 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_PREDICATES_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
//#include <utility>
#include <boost/mpl/assert.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/geometry/index/detail/tags.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
namespace predicates {
// ------------------------------------------------------------------ //
// predicates
// ------------------------------------------------------------------ //
template <typename Fun, bool IsFunction>
struct satisfies_impl
{
satisfies_impl() : fun(NULL) {}
satisfies_impl(Fun f) : fun(f) {}
Fun * fun;
};
template <typename Fun>
struct satisfies_impl<Fun, false>
{
satisfies_impl() {}
satisfies_impl(Fun const& f) : fun(f) {}
Fun fun;
};
template <typename Fun, bool Negated>
struct satisfies
: satisfies_impl<Fun, ::boost::is_function<Fun>::value>
{
typedef satisfies_impl<Fun, ::boost::is_function<Fun>::value> base;
satisfies() {}
satisfies(Fun const& f) : base(f) {}
satisfies(base const& b) : base(b) {}
};
// ------------------------------------------------------------------ //
struct contains_tag {};
struct covered_by_tag {};
struct covers_tag {};
struct disjoint_tag {};
struct intersects_tag {};
struct overlaps_tag {};
struct touches_tag {};
struct within_tag {};
template <typename Geometry, typename Tag, bool Negated>
struct spatial_predicate
{
spatial_predicate() {}
spatial_predicate(Geometry const& g) : geometry(g) {}
Geometry geometry;
};
// ------------------------------------------------------------------ //
// CONSIDER: separated nearest<> and path<> may be replaced by
// nearest_predicate<Geometry, Tag>
// where Tag = point_tag | path_tag
// IMPROVEMENT: user-defined nearest predicate allowing to define
// all or only geometrical aspects of the search
template <typename PointOrRelation>
struct nearest
{
nearest()
// : count(0)
{}
nearest(PointOrRelation const& por, unsigned k)
: point_or_relation(por)
, count(k)
{}
PointOrRelation point_or_relation;
unsigned count;
};
template <typename SegmentOrLinestring>
struct path
{
path()
// : count(0)
{}
path(SegmentOrLinestring const& g, unsigned k)
: geometry(g)
, count(k)
{}
SegmentOrLinestring geometry;
unsigned count;
};
} // namespace predicates
// ------------------------------------------------------------------ //
// predicate_check
// ------------------------------------------------------------------ //
template <typename Predicate, typename Tag>
struct predicate_check
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_PREDICATE_OR_TAG,
(predicate_check));
};
// ------------------------------------------------------------------ //
template <typename Fun>
struct predicate_check<predicates::satisfies<Fun, false>, value_tag>
{
template <typename Value, typename Indexable>
static inline bool apply(predicates::satisfies<Fun, false> const& p, Value const& v, Indexable const&)
{
return p.fun(v);
}
};
template <typename Fun>
struct predicate_check<predicates::satisfies<Fun, true>, value_tag>
{
template <typename Value, typename Indexable>
static inline bool apply(predicates::satisfies<Fun, true> const& p, Value const& v, Indexable const&)
{
return !p.fun(v);
}
};
// ------------------------------------------------------------------ //
template <typename Tag>
struct spatial_predicate_call
{
BOOST_MPL_ASSERT_MSG(false, NOT_IMPLEMENTED_FOR_THIS_TAG, (Tag));
};
template <>
struct spatial_predicate_call<predicates::contains_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::within(g2, g1);
}
};
template <>
struct spatial_predicate_call<predicates::covered_by_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::covered_by(g1, g2);
}
};
template <>
struct spatial_predicate_call<predicates::covers_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::covered_by(g2, g1);
}
};
template <>
struct spatial_predicate_call<predicates::disjoint_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::disjoint(g1, g2);
}
};
template <>
struct spatial_predicate_call<predicates::intersects_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::intersects(g1, g2);
}
};
template <>
struct spatial_predicate_call<predicates::overlaps_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::overlaps(g1, g2);
}
};
template <>
struct spatial_predicate_call<predicates::touches_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::touches(g1, g2);
}
};
template <>
struct spatial_predicate_call<predicates::within_tag>
{
template <typename G1, typename G2>
static inline bool apply(G1 const& g1, G2 const& g2)
{
return geometry::within(g1, g2);
}
};
// ------------------------------------------------------------------ //
// spatial predicate
template <typename Geometry, typename Tag>
struct predicate_check<predicates::spatial_predicate<Geometry, Tag, false>, value_tag>
{
typedef predicates::spatial_predicate<Geometry, Tag, false> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return spatial_predicate_call<Tag>::apply(i, p.geometry);
}
};
// negated spatial predicate
template <typename Geometry, typename Tag>
struct predicate_check<predicates::spatial_predicate<Geometry, Tag, true>, value_tag>
{
typedef predicates::spatial_predicate<Geometry, Tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return !spatial_predicate_call<Tag>::apply(i, p.geometry);
}
};
// ------------------------------------------------------------------ //
template <typename DistancePredicates>
struct predicate_check<predicates::nearest<DistancePredicates>, value_tag>
{
template <typename Value, typename Box>
static inline bool apply(predicates::nearest<DistancePredicates> const&, Value const&, Box const&)
{
return true;
}
};
template <typename Linestring>
struct predicate_check<predicates::path<Linestring>, value_tag>
{
template <typename Value, typename Box>
static inline bool apply(predicates::path<Linestring> const&, Value const&, Box const&)
{
return true;
}
};
// ------------------------------------------------------------------ //
// predicates_check for bounds
// ------------------------------------------------------------------ //
template <typename Fun, bool Negated>
struct predicate_check<predicates::satisfies<Fun, Negated>, bounds_tag>
{
template <typename Value, typename Box>
static bool apply(predicates::satisfies<Fun, Negated> const&, Value const&, Box const&)
{
return true;
}
};
// ------------------------------------------------------------------ //
// NOT NEGATED
// value_tag bounds_tag
// ---------------------------
// contains(I,G) covers(I,G)
// covered_by(I,G) intersects(I,G)
// covers(I,G) covers(I,G)
// disjoint(I,G) !covered_by(I,G)
// intersects(I,G) intersects(I,G)
// overlaps(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false
// touches(I,G) intersects(I,G)
// within(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false
// spatial predicate - default
template <typename Geometry, typename Tag>
struct predicate_check<predicates::spatial_predicate<Geometry, Tag, false>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, Tag, false> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return spatial_predicate_call<predicates::intersects_tag>::apply(i, p.geometry);
}
};
// spatial predicate - contains
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::contains_tag, false>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::contains_tag, false> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return spatial_predicate_call<predicates::covers_tag>::apply(i, p.geometry);
}
};
// spatial predicate - covers
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::covers_tag, false>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::covers_tag, false> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return spatial_predicate_call<predicates::covers_tag>::apply(i, p.geometry);
}
};
// spatial predicate - disjoint
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::disjoint_tag, false>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::disjoint_tag, false> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return !spatial_predicate_call<predicates::covered_by_tag>::apply(i, p.geometry);
}
};
// NEGATED
// value_tag bounds_tag
// ---------------------------
// !contains(I,G) TRUE
// !covered_by(I,G) !covered_by(I,G)
// !covers(I,G) TRUE
// !disjoint(I,G) !disjoint(I,G)
// !intersects(I,G) !covered_by(I,G)
// !overlaps(I,G) TRUE
// !touches(I,G) !intersects(I,G)
// !within(I,G) !within(I,G)
// negated spatial predicate - default
template <typename Geometry, typename Tag>
struct predicate_check<predicates::spatial_predicate<Geometry, Tag, true>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, Tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return !spatial_predicate_call<Tag>::apply(i, p.geometry);
}
};
// negated spatial predicate - contains
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::contains_tag, true>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::contains_tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& , Value const&, Indexable const& )
{
return true;
}
};
// negated spatial predicate - covers
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::covers_tag, true>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::covers_tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& , Value const&, Indexable const& )
{
return true;
}
};
// negated spatial predicate - intersects
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::intersects_tag, true>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::intersects_tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return !spatial_predicate_call<predicates::covered_by_tag>::apply(i, p.geometry);
}
};
// negated spatial predicate - overlaps
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::overlaps_tag, true>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::overlaps_tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& , Value const&, Indexable const& )
{
return true;
}
};
// negated spatial predicate - touches
template <typename Geometry>
struct predicate_check<predicates::spatial_predicate<Geometry, predicates::touches_tag, true>, bounds_tag>
{
typedef predicates::spatial_predicate<Geometry, predicates::touches_tag, true> Pred;
template <typename Value, typename Indexable>
static inline bool apply(Pred const& p, Value const&, Indexable const& i)
{
return !spatial_predicate_call<predicates::intersects_tag>::apply(i, p.geometry);
}
};
// ------------------------------------------------------------------ //
template <typename DistancePredicates>
struct predicate_check<predicates::nearest<DistancePredicates>, bounds_tag>
{
template <typename Value, typename Box>
static inline bool apply(predicates::nearest<DistancePredicates> const&, Value const&, Box const&)
{
return true;
}
};
template <typename Linestring>
struct predicate_check<predicates::path<Linestring>, bounds_tag>
{
template <typename Value, typename Box>
static inline bool apply(predicates::path<Linestring> const&, Value const&, Box const&)
{
return true;
}
};
// ------------------------------------------------------------------ //
// predicates_length
// ------------------------------------------------------------------ //
template <typename T>
struct predicates_length
{
static const unsigned value = 1;
};
//template <typename F, typename S>
//struct predicates_length< std::pair<F, S> >
//{
// static const unsigned value = 2;
//};
//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
//struct predicates_length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
//{
// static const unsigned value = boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value;
//};
template <typename Head, typename Tail>
struct predicates_length< boost::tuples::cons<Head, Tail> >
{
static const unsigned value = boost::tuples::length< boost::tuples::cons<Head, Tail> >::value;
};
// ------------------------------------------------------------------ //
// predicates_element
// ------------------------------------------------------------------ //
template <unsigned I, typename T>
struct predicates_element
{
BOOST_MPL_ASSERT_MSG((I < 1), INVALID_INDEX, (predicates_element));
typedef T type;
static type const& get(T const& p) { return p; }
};
//template <unsigned I, typename F, typename S>
//struct predicates_element< I, std::pair<F, S> >
//{
// BOOST_MPL_ASSERT_MSG((I < 2), INVALID_INDEX, (predicates_element));
//
// typedef F type;
// static type const& get(std::pair<F, S> const& p) { return p.first; }
//};
//
//template <typename F, typename S>
//struct predicates_element< 1, std::pair<F, S> >
//{
// typedef S type;
// static type const& get(std::pair<F, S> const& p) { return p.second; }
//};
//
//template <unsigned I, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
//struct predicates_element< I, boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
//{
// typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> predicate_type;
//
// typedef typename boost::tuples::element<I, predicate_type>::type type;
// static type const& get(predicate_type const& p) { return boost::get<I>(p); }
//};
template <unsigned I, typename Head, typename Tail>
struct predicates_element< I, boost::tuples::cons<Head, Tail> >
{
typedef boost::tuples::cons<Head, Tail> predicate_type;
typedef typename boost::tuples::element<I, predicate_type>::type type;
static type const& get(predicate_type const& p) { return boost::get<I>(p); }
};
// ------------------------------------------------------------------ //
// predicates_check
// ------------------------------------------------------------------ //
//template <typename PairPredicates, typename Tag, unsigned First, unsigned Last>
//struct predicates_check_pair {};
//
//template <typename PairPredicates, typename Tag, unsigned I>
//struct predicates_check_pair<PairPredicates, Tag, I, I>
//{
// template <typename Value, typename Indexable>
// static inline bool apply(PairPredicates const& , Value const& , Indexable const& )
// {
// return true;
// }
//};
//
//template <typename PairPredicates, typename Tag>
//struct predicates_check_pair<PairPredicates, Tag, 0, 1>
//{
// template <typename Value, typename Indexable>
// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i)
// {
// return predicate_check<typename PairPredicates::first_type, Tag>::apply(p.first, v, i);
// }
//};
//
//template <typename PairPredicates, typename Tag>
//struct predicates_check_pair<PairPredicates, Tag, 1, 2>
//{
// template <typename Value, typename Indexable>
// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i)
// {
// return predicate_check<typename PairPredicates::second_type, Tag>::apply(p.second, v, i);
// }
//};
//
//template <typename PairPredicates, typename Tag>
//struct predicates_check_pair<PairPredicates, Tag, 0, 2>
//{
// template <typename Value, typename Indexable>
// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i)
// {
// return predicate_check<typename PairPredicates::first_type, Tag>::apply(p.first, v, i)
// && predicate_check<typename PairPredicates::second_type, Tag>::apply(p.second, v, i);
// }
//};
template <typename TuplePredicates, typename Tag, unsigned First, unsigned Last>
struct predicates_check_tuple
{
template <typename Value, typename Indexable>
static inline bool apply(TuplePredicates const& p, Value const& v, Indexable const& i)
{
return
predicate_check<
typename boost::tuples::element<First, TuplePredicates>::type,
Tag
>::apply(boost::get<First>(p), v, i) &&
predicates_check_tuple<TuplePredicates, Tag, First+1, Last>::apply(p, v, i);
}
};
template <typename TuplePredicates, typename Tag, unsigned First>
struct predicates_check_tuple<TuplePredicates, Tag, First, First>
{
template <typename Value, typename Indexable>
static inline bool apply(TuplePredicates const& , Value const& , Indexable const& )
{
return true;
}
};
template <typename Predicate, typename Tag, unsigned First, unsigned Last>
struct predicates_check_impl
{
static const bool check = First < 1 && Last <= 1 && First <= Last;
BOOST_MPL_ASSERT_MSG((check), INVALID_INDEXES, (predicates_check_impl));
template <typename Value, typename Indexable>
static inline bool apply(Predicate const& p, Value const& v, Indexable const& i)
{
return predicate_check<Predicate, Tag>::apply(p, v, i);
}
};
//template <typename Predicate1, typename Predicate2, typename Tag, size_t First, size_t Last>
//struct predicates_check_impl<std::pair<Predicate1, Predicate2>, Tag, First, Last>
//{
// BOOST_MPL_ASSERT_MSG((First < 2 && Last <= 2 && First <= Last), INVALID_INDEXES, (predicates_check_impl));
//
// template <typename Value, typename Indexable>
// static inline bool apply(std::pair<Predicate1, Predicate2> const& p, Value const& v, Indexable const& i)
// {
// return predicate_check<Predicate1, Tag>::apply(p.first, v, i)
// && predicate_check<Predicate2, Tag>::apply(p.second, v, i);
// }
//};
//
//template <
// typename T0, typename T1, typename T2, typename T3, typename T4,
// typename T5, typename T6, typename T7, typename T8, typename T9,
// typename Tag, unsigned First, unsigned Last
//>
//struct predicates_check_impl<
// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
// Tag, First, Last
//>
//{
// typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> predicates_type;
//
// static const unsigned pred_len = boost::tuples::length<predicates_type>::value;
// BOOST_MPL_ASSERT_MSG((First < pred_len && Last <= pred_len && First <= Last), INVALID_INDEXES, (predicates_check_impl));
//
// template <typename Value, typename Indexable>
// static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i)
// {
// return predicates_check_tuple<
// predicates_type,
// Tag, First, Last
// >::apply(p, v, i);
// }
//};
template <typename Head, typename Tail, typename Tag, unsigned First, unsigned Last>
struct predicates_check_impl<
boost::tuples::cons<Head, Tail>,
Tag, First, Last
>
{
typedef boost::tuples::cons<Head, Tail> predicates_type;
static const unsigned pred_len = boost::tuples::length<predicates_type>::value;
static const bool check = First < pred_len && Last <= pred_len && First <= Last;
BOOST_MPL_ASSERT_MSG((check), INVALID_INDEXES, (predicates_check_impl));
template <typename Value, typename Indexable>
static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i)
{
return predicates_check_tuple<
predicates_type,
Tag, First, Last
>::apply(p, v, i);
}
};
template <typename Tag, unsigned First, unsigned Last, typename Predicates, typename Value, typename Indexable>
inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i)
{
return detail::predicates_check_impl<Predicates, Tag, First, Last>
::apply(p, v, i);
}
// ------------------------------------------------------------------ //
// nearest predicate helpers
// ------------------------------------------------------------------ //
// predicates_is_nearest
template <typename P>
struct predicates_is_distance
{
static const unsigned value = 0;
};
template <typename DistancePredicates>
struct predicates_is_distance< predicates::nearest<DistancePredicates> >
{
static const unsigned value = 1;
};
template <typename Linestring>
struct predicates_is_distance< predicates::path<Linestring> >
{
static const unsigned value = 1;
};
// predicates_count_nearest
template <typename T>
struct predicates_count_distance
{
static const unsigned value = predicates_is_distance<T>::value;
};
//template <typename F, typename S>
//struct predicates_count_distance< std::pair<F, S> >
//{
// static const unsigned value = predicates_is_distance<F>::value
// + predicates_is_distance<S>::value;
//};
template <typename Tuple, unsigned N>
struct predicates_count_distance_tuple
{
static const unsigned value =
predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value
+ predicates_count_distance_tuple<Tuple, N-1>::value;
};
template <typename Tuple>
struct predicates_count_distance_tuple<Tuple, 1>
{
static const unsigned value =
predicates_is_distance<typename boost::tuples::element<0, Tuple>::type>::value;
};
//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
//struct predicates_count_distance< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
//{
// static const unsigned value = predicates_count_distance_tuple<
// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
// boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value
// >::value;
//};
template <typename Head, typename Tail>
struct predicates_count_distance< boost::tuples::cons<Head, Tail> >
{
static const unsigned value = predicates_count_distance_tuple<
boost::tuples::cons<Head, Tail>,
boost::tuples::length< boost::tuples::cons<Head, Tail> >::value
>::value;
};
// predicates_find_nearest
template <typename T>
struct predicates_find_distance
{
static const unsigned value = predicates_is_distance<T>::value ? 0 : 1;
};
//template <typename F, typename S>
//struct predicates_find_distance< std::pair<F, S> >
//{
// static const unsigned value = predicates_is_distance<F>::value ? 0 :
// (predicates_is_distance<S>::value ? 1 : 2);
//};
template <typename Tuple, unsigned N>
struct predicates_find_distance_tuple
{
static const bool is_found = predicates_find_distance_tuple<Tuple, N-1>::is_found
|| predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value;
static const unsigned value = predicates_find_distance_tuple<Tuple, N-1>::is_found ?
predicates_find_distance_tuple<Tuple, N-1>::value :
(predicates_is_distance<typename boost::tuples::element<N-1, Tuple>::type>::value ?
N-1 : boost::tuples::length<Tuple>::value);
};
template <typename Tuple>
struct predicates_find_distance_tuple<Tuple, 1>
{
static const bool is_found = predicates_is_distance<typename boost::tuples::element<0, Tuple>::type>::value;
static const unsigned value = is_found ? 0 : boost::tuples::length<Tuple>::value;
};
//template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
//struct predicates_find_distance< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
//{
// static const unsigned value = predicates_find_distance_tuple<
// boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>,
// boost::tuples::length< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >::value
// >::value;
//};
template <typename Head, typename Tail>
struct predicates_find_distance< boost::tuples::cons<Head, Tail> >
{
static const unsigned value = predicates_find_distance_tuple<
boost::tuples::cons<Head, Tail>,
boost::tuples::length< boost::tuples::cons<Head, Tail> >::value
>::value;
};
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
@@ -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
@@ -0,0 +1,585 @@
// Boost.Geometry Index
//
// 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_SERIALIZATION_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
//#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/version.hpp>
//#include <boost/serialization/nvp.hpp>
// TODO
// how about using the unsigned type capable of storing Max in compile-time versions?
// TODO
// - add wrappers for Point and Box and implement serialize for those wrappers instead of
// raw geometries
// PROBLEM: after implementing this, how Values would be set?
// - store the name of the parameters to know how to load and detect errors
// - in the header, once store info about the Indexable and Bounds types (geometry type, point CS, Dim, etc.)
// each geometry save without this info
// TODO - move to index/detail/serialization.hpp
namespace boost { namespace geometry { namespace index { namespace detail {
// TODO - use boost::move?
template<typename T>
class serialization_storage
{
public:
template <typename Archive>
serialization_storage(Archive & ar, unsigned int version)
{
boost::serialization::load_construct_data_adl(ar, this->address(), version);
}
~serialization_storage()
{
this->address()->~T();
}
T * address()
{
return static_cast<T*>(m_storage.address());
}
private:
boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value> m_storage;
};
// TODO - save and load item_version? see: collections_load_imp and collections_save_imp
// this should be done once for the whole container
// versions of all used types should be stored
template <typename T, typename Archive> inline
T serialization_load(const char * name, Archive & ar)
{
namespace bs = boost::serialization;
serialization_storage<T> storage(ar, bs::version<T>::value); // load_construct_data
ar >> boost::serialization::make_nvp(name, *storage.address()); // serialize
//ar >> *storage.address(); // serialize
return *storage.address();
}
template <typename T, typename Archive> inline
void serialization_save(T const& t, const char * name, Archive & ar)
{
namespace bs = boost::serialization;
bs::save_construct_data_adl(ar, boost::addressof(t), bs::version<T>::value); // save_construct_data
ar << boost::serialization::make_nvp(name, t); // serialize
//ar << t; // serialize
}
}}}}
// TODO - move to index/serialization/rtree.hpp
namespace boost { namespace serialization {
// boost::geometry::index::linear
template<class Archive, size_t Max, size_t Min>
void save_construct_data(Archive & ar, const boost::geometry::index::linear<Max, Min> * params, unsigned int )
{
size_t max = params->get_max_elements(), min = params->get_min_elements();
ar << boost::serialization::make_nvp("max", max);
ar << boost::serialization::make_nvp("min", min);
}
template<class Archive, size_t Max, size_t Min>
void load_construct_data(Archive & ar, boost::geometry::index::linear<Max, Min> * params, unsigned int )
{
size_t max, min;
ar >> boost::serialization::make_nvp("max", max);
ar >> boost::serialization::make_nvp("min", min);
if ( max != params->get_max_elements() || min != params->get_min_elements() )
// TODO change exception type
BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
// the constructor musn't be called for this type
//::new(params)boost::geometry::index::linear<Max, Min>();
}
template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::linear<Max, Min> &, unsigned int) {}
// boost::geometry::index::quadratic
template<class Archive, size_t Max, size_t Min>
void save_construct_data(Archive & ar, const boost::geometry::index::quadratic<Max, Min> * params, unsigned int )
{
size_t max = params->get_max_elements(), min = params->get_min_elements();
ar << boost::serialization::make_nvp("max", max);
ar << boost::serialization::make_nvp("min", min);
}
template<class Archive, size_t Max, size_t Min>
void load_construct_data(Archive & ar, boost::geometry::index::quadratic<Max, Min> * params, unsigned int )
{
size_t max, min;
ar >> boost::serialization::make_nvp("max", max);
ar >> boost::serialization::make_nvp("min", min);
if ( max != params->get_max_elements() || min != params->get_min_elements() )
// TODO change exception type
BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
// the constructor musn't be called for this type
//::new(params)boost::geometry::index::quadratic<Max, Min>();
}
template<class Archive, size_t Max, size_t Min> void serialize(Archive &, boost::geometry::index::quadratic<Max, Min> &, unsigned int) {}
// boost::geometry::index::rstar
template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
void save_construct_data(Archive & ar, const boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int )
{
size_t max = params->get_max_elements()
, min = params->get_min_elements()
, re = params->get_reinserted_elements()
, oct = params->get_overlap_cost_threshold();
ar << boost::serialization::make_nvp("max", max);
ar << boost::serialization::make_nvp("min", min);
ar << boost::serialization::make_nvp("re", re);
ar << boost::serialization::make_nvp("oct", oct);
}
template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
void load_construct_data(Archive & ar, boost::geometry::index::rstar<Max, Min, RE, OCT> * params, unsigned int )
{
size_t max, min, re, oct;
ar >> boost::serialization::make_nvp("max", max);
ar >> boost::serialization::make_nvp("min", min);
ar >> boost::serialization::make_nvp("re", re);
ar >> boost::serialization::make_nvp("oct", oct);
if ( max != params->get_max_elements() || min != params->get_min_elements() ||
re != params->get_reinserted_elements() || oct != params->get_overlap_cost_threshold() )
// TODO change exception type
BOOST_THROW_EXCEPTION(std::runtime_error("parameters not compatible"));
// the constructor musn't be called for this type
//::new(params)boost::geometry::index::rstar<Max, Min, RE, OCT>();
}
template<class Archive, size_t Max, size_t Min, size_t RE, size_t OCT>
void serialize(Archive &, boost::geometry::index::rstar<Max, Min, RE, OCT> &, unsigned int) {}
// boost::geometry::index::dynamic_linear
template<class Archive>
inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_linear * params, unsigned int )
{
size_t max = params->get_max_elements(), min = params->get_min_elements();
ar << boost::serialization::make_nvp("max", max);
ar << boost::serialization::make_nvp("min", min);
}
template<class Archive>
inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_linear * params, unsigned int )
{
size_t max, min;
ar >> boost::serialization::make_nvp("max", max);
ar >> boost::serialization::make_nvp("min", min);
::new(params)boost::geometry::index::dynamic_linear(max, min);
}
template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_linear &, unsigned int) {}
// boost::geometry::index::dynamic_quadratic
template<class Archive>
inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_quadratic * params, unsigned int )
{
size_t max = params->get_max_elements(), min = params->get_min_elements();
ar << boost::serialization::make_nvp("max", max);
ar << boost::serialization::make_nvp("min", min);
}
template<class Archive>
inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_quadratic * params, unsigned int )
{
size_t max, min;
ar >> boost::serialization::make_nvp("max", max);
ar >> boost::serialization::make_nvp("min", min);
::new(params)boost::geometry::index::dynamic_quadratic(max, min);
}
template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_quadratic &, unsigned int) {}
// boost::geometry::index::dynamic_rstar
template<class Archive>
inline void save_construct_data(Archive & ar, const boost::geometry::index::dynamic_rstar * params, unsigned int )
{
size_t max = params->get_max_elements()
, min = params->get_min_elements()
, re = params->get_reinserted_elements()
, oct = params->get_overlap_cost_threshold();
ar << boost::serialization::make_nvp("max", max);
ar << boost::serialization::make_nvp("min", min);
ar << boost::serialization::make_nvp("re", re);
ar << boost::serialization::make_nvp("oct", oct);
}
template<class Archive>
inline void load_construct_data(Archive & ar, boost::geometry::index::dynamic_rstar * params, unsigned int )
{
size_t max, min, re, oct;
ar >> boost::serialization::make_nvp("max", max);
ar >> boost::serialization::make_nvp("min", min);
ar >> boost::serialization::make_nvp("re", re);
ar >> boost::serialization::make_nvp("oct", oct);
::new(params)boost::geometry::index::dynamic_rstar(max, min, re, oct);
}
template<class Archive> void serialize(Archive &, boost::geometry::index::dynamic_rstar &, unsigned int) {}
}} // boost::serialization
// TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename P, size_t I = 0, size_t D = geometry::dimension<P>::value>
struct serialize_point
{
template <typename Archive>
static inline void save(Archive & ar, P const& p, unsigned int version)
{
typename coordinate_type<P>::type c = get<I>(p);
ar << boost::serialization::make_nvp("c", c);
serialize_point<P, I+1, D>::save(ar, p, version);
}
template <typename Archive>
static inline void load(Archive & ar, P & p, unsigned int version)
{
typename geometry::coordinate_type<P>::type c;
ar >> boost::serialization::make_nvp("c", c);
set<I>(p, c);
serialize_point<P, I+1, D>::load(ar, p, version);
}
};
template <typename P, size_t D>
struct serialize_point<P, D, D>
{
template <typename Archive> static inline void save(Archive &, P const&, unsigned int) {}
template <typename Archive> static inline void load(Archive &, P &, unsigned int) {}
};
}}}}
// TODO - move to index/detail/serialization.hpp or maybe geometry/serialization.hpp
namespace boost { namespace serialization {
template<class Archive, typename T, size_t D, typename C>
void save(Archive & ar, boost::geometry::model::point<T, D, C> const& p, unsigned int version)
{
boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::save(ar, p, version);
}
template<class Archive, typename T, size_t D, typename C>
void load(Archive & ar, boost::geometry::model::point<T, D, C> & p, unsigned int version)
{
boost::geometry::index::detail::serialize_point< boost::geometry::model::point<T, D, C> >::load(ar, p, version);
}
template<class Archive, typename T, size_t D, typename C>
inline void serialize(Archive & ar, boost::geometry::model::point<T, D, C> & o, const unsigned int version) { split_free(ar, o, version); }
template<class Archive, typename P>
inline void serialize(Archive & ar, boost::geometry::model::box<P> & b, const unsigned int)
{
ar & boost::serialization::make_nvp("min", b.min_corner());
ar & boost::serialization::make_nvp("max", b.max_corner());
}
}} // boost::serialization
// TODO - move to index/detail/rtree/visitors/save.hpp
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { namespace visitors {
// TODO move saving and loading of the rtree outside the rtree, this will require adding some kind of members_view
template <typename Archive, typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class save
: 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;
save(Archive & archive, unsigned int version)
: m_archive(archive), m_version(version)
{}
inline void operator()(internal_node const& n)
{
typedef typename rtree::elements_type<internal_node>::type elements_type;
elements_type const& elements = rtree::elements(n);
// CONSIDER: change to elements_type::size_type or size_type
// or use fixed-size type like uint32 or even uint16?
size_t s = elements.size();
m_archive << boost::serialization::make_nvp("s", s);
for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
{
serialization_save(it->first, "b", m_archive);
rtree::apply_visitor(*this, *it->second);
}
}
inline void operator()(leaf const& l)
{
typedef typename rtree::elements_type<leaf>::type elements_type;
//typedef typename elements_type::size_type elements_size;
elements_type const& elements = rtree::elements(l);
// CONSIDER: change to elements_type::size_type or size_type
// or use fixed-size type like uint32 or even uint16?
size_t s = elements.size();
m_archive << boost::serialization::make_nvp("s", s);
for (typename elements_type::const_iterator it = elements.begin() ; it != elements.end() ; ++it)
{
serialization_save(*it, "v", m_archive);
}
}
private:
Archive & m_archive;
unsigned int m_version;
};
}}}}}} // boost::geometry::index::detail::rtree::visitors
// TODO - move to index/detail/rtree/load.hpp
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
class load
{
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::node_pointer node_pointer;
typedef rtree::subtree_destroyer<Value, Options, Translator, Box, Allocators> subtree_destroyer;
typedef typename Allocators::size_type size_type;
public:
template <typename Archive> inline static
node_pointer apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, Translator const& translator, Allocators & allocators)
{
values_count = 0;
return raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators);
}
private:
template <typename Archive> inline static
node_pointer raw_apply(Archive & ar, unsigned int version, size_type leafs_level, size_type & values_count, parameters_type const& parameters, Translator const& translator, Allocators & allocators, size_type current_level = 0)
{
//BOOST_GEOMETRY_INDEX_ASSERT(current_level <= leafs_level, "invalid parameter");
typedef typename rtree::elements_type<internal_node>::type elements_type;
typedef typename elements_type::value_type element_type;
//typedef typename elements_type::size_type elements_size;
// CONSIDER: change to elements_type::size_type or size_type
// or use fixed-size type like uint32 or even uint16?
size_t elements_count;
ar >> boost::serialization::make_nvp("s", elements_count);
if ( elements_count < parameters.get_min_elements() || parameters.get_max_elements() < elements_count )
BOOST_THROW_EXCEPTION(std::runtime_error("rtree loading error"));
if ( current_level < leafs_level )
{
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);
elements_type & elements = rtree::elements(in);
elements.reserve(elements_count); // MAY THROW (A)
for ( size_t i = 0 ; i < elements_count ; ++i )
{
typedef typename elements_type::value_type::first_type box_type;
box_type b = serialization_load<box_type>("b", ar);
node_pointer n = raw_apply(ar, version, leafs_level, values_count, parameters, translator, allocators, current_level+1); // recursive call
elements.push_back(element_type(b, n));
}
auto_remover.release();
return n;
}
else
{
BOOST_GEOMETRY_INDEX_ASSERT(current_level == leafs_level, "unexpected value");
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);
typedef typename rtree::elements_type<leaf>::type elements_type;
typedef typename elements_type::value_type element_type;
elements_type & elements = rtree::elements(l);
values_count += elements_count;
elements.reserve(elements_count); // MAY THROW (A)
for ( size_t i = 0 ; i < elements_count ; ++i )
{
element_type el = serialization_load<element_type>("v", ar); // MAY THROW (C)
elements.push_back(el); // MAY THROW (C)
}
auto_remover.release();
return n;
}
}
};
}}}}} // boost::geometry::index::detail::rtree
// TODO - move to index/detail/rtree/private_view.hpp
namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree {
template <typename Rtree>
class const_private_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;
const_private_view(Rtree const& rt) : m_rtree(rt) {}
typedef typename Rtree::members_holder members_holder;
members_holder const& members() const { return m_rtree.m_members; }
private:
const_private_view(const_private_view const&);
const_private_view & operator=(const_private_view const&);
Rtree const& m_rtree;
};
template <typename Rtree>
class private_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;
private_view(Rtree & rt) : m_rtree(rt) {}
typedef typename Rtree::members_holder members_holder;
members_holder & members() { return m_rtree.m_members; }
members_holder const& members() const { return m_rtree.m_members; }
private:
private_view(private_view const&);
private_view & operator=(private_view const&);
Rtree & m_rtree;
};
}}}}} // namespace boost::geometry::index::detail::rtree
// TODO - move to index/serialization/rtree.hpp
namespace boost { namespace serialization {
template<class Archive, typename V, typename P, typename I, typename E, typename A>
void save(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version)
{
namespace detail = boost::geometry::index::detail;
typedef boost::geometry::index::rtree<V, P, I, E, A> rtree;
typedef detail::rtree::const_private_view<rtree> view;
typedef typename view::translator_type translator_type;
typedef typename view::value_type value_type;
typedef typename view::options_type options_type;
typedef typename view::box_type box_type;
typedef typename view::allocators_type allocators_type;
view tree(rt);
detail::serialization_save(tree.members().parameters(), "parameters", ar);
ar << boost::serialization::make_nvp("values_count", tree.members().values_count);
ar << boost::serialization::make_nvp("leafs_level", tree.members().leafs_level);
if ( tree.members().values_count )
{
BOOST_GEOMETRY_INDEX_ASSERT(tree.members().root, "root shouldn't be null_ptr");
detail::rtree::visitors::save<Archive, value_type, options_type, translator_type, box_type, allocators_type> save_v(ar, version);
detail::rtree::apply_visitor(save_v, *tree.members().root);
}
}
template<class Archive, typename V, typename P, typename I, typename E, typename A>
void load(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version)
{
namespace detail = boost::geometry::index::detail;
typedef boost::geometry::index::rtree<V, P, I, E, A> rtree;
typedef detail::rtree::private_view<rtree> view;
typedef typename view::size_type size_type;
typedef typename view::translator_type translator_type;
typedef typename view::value_type value_type;
typedef typename view::options_type options_type;
typedef typename view::box_type box_type;
typedef typename view::allocators_type allocators_type;
typedef typename options_type::parameters_type parameters_type;
typedef typename allocators_type::node_pointer node_pointer;
typedef detail::rtree::subtree_destroyer<value_type, options_type, translator_type, box_type, allocators_type> subtree_destroyer;
view tree(rt);
parameters_type params = detail::serialization_load<parameters_type>("parameters", ar);
size_type values_count, leafs_level;
ar >> boost::serialization::make_nvp("values_count", values_count);
ar >> boost::serialization::make_nvp("leafs_level", leafs_level);
node_pointer n(0);
if ( 0 < values_count )
{
size_type loaded_values_count = 0;
n = detail::rtree::load<value_type, options_type, translator_type, box_type, allocators_type>
::apply(ar, version, leafs_level, loaded_values_count, params, tree.members().translator(), tree.members().allocators()); // MAY THROW
subtree_destroyer remover(n, tree.members().allocators());
if ( loaded_values_count != values_count )
BOOST_THROW_EXCEPTION(std::runtime_error("unexpected number of values")); // TODO change exception type
remover.release();
}
tree.members().parameters() = params;
tree.members().values_count = values_count;
tree.members().leafs_level = leafs_level;
subtree_destroyer remover(tree.members().root, tree.members().allocators());
tree.members().root = n;
}
template<class Archive, typename V, typename P, typename I, typename E, typename A> inline
void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> & rt, unsigned int version)
{
split_free(ar, rt, version);
}
template<class Archive, typename V, typename P, typename I, typename E, typename A> inline
void serialize(Archive & ar, boost::geometry::index::rtree<V, P, I, E, A> const& rt, unsigned int version)
{
split_free(ar, rt, version);
}
}} // boost::serialization
#endif // BOOST_GEOMETRY_INDEX_DETAIL_SERIALIZATION_HPP
@@ -0,0 +1,25 @@
// Boost.Geometry Index
//
// Tags used by the predicates checks 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_TAGS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_TAGS_HPP
namespace boost { namespace geometry { namespace index {
namespace detail {
struct value_tag {};
struct bounds_tag {};
} // namespace detail
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_RTREE_TAGS_HPP
@@ -0,0 +1,60 @@
// Boost.Geometry Index
//
// 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_TRANSLATOR_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP
namespace boost { namespace geometry { namespace index {
namespace detail {
template <typename IndexableGetter, typename EqualTo>
struct translator
: public IndexableGetter
, public EqualTo
{
typedef typename IndexableGetter::result_type result_type;
translator(IndexableGetter const& i, EqualTo const& e)
: IndexableGetter(i), EqualTo(e)
{}
template <typename Value>
result_type operator()(Value const& value) const
{
return IndexableGetter::operator()(value);
}
template <typename Value>
bool equals(Value const& v1, Value const& v2) const
{
return EqualTo::operator()(v1, v2);
}
};
template <typename IndexableGetter>
struct result_type
{
typedef typename IndexableGetter::result_type type;
};
template <typename IndexableGetter>
struct indexable_type
{
typedef typename boost::remove_const<
typename boost::remove_reference<
typename result_type<IndexableGetter>::type
>::type
>::type type;
};
} // namespace detail
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP
@@ -0,0 +1,204 @@
// Boost.Geometry Index
//
// 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_TUPLES_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_TUPLES_HPP
#include <boost/tuple/tuple.hpp>
#include <boost/type_traits/is_same.hpp>
// TODO move this to index/tuples and separate algorithms
namespace boost { namespace geometry { namespace index { namespace detail {
namespace tuples {
// find_index
namespace detail {
template <typename Tuple, typename El, size_t N>
struct find_index;
template <typename Tuple, typename El, size_t N, typename CurrentEl>
struct find_index_impl
{
static const size_t value = find_index<Tuple, El, N - 1>::value;
};
template <typename Tuple, typename El, size_t N>
struct find_index_impl<Tuple, El, N, El>
{
static const size_t value = N - 1;
};
template <typename Tuple, typename El, typename CurrentEl>
struct find_index_impl<Tuple, El, 1, CurrentEl>
{
BOOST_MPL_ASSERT_MSG(
(false),
ELEMENT_NOT_FOUND,
(find_index_impl));
};
template <typename Tuple, typename El>
struct find_index_impl<Tuple, El, 1, El>
{
static const size_t value = 0;
};
template <typename Tuple, typename El, size_t N>
struct find_index
{
static const size_t value =
find_index_impl<
Tuple,
El,
N,
typename boost::tuples::element<N - 1, Tuple>::type
>::value;
};
} // namespace detail
template <typename Tuple, typename El>
struct find_index
{
static const size_t value =
detail::find_index<
Tuple,
El,
boost::tuples::length<Tuple>::value
>::value;
};
// has
namespace detail {
template <typename Tuple, typename El, size_t N>
struct has
{
static const bool value
= boost::is_same<
typename boost::tuples::element<N - 1, Tuple>::type,
El
>::value
|| has<Tuple, El, N - 1>::value;
};
template <typename Tuple, typename El>
struct has<Tuple, El, 1>
{
static const bool value
= boost::is_same<
typename boost::tuples::element<0, Tuple>::type,
El
>::value;
};
} // namespace detail
template <typename Tuple, typename El>
struct has
{
static const bool value
= detail::has<
Tuple,
El,
boost::tuples::length<Tuple>::value
>::value;
};
// add
template <typename Tuple, typename El>
struct add
{
BOOST_MPL_ASSERT_MSG(
(false),
NOT_IMPLEMENTED_FOR_THIS_TUPLE_TYPE,
(add));
};
template <typename T1, typename T>
struct add<boost::tuple<T1>, T>
{
typedef boost::tuple<T1, T> type;
};
template <typename T1, typename T2, typename T>
struct add<boost::tuple<T1, T2>, T>
{
typedef boost::tuple<T1, T2, T> type;
};
// add_if
template <typename Tuple, typename El, bool Cond>
struct add_if
{
typedef Tuple type;
};
template <typename Tuple, typename El>
struct add_if<Tuple, El, true>
{
typedef typename add<Tuple, El>::type type;
};
// add_unique
template <typename Tuple, typename El>
struct add_unique
{
typedef typename add_if<
Tuple,
El,
!has<Tuple, El>::value
>::type type;
};
template <typename Tuple,
typename T,
size_t I = 0,
size_t N = boost::tuples::length<Tuple>::value>
struct push_back
{
typedef
boost::tuples::cons<
typename boost::tuples::element<I, Tuple>::type,
typename push_back<Tuple, T, I+1, N>::type
> type;
static type apply(Tuple const& tup, T const& t)
{
return
type(
boost::get<I>(tup),
push_back<Tuple, T, I+1, N>::apply(tup, t)
);
}
};
template <typename Tuple, typename T, size_t N>
struct push_back<Tuple, T, N, N>
{
typedef boost::tuples::cons<T, boost::tuples::null_type> type;
static type apply(Tuple const&, T const& t)
{
return type(t, boost::tuples::null_type());
}
};
} // namespace tuples
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_TAGS_HPP
@@ -0,0 +1,46 @@
// Boost.Geometry Index
//
// 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)
#include <boost/swap.hpp>
//#include <boost/type_traits/is_empty.hpp>
#ifndef BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP
namespace boost { namespace geometry { namespace index { namespace detail {
template<class T>
static inline void assign_cond(T & l, T const& r, boost::mpl::bool_<true> const&)
{
l = r;
}
template<class T>
static inline void assign_cond(T &, T const&, boost::mpl::bool_<false> const&) {}
template<class T>
static inline void move_cond(T & l, T & r, boost::mpl::bool_<true> const&)
{
l = ::boost::move(r);
}
template<class T>
static inline void move_cond(T &, T &, boost::mpl::bool_<false> const&) {}
template <typename T> inline
void swap_cond(T & l, T & r, boost::mpl::bool_<true> const&)
{
::boost::swap(l, r);
}
template <typename T> inline
void swap_cond(T &, T &, boost::mpl::bool_<false> const&) {}
}}}} // namespace boost::geometry::index::detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_UTILITIES_HPP
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,760 @@
// Boost.Geometry
//
// varray details
//
// Copyright (c) 2012-2015 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2011-2013 Andrew Hundt.
//
// 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_VARRAY_DETAIL_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP
#include <cstddef>
#include <cstring>
#include <memory>
#include <limits>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/int.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/has_trivial_assign.hpp>
#include <boost/type_traits/has_trivial_copy.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/type_traits/has_trivial_move_constructor.hpp>
#include <boost/type_traits/has_trivial_move_assign.hpp>
//#include <boost/type_traits/has_nothrow_constructor.hpp>
//#include <boost/type_traits/has_nothrow_copy.hpp>
//#include <boost/type_traits/has_nothrow_assign.hpp>
//#include <boost/type_traits/has_nothrow_destructor.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/config.hpp>
#include <boost/move/move.hpp>
#include <boost/core/addressof.hpp>
#include <boost/iterator/iterator_traits.hpp>
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <boost/move/detail/fwd_macros.hpp>
#endif
// TODO - move vectors iterators optimization to the other, optional file instead of checking defines?
#if defined(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS)
#include <vector>
#include <boost/container/vector.hpp>
#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION && !BOOST_NO_EXCEPTIONS
namespace boost { namespace geometry { namespace index { namespace detail { namespace varray_detail {
template <typename I>
struct are_elements_contiguous : boost::is_pointer<I>
{};
// EXPERIMENTAL - not finished
// Conditional setup - mark vector iterators defined in known implementations
// as iterators pointing to contiguous ranges
#if defined(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION) && !defined(BOOST_NO_EXCEPTIONS)
template <typename Pointer>
struct are_elements_contiguous<
boost::container::container_detail::vector_const_iterator<Pointer>
> : boost::true_type
{};
template <typename Pointer>
struct are_elements_contiguous<
boost::container::container_detail::vector_iterator<Pointer>
> : boost::true_type
{};
#if defined(BOOST_DINKUMWARE_STDLIB)
template <typename T>
struct are_elements_contiguous<
std::_Vector_const_iterator<T>
> : boost::true_type
{};
template <typename T>
struct are_elements_contiguous<
std::_Vector_iterator<T>
> : boost::true_type
{};
#elif defined(BOOST_GNU_STDLIB)
template <typename P, typename T, typename A>
struct are_elements_contiguous<
__gnu_cxx::__normal_iterator<P, std::vector<T, A> >
> : boost::true_type
{};
#elif defined(_LIBCPP_VERSION)
// TODO - test it first
//template <typename P>
//struct are_elements_contiguous<
// __wrap_iter<P>
//> : boost::true_type
//{};
#else // OTHER_STDLIB
// TODO - add other iterators implementations
#endif // STDLIB
#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_ENABLE_VECTOR_OPTIMIZATION && !BOOST_NO_EXCEPTIONS
// True if iterator values are the same and both iterators points to the ranges of contiguous elements
template <typename I, typename O>
struct are_corresponding :
::boost::mpl::and_<
::boost::is_same<
::boost::remove_const<
typename ::boost::iterator_value<I>::type
>,
::boost::remove_const<
typename ::boost::iterator_value<O>::type
>
>,
are_elements_contiguous<I>,
are_elements_contiguous<O>
>
{};
template <typename I, typename V>
struct is_corresponding_value :
::boost::is_same<
::boost::remove_const<
typename ::boost::iterator_value<I>::type
>,
::boost::remove_const<V>
>
{};
// destroy(I, I)
template <typename I>
void destroy_dispatch(I /*first*/, I /*last*/,
boost::true_type const& /*has_trivial_destructor*/)
{}
template <typename I>
void destroy_dispatch(I first, I last,
boost::false_type const& /*has_trivial_destructor*/)
{
typedef typename boost::iterator_value<I>::type value_type;
for ( ; first != last ; ++first )
first->~value_type();
}
template <typename I>
void destroy(I first, I last)
{
typedef typename boost::iterator_value<I>::type value_type;
destroy_dispatch(first, last, has_trivial_destructor<value_type>());
}
// destroy(I)
template <typename I>
void destroy_dispatch(I /*pos*/,
boost::true_type const& /*has_trivial_destructor*/)
{}
template <typename I>
void destroy_dispatch(I pos,
boost::false_type const& /*has_trivial_destructor*/)
{
typedef typename boost::iterator_value<I>::type value_type;
pos->~value_type();
}
template <typename I>
void destroy(I pos)
{
typedef typename boost::iterator_value<I>::type value_type;
destroy_dispatch(pos, has_trivial_destructor<value_type>());
}
// copy(I, I, O)
template <typename I, typename O>
inline O copy_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memmove*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename O>
inline O copy_dispatch(I first, I last, O dst,
boost::mpl::bool_<false> const& /*use_memmove*/)
{
return std::copy(first, last, dst); // may throw
}
template <typename I, typename O>
inline O copy(I first, I last, O dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, O>,
::boost::has_trivial_assign<
typename ::boost::iterator_value<O>::type
>
>::type
use_memmove;
return copy_dispatch(first, last, dst, use_memmove()); // may throw
}
// uninitialized_copy(I, I, O)
template <typename I, typename O>
inline
O uninitialized_copy_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename F>
inline
F uninitialized_copy_dispatch(I first, I last, F dst,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
return std::uninitialized_copy(first, last, dst); // may throw
}
template <typename I, typename F>
inline
F uninitialized_copy(I first, I last, F dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, F>,
::boost::has_trivial_copy<
typename ::boost::iterator_value<F>::type
>
>::type
use_memcpy;
return uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw
}
// uninitialized_move(I, I, O)
template <typename I, typename O>
inline
O uninitialized_move_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memcpy(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename O>
inline
O uninitialized_move_dispatch(I first, I last, O dst,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
//return boost::uninitialized_move(first, last, dst); // may throw
O o = dst;
BOOST_TRY
{
typedef typename std::iterator_traits<O>::value_type value_type;
for (; first != last; ++first, ++o )
new (boost::addressof(*o)) value_type(boost::move(*first));
}
BOOST_CATCH(...)
{
destroy(dst, o);
BOOST_RETHROW;
}
BOOST_CATCH_END
return dst;
}
template <typename I, typename O>
inline
O uninitialized_move(I first, I last, O dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, O>,
::boost::has_trivial_copy<
typename ::boost::iterator_value<O>::type
>
>::type
use_memcpy;
return uninitialized_move_dispatch(first, last, dst, use_memcpy()); // may throw
}
// TODO - move uses memmove - implement 2nd version using memcpy?
// move(I, I, O)
template <typename I, typename O>
inline
O move_dispatch(I first, I last, O dst,
boost::mpl::bool_<true> const& /*use_memmove*/)
{
typedef typename boost::iterator_value<I>::type value_type;
typename boost::iterator_difference<I>::type d = std::distance(first, last);
::memmove(boost::addressof(*dst), boost::addressof(*first), sizeof(value_type) * d);
return dst + d;
}
template <typename I, typename O>
inline
O move_dispatch(I first, I last, O dst,
boost::mpl::bool_<false> const& /*use_memmove*/)
{
return boost::move(first, last, dst); // may throw
}
template <typename I, typename O>
inline
O move(I first, I last, O dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<I, O>,
::boost::has_trivial_assign<
typename ::boost::iterator_value<O>::type
>
>::type
use_memmove;
return move_dispatch(first, last, dst, use_memmove()); // may throw
}
// move_backward(BDI, BDI, BDO)
template <typename BDI, typename BDO>
inline
BDO move_backward_dispatch(BDI first, BDI last, BDO dst,
boost::mpl::bool_<true> const& /*use_memmove*/)
{
typedef typename boost::iterator_value<BDI>::type value_type;
typename boost::iterator_difference<BDI>::type d = std::distance(first, last);
BDO foo(dst - d);
::memmove(boost::addressof(*foo), boost::addressof(*first), sizeof(value_type) * d);
return foo;
}
template <typename BDI, typename BDO>
inline
BDO move_backward_dispatch(BDI first, BDI last, BDO dst,
boost::mpl::bool_<false> const& /*use_memmove*/)
{
return boost::move_backward(first, last, dst); // may throw
}
template <typename BDI, typename BDO>
inline
BDO move_backward(BDI first, BDI last, BDO dst)
{
typedef typename
::boost::mpl::and_<
are_corresponding<BDI, BDO>,
::boost::has_trivial_assign<
typename ::boost::iterator_value<BDO>::type
>
>::type
use_memmove;
return move_backward_dispatch(first, last, dst, use_memmove()); // may throw
}
template <typename T>
struct has_nothrow_move : public
::boost::mpl::or_<
boost::mpl::bool_<
::boost::has_nothrow_move<
typename ::boost::remove_const<T>::type
>::value
>,
boost::mpl::bool_<
::boost::has_nothrow_move<T>::value
>
>
{};
// uninitialized_move_if_noexcept(I, I, O)
template <typename I, typename O>
inline
O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/)
{ return varray_detail::uninitialized_move(first, last, dst); }
template <typename I, typename O>
inline
O uninitialized_move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/)
{ return varray_detail::uninitialized_copy(first, last, dst); }
template <typename I, typename O>
inline
O uninitialized_move_if_noexcept(I first, I last, O dst)
{
typedef typename has_nothrow_move<
typename ::boost::iterator_value<O>::type
>::type use_move;
return uninitialized_move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw
}
// move_if_noexcept(I, I, O)
template <typename I, typename O>
inline
O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<true> const& /*use_move*/)
{ return move(first, last, dst); }
template <typename I, typename O>
inline
O move_if_noexcept_dispatch(I first, I last, O dst, boost::mpl::bool_<false> const& /*use_move*/)
{ return copy(first, last, dst); }
template <typename I, typename O>
inline
O move_if_noexcept(I first, I last, O dst)
{
typedef typename has_nothrow_move<
typename ::boost::iterator_value<O>::type
>::type use_move;
return move_if_noexcept_dispatch(first, last, dst, use_move()); // may throw
}
// uninitialized_fill(I, I)
template <typename I>
inline
void uninitialized_fill_dispatch(I /*first*/, I /*last*/,
boost::true_type const& /*has_trivial_constructor*/,
boost::true_type const& /*disable_trivial_init*/)
{}
template <typename I>
inline
void uninitialized_fill_dispatch(I first, I last,
boost::true_type const& /*has_trivial_constructor*/,
boost::false_type const& /*disable_trivial_init*/)
{
typedef typename boost::iterator_value<I>::type value_type;
for ( ; first != last ; ++first )
new (boost::addressof(*first)) value_type();
}
template <typename I, typename DisableTrivialInit>
inline
void uninitialized_fill_dispatch(I first, I last,
boost::false_type const& /*has_trivial_constructor*/,
DisableTrivialInit const& /*not_used*/)
{
typedef typename boost::iterator_value<I>::type value_type;
I it = first;
BOOST_TRY
{
for ( ; it != last ; ++it )
new (boost::addressof(*it)) value_type(); // may throw
}
BOOST_CATCH(...)
{
destroy(first, it);
BOOST_RETHROW;
}
BOOST_CATCH_END
}
template <typename I, typename DisableTrivialInit>
inline
void uninitialized_fill(I first, I last, DisableTrivialInit const& disable_trivial_init)
{
typedef typename boost::iterator_value<I>::type value_type;
uninitialized_fill_dispatch(first, last, boost::has_trivial_constructor<value_type>(), disable_trivial_init); // may throw
}
// construct(I)
template <typename I>
inline
void construct_dispatch(boost::mpl::bool_<true> const& /*dont_init*/, I /*pos*/)
{}
template <typename I>
inline
void construct_dispatch(boost::mpl::bool_<false> const& /*dont_init*/, I pos)
{
typedef typename ::boost::iterator_value<I>::type value_type;
new (static_cast<void*>(::boost::addressof(*pos))) value_type(); // may throw
}
template <typename DisableTrivialInit, typename I>
inline
void construct(DisableTrivialInit const&, I pos)
{
typedef typename ::boost::iterator_value<I>::type value_type;
typedef typename ::boost::mpl::and_<
boost::has_trivial_constructor<value_type>,
DisableTrivialInit
>::type dont_init;
construct_dispatch(dont_init(), pos); // may throw
}
// construct(I, V)
template <typename I, typename V>
inline
void construct_copy_dispatch(I pos, V const& v,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
}
template <typename I, typename P>
inline
void construct_copy_dispatch(I pos, P const& p,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type V;
new (static_cast<void*>(boost::addressof(*pos))) V(p); // may throw
}
template <typename DisableTrivialInit, typename I, typename P>
inline
void construct(DisableTrivialInit const&,
I pos, P const& p)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, P>,
::boost::has_trivial_copy<P>
>::type
use_memcpy;
construct_copy_dispatch(pos, p, use_memcpy()); // may throw
}
// Needed by push_back(V &&)
template <typename I, typename V>
inline
void construct_move_dispatch(I pos, V const& v,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
}
template <typename I, typename P>
inline
void construct_move_dispatch(I pos, BOOST_RV_REF(P) p,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
typedef typename boost::iterator_value<I>::type V;
new (static_cast<void*>(boost::addressof(*pos))) V(::boost::move(p)); // may throw
}
template <typename DisableTrivialInit, typename I, typename P>
inline
void construct(DisableTrivialInit const&, I pos, BOOST_RV_REF(P) p)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, P>,
::boost::has_trivial_move_constructor<P>
>::type
use_memcpy;
construct_move_dispatch(pos, ::boost::move(p), use_memcpy()); // may throw
}
// Needed by emplace_back() and emplace()
#if !defined(BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE)
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <typename DisableTrivialInit, typename I, class ...Args>
inline
void construct(DisableTrivialInit const&,
I pos,
BOOST_FWD_REF(Args) ...args)
{
typedef typename boost::iterator_value<I>::type V;
new (static_cast<void*>(boost::addressof(*pos))) V(::boost::forward<Args>(args)...); // may throw
}
#else // !BOOST_NO_CXX11_VARIADIC_TEMPLATES
// BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 const& p0
// !BOOST_NO_CXX11_RVALUE_REFERENCES -> P0 && p0
// which means that version with one parameter may take V const& v
#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_CONSTRUCT(N) \
template <typename DisableTrivialInit, typename I, typename P BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
inline \
void construct(DisableTrivialInit const&, \
I pos, \
BOOST_FWD_REF(P) p \
BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \
{ \
typedef typename boost::iterator_value<I>::type V; \
new \
(static_cast<void*>(boost::addressof(*pos))) \
V(boost::forward<P>(p) BOOST_MOVE_I##N BOOST_MOVE_FWD##N); /*may throw*/ \
} \
BOOST_MOVE_ITERATE_1TO9(BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_CONSTRUCT)
#undef BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_CONSTRUCT
#endif // !BOOST_NO_CXX11_VARIADIC_TEMPLATES
#endif // !BOOST_CONTAINER_VARRAY_DISABLE_EMPLACE
// assign(I, V)
template <typename I, typename V>
inline
void assign_copy_dispatch(I pos, V const& v,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
// TODO - use memmove here?
::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
}
template <typename I, typename V>
inline
void assign_copy_dispatch(I pos, V const& v,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
*pos = v; // may throw
}
template <typename I, typename V>
inline
void assign(I pos, V const& v)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, V>,
::boost::has_trivial_assign<V>
>::type
use_memcpy;
assign_copy_dispatch(pos, v, use_memcpy()); // may throw
}
template <typename I, typename V>
inline
void assign_move_dispatch(I pos, V const& v,
boost::mpl::bool_<true> const& /*use_memcpy*/)
{
// TODO - use memmove here?
::memcpy(boost::addressof(*pos), boost::addressof(v), sizeof(V));
}
template <typename I, typename V>
inline
void assign_move_dispatch(I pos, BOOST_RV_REF(V) v,
boost::mpl::bool_<false> const& /*use_memcpy*/)
{
*pos = boost::move(v); // may throw
}
template <typename I, typename V>
inline
void assign(I pos, BOOST_RV_REF(V) v)
{
typedef typename
::boost::mpl::and_<
is_corresponding_value<I, V>,
::boost::has_trivial_move_assign<V>
>::type
use_memcpy;
assign_move_dispatch(pos, ::boost::move(v), use_memcpy());
}
// uninitialized_copy_s
template <typename I, typename F>
inline std::size_t uninitialized_copy_s(I first, I last, F dest, std::size_t max_count)
{
std::size_t count = 0;
F it = dest;
BOOST_TRY
{
for ( ; first != last ; ++it, ++first, ++count )
{
if ( max_count <= count )
return (std::numeric_limits<std::size_t>::max)();
// dummy 0 as DisableTrivialInit
construct(0, it, *first); // may throw
}
}
BOOST_CATCH(...)
{
destroy(dest, it);
BOOST_RETHROW;
}
BOOST_CATCH_END
return count;
}
// scoped_destructor
template<class T>
class scoped_destructor
{
public:
scoped_destructor(T * ptr) : m_ptr(ptr) {}
~scoped_destructor()
{
if(m_ptr)
destroy(m_ptr);
}
void release() { m_ptr = 0; }
private:
T * m_ptr;
};
}}}}} // namespace boost::geometry::index::detail::varray_detail
#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_DETAIL_HPP
@@ -0,0 +1,204 @@
// Boost.Geometry Index
//
// Spatial index distance predicates, calculators and checkers used in nearest neighbor query
//
// 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_DISTANCE_PREDICATES_HPP
#define BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP
#include <boost/geometry/index/detail/distance_predicates.hpp>
/*!
\defgroup nearest_relations Nearest relations (boost::geometry::index::)
*/
namespace boost { namespace geometry { namespace index {
// relations generators
#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
/*!
\brief Generate to_nearest() relationship.
Generate a nearest query Point and Value's Indexable relationship while calculating
distances. This function may be used to define that knn query should calculate distances
as smallest as possible between query Point and Indexable's points. In other words it
should be the distance to the nearest Indexable's point. This function may be also used
to define distances bounds which indicates that Indexable's nearest point should be
closer or further than value v. This is default relation.
\ingroup nearest_relations
\tparam T Type of wrapped object. This may be a Point for PointRelation or CoordinateType for
MinRelation or MaxRelation
\param v Point or distance value.
*/
template <typename T>
detail::to_nearest<T> to_nearest(T const& v)
{
return detail::to_nearest<T>(v);
}
/*!
\brief Generate to_centroid() relationship.
Generate a nearest query Point and Value's Indexable relationship while calculating
distances. This function may be used to define that knn query should calculate distances
between query Point and Indexable's centroid. This function may be also used
to define distances bounds which indicates that Indexable's centroid should be
closer or further than value v.
\ingroup nearest_relations
\tparam T Type of wrapped object. This may be a Point for PointRelation or some CoordinateType for
MinRelation or MaxRelation
\param v Point or distance value.
*/
template <typename T>
detail::to_centroid<T> to_centroid(T const& v)
{
return detail::to_centroid<T>(v);
}
/*!
\brief Generate to_furthest() relationship.
Generate a nearest query Point and Value's Indexable relationship while calculating
distances. This function may be used to define that knn query should calculate distances
as biggest as possible between query Point and Indexable's points. In other words it
should be the distance to the furthest Indexable's point. This function may be also used
to define distances bounds which indicates that Indexable's furthest point should be
closer or further than value v.
\ingroup nearest_relations
\tparam T Type of wrapped object. This may be a Point for PointRelation or some CoordinateType for
MinRelation or MaxRelation
\param v Point or distance value.
*/
template <typename T>
detail::to_furthest<T> to_furthest(T const& v)
{
return detail::to_furthest<T>(v);
}
#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
// distance predicates generators
/*!
\brief Generate unbounded() distance predicate.
Generate a distance predicate. This defines distances bounds which are used by knn query.
This function indicates that there is no distance bounds and Values should be returned
if distances between Point and Indexable are the smallest. Distance calculation is defined
by PointRelation. This is default nearest predicate.
\ingroup distance_predicates
\tparam PointRelation PointRelation type.
\param pr The point relation. This may be generated by \c index::to_nearest(),
\c index::to_centroid() or \c index::to_furthest() with \c Point passed as a parameter.
*/
//template <typename PointRelation>
//inline detail::unbounded<PointRelation>
//unbounded(PointRelation const& pr)
//{
// return detail::unbounded<PointRelation>(pr);
//}
/*!
\brief Generate min_bounded() distance predicate.
Generate a distance predicate. This defines distances bounds which are used by knn query.
This function indicates that Values should be returned only if distances between Point and
Indexable are greater or equal to some min_distance passed in MinRelation. Check for closest Value is
defined by PointRelation. So it is possible e.g. to return Values with centroids closest to some
Point but only if nearest points are further than some distance.
\ingroup distance_predicates
\tparam PointRelation PointRelation type.
\tparam MinRelation MinRelation type.
\param pr The point relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with \c Point passed as a parameter.
\param minr The minimum bound relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with distance value passed as a parameter.
*/
//template <typename PointRelation, typename MinRelation>
//inline detail::min_bounded<PointRelation, MinRelation>
//min_bounded(PointRelation const& pr, MinRelation const& minr)
//{
// return detail::min_bounded<PointRelation, MinRelation>(pr, minr);
//}
/*!
\brief Generate max_bounded() distance predicate.
Generate a distance predicate. This defines distances bounds which are used by knn query.
This function indicates that Values should be returned only if distances between Point and
Indexable are lesser or equal to some max_distance passed in MaxRelation. Check for closest Value is
defined by PointRelation. So it is possible e.g. to return Values with centroids closest to some
Point but only if nearest points are closer than some distance.
\ingroup distance_predicates
\tparam PointRelation PointRelation type.
\tparam MaxRelation MaxRelation type.
\param pr The point relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with \c Point passed as a parameter.
\param maxr The maximum bound relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with distance value passed as a parameter.
*/
//template <typename PointRelation, typename MaxRelation>
//inline detail::max_bounded<PointRelation, MaxRelation>
//max_bounded(PointRelation const& pr, MaxRelation const& maxr)
//{
// return detail::max_bounded<PointRelation, MaxRelation>(pr, maxr);
//}
/*!
\brief Generate bounded() distance predicate.
Generate a distance predicate. This defines distances bounds which are used by knn query.
This function indicates that Values should be returned only if distances between Point and
Indexable are greater or equal to some min_distance passed in MinRelation and lesser or equal to
some max_distance passed in MaxRelation. Check for closest Value is defined by PointRelation.
So it is possible e.g. to return Values with centroids closest to some Point but only if nearest
points are further than some distance and closer than some other distance.
\ingroup distance_predicates
\tparam PointRelation PointRelation type.
\tparam MinRelation MinRelation type.
\tparam MaxRelation MaxRelation type.
\param pr The point relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with \c Point passed as a parameter.
\param minr The minimum bound relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with distance value passed as a parameter.
\param maxr The maximum bound relation. This may be generated by \c to_nearest(),
\c to_centroid() or \c to_furthest() with distance value passed as a parameter.
*/
//template <typename PointRelation, typename MinRelation, typename MaxRelation>
//inline detail::bounded<PointRelation, MinRelation, MaxRelation>
//bounded(PointRelation const& pr, MinRelation const& minr, MaxRelation const& maxr)
//{
// return detail::bounded<PointRelation, MinRelation, MaxRelation>(pr, minr, maxr);
//}
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP
@@ -0,0 +1,267 @@
// Boost.Geometry Index
//
// Copyright (c) 2011-2016 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_EQUAL_TO_HPP
#define BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/index/indexable.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename Geometry,
typename Tag = typename geometry::tag<Geometry>::type>
struct equals
{
inline static bool apply(Geometry const& g1, Geometry const& g2)
{
return geometry::equals(g1, g2);
}
};
template <typename Geometry, typename Tag>
struct equals<Geometry *, Tag>
{
inline static bool apply(const Geometry * g1, const Geometry * g2)
{
return g1 == g2;
}
};
template <typename T>
struct equals<T, void>
{
inline static bool apply(T const& v1, T const& v2)
{
return v1 == v2;
}
};
template <typename T>
struct equals<T *, void>
{
inline static bool apply(const T * v1, const T * v2)
{
return v1 == v2;
}
};
template <typename Tuple, size_t I, size_t N>
struct tuple_equals
{
inline static bool apply(Tuple const& t1, Tuple const& t2)
{
typedef typename boost::tuples::element<I, Tuple>::type T;
return equals<T>::apply(boost::get<I>(t1), boost::get<I>(t2))
&& tuple_equals<Tuple, I+1, N>::apply(t1, t2);
}
};
template <typename Tuple, size_t I>
struct tuple_equals<Tuple, I, I>
{
inline static bool apply(Tuple const&, Tuple const&)
{
return true;
}
};
// TODO: Consider this: Since equal_to<> is using geometry::equals() it's possible that
// two compared Indexables are not exactly the same! They will be spatially equal
// but not strictly equal. Consider 2 Segments with reversed order of points.
// Therefore it's possible that during the Value removal different value will be
// removed than the one that was passed.
/*!
\brief The function object comparing Values.
It compares Geometries using geometry::equals() function. Other types are compared using operator==.
The default version handles Values which are Indexables.
This template is also specialized for std::pair<T1, T2> and boost::tuple<...>.
\tparam Value The type of objects which are compared by this function object.
\tparam IsIndexable If true, Values are compared using boost::geometry::equals() functions.
*/
template <typename Value,
bool IsIndexable = is_indexable<Value>::value>
struct equal_to
{
/*! \brief The type of result returned by function object. */
typedef bool result_type;
/*!
\brief Compare values. If Value is a Geometry geometry::equals() function is used.
\param l First value.
\param r Second value.
\return true if values are equal.
*/
inline bool operator()(Value const& l, Value const& r) const
{
return detail::equals<Value>::apply(l ,r);
}
};
/*!
\brief The function object comparing Values.
This specialization compares values of type std::pair<T1, T2>.
It compares pairs' first values, then second values.
\tparam T1 The first type.
\tparam T2 The second type.
*/
template <typename T1, typename T2>
struct equal_to<std::pair<T1, T2>, false>
{
/*! \brief The type of result returned by function object. */
typedef bool result_type;
/*!
\brief Compare values. If pair<> Value member is a Geometry geometry::equals() function is used.
\param l First value.
\param r Second value.
\return true if values are equal.
*/
inline bool operator()(std::pair<T1, T2> const& l, std::pair<T1, T2> const& r) const
{
return detail::equals<T1>::apply(l.first, r.first)
&& detail::equals<T2>::apply(l.second, r.second);
}
};
/*!
\brief The function object comparing Values.
This specialization compares values of type boost::tuple<...>.
It compares all members of the tuple from the first one to the last one.
*/
template <typename T0, typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8, typename T9>
struct equal_to<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, false>
{
typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> value_type;
/*! \brief The type of result returned by function object. */
typedef bool result_type;
/*!
\brief Compare values. If tuple<> Value member is a Geometry geometry::equals() function is used.
\param l First value.
\param r Second value.
\return true if values are equal.
*/
inline bool operator()(value_type const& l, value_type const& r) const
{
return detail::tuple_equals<
value_type, 0, boost::tuples::length<value_type>::value
>::apply(l ,r);
}
};
}}}} // namespace boost::geometry::index::detail
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <tuple>
namespace boost { namespace geometry { namespace index { namespace detail {
template <typename Tuple, size_t I, size_t N>
struct std_tuple_equals
{
inline static bool apply(Tuple const& t1, Tuple const& t2)
{
typedef typename std::tuple_element<I, Tuple>::type T;
return equals<T>::apply(std::get<I>(t1), std::get<I>(t2))
&& std_tuple_equals<Tuple, I+1, N>::apply(t1, t2);
}
};
template <typename Tuple, size_t I>
struct std_tuple_equals<Tuple, I, I>
{
inline static bool apply(Tuple const&, Tuple const&)
{
return true;
}
};
/*!
\brief The function object comparing Values.
This specialization compares values of type std::tuple<Args...>.
It's defined if the compiler supports tuples and variadic templates.
It compares all members of the tuple from the first one to the last one.
*/
template <typename ...Args>
struct equal_to<std::tuple<Args...>, false>
{
typedef std::tuple<Args...> value_type;
/*! \brief The type of result returned by function object. */
typedef bool result_type;
/*!
\brief Compare values. If tuple<> Value member is a Geometry geometry::equals() function is used.
\param l First value.
\param r Second value.
\return true if values are equal.
*/
bool operator()(value_type const& l, value_type const& r) const
{
return detail::std_tuple_equals<
value_type, 0, std::tuple_size<value_type>::value
>::apply(l ,r);
}
};
}}}} // namespace boost::geometry::index::detail
#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
namespace boost { namespace geometry { namespace index {
/*!
\brief The function object comparing Values.
The default version handles Values which are Indexables, std::pair<T1, T2>, boost::tuple<...>
and std::tuple<...> if STD tuples and variadic templates are supported.
All members are compared from left to right, Geometries using boost::geometry::equals() function,
other types using operator==.
\tparam Value The type of objects which are compared by this function object.
*/
template <typename Value>
struct equal_to
: detail::equal_to<Value>
{
/*! \brief The type of result returned by function object. */
typedef typename detail::equal_to<Value>::result_type result_type;
/*!
\brief Compare Values.
\param l First value.
\param r Second value.
\return true if Values are equal.
*/
inline bool operator()(Value const& l, Value const& r) const
{
return detail::equal_to<Value>::operator()(l ,r);
}
};
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP
@@ -0,0 +1,196 @@
// Boost.Geometry Index
//
// 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_INDEXABLE_HPP
#define BOOST_GEOMETRY_INDEX_INDEXABLE_HPP
#include <boost/mpl/assert.hpp>
#include <boost/geometry/index/detail/is_indexable.hpp>
namespace boost { namespace geometry { namespace index { namespace detail {
/*!
\brief The function object extracting Indexable from Value.
It translates Value object to Indexable object. The default version handles Values which are Indexables.
This template is also specialized for std::pair<Indexable, T2>, boost::tuple<Indexable, ...>
and std::tuple<Indexable, ...>.
\tparam Value The Value type which may be translated directly to the Indexable.
\tparam IsIndexable If true, the const reference to Value is returned.
*/
template <typename Value, bool IsIndexable = is_indexable<Value>::value>
struct indexable
{
BOOST_MPL_ASSERT_MSG(
(detail::is_indexable<Value>::value),
NOT_VALID_INDEXABLE_TYPE,
(Value)
);
/*! \brief The type of result returned by function object. */
typedef Value const& result_type;
/*!
\brief Return indexable extracted from the value.
\param v The value.
\return The indexable.
*/
inline result_type operator()(Value const& v) const
{
return v;
}
};
/*!
\brief The function object extracting Indexable from Value.
This specialization translates from std::pair<Indexable, T2>.
\tparam Indexable The Indexable type.
\tparam T2 The second type.
*/
template <typename Indexable, typename T2>
struct indexable<std::pair<Indexable, T2>, false>
{
BOOST_MPL_ASSERT_MSG(
(detail::is_indexable<Indexable>::value),
NOT_VALID_INDEXABLE_TYPE,
(Indexable)
);
/*! \brief The type of result returned by function object. */
typedef Indexable const& result_type;
/*!
\brief Return indexable extracted from the value.
\param v The value.
\return The indexable.
*/
inline result_type operator()(std::pair<Indexable, T2> const& v) const
{
return v.first;
}
};
/*!
\brief The function object extracting Indexable from Value.
This specialization translates from boost::tuple<Indexable, ...>.
\tparam Indexable The Indexable type.
*/
template <typename Indexable, typename T1, typename T2, typename T3, typename T4,
typename T5, typename T6, typename T7, typename T8, typename T9>
struct indexable<boost::tuple<Indexable, T1, T2, T3, T4, T5, T6, T7, T8, T9>, false>
{
typedef boost::tuple<Indexable, T1, T2, T3, T4, T5, T6, T7, T8, T9> value_type;
BOOST_MPL_ASSERT_MSG(
(detail::is_indexable<Indexable>::value),
NOT_VALID_INDEXABLE_TYPE,
(Indexable)
);
/*! \brief The type of result returned by function object. */
typedef Indexable const& result_type;
/*!
\brief Return indexable extracted from the value.
\param v The value.
\return The indexable.
*/
inline result_type operator()(value_type const& v) const
{
return boost::get<0>(v);
}
};
}}}} // namespace boost::geometry::index::detail
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <tuple>
namespace boost { namespace geometry { namespace index { namespace detail {
/*!
\brief The function object extracting Indexable from Value.
This specialization translates from std::tuple<Indexable, Args...>.
It's defined if the compiler supports tuples and variadic templates.
\tparam Indexable The Indexable type.
*/
template <typename Indexable, typename ...Args>
struct indexable<std::tuple<Indexable, Args...>, false>
{
typedef std::tuple<Indexable, Args...> value_type;
BOOST_MPL_ASSERT_MSG(
(detail::is_indexable<Indexable>::value),
NOT_VALID_INDEXABLE_TYPE,
(Indexable)
);
/*! \brief The type of result returned by function object. */
typedef Indexable const& result_type;
/*!
\brief Return indexable extracted from the value.
\param v The value.
\return The indexable.
*/
result_type operator()(value_type const& v) const
{
return std::get<0>(v);
}
};
}}}} // namespace boost::geometry::index::detail
#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
namespace boost { namespace geometry { namespace index {
/*!
\brief The function object extracting Indexable from Value.
It translates Value object to Indexable object. By default, it can handle Values which are Indexables,
std::pair<Indexable, T2>, boost::tuple<Indexable, ...> and std::tuple<Indexable, ...> if STD tuples
and variadic templates are supported.
\tparam Value The Value type which may be translated directly to the Indexable.
*/
template <typename Value>
struct indexable
: detail::indexable<Value>
{
/*! \brief The type of result returned by function object. It should be const Indexable reference. */
typedef typename detail::indexable<Value>::result_type result_type;
/*!
\brief Return indexable extracted from the value.
\param v The value.
\return The indexable.
*/
inline result_type operator()(Value const& v) const
{
return detail::indexable<Value>::operator()(v);
}
};
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_INDEXABLE_HPP
@@ -0,0 +1,78 @@
// Boost.Geometry Index
//
// Insert iterator
//
// 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_INSERTER_HPP
#define BOOST_GEOMETRY_INDEX_INSERTER_HPP
#include <iterator>
/*!
\defgroup inserters Inserters (boost::geometry::index::)
*/
namespace boost { namespace geometry { namespace index {
template <class Container>
class insert_iterator :
public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
typedef Container container_type;
inline explicit insert_iterator(Container & c)
: container(&c)
{}
insert_iterator & operator=(typename Container::value_type const& value)
{
container->insert(value);
return *this;
}
insert_iterator & operator* ()
{
return *this;
}
insert_iterator & operator++ ()
{
return *this;
}
insert_iterator operator++(int)
{
return *this;
}
private:
Container * container;
};
/*!
\brief Insert iterator generator.
Returns insert iterator capable to insert values to the container
(spatial index) which has member function insert(value_type const&) defined.
\ingroup inserters
\param c The reference to the container (spatial index) to which values will be inserted.
\return The insert iterator inserting values to the container.
*/
template <typename Container>
insert_iterator<Container> inserter(Container & c)
{
return insert_iterator<Container>(c);
}
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_INSERTER_HPP
@@ -0,0 +1,258 @@
// Boost.Geometry Index
//
// R-tree algorithms parameters
//
// 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_PARAMETERS_HPP
#define BOOST_GEOMETRY_INDEX_PARAMETERS_HPP
#include <limits>
#include <boost/mpl/assert.hpp>
#include <boost/geometry/index/detail/exception.hpp>
namespace boost { namespace geometry { namespace index {
namespace detail {
template <size_t MaxElements>
struct default_min_elements_s
{
static const size_t raw_value = (MaxElements * 3) / 10;
static const size_t value = 1 <= raw_value ? raw_value : 1;
};
inline size_t default_min_elements_d()
{
return (std::numeric_limits<size_t>::max)();
}
inline size_t default_min_elements_d_calc(size_t max_elements, size_t min_elements)
{
if ( default_min_elements_d() == min_elements )
{
size_t raw_value = (max_elements * 3) / 10;
return 1 <= raw_value ? raw_value : 1;
}
return min_elements;
}
template <size_t MaxElements>
struct default_rstar_reinserted_elements_s
{
static const size_t value = (MaxElements * 3) / 10;
};
inline size_t default_rstar_reinserted_elements_d()
{
return (std::numeric_limits<size_t>::max)();
}
inline size_t default_rstar_reinserted_elements_d_calc(size_t max_elements, size_t reinserted_elements)
{
if ( default_rstar_reinserted_elements_d() == reinserted_elements )
{
return (max_elements * 3) / 10;
}
return reinserted_elements;
}
} // namespace detail
/*!
\brief Linear r-tree creation algorithm parameters.
\tparam MaxElements Maximum number of elements in nodes.
\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max.
*/
template <size_t MaxElements,
size_t MinElements = detail::default_min_elements_s<MaxElements>::value>
struct linear
{
BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1),
INVALID_STATIC_MIN_MAX_PARAMETERS, (linear));
static const size_t max_elements = MaxElements;
static const size_t min_elements = MinElements;
static size_t get_max_elements() { return MaxElements; }
static size_t get_min_elements() { return MinElements; }
};
/*!
\brief Quadratic r-tree creation algorithm parameters.
\tparam MaxElements Maximum number of elements in nodes.
\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max.
*/
template <size_t MaxElements,
size_t MinElements = detail::default_min_elements_s<MaxElements>::value>
struct quadratic
{
BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1),
INVALID_STATIC_MIN_MAX_PARAMETERS, (quadratic));
static const size_t max_elements = MaxElements;
static const size_t min_elements = MinElements;
static size_t get_max_elements() { return MaxElements; }
static size_t get_min_elements() { return MinElements; }
};
/*!
\brief R*-tree creation algorithm parameters.
\tparam MaxElements Maximum number of elements in nodes.
\tparam MinElements Minimum number of elements in nodes. Default: 0.3*Max.
\tparam ReinsertedElements The number of elements reinserted by forced reinsertions algorithm.
If 0 forced reinsertions are disabled. Maximum value is Max+1-Min.
Greater values are truncated. Default: 0.3*Max.
\tparam OverlapCostThreshold The number of most suitable leafs taken into account while choosing
the leaf node to which currently inserted value will be added. If
value is in range (0, MaxElements) - the algorithm calculates
nearly minimum overlap cost, otherwise all leafs are analyzed
and true minimum overlap cost is calculated. Default: 32.
*/
template <size_t MaxElements,
size_t MinElements = detail::default_min_elements_s<MaxElements>::value,
size_t ReinsertedElements = detail::default_rstar_reinserted_elements_s<MaxElements>::value,
size_t OverlapCostThreshold = 32>
struct rstar
{
BOOST_MPL_ASSERT_MSG((0 < MinElements && 2*MinElements <= MaxElements+1),
INVALID_STATIC_MIN_MAX_PARAMETERS, (rstar));
static const size_t max_elements = MaxElements;
static const size_t min_elements = MinElements;
static const size_t reinserted_elements = ReinsertedElements;
static const size_t overlap_cost_threshold = OverlapCostThreshold;
static size_t get_max_elements() { return MaxElements; }
static size_t get_min_elements() { return MinElements; }
static size_t get_reinserted_elements() { return ReinsertedElements; }
static size_t get_overlap_cost_threshold() { return OverlapCostThreshold; }
};
//template <size_t MaxElements, size_t MinElements>
//struct kmeans
//{
// static const size_t max_elements = MaxElements;
// static const size_t min_elements = MinElements;
//};
/*!
\brief Linear r-tree creation algorithm parameters - run-time version.
*/
class dynamic_linear
{
public:
/*!
\brief The constructor.
\param max_elements Maximum number of elements in nodes.
\param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
*/
explicit dynamic_linear(size_t max_elements,
size_t min_elements = detail::default_min_elements_d())
: m_max_elements(max_elements)
, m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
{
if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1))
detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_linear");
}
size_t get_max_elements() const { return m_max_elements; }
size_t get_min_elements() const { return m_min_elements; }
private:
size_t m_max_elements;
size_t m_min_elements;
};
/*!
\brief Quadratic r-tree creation algorithm parameters - run-time version.
*/
class dynamic_quadratic
{
public:
/*!
\brief The constructor.
\param max_elements Maximum number of elements in nodes.
\param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
*/
explicit dynamic_quadratic(size_t max_elements,
size_t min_elements = detail::default_min_elements_d())
: m_max_elements(max_elements)
, m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
{
if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1))
detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_quadratic");
}
size_t get_max_elements() const { return m_max_elements; }
size_t get_min_elements() const { return m_min_elements; }
private:
size_t m_max_elements;
size_t m_min_elements;
};
/*!
\brief R*-tree creation algorithm parameters - run-time version.
*/
class dynamic_rstar
{
public:
/*!
\brief The constructor.
\param max_elements Maximum number of elements in nodes.
\param min_elements Minimum number of elements in nodes. Default: 0.3*Max.
\param reinserted_elements The number of elements reinserted by forced reinsertions algorithm.
If 0 forced reinsertions are disabled. Maximum value is Max-Min+1.
Greater values are truncated. Default: 0.3*Max.
\param overlap_cost_threshold The number of most suitable leafs taken into account while choosing
the leaf node to which currently inserted value will be added. If
value is in range (0, MaxElements) - the algorithm calculates
nearly minimum overlap cost, otherwise all leafs are analyzed
and true minimum overlap cost is calculated. Default: 32.
*/
explicit dynamic_rstar(size_t max_elements,
size_t min_elements = detail::default_min_elements_d(),
size_t reinserted_elements = detail::default_rstar_reinserted_elements_d(),
size_t overlap_cost_threshold = 32)
: m_max_elements(max_elements)
, m_min_elements(detail::default_min_elements_d_calc(max_elements, min_elements))
, m_reinserted_elements(detail::default_rstar_reinserted_elements_d_calc(max_elements, reinserted_elements))
, m_overlap_cost_threshold(overlap_cost_threshold)
{
if (!(0 < m_min_elements && 2*m_min_elements <= m_max_elements+1))
detail::throw_invalid_argument("invalid min or/and max parameters of dynamic_rstar");
}
size_t get_max_elements() const { return m_max_elements; }
size_t get_min_elements() const { return m_min_elements; }
size_t get_reinserted_elements() const { return m_reinserted_elements; }
size_t get_overlap_cost_threshold() const { return m_overlap_cost_threshold; }
private:
size_t m_max_elements;
size_t m_min_elements;
size_t m_reinserted_elements;
size_t m_overlap_cost_threshold;
};
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_PARAMETERS_HPP
@@ -0,0 +1,421 @@
// Boost.Geometry Index
//
// Spatial query predicates
//
// 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_PREDICATES_HPP
#define BOOST_GEOMETRY_INDEX_PREDICATES_HPP
#include <boost/geometry/index/detail/predicates.hpp>
#include <boost/geometry/index/detail/tuples.hpp>
/*!
\defgroup predicates Predicates (boost::geometry::index::)
*/
namespace boost { namespace geometry { namespace index {
/*!
\brief Generate \c contains() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::within(Geometry, Indexable)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::contains(box), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::contains_tag, false>
contains(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::contains_tag,
false
>(g);
}
/*!
\brief Generate \c covered_by() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::covered_by(Indexable, Geometry)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::covered_by(box), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::covered_by_tag, false>
covered_by(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::covered_by_tag,
false
>(g);
}
/*!
\brief Generate \c covers() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::covered_by(Geometry, Indexable)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::covers(box), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::covers_tag, false>
covers(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::covers_tag,
false
>(g);
}
/*!
\brief Generate \c disjoint() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::disjoint(Indexable, Geometry)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::disjoint(box), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::disjoint_tag, false>
disjoint(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::disjoint_tag,
false
>(g);
}
/*!
\brief Generate \c intersects() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::intersects(Indexable, Geometry)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::intersects(box), std::back_inserter(result));
bgi::query(spatial_index, bgi::intersects(ring), std::back_inserter(result));
bgi::query(spatial_index, bgi::intersects(polygon), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::intersects_tag, false>
intersects(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::intersects_tag,
false
>(g);
}
/*!
\brief Generate \c overlaps() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::overlaps(Indexable, Geometry)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::overlaps(box), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::overlaps_tag, false>
overlaps(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::overlaps_tag,
false
>(g);
}
#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
/*!
\brief Generate \c touches() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::touches(Indexable, Geometry)</tt>
returns true.
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::touches_tag, false>
touches(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::touches_tag,
false
>(g);
}
#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
/*!
\brief Generate \c within() predicate.
Generate a predicate defining Value and Geometry relationship.
Value will be returned by the query if <tt>bg::within(Indexable, Geometry)</tt>
returns true.
\par Example
\verbatim
bgi::query(spatial_index, bgi::within(box), std::back_inserter(result));
\endverbatim
\ingroup predicates
\tparam Geometry The Geometry type.
\param g The Geometry object.
*/
template <typename Geometry> inline
detail::predicates::spatial_predicate<Geometry, detail::predicates::within_tag, false>
within(Geometry const& g)
{
return detail::predicates::spatial_predicate
<
Geometry,
detail::predicates::within_tag,
false
>(g);
}
/*!
\brief Generate satisfies() predicate.
A wrapper around user-defined UnaryPredicate checking if Value should be returned by spatial query.
\par Example
\verbatim
bool is_red(Value const& v) { return v.is_red(); }
struct is_red_o {
template <typename Value> bool operator()(Value const& v) { return v.is_red(); }
}
// ...
rt.query(index::intersects(box) && index::satisfies(is_red),
std::back_inserter(result));
rt.query(index::intersects(box) && index::satisfies(is_red_o()),
std::back_inserter(result));
#ifndef BOOST_NO_CXX11_LAMBDAS
rt.query(index::intersects(box) && index::satisfies([](Value const& v) { return v.is_red(); }),
std::back_inserter(result));
#endif
\endverbatim
\ingroup predicates
\tparam UnaryPredicate A type of unary predicate function or function object.
\param pred The unary predicate function or function object.
*/
template <typename UnaryPredicate> inline
detail::predicates::satisfies<UnaryPredicate, false>
satisfies(UnaryPredicate const& pred)
{
return detail::predicates::satisfies<UnaryPredicate, false>(pred);
}
/*!
\brief Generate nearest() predicate.
When nearest predicate is passed to the query, k-nearest neighbour search will be performed.
\c nearest() predicate takes a \c Geometry from which distances to \c Values are calculated
and the maximum number of \c Values that should be returned. Internally
boost::geometry::comparable_distance() is used to perform the calculation.
\par Example
\verbatim
bgi::query(spatial_index, bgi::nearest(pt, 5), std::back_inserter(result));
bgi::query(spatial_index, bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result));
bgi::query(spatial_index, bgi::nearest(box, 5), std::back_inserter(result));
\endverbatim
\warning
Only one \c nearest() predicate may be used in a query.
\ingroup predicates
\param geometry The geometry from which distance is calculated.
\param k The maximum number of values to return.
*/
template <typename Geometry> inline
detail::predicates::nearest<Geometry>
nearest(Geometry const& geometry, unsigned k)
{
return detail::predicates::nearest<Geometry>(geometry, k);
}
#ifdef BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
/*!
\brief Generate path() predicate.
When path predicate is passed to the query, the returned values are k values along the path closest to
its begin. \c path() predicate takes a \c Segment or a \c Linestring defining the path and the maximum
number of \c Values that should be returned.
\par Example
\verbatim
bgi::query(spatial_index, bgi::path(segment, 5), std::back_inserter(result));
bgi::query(spatial_index, bgi::path(linestring, 5) && bgi::intersects(box), std::back_inserter(result));
\endverbatim
\warning
Only one distance predicate (\c nearest() or \c path()) may be used in a query.
\ingroup predicates
\param linestring The path along which distance is calculated.
\param k The maximum number of values to return.
*/
template <typename SegmentOrLinestring> inline
detail::predicates::path<SegmentOrLinestring>
path(SegmentOrLinestring const& linestring, unsigned k)
{
return detail::predicates::path<SegmentOrLinestring>(linestring, k);
}
#endif // BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL
namespace detail { namespace predicates {
// operator! generators
template <typename Fun, bool Negated> inline
satisfies<Fun, !Negated>
operator!(satisfies<Fun, Negated> const& p)
{
return satisfies<Fun, !Negated>(p);
}
template <typename Geometry, typename Tag, bool Negated> inline
spatial_predicate<Geometry, Tag, !Negated>
operator!(spatial_predicate<Geometry, Tag, Negated> const& p)
{
return spatial_predicate<Geometry, Tag, !Negated>(p.geometry);
}
// operator&& generators
template <typename Pred1, typename Pred2> inline
boost::tuples::cons<
Pred1,
boost::tuples::cons<Pred2, boost::tuples::null_type>
>
operator&&(Pred1 const& p1, Pred2 const& p2)
{
/*typedef typename boost::mpl::if_c<is_predicate<Pred1>::value, Pred1, Pred1 const&>::type stored1;
typedef typename boost::mpl::if_c<is_predicate<Pred2>::value, Pred2, Pred2 const&>::type stored2;*/
namespace bt = boost::tuples;
return
bt::cons< Pred1, bt::cons<Pred2, bt::null_type> >
( p1, bt::cons<Pred2, bt::null_type>(p2, bt::null_type()) );
}
template <typename Head, typename Tail, typename Pred> inline
typename tuples::push_back<
boost::tuples::cons<Head, Tail>, Pred
>::type
operator&&(boost::tuples::cons<Head, Tail> const& t, Pred const& p)
{
//typedef typename boost::mpl::if_c<is_predicate<Pred>::value, Pred, Pred const&>::type stored;
namespace bt = boost::tuples;
return
tuples::push_back<
bt::cons<Head, Tail>, Pred
>::apply(t, p);
}
}} // namespace detail::predicates
}}} // namespace boost::geometry::index
#endif // BOOST_GEOMETRY_INDEX_PREDICATES_HPP
File diff suppressed because it is too large Load Diff