diff --git a/include/boost/geometry/index/adaptors/query.hpp b/include/boost/geometry/index/adaptors/query.hpp new file mode 100644 index 000000000..472b3693b --- /dev/null +++ b/include/boost/geometry/index/adaptors/query.hpp @@ -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 +class query_range +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEX, + (query_range)); + + typedef int* iterator; + typedef const int* const_iterator; + + template + 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 +struct query +{ + inline explicit query(Predicates const& pred) + : predicates(pred) + {} + + Predicates const& predicates; +}; + +template +index::adaptors::detail::query_range +operator|( + Index const& si, + index::adaptors::detail::query const& f) +{ + return index::adaptors::detail::query_range(si, f.predicates); +} + +} // namespace detail + +/*! +\brief The query index adaptor generator. + +\ingroup adaptors + +\param pred Predicates. +*/ +template +detail::query +queried(Predicates const& pred) +{ + return detail::query(pred); +} + +} // namespace adaptors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_ADAPTORS_QUERY_HPP diff --git a/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp b/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp new file mode 100644 index 000000000..269a2c9c3 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/comparable_distance_centroid.hpp @@ -0,0 +1,77 @@ +// Boost.Geometry Index +// +// squared distance between point and centroid of the box or point +// +// 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_COMPARABLE_DISTANCE_CENTROID_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP + +#include +#include + +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 +{ + typedef typename geometry::default_distance_result::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 +{ + typedef typename geometry::default_distance_result::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i) + { + typedef typename index::detail::traits::coordinate_type::type point_coord_t; + typedef typename index::detail::traits::coordinate_type::type indexable_coord_t; + + point_coord_t pt_c = geometry::get(pt); + indexable_coord_t ind_c_min = geometry::get(i); + indexable_coord_t ind_c_max = geometry::get(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 geometry::default_distance_result::type +comparable_distance_centroid(Point const& pt, Indexable const& i) +{ + return detail::sum_for_indexable< + Point, + Indexable, + typename index::detail::traits::tag::type, + detail::comparable_distance_centroid_tag, + index::detail::traits::dimension::value + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // #define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_CENTROID_HPP + diff --git a/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp b/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp new file mode 100644 index 000000000..1646a82d6 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/comparable_distance_far.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry Index +// +// squared distance between point and furthest point of the box or point +// +// 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_COMPARABLE_DISTANCE_FAR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP + +#include +#include + +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 +{ + typedef typename geometry::default_distance_result::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i) + { + typedef typename index::detail::traits::coordinate_type::type point_coord_t; + typedef typename index::detail::traits::coordinate_type::type indexable_coord_t; + + point_coord_t pt_c = geometry::get(pt); + indexable_coord_t ind_c_min = geometry::get(i); + indexable_coord_t ind_c_max = geometry::get(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 geometry::default_distance_result::type +comparable_distance_far(Point const& pt, Indexable const& i) +{ + return detail::sum_for_indexable< + Point, + Indexable, + typename index::detail::traits::tag::type, + detail::comparable_distance_far_tag, + index::detail::traits::dimension::value + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_FAR_HPP diff --git a/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp b/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp new file mode 100644 index 000000000..221d3ee3f --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/comparable_distance_near.hpp @@ -0,0 +1,77 @@ +// Boost.Geometry Index +// +// squared distance between point and nearest point of the box or point +// +// 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_COMPARABLE_DISTANCE_NEAR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP + +#include + +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 +{ + typedef typename geometry::default_distance_result::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 +{ + typedef typename geometry::default_distance_result::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i) + { + typedef typename index::detail::traits::coordinate_type::type point_coord_t; + typedef typename index::detail::traits::coordinate_type::type indexable_coord_t; + + point_coord_t pt_c = geometry::get(pt); + indexable_coord_t ind_c_min = geometry::get(i); + indexable_coord_t ind_c_max = geometry::get(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 geometry::default_distance_result::type +comparable_distance_near(Point const& pt, Indexable const& i) +{ + return detail::sum_for_indexable< + Point, + Indexable, + typename index::detail::traits::tag::type, + detail::comparable_distance_near_tag, + index::detail::traits::dimension::value + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_COMPARABLE_DISTANCE_NEAR_HPP diff --git a/include/boost/geometry/index/detail/algorithms/content.hpp b/include/boost/geometry/index/detail/algorithms/content.hpp new file mode 100644 index 000000000..0677fe564 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/content.hpp @@ -0,0 +1,85 @@ +// Boost.Geometry Index +// +// n-dimensional box's content (hypervolume) - 2d area, 3d volume, ... +// +// 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_CONTENT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template +struct default_content_result +{ + typedef typename select_most_precise< + typename detail::traits::coordinate_type::type, + long double + >::type type; +}; + +namespace dispatch { + +template +struct content_for_each_dimension +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + BOOST_STATIC_ASSERT(CurrentDimension <= traits::dimension::value); + + static inline typename detail::default_content_result::type apply(Box const& b) + { + return content_for_each_dimension::apply(b) * + ( detail::get(b) - detail::get(b) ); + } +}; + +template +struct content_for_each_dimension +{ + static inline typename detail::default_content_result::type apply(Box const& b) + { + return detail::get(b) - detail::get(b); + } +}; + +template +struct content +{ + // TODO: awulkiew - static assert? +}; + +template +struct content +{ + static typename detail::default_content_result::type apply(Indexable const&) + { + return 0; + } +}; + +template +struct content +{ + static typename default_content_result::type apply(Indexable const& b) + { + return dispatch::content_for_each_dimension::value>::apply(b); + } +}; + +} // namespace dispatch + +template +typename default_content_result::type content(Indexable const& b) +{ + return dispatch::content::type + >::apply(b); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_CONTENT_HPP diff --git a/include/boost/geometry/index/detail/algorithms/diff_abs.hpp b/include/boost/geometry/index/detail/algorithms/diff_abs.hpp new file mode 100644 index 000000000..a89784d7f --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/diff_abs.hpp @@ -0,0 +1,24 @@ +// 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 +inline T diff_abs(T const& v1, T const& v2) +{ + return v1 < v2 ? v2 - v1 : v1 - v2; +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_DIFF_ABS_HPP diff --git a/include/boost/geometry/index/detail/algorithms/intersection_content.hpp b/include/boost/geometry/index/detail/algorithms/intersection_content.hpp new file mode 100644 index 000000000..955d6eb65 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/intersection_content.hpp @@ -0,0 +1,36 @@ +// Boost.Geometry Index +// +// boxes union/intersection area/volume +// +// 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_INTERSECTION_CONTENT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_INTERSECTION_CONTENT_HPP + +#include +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +/** + * \brief Compute the area of the intersection of b1 and b2 + */ +template +inline typename default_content_result::type intersection_content(Box const& box1, Box const& box2) +{ + if ( geometry::intersects(box1, box2) ) + { + Box box_intersection; + 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 diff --git a/include/boost/geometry/index/detail/algorithms/is_valid.hpp b/include/boost/geometry/index/detail/algorithms/is_valid.hpp new file mode 100644 index 000000000..327e629af --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/is_valid.hpp @@ -0,0 +1,79 @@ +// Boost.Geometry Index +// +// n-dimensional box's / point validity check +// +// 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_IS_VALID_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_IS_VALID_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace dispatch { + +template +struct is_valid_box +{ + BOOST_MPL_ASSERT_MSG( + (0 < Dimension && Dimension <= detail::traits::dimension::value), + INVALID_DIMENSION_PARAMETER, + (is_valid_box)); + + static inline bool apply(Box const& b) + { + return is_valid_box::apply(b) && + ( detail::get(b) <= detail::get(b) ); + } +}; + +template +struct is_valid_box +{ + static inline bool apply(Box const& b) + { + return detail::get(b) <= detail::get(b); + } +}; + +template +struct is_valid +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEXABLE, + (is_valid)); +}; + +template +struct is_valid +{ + static inline bool apply(Indexable const&) + { + return true; + } +}; + +template +struct is_valid +{ + static inline bool apply(Indexable const& b) + { + return dispatch::is_valid_box::value>::apply(b); + } +}; + +} // namespace dispatch + +template +inline bool is_valid(Indexable const& b) +{ + return dispatch::is_valid::type>::apply(b); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_DETAIL_INDEX_ALGORITHMS_IS_VALID_HPP diff --git a/include/boost/geometry/index/detail/algorithms/margin.hpp b/include/boost/geometry/index/detail/algorithms/margin.hpp new file mode 100644 index 000000000..a5b934815 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/margin.hpp @@ -0,0 +1,128 @@ +// Boost.Geometry Index +// +// n-dimensional box's margin value (hypersurface), 2d perimeter, 3d surface, etc... +// +// 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_MARGIN_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +template +struct default_margin_result +{ + typedef typename select_most_precise< + typename coordinate_type::type, + long double + >::type type; +}; + +//template +//struct margin_for_each_edge +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// BOOST_STATIC_ASSERT(0 < EdgeDimension); +// +// static inline typename default_margin_result::type apply(Box const& b) +// { +// return margin_for_each_edge::apply(b) * +// ( geometry::get(b) - geometry::get(b) ); +// } +//}; +// +//template +//struct margin_for_each_edge +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// +// static inline typename default_margin_result::type apply(Box const& b) +// { +// return margin_for_each_edge::apply(b); +// } +//}; +// +//template +//struct margin_for_each_edge +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// +// static inline typename default_margin_result::type apply(Box const& b) +// { +// return geometry::get(b) - geometry::get(b); +// } +//}; +// +//template +//struct margin_for_each_edge +//{ +// static inline typename default_margin_result::type apply(Box const& /*b*/) +// { +// return 1; +// } +//}; +// +//template +//struct margin_for_each_dimension +//{ +// BOOST_STATIC_ASSERT(0 < CurrentDimension); +// BOOST_STATIC_ASSERT(CurrentDimension <= detail::traits::dimension::value); +// +// static inline typename default_margin_result::type apply(Box const& b) +// { +// return margin_for_each_dimension::apply(b) + +// margin_for_each_edge::value>::apply(b); +// } +//}; +// +//template +//struct margin_for_each_dimension +//{ +// static inline typename default_margin_result::type apply(Box const& b) +// { +// return margin_for_each_edge::value>::apply(b); +// } +//}; + +template +struct simple_margin_for_each_dimension +{ + BOOST_STATIC_ASSERT(0 < CurrentDimension); + BOOST_STATIC_ASSERT(CurrentDimension <= detail::traits::dimension::value); + + static inline typename default_margin_result::type apply(Box const& b) + { + return simple_margin_for_each_dimension::apply(b) + + geometry::get(b) - geometry::get(b); + } +}; + +template +struct simple_margin_for_each_dimension +{ + static inline typename default_margin_result::type apply(Box const& b) + { + return geometry::get(b) - geometry::get(b); + } +}; + +template +typename default_margin_result::type comparable_margin(Box const& b) +{ + //return detail::margin_for_each_dimension::value>::apply(b); + return detail::simple_margin_for_each_dimension::value>::apply(b); +} + +//template +//typename default_margin_result::type margin(Box const& b) +//{ +// return 2 * detail::margin_for_each_dimension::value>::apply(b); +//} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MARGIN_HPP diff --git a/include/boost/geometry/index/detail/algorithms/minmaxdist.hpp b/include/boost/geometry/index/detail/algorithms/minmaxdist.hpp new file mode 100644 index 000000000..d2429cbb2 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/minmaxdist.hpp @@ -0,0 +1,119 @@ +// Boost.Geometry Index +// +// minmaxdist 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_MINMAXDIST_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP + +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +struct minmaxdist_tag {}; + +template < + typename Point, + typename BoxIndexable, + size_t DimensionIndex> +struct smallest_for_indexable_dimension +{ + typedef typename geometry::default_distance_result::type result_type; + + inline static result_type apply(Point const& pt, BoxIndexable const& i, result_type const& maxd) + { + typedef typename index::traits::coordinate_type::type point_coord_t; + typedef typename index::traits::coordinate_type::type indexable_coord_t; + + point_coord_t pt_c = geometry::get(pt); + indexable_coord_t ind_c_min = geometry::get(i); + indexable_coord_t ind_c_max = geometry::get(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 +struct minmaxdist_impl +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_INDEXABLE_TAG_TYPE, + (minmaxdist_impl)); +}; + +template +struct minmaxdist_impl +{ + typedef typename geometry::default_distance_result::type result_type; + + inline static result_type apply(Point const& pt, Indexable const& i) + { + return geometry::comparable_distance(pt, i); + } +}; + +template +struct minmaxdist_impl +{ + typedef typename geometry::default_distance_result::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, + index::traits::dimension::value + >::apply(pt, i, maxd); + } +}; + +/** + * This is comparable distace. + */ +template +typename geometry::default_distance_result::type +minmaxdist(Point const& pt, Indexable const& i) +{ + return detail::minmaxdist_impl< + Point, + Indexable, + typename index::traits::tag::type + >::apply(pt, i); +} + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_MINMAXDIST_HPP diff --git a/include/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp b/include/boost/geometry/index/detail/algorithms/smallest_for_indexable.hpp new file mode 100644 index 000000000..3ca335d5a --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/smallest_for_indexable.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 + 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 +{ + typedef typename smallest_for_indexable_dimension< + Geometry, Indexable, IndexableTag, AlgoTag, 0 + >::result_type result_type; + + template + 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 diff --git a/include/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp b/include/boost/geometry/index/detail/algorithms/sum_for_indexable.hpp new file mode 100644 index 000000000..4aef36352 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/sum_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 +{ + 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 diff --git a/include/boost/geometry/index/detail/algorithms/union_content.hpp b/include/boost/geometry/index/detail/algorithms/union_content.hpp new file mode 100644 index 000000000..3acdc3d19 --- /dev/null +++ b/include/boost/geometry/index/detail/algorithms/union_content.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 +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +/** + * \brief Compute the area of the union of b1 and b2 + */ +template +inline typename default_content_result::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 diff --git a/include/boost/geometry/index/detail/assert.hpp b/include/boost/geometry/index/detail/assert.hpp new file mode 100644 index 000000000..1ac4f5490 --- /dev/null +++ b/include/boost/geometry/index/detail/assert.hpp @@ -0,0 +1,27 @@ +// 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 + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP + +#define BOOST_GEOMETRY_INDEX_ASSERT(CONDITION, TEXT_MSG) \ + BOOST_ASSERT_MSG(CONDITION, TEXT_MSG) + +#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) + +#define BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(PARAM) + +#else + +#define BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(PARAM) PARAM + +#endif + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_ASSERT_HPP diff --git a/include/boost/geometry/index/detail/config_begin.hpp b/include/boost/geometry/index/detail/config_begin.hpp new file mode 100644 index 000000000..a5a488ff6 --- /dev/null +++ b/include/boost/geometry/index/detail/config_begin.hpp @@ -0,0 +1,24 @@ +// 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 + +#ifdef BOOST_MSVC + + #define BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(A) (void)A; + + #pragma warning (push) + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4127) // conditional expression is constant + +#else //BOOST_MSVC + + #define BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(A) + +#endif //BOOST_MSVC + diff --git a/include/boost/geometry/index/detail/config_end.hpp b/include/boost/geometry/index/detail/config_end.hpp new file mode 100644 index 000000000..d144c3369 --- /dev/null +++ b/include/boost/geometry/index/detail/config_end.hpp @@ -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 + diff --git a/include/boost/geometry/index/detail/distance_predicates.hpp b/include/boost/geometry/index/detail/distance_predicates.hpp new file mode 100644 index 000000000..e80176ec0 --- /dev/null +++ b/include/boost/geometry/index/detail/distance_predicates.hpp @@ -0,0 +1,866 @@ +// Boost.Geometry Index +// +// Spatial index distance predicates, calculators and checkers +// used in nearest query - specialized for envelopes +// +// 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_DISTANCE_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_DISTANCE_PREDICATES_HPP + +#include +#include +#include + +#include + +#include + +// TODO - optimization +// For Boxes and Points all types of distances may be calculated +// - near, far and centroid. For points those are the same distance +// calculate them for Boxes only! +// for Points calculate only 1 distance + +namespace boost { namespace geometry { namespace index { namespace detail { + +// ------------------------------------------------------------------ // +// relations +// ------------------------------------------------------------------ // + +template +struct to_nearest +{ + to_nearest(T const& v) : value(v) {} + T value; +}; + +template +struct to_centroid +{ + to_centroid(T const& v) : value(v) {} + T value; +}; + +template +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 +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 +struct relation< to_nearest > +{ + typedef T value_type; + typedef to_nearest_tag tag; + static inline T const& value(to_nearest const& r) { return r.value; } + static inline T & value(to_nearest & r) { return r.value; } +}; + +template +struct relation< to_centroid > +{ + typedef T value_type; + typedef to_centroid_tag tag; + static inline T const& value(to_centroid const& r) { return r.value; } + static inline T & value(to_centroid & r) { return r.value; } +}; + +template +struct relation< to_furthest > +{ + typedef T value_type; + typedef to_furthest_tag tag; + static inline T const& value(to_furthest const& r) { return r.value; } + static inline T & value(to_furthest & r) { return r.value; } +}; + +// ------------------------------------------------------------------ // +// distance predicates +// ------------------------------------------------------------------ // + +//template +//struct unbounded +// : nonassignable +//{ +// inline explicit unbounded(PointRelation const& pr) +// : point_relation(pr) +// {} +// +// PointRelation point_relation; +//}; +// +//template +//struct min_bounded +// : nonassignable +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// inline min_bounded(PointRelation const& pr, MinRelation const& min_rel) +// : point_relation(pr) +// , comparable_min( +// relation::value(min_rel) * +// relation::value(min_rel) ) +// {} +// +// PointRelation point_relation; +// distance_type comparable_min; +//}; +// +//template +//struct max_bounded +// : nonassignable +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// inline max_bounded(PointRelation const& pr, MaxRelation const& max_rel) +// : point_relation(pr) +// , comparable_max( +// relation::value(max_rel) * +// relation::value(max_rel) ) +// {} +// +// PointRelation point_relation; +// distance_type comparable_max; +//}; +// +//template +//struct bounded +// : nonassignable +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// inline bounded(PointRelation const& pr, MinRelation const& min_rel, MaxRelation const& max_rel) +// : point_relation(pr) +// , comparable_min( +// relation::value(min_rel) * +// relation::value(min_rel) ) +// , comparable_max( +// relation::value(max_rel) * +// relation::value(max_rel) ) +// {} +// +// PointRelation point_relation; +// distance_type comparable_min; +// distance_type comparable_max; +//}; + +// ------------------------------------------------------------------ // +// point_relation trait +// ------------------------------------------------------------------ // + +template +struct point_relation +{ + typedef PointRelation type; +}; + +//template +//struct point_relation< detail::unbounded > +//{ +// typedef PointRelation type; +//}; +// +//template +//struct point_relation< detail::min_bounded > +//{ +// typedef PointRelation type; +//}; +// +//template +//struct point_relation< detail::max_bounded > +//{ +// typedef PointRelation type; +//}; +// +//template +//struct point_relation< detail::bounded > +//{ +// typedef PointRelation type; +//}; + +// ------------------------------------------------------------------ // +// helpers +// ------------------------------------------------------------------ // + +// algorithms + +// cdist + +template +struct cdist +{ + T value; +}; + +// cdist_merge + +template +struct cdist_merge +{ + typedef typename detail::tuples::add_unique< + CDistTuple, + CDist + >::type type; +}; + +template +struct cdist_merge< + cdist, + cdist > +{ + typedef boost::tuple< + cdist, + cdist + > type; +}; + +template +struct cdist_merge< + cdist, + cdist > +{ + typedef cdist type; +}; + +// cdist_value_type + +template +struct cdist_value +{ + typedef typename cdist_value< + typename boost::tuples::element<0, CDistTuple>::type + >::type type; + + template + static inline type & get(CDistTuple & cdtup) + { + return boost::get< + tuples::find_index< + CDistTuple, + cdist + >::value + >(cdtup).value; + } + + template + static inline type const& get(CDistTuple const& cdtup) + { + return boost::get< + tuples::find_index< + CDistTuple, + cdist + >::value + >(cdtup).value; + } +}; + +template +struct cdist_value< + cdist +> +{ + typedef T type; + + template + static inline type & get(cdist & cd) + { + BOOST_MPL_ASSERT_MSG( + (boost::is_same< cdist, cdist >::value), + TAGS_DO_NOT_MATCH, + (cdist_value)); + + return cd.value; + } + + template + static inline type const& get(cdist const& cd) + { + BOOST_MPL_ASSERT_MSG( + (boost::is_same< cdist, cdist >::value), + TAGS_DO_NOT_MATCH, + (cdist_value)); + + return cd.value; + } +}; + +// distances_calc_impl_rel + +template +struct distances_calc_impl_rel +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_RELATION, + (distances_calc_impl_rel)); +}; + +template +struct distances_calc_impl_rel< + cdist +> +{ + template + typename geometry::default_distance_result::type + static inline apply(Point const& p, Indexable const& i) + { + return index::detail::comparable_distance_near(p, i); + } +}; + +template +struct distances_calc_impl_rel< + cdist +> +{ + template + typename geometry::default_distance_result::type + static inline apply(Point const& p, Indexable const& i) + { + return index::detail::comparable_distance_centroid(p, i); + } +}; + +template +struct distances_calc_impl_rel< + cdist +> +{ + template + typename geometry::default_distance_result::type + static inline apply(Point const& p, Indexable const& i) + { + return index::detail::comparable_distance_far(p, i); + } +}; + +// distances_calc_impl_tuple + +template +struct distances_calc_impl_tuple +{ + // TODO MPL ASSERT 0 < N + static inline void apply(Distances & d, Point const& p, Indexable const&i) + { + boost::get(d).value = + distances_calc_impl_rel< + typename boost::tuples::element::type + >::apply(p, i); + + distances_calc_impl_tuple< + Distances, + Point, + Indexable, + N - 1 + >::apply(d, p, i); + } +}; + +template +struct distances_calc_impl_tuple +{ + static inline void apply(Distances & d, Point const& p, Indexable const&i) + { + boost::get<0>(d).value = + distances_calc_impl_rel< + typename boost::tuples::element<0, Distances>::type + >::apply(p, i); + } +}; + +// distances_calc_impl + +template +struct distances_calc_impl +{ + static inline void apply(Distances & d, Point const& p, Indexable const&i) + { + distances_calc_impl_tuple< + Distances, + Point, + Indexable, + boost::tuples::length::value + >::apply(d, p, i); + } +}; + +template +struct distances_calc_impl< + cdist, + Point, + Indexable +> +{ + static inline void apply(cdist & d, Point const& p, Indexable const&i) + { + d.value = distances_calc_impl_rel< + cdist + >::apply(p, i); + } +}; + +// ------------------------------------------------------------------ // +// distance_calc and distances_predicates_check +// ------------------------------------------------------------------ // + +template +struct distances_calc +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG, + (distances_calc)); +}; + +template +struct distances_predicates_check +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG, + (distances_predicates_check)); +}; + +// ------------------------------------------------------------------ // +// distance_calc for value_tag +// ------------------------------------------------------------------ // + +template +struct distances_calc +{ + typedef typename detail::relation::value_type point_type; + typedef typename detail::relation::tag point_relation_tag; + typedef typename geometry::default_distance_result::type distance_type; + + typedef detail::cdist result_type; + + static inline result_type apply(PointRelation const& p, Indexable const& i) + { + result_type res; + distances_calc_impl + ::apply(res, relation::value(p), i); + return res; + } +}; + +//template +//struct distances_calc< +// detail::unbounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename detail::relation::tag point_relation_tag; +// typedef typename geometry::default_distance_result::type distance_type; +// +// typedef detail::cdist result_type; +// +// static inline result_type apply(detail::unbounded const& pp, Indexable const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; +// +//template +//struct distances_calc< +// detail::min_bounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename detail::relation::tag point_relation_tag; +// typedef typename geometry::default_distance_result::type distance_type; +// typedef typename detail::relation::tag min_relation_tag; +// +// typedef typename detail::cdist_merge< +// cdist, +// cdist +// >::type result_type; +// +// static inline result_type apply(detail::min_bounded const& pp, Indexable const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; +// +//template +//struct distances_calc< +// detail::max_bounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename detail::relation::tag point_relation_tag; +// typedef typename geometry::default_distance_result::type distance_type; +// typedef typename detail::relation::tag max_relation_tag; +// +// typedef typename detail::cdist_merge< +// cdist, +// cdist +// >::type result_type; +// +// static inline result_type apply(detail::max_bounded const& pp, Indexable const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; +// +//template +//struct distances_calc< +// detail::bounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename detail::relation::tag point_relation_tag; +// typedef typename geometry::default_distance_result::type distance_type; +// typedef typename detail::relation::tag min_relation_tag; +// typedef typename detail::relation::tag max_relation_tag; +// +// typedef typename detail::cdist_merge< +// typename detail::cdist_merge< +// cdist, +// cdist +// >::type, +// cdist +// >::type result_type; +// +// static inline result_type apply( +// detail::bounded const& pp, +// Indexable const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; + +// ------------------------------------------------------------------ // +// distance_predicates_check for value_tag +// ------------------------------------------------------------------ // + +template +struct distances_predicates_check +{ + template + static inline bool apply(PointRelation const&, Distances const&) + { + return true; + } +}; + +//template +//struct distances_predicates_check< +// detail::unbounded, +// Indexable, +// value_tag +//> +//{ +// template +// static inline bool apply(detail::unbounded const&, Distances const&) +// { +// return true; +// } +//}; +// +//template +//struct distances_predicates_check< +// detail::min_bounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::tag min_relation_tag; +// +// template +// static inline bool apply( +// detail::min_bounded const& pred, +// Distances const& d) +// { +// return pred.comparable_min <= +// detail::cdist_value::template get(d); +// } +//}; +// +//template +//struct distances_predicates_check< +// detail::max_bounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::tag max_relation_tag; +// +// template +// static inline bool apply( +// detail::max_bounded const& pred, +// Distances const& d) +// { +// return pred.comparable_max <= +// detail::cdist_value::template get(d); +// } +//}; +// +//template +//struct distances_predicates_check< +// detail::bounded, +// Indexable, +// value_tag +//> +//{ +// typedef typename detail::relation::tag min_relation_tag; +// typedef typename detail::relation::tag max_relation_tag; +// +// template +// static inline bool apply( +// detail::bounded const& pred, +// Distances const& d) +// { +// return pred.comparable_min +// <= detail::cdist_value::template get(d) +// && detail::cdist_value::template get(d) +// <= pred.comparable_max; +// } +//}; + +// ------------------------------------------------------------------ // +// distance_calc for bounds_tag +// ------------------------------------------------------------------ // + +template +struct distances_calc< + PointRelation, + Box, + bounds_tag> +{ + typedef typename detail::relation::value_type point_type; + typedef typename geometry::default_distance_result::type distance_type; + + typedef detail::cdist result_type; + + static inline result_type apply(PointRelation const& p, Box const& i) + { + result_type res; + distances_calc_impl + ::apply(res, relation::value(p), i); + return res; + } +}; + +//template +//struct distances_calc< +// detail::unbounded, +// Box, +// bounds_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// typedef detail::cdist result_type; +// +// static inline result_type apply(detail::unbounded const& pp, Box const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; +// +//template +//struct distances_calc< +// detail::min_bounded, +// Box, +// bounds_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// typedef typename detail::cdist_merge< +// cdist, +// cdist +// >::type result_type; +// +// static inline result_type apply(detail::min_bounded const& pp, Box const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; +// +//template +//struct distances_calc< +// detail::max_bounded, +// Box, +// bounds_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// typedef cdist result_type; +// +// static inline result_type apply(detail::max_bounded const& pp, Box const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; +// +//template +//struct distances_calc< +// detail::bounded, +// Box, +// bounds_tag +//> +//{ +// typedef typename detail::relation::value_type point_type; +// typedef typename geometry::default_distance_result::type distance_type; +// +// typedef typename detail::cdist_merge< +// cdist, +// cdist +// >::type result_type; +// +// static inline result_type apply(detail::bounded const& pp, Box const& i) +// { +// result_type res; +// distances_calc_impl +// ::apply(res, relation::value(pp.point_relation), i); +// return res; +// } +//}; + +// ------------------------------------------------------------------ // +// distance_predicates_check for bounds_tag +// ------------------------------------------------------------------ // + +template +struct distances_predicates_check< + PointRelation, + Box, + bounds_tag> +{ + template + static inline bool apply(PointRelation const&, Distances const&) + { + return true; + } +}; + +//template +//struct distances_predicates_check< +// detail::unbounded, +// Box, +// bounds_tag> +//{ +// template +// static inline bool apply( +// detail::unbounded const&, +// Distances const&) +// { +// return true; +// } +//}; +// +//template +//struct distances_predicates_check< +// detail::min_bounded, +// Box, +// bounds_tag> +//{ +// template +// static inline bool apply( +// detail::min_bounded const& pred, +// Distances const& d) +// { +// return pred.comparable_min +// <= cdist_value::template get(d); +// } +//}; +// +//template +//struct distances_predicates_check< +// detail::max_bounded, +// Box, +// bounds_tag> +//{ +// template +// static inline bool apply( +// detail::max_bounded const& pred, +// Distances const& d) +// { +// return cdist_value::template get(d) +// <= pred.comparable_max; +// } +//}; +// +//template +//struct distances_predicates_check< +// detail::bounded, +// Box, +// bounds_tag> +//{ +// template +// static inline bool apply( +// detail::bounded const& pred, +// Distances const& d) +// { +// return pred.comparable_min +// <= cdist_value::template get(d) +// && cdist_value::template get(d) +// <= pred.comparable_max; +// } +//}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_RTREE_DISTANCE_PREDICATES_HPP diff --git a/include/boost/geometry/index/detail/indexable.hpp b/include/boost/geometry/index/detail/indexable.hpp new file mode 100644 index 000000000..f0791b170 --- /dev/null +++ b/include/boost/geometry/index/detail/indexable.hpp @@ -0,0 +1,139 @@ +// Boost.Geometry Index +// +// Indexable's traits and related functions +// +// 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_INDEXABLE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_INDEXABLE_HPP + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace dispatch { + +template +struct point_type +{ + typedef void type; +}; + +template +struct point_type +{ + typedef typename geometry::traits::point_type::type type; +}; + +template +struct point_type +{ + typedef Indexable type; +}; + +} // namespace dispatch + +namespace traits { + +template +struct point_type +{ + typedef typename dispatch::point_type< + Indexable, + typename geometry::traits::tag::type + >::type type; +}; + +template +struct coordinate_system +{ + typedef typename geometry::traits::coordinate_system< + typename point_type::type + >::type type; +}; + +template +struct coordinate_type +{ + typedef typename geometry::traits::coordinate_type< + typename point_type::type + >::type type; +}; + +template +struct dimension +{ + static const size_t value = + geometry::traits::dimension< + typename point_type::type + >::value; +}; + +template +struct tag +{ + typedef typename geometry::traits::tag< + Indexable + >::type type; +}; + +} // namespace traits + +namespace dispatch { + +template +struct indexable_indexed_access {}; + +template +struct indexable_indexed_access +{ + typedef typename traits::point_type::type point_type; + typedef typename traits::coordinate_type::type coordinate_type; + + static inline coordinate_type get(Indexable const& i) + { + return geometry::get(i); + } +}; + +template +struct indexable_indexed_access +{ + typedef typename traits::coordinate_type::type coordinate_type; + + static inline coordinate_type get(Indexable const& i) + { + return geometry::get(i); + } +}; + +} // namespace dispatch + +template +typename traits::coordinate_type::type get(Indexable const& i) +{ + return dispatch::indexable_indexed_access< + Corner, + DimensionIndex, + Indexable, + typename geometry::traits::tag::type + >::get(i); +} + +template +struct default_box_type +{ + typedef geometry::model::box< + geometry::model::point< + typename traits::coordinate_type::type, + traits::dimension::value, + typename traits::coordinate_system::type + > + > type; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_INDEXABLE_HPP diff --git a/include/boost/geometry/index/detail/predicates.hpp b/include/boost/geometry/index/detail/predicates.hpp new file mode 100644 index 000000000..93874aa40 --- /dev/null +++ b/include/boost/geometry/index/detail/predicates.hpp @@ -0,0 +1,903 @@ +// Boost.Geometry Index +// +// Spatial query predicates definition and checks. +// +// 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_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP + +#include +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +// ------------------------------------------------------------------ // +// predicates +// ------------------------------------------------------------------ // + +//struct empty {}; + +template +struct satisfies +{ + satisfies(Fun const& f) : fun(f) {} + Fun const& fun; +}; + +template +struct covered_by +{ + covered_by(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct disjoint +{ + disjoint(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct intersects +{ + intersects(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct overlaps +{ + overlaps(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +//template +//struct touches +//{ +// touches(Geometry const& g) : geometry(g) {} +// Geometry geometry; +//}; + +template +struct within +{ + within(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct not_covered_by +{ + not_covered_by(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct not_disjoint +{ + not_disjoint(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct not_intersects +{ + not_intersects(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct not_overlaps +{ + not_overlaps(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +//template +//struct not_touches +//{ +// not_touches(Geometry const& g) : geometry(g) {} +// Geometry geometry; +//}; + +template +struct not_within +{ + not_within(Geometry const& g) : geometry(g) {} + Geometry const& geometry; +}; + +template +struct nearest +{ + nearest(DistancePredicates const& dpred, unsigned k) + : distance_predicates(dpred) + , count(k) + {} + DistancePredicates const& distance_predicates; + unsigned count; +}; + +// ------------------------------------------------------------------ // +// is_predicate +// ------------------------------------------------------------------ // + +//template struct is_predicate { static const bool value = false; }; +////template <> struct is_predicate< empty > { static const bool value = true; }; +//template struct is_predicate< satisfies > { static const bool value = true; }; +//template struct is_predicate< covered_by > { static const bool value = true; }; +//template struct is_predicate< disjoint > { static const bool value = true; }; +//template struct is_predicate< intersects > { static const bool value = true; }; +//template struct is_predicate< overlaps > { static const bool value = true; }; +////template struct is_predicate< touches > { static const bool value = true; }; +//template struct is_predicate< within > { static const bool value = true; }; +//template struct is_predicate< not_covered_by > { static const bool value = true; }; +//template struct is_predicate< not_disjoint > { static const bool value = true; }; +//template struct is_predicate< not_intersects > { static const bool value = true; }; +//template struct is_predicate< not_overlaps > { static const bool value = true; }; +////template struct is_predicate< not_touches > { static const bool value = true; }; +//template struct is_predicate< not_within > { static const bool value = true; }; +//template struct is_predicate< nearest

> { static const bool value = true; }; + +// ------------------------------------------------------------------ // +// predicate_check_default +// ------------------------------------------------------------------ // + +//template +//struct predicate_check_default +//{ +// BOOST_MPL_ASSERT_MSG( +// (false), +// NOT_IMPLEMENTED_FOR_THESE_TAGS, +// (predicate_check_default)); +//}; + +// ------------------------------------------------------------------ // +// predicate_check +// ------------------------------------------------------------------ // + +template +struct predicate_check +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_PREDICATE_OR_TAG, + (predicate_check)); +}; + +// ------------------------------------------------------------------ // +// predicate_check_default for value +// ------------------------------------------------------------------ // + +//template +//struct predicate_check_default +//{ +// template +// static inline bool apply(Geometry const& g, Value const&, Indexable const& i) +// { +// return geometry::intersects(i, g); +// } +//}; +// +//template +//struct predicate_check_default +//{ +// template +// static inline bool apply(Unary const& u, Value const& v, Indexable const&) +// { +// return u(v); +// } +//}; + +// ------------------------------------------------------------------ // +// predicate_check for value +// ------------------------------------------------------------------ // + +//template +//struct predicate_check +//{ +// template +// static inline bool apply(GeometryOrUnary const& g, Value const& v, Indexable const& i) +// { +// return predicate_check_default< +// GeometryOrUnary, typename geometry::traits::tag::type, bounds_tag +// >::apply(g, v, i); +// } +//}; + +//template <> +//struct predicate_check +//{ +// template +// static inline bool apply(empty const&, Value const&, Indexable const&) +// { +// return true; +// } +//}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(satisfies const& p, Value const& v, Indexable const&) + { + return p.fun(v); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(covered_by const& p, Value const&, Indexable const& i) + { + return geometry::covered_by(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(disjoint const& p, Value const&, Indexable const& i) + { + return geometry::disjoint(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(intersects const& p, Value const&, Indexable const& i) + { + return geometry::intersects(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(overlaps const& p, Value const&, Indexable const& i) + { + return geometry::overlaps(i, p.geometry); + } +}; + +//template +//struct predicate_check, value_tag> +//{ +// template +// static inline bool apply(touches const& p, Value const&, Indexable const& i) +// { +// return geometry::touches(i, p.geometry); +// } +//}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(within const& p, Value const&, Indexable const& i) + { + return geometry::within(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(not_covered_by const& p, Value const&, Indexable const& i) + { + return !geometry::covered_by(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(not_disjoint const& p, Value const&, Indexable const& i) + { + return !geometry::disjoint(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(not_intersects const& p, Value const&, Indexable const& i) + { + return !geometry::intersects(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(not_overlaps const& p, Value const&, Indexable const& i) + { + return !geometry::overlaps(i, p.geometry); + } +}; + +//template +//struct predicate_check, value_tag> +//{ +// template +// static inline bool apply(not_touches const& p, Value const&, Indexable const& i) +// { +// return !geometry::touches(i, p.geometry); +// } +//}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(not_within const& p, Value const&, Indexable const& i) + { + return !geometry::within(i, p.geometry); + } +}; + +template +struct predicate_check, value_tag> +{ + template + static inline bool apply(nearest const&, Value const&, Box const&) + { + return true; + } +}; + +// ------------------------------------------------------------------ // +// predicate_check_default for bounds +// ------------------------------------------------------------------ // + +//template +//struct predicate_check_default +//{ +// template +// static inline bool apply(Geometry const& g, Value const&, Indexable const& i) +// { +// return geometry::intersects(i, g); +// } +//}; +// +//template +//struct predicate_check_default +//{ +// template +// static inline bool apply(Unary const&, Value const&, Indexable const&) +// { +// return true; +// } +//}; + +// ------------------------------------------------------------------ // +// predicates_chec for bounds +// ------------------------------------------------------------------ // + +//template +//struct predicate_check +//{ +// template +// static inline bool apply(GeometryOrUnary const& g, Value const& v, Indexable const& i) +// { +// return predicate_check_default< +// GeometryOrUnary, typename geometry::traits::tag::type, bounds_tag +// >::apply(g, v, i); +// } +//}; + +//template <> +//struct predicate_check +//{ +// template +// static inline bool apply(Geometry const&, Value const&, Indexable const&) +// { +// return true; +// } +//}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(satisfies const&, Value const&, Box const&) + { + return true; + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(covered_by const& p, Value const&, Box const& i) + { + return geometry::intersects(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(disjoint const& p, Value const&, Box const& i) + { + return !geometry::covered_by(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static inline bool apply(intersects const& p, Value const&, Indexable const& i) + { + return geometry::intersects(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static inline bool apply(overlaps const& p, Value const&, Box const& i) + { + // TODO: awulkiew - possibly change to the version without border case + // e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false + return geometry::intersects(i, p.geometry); + } +}; + +//template +//struct predicate_check, bounds_tag> +//{ +// template +// static bool apply(touches const& p, Value const&, Box const& i) +// { +// return geometry::intersects(i, p.geometry); +// } +//}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(within const& p, Value const&, Box const& i) + { + // TODO: awulkiew - possibly change to the version without border case + // e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false + return geometry::intersects(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(not_covered_by const& p, Value const&, Box const& i) + { + return !geometry::covered_by(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(not_disjoint const& p, Value const&, Box const& i) + { + return !geometry::disjoint(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(not_intersects const& p, Value const&, Box const& i) + { + return !geometry::covered_by(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(not_overlaps const& , Value const&, Box const& ) + { + return true; + } +}; + +//template +//struct predicate_check, bounds_tag> +//{ +// template +// static bool apply(not_touches const& p, Value const&, Box const& i) +// { +// return !geometry::intersects(i, p.geometry); +// } +//}; + +template +struct predicate_check, bounds_tag> +{ + template + static bool apply(not_within const& p, Value const&, Box const& i) + { + return !geometry::within(i, p.geometry); + } +}; + +template +struct predicate_check, bounds_tag> +{ + template + static inline bool apply(nearest const&, Value const&, Box const&) + { + return true; + } +}; + +// ------------------------------------------------------------------ // +// predicates_length +// ------------------------------------------------------------------ // + +template +struct predicates_length +{ + static const unsigned value = 1; +}; + +//template +//struct predicates_length< std::pair > +//{ +// static const unsigned value = 2; +//}; + +//template +//struct predicates_length< boost::tuple > +//{ +// static const unsigned value = boost::tuples::length< boost::tuple >::value; +//}; + +template +struct predicates_length< boost::tuples::cons > +{ + static const unsigned value = boost::tuples::length< boost::tuples::cons >::value; +}; + +// ------------------------------------------------------------------ // +// predicates_element +// ------------------------------------------------------------------ // + +template +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 +//struct predicates_element< I, std::pair > +//{ +// BOOST_MPL_ASSERT_MSG((I < 2), INVALID_INDEX, (predicates_element)); +// +// typedef F type; +// static type const& get(std::pair const& p) { return p.first; } +//}; +// +//template +//struct predicates_element< 1, std::pair > +//{ +// typedef S type; +// static type const& get(std::pair const& p) { return p.second; } +//}; +// +//template +//struct predicates_element< I, boost::tuple > +//{ +// typedef boost::tuple predicate_type; +// +// typedef typename boost::tuples::element::type type; +// static type const& get(predicate_type const& p) { return boost::get(p); } +//}; + +template +struct predicates_element< I, boost::tuples::cons > +{ + typedef boost::tuples::cons predicate_type; + + typedef typename boost::tuples::element::type type; + static type const& get(predicate_type const& p) { return boost::get(p); } +}; + +// ------------------------------------------------------------------ // +// predicates_check +// ------------------------------------------------------------------ // + +//template +//struct predicates_check_pair {}; +// +//template +//struct predicates_check_pair +//{ +// template +// static inline bool apply(PairPredicates const& , Value const& , Indexable const& ) +// { +// return true; +// } +//}; +// +//template +//struct predicates_check_pair +//{ +// template +// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i) +// { +// return predicate_check::apply(p.first, v, i); +// } +//}; +// +//template +//struct predicates_check_pair +//{ +// template +// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i) +// { +// return predicate_check::apply(p.second, v, i); +// } +//}; +// +//template +//struct predicates_check_pair +//{ +// template +// static inline bool apply(PairPredicates const& p, Value const& v, Indexable const& i) +// { +// return predicate_check::apply(p.first, v, i) +// && predicate_check::apply(p.second, v, i); +// } +//}; + +template +struct predicates_check_tuple +{ + template + static inline bool apply(TuplePredicates const& p, Value const& v, Indexable const& i) + { + return + predicate_check< + typename boost::tuples::element::type, + Tag + >::apply(boost::get(p), v, i) && + predicates_check_tuple::apply(p, v, i); + } +}; + +template +struct predicates_check_tuple +{ + template + static inline bool apply(TuplePredicates const& , Value const& , Indexable const& ) + { + return true; + } +}; + +template +struct predicates_check_impl +{ + BOOST_MPL_ASSERT_MSG((First < 1 && Last <= 1 && First <= Last), INVALID_INDEXES, (predicates_check_impl)); + + template + static inline bool apply(Predicate const& p, Value const& v, Indexable const& i) + { + return predicate_check::apply(p, v, i); + } +}; + +//template +//struct predicates_check_impl, Tag, First, Last> +//{ +// BOOST_MPL_ASSERT_MSG((First < 2 && Last <= 2 && First <= Last), INVALID_INDEXES, (predicates_check_impl)); +// +// template +// static inline bool apply(std::pair const& p, Value const& v, Indexable const& i) +// { +// return predicate_check::apply(p.first, v, i) +// && predicate_check::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, +// Tag, First, Last +//> +//{ +// typedef boost::tuple predicates_type; +// +// static const unsigned pred_len = boost::tuples::length::value; +// BOOST_MPL_ASSERT_MSG((First < pred_len && Last <= pred_len && First <= Last), INVALID_INDEXES, (predicates_check_impl)); +// +// template +// 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 +struct predicates_check_impl< + boost::tuples::cons, + Tag, First, Last +> +{ + typedef boost::tuples::cons predicates_type; + + static const unsigned pred_len = boost::tuples::length::value; + BOOST_MPL_ASSERT_MSG((First < pred_len && Last <= pred_len && First <= Last), INVALID_INDEXES, (predicates_check_impl)); + + template + 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 +inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i) +{ + return detail::predicates_check_impl + ::apply(p, v, i); +} + +// ------------------------------------------------------------------ // +// nearest predicate helpers +// ------------------------------------------------------------------ // + +// predicates_is_nearest + +template +struct predicates_is_nearest +{ + static const unsigned value = 0; +}; + +template +struct predicates_is_nearest< nearest > +{ + static const unsigned value = 1; +}; + +// predicates_count_nearest + +template +struct predicates_count_nearest +{ + static const unsigned value = predicates_is_nearest::value; +}; + +//template +//struct predicates_count_nearest< std::pair > +//{ +// static const unsigned value = predicates_is_nearest::value +// + predicates_is_nearest::value; +//}; + +template +struct predicates_count_nearest_tuple +{ + static const unsigned value = + predicates_is_nearest::type>::value + + predicates_count_nearest_tuple::value; +}; + +template +struct predicates_count_nearest_tuple +{ + static const unsigned value = + predicates_is_nearest::type>::value; +}; + +//template +//struct predicates_count_nearest< boost::tuple > +//{ +// static const unsigned value = predicates_count_nearest_tuple< +// boost::tuple, +// boost::tuples::length< boost::tuple >::value +// >::value; +//}; + +template +struct predicates_count_nearest< boost::tuples::cons > +{ + static const unsigned value = predicates_count_nearest_tuple< + boost::tuples::cons, + boost::tuples::length< boost::tuples::cons >::value + >::value; +}; + +// predicates_find_nearest + +template +struct predicates_find_nearest +{ + static const unsigned value = predicates_is_nearest::value ? 0 : 1; +}; + +//template +//struct predicates_find_nearest< std::pair > +//{ +// static const unsigned value = predicates_is_nearest::value ? 0 : +// (predicates_is_nearest::value ? 1 : 2); +//}; + +template +struct predicates_find_nearest_tuple +{ + static const bool is_found = predicates_find_nearest_tuple::is_found + || predicates_is_nearest::type>::value; + + static const unsigned value = predicates_find_nearest_tuple::is_found ? + predicates_find_nearest_tuple::value : + (predicates_is_nearest::type>::value ? + N-1 : boost::tuples::length::value); +}; + +template +struct predicates_find_nearest_tuple +{ + static const bool is_found = predicates_is_nearest::type>::value; + static const unsigned value = is_found ? 0 : boost::tuples::length::value; +}; + +//template +//struct predicates_find_nearest< boost::tuple > +//{ +// static const unsigned value = predicates_find_nearest_tuple< +// boost::tuple, +// boost::tuples::length< boost::tuple >::value +// >::value; +//}; + +template +struct predicates_find_nearest< boost::tuples::cons > +{ + static const unsigned value = predicates_find_nearest_tuple< + boost::tuples::cons, + boost::tuples::length< boost::tuples::cons >::value + >::value; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP diff --git a/include/boost/geometry/index/detail/pushable_array.hpp b/include/boost/geometry/index/detail/pushable_array.hpp new file mode 100644 index 000000000..180d46580 --- /dev/null +++ b/include/boost/geometry/index/detail/pushable_array.hpp @@ -0,0 +1,171 @@ +// 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_PUSHABLE_ARRAY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_PUSHABLE_ARRAY_HPP + +#include + +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +template +class pushable_array +{ + typedef typename boost::array array_type; + +public: + typedef typename array_type::value_type value_type; + typedef typename array_type::size_type size_type; + typedef typename array_type::iterator iterator; + typedef typename array_type::const_iterator const_iterator; + typedef typename array_type::reverse_iterator reverse_iterator; + typedef typename array_type::const_reverse_iterator const_reverse_iterator; + typedef typename array_type::reference reference; + typedef typename array_type::const_reference const_reference; + + inline pushable_array() + : m_size(0) + {} + + inline explicit pushable_array(size_type s) + : m_size(s) + { + BOOST_GEOMETRY_INDEX_ASSERT(s <= Capacity, "size too big"); + } + + inline void resize(size_type s) + { + BOOST_GEOMETRY_INDEX_ASSERT(s <= Capacity, "size too big"); + m_size = s; + } + + inline void reserve(size_type /*s*/) + { + //BOOST_GEOMETRY_INDEX_ASSERT(s <= Capacity, "size too big"); + // do nothing + } + + inline Element & operator[](size_type i) + { + BOOST_GEOMETRY_INDEX_ASSERT(i < m_size, "index of the element outside the container"); + return m_array[i]; + } + + inline Element const& operator[](size_type i) const + { + BOOST_GEOMETRY_INDEX_ASSERT(i < m_size, "index of the element outside the container"); + return m_array[i]; + } + + inline Element const& front() const + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return m_array.front(); + } + + inline Element & front() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return m_array.front(); + } + + inline Element const& back() const + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return *(begin() + (m_size - 1)); + } + + inline Element & back() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + return *(begin() + (m_size - 1)); + } + + inline iterator begin() + { + return m_array.begin(); + } + + inline iterator end() + { + return m_array.begin() + m_size; + } + + inline const_iterator begin() const + { + return m_array.begin(); + } + + inline const_iterator end() const + { + return m_array.begin() + m_size; + } + + inline reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + inline reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + inline const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + inline const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + inline void clear() + { + m_size = 0; + } + + inline void push_back(Element const& v) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_size < Capacity, "can't further increase the size of the container"); + m_array[m_size] = v; + ++m_size; + } + + inline void pop_back() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_size, "there are no elements in the container"); + --m_size; + } + + inline bool empty() const + { + return m_size == 0; + } + + inline size_t size() const + { + return m_size; + } + + inline size_t capacity() const + { + return Capacity; + } + +private: + boost::array m_array; + size_type m_size; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_PUSHABLE_ARRAY_HPP diff --git a/include/boost/geometry/index/detail/rtree/adaptors.hpp b/include/boost/geometry/index/detail/rtree/adaptors.hpp new file mode 100644 index 000000000..4e0eb9ba0 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/adaptors.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 +#include + +#include + +namespace boost { namespace geometry { namespace index { + +template +class rtree; + +namespace adaptors { namespace detail { + +template +class query_range< index::rtree > +{ +public: + typedef std::vector result_type; + typedef typename result_type::iterator iterator; + typedef typename result_type::const_iterator const_iterator; + + template inline + query_range(index::rtree 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 diff --git a/include/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp b/include/boost/geometry/index/detail/rtree/kmeans/kmeans.hpp new file mode 100644 index 000000000..3f61482b2 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/kmeans/kmeans.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 + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_KMEANS_KMEANS_HPP diff --git a/include/boost/geometry/index/detail/rtree/kmeans/split.hpp b/include/boost/geometry/index/detail/rtree/kmeans/split.hpp new file mode 100644 index 000000000..f19654972 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/kmeans/split.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 +#include + +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 +class split +{ +protected: + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename Options::parameters_type parameters_type; + +public: + template + 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 diff --git a/include/boost/geometry/index/detail/rtree/linear/linear.hpp b/include/boost/geometry/index/detail/rtree/linear/linear.hpp new file mode 100644 index 000000000..1461692a1 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/linear/linear.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 + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_LINEAR_HPP diff --git a/include/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp b/include/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp new file mode 100644 index 000000000..dc423777b --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/linear/redistribute_elements.hpp @@ -0,0 +1,333 @@ +// Boost.Geometry Index +// +// R-tree linear split algorithm implementation +// +// 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_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP + +#include + +#include + +#include +#include +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace linear { + +// 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. + +// TODO: Implement separate version for Points + +// What if width calculated inside find_greatest_normalized_separation::apply() is near 0? +// What epsilon should be taken to calculation and what would be the value of resulting separation? + +// from void find_normalized_separations(std::vector const& boxes, T& separation, unsigned int& first, unsigned int& second) const + +template +struct find_greatest_normalized_separation +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& translator, + coordinate_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_low = index::detail::get(rtree::element_indexable(elements[0], translator)); + coordinate_type highest_high = index::detail::get(rtree::element_indexable(elements[0], translator)); + // 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 ) + { + coordinate_type min_coord = index::detail::get(rtree::element_indexable(elements[i], translator)); + coordinate_type max_coord = index::detail::get(rtree::element_indexable(elements[i], translator)); + + 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; + coordinate_type highest_low = index::detail::get(rtree::element_indexable(elements[highest_low_index], translator)); + for ( size_t i = highest_low_index ; i < elements_count ; ++i ) + { + coordinate_type min_coord = index::detail::get(rtree::element_indexable(elements[i], translator)); + 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; + + // TODO: awulkiew - following separation calculation has two flaws: + // 1. for floating point numbers width should be compared witn some EPS + // 2. separation calculation won't work for unsigned numbers + // but there should be possible to calculate negative value (cast to some floating point type?) + + // Temporary workaround + BOOST_STATIC_ASSERT(!boost::is_unsigned::value); + + if ( width == 0 ) + separation = 0; + // (highest_low - lowest_high) == 0 + else + separation = (highest_low - lowest_high) / width; + + seed1 = highest_low_index; + seed2 = lowest_high_index; + + BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(parameters) + } +}; + +template +struct pick_seeds_impl +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + coordinate_type & separation, + size_t & seed1, + size_t & seed2) + { + pick_seeds_impl::apply(elements, parameters, tr, separation, seed1, seed2); + + coordinate_type current_separation; + size_t s1, s2; + find_greatest_normalized_separation::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 +struct pick_seeds_impl +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + coordinate_type & separation, + size_t & seed1, + size_t & seed2) + { + find_greatest_normalized_separation::apply(elements, parameters, tr, separation, seed1, seed2); + } +}; + +// from void linear_pick_seeds(node_pointer const& n, unsigned int &seed1, unsigned int &seed2) const + +template +struct pick_seeds +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_type; + + static const size_t dimension = index::detail::traits::dimension::value; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + size_t & seed1, + size_t & seed2) + { + coordinate_type separation = 0; + pick_seeds_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 +struct redistribute_elements +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + template + 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::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_type; + typedef typename index::detail::default_content_result::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 + elements_type elements_copy(elements1); // MAY THROW, STRONG (alloc, copy) + + // calculate initial seeds + size_t seed1 = 0; + size_t seed2 = 0; + linear::pick_seeds< + elements_type, + parameters_type, + Translator + >::apply(elements_copy, parameters, translator, seed1, seed2); + + // prepare nodes' elements containers + elements1.clear(); + BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "unexpected container state"); + + 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 + geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1); + geometry::convert(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; + } + } + } + catch (...) + { + elements1.clear(); + elements2.clear(); + + rtree::destroy_elements::apply(elements_copy, allocators); + //elements_copy.clear(); + + throw; // RETHROW, BASIC + } + } +}; + +}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_LINEAR_REDISTRIBUTE_ELEMENTS_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp b/include/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp new file mode 100644 index 000000000..dd55c6d76 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/auto_deallocator.hpp @@ -0,0 +1,38 @@ +// Boost.Geometry Index +// +// R-tree auto deallocator +// +// 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_AUTO_DEALLOCATOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template +class auto_deallocator +{ + auto_deallocator(auto_deallocator const&); + auto_deallocator & operator=(auto_deallocator const&); +public: + typedef typename Alloc::pointer pointer; + inline auto_deallocator(Alloc & a, pointer p) : m_alloc(a), m_ptr(p) {} + inline ~auto_deallocator() { if ( m_ptr ) boost::container::allocator_traits::deallocate(m_alloc, m_ptr, 1); } + inline void release() { m_ptr = 0; } + inline pointer ptr() { return m_ptr; } +private: + Alloc & m_alloc; + pointer m_ptr; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_AUTO_DEALLOCATOR_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/concept.hpp b/include/boost/geometry/index/detail/rtree/node/concept.hpp new file mode 100644 index 000000000..30fa44d26 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/concept.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 +struct node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (node)); +}; + +template +struct internal_node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (internal_node)); +}; + +template +struct leaf +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (leaf)); +}; + +template +struct visitor +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (visitor)); +}; + +template +class allocators +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TAG_TYPE, + (allocators)); +}; + +template +struct create_node +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_NODE_TYPE, + (create_node)); +}; + +template +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 diff --git a/include/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp b/include/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp new file mode 100644 index 000000000..477d937db --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/dynamic_visitor.hpp @@ -0,0 +1,88 @@ +// Boost.Geometry Index +// +// R-tree nodes dynamic visitor and nodes base type +// +// 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_DYNAMIC_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// visitor forward declaration +template +struct dynamic_visitor; + +// node + +template +struct dynamic_node +{ + virtual ~dynamic_node() {} + virtual void apply_visitor(dynamic_visitor &) = 0; + virtual void apply_visitor(dynamic_visitor &) const = 0; +}; + +// nodes variants forward declarations + +template +struct dynamic_internal_node; + +template +struct dynamic_leaf; + +// visitor + +template +struct dynamic_visitor +{ + typedef dynamic_internal_node internal_node; + typedef dynamic_leaf leaf; + + virtual ~dynamic_visitor() {} + + virtual void operator()(internal_node const&) = 0; + virtual void operator()(leaf const&) = 0; +}; + +template +struct dynamic_visitor +{ + typedef dynamic_internal_node internal_node; + typedef dynamic_leaf leaf; + + virtual ~dynamic_visitor() {} + + virtual void operator()(internal_node &) = 0; + virtual void operator()(leaf &) = 0; +}; + +// nodes conversion + +template +inline Derived & get(dynamic_node & n) +{ + BOOST_GEOMETRY_INDEX_ASSERT(dynamic_cast(&n), "can't cast to a Derived type"); + return static_cast(n); +} + +// apply visitor + +template +inline void apply_visitor(Visitor & v, Visitable & n) +{ + BOOST_GEOMETRY_INDEX_ASSERT(&n, "null ptr"); + n.apply_visitor(v); +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_DYNAMIC_VISITOR_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/node.hpp b/include/boost/geometry/index/detail/rtree/node/node.hpp new file mode 100644 index 000000000..d35dcbb6f --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/node.hpp @@ -0,0 +1,173 @@ +// Boost.Geometry Index +// +// R-tree 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_NODE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_HPP + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// elements box + +template +inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr) +{ + Box result; + + if ( first == last ) + { + geometry::assign_inverse(result); + return result; + } + + geometry::convert(element_indexable(*first, tr), result); + ++first; + + for ( ; first != last ; ++first ) + geometry::expand(result, element_indexable(*first, tr)); + + return result; +} + +// destroys subtree if the element is internal node's element +template +struct destroy_element +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef rtree::node_auto_ptr node_auto_ptr; + + inline static void apply(typename internal_node::elements_type::value_type & element, Allocators & allocators) + { + node_auto_ptr 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 +struct destroy_elements +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef rtree::node_auto_ptr node_auto_ptr; + + inline static void apply(typename internal_node::elements_type & elements, Allocators & allocators) + { + for ( size_t i = 0 ; i < elements.size() ; ++i ) + { + node_auto_ptr dummy(elements[i].second, allocators); + elements[i].second = 0; + } + } + + inline static void apply(typename leaf::elements_type &, Allocators &) + {} + + inline static void apply(typename internal_node::elements_type::iterator first, + typename internal_node::elements_type::iterator last, + Allocators & allocators) + { + for ( ; first != last ; ++first ) + { + node_auto_ptr dummy(first->second, allocators); + first->second = 0; + } + } + + inline static void apply(typename leaf::elements_type::iterator /*first*/, + typename leaf::elements_type::iterator /*last*/, + Allocators & /*allocators*/) + {} +}; + +// clears node, deletes all subtrees stored in node +template +struct clear_node +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + inline static void apply(node & node, Allocators & allocators) + { + rtree::visitors::is_leaf ilv; + rtree::apply_visitor(ilv, node); + if ( ilv.result ) + { + apply(rtree::get(node), allocators); + } + else + { + apply(rtree::get(node), allocators); + } + } + + inline static void apply(internal_node & internal_node, Allocators & allocators) + { + destroy_elements::apply(rtree::elements(internal_node), allocators); + rtree::elements(internal_node).clear(); + } + + inline static void apply(leaf & leaf, Allocators &) + { + rtree::elements(leaf).clear(); + } +}; + +template +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 diff --git a/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp b/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp new file mode 100644 index 000000000..5e25dcfbf --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/node_auto_ptr.hpp @@ -0,0 +1,79 @@ +// Boost.Geometry Index +// +// R-tree node auto ptr +// +// 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_NODE_AUTO_PTR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_AUTO_PTR_HPP + +#include + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template +class node_auto_ptr + : boost::noncopyable +{ + typedef typename rtree::node::type node; + typedef typename Allocators::node_pointer pointer; + +public: + node_auto_ptr(pointer ptr, Allocators & allocators) + : m_ptr(ptr) + , m_allocators(allocators) + {} + + ~node_auto_ptr() + { + reset(); + } + + void reset(pointer ptr = 0) + { + if ( m_ptr ) + { + detail::rtree::visitors::destroy 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_NODE_AUTO_PTR_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp b/include/boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp new file mode 100644 index 000000000..7d7bc401e --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/node_d_mem_dynamic.hpp @@ -0,0 +1,329 @@ +// Boost.Geometry Index +// +// R-tree nodes based on run-time polymorphism, storing std::vectors +// +// 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_NODE_DEFAULT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template +struct dynamic_internal_node + : public dynamic_node +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + rtree::ptr_pair + >::other elements_allocator_type; + + typedef boost::container::vector< + rtree::ptr_pair, + elements_allocator_type + > elements_type; + + template + inline dynamic_internal_node(Al const& al) + : elements(al) + {} + + void apply_visitor(dynamic_visitor & v) { v(*this); } + void apply_visitor(dynamic_visitor & v) const { v(*this); } + + elements_type elements; +}; + +template +struct dynamic_leaf + : public dynamic_node +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef boost::container::vector< + Value, + elements_allocator_type + > elements_type; + + template + inline dynamic_leaf(Al const& al) + : elements(al) + {} + + void apply_visitor(dynamic_visitor & v) { v(*this); } + void apply_visitor(dynamic_visitor & v) const { v(*this); } + + elements_type elements; +}; + +// nodes traits + +template +struct node +{ + typedef dynamic_node type; +}; + +template +struct internal_node +{ + typedef dynamic_internal_node type; +}; + +template +struct leaf +{ + typedef dynamic_leaf type; +}; + +// visitor traits + +template +struct visitor +{ + typedef dynamic_visitor type; +}; + +// element's indexable type + +template +struct element_indexable_type +{ + typedef typename indexable_type::type type; +}; + +template +struct element_indexable_type< + rtree::ptr_pair, + Translator +> +{ + typedef First type; +}; + +// element's indexable getter + +template +typename result_type::type +element_indexable(Element const& el, Translator const& tr) +{ + return tr(el); +} + +template +First const& +element_indexable(rtree::ptr_pair const& el, Translator const& /*tr*/) +{ + return el.first; +} + +// nodes elements + +template +struct elements_type +{ + typedef typename Node::elements_type type; +}; + +template +inline typename elements_type::type & +elements(Node & n) +{ + return n.elements; +} + +template +inline typename elements_type::type const& +elements(Node const& n) +{ + return n.elements; +} + +// elements derived type +template +struct container_from_elements_type +{ + typedef boost::container::vector type; +}; + +// allocators + +template +class allocators + : public Allocator::template rebind< + typename internal_node, node_d_mem_dynamic_tag>::type + >::other + , public Allocator::template rebind< + typename leaf, node_d_mem_dynamic_tag>::type + >::other +{ +public: + typedef typename Allocator::size_type size_type; + + typedef typename Allocator::template rebind< + typename node::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node::type + >::other internal_node_allocator_type; + + typedef typename Allocator::template rebind< + typename leaf::type + >::other leaf_allocator_type; + + inline allocators() + : internal_node_allocator_type() + , leaf_allocator_type() + {} + + inline explicit allocators(Allocator 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())) + {} + + 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 + 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 +struct create_dynamic_node +{ + template + static inline BaseNodePtr apply(AllocNode & alloc_node) + { + typedef boost::container::allocator_traits Al; + typedef typename Al::pointer P; + + P p = Al::allocate(alloc_node, 1); + + if ( 0 == p ) + throw std::bad_alloc(); // TODO throw different exception + + auto_deallocator deallocator(alloc_node, p); + + Al::construct(alloc_node, boost::addressof(*p), alloc_node); + + deallocator.release(); + return p; + } +}; + +// destroy_node_impl + +template +struct destroy_dynamic_node +{ + template + static inline void apply(AllocNode & alloc_node, BaseNodePtr n) + { + typedef boost::container::allocator_traits Al; + typedef typename Al::pointer P; + + P p(&static_cast(rtree::get(*n))); + Al::destroy(alloc_node, boost::addressof(*p)); + Al::deallocate(alloc_node, p, 1); + } +}; + +// create_node + +template +struct create_node< + Allocators, + dynamic_internal_node +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_dynamic_node< + typename Allocators::node_pointer, + dynamic_internal_node + >::apply(allocators.internal_node_allocator()); + } +}; + +template +struct create_node< + Allocators, + dynamic_leaf +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_dynamic_node< + typename Allocators::node_pointer, + dynamic_leaf + >::apply(allocators.leaf_allocator()); + } +}; + +// destroy_node + +template +struct destroy_node< + Allocators, + dynamic_internal_node +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_dynamic_node< + dynamic_internal_node + >::apply(allocators.internal_node_allocator(), n); + } +}; + +template +struct destroy_node< + Allocators, + dynamic_leaf +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_dynamic_node< + dynamic_leaf + >::apply(allocators.leaf_allocator(), n); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp b/include/boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp new file mode 100644 index 000000000..a73437045 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/node_d_mem_static.hpp @@ -0,0 +1,172 @@ +// Boost.Geometry Index +// +// R-tree nodes based on runtime-polymorphism, storing static-size containers +// +// 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_NODE_DEFAULT_STATIC_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template +struct dynamic_internal_node + : public dynamic_node +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + rtree::ptr_pair + >::other elements_allocator_type; + + typedef detail::varray< + rtree::ptr_pair, + Parameters::max_elements + 1, + elements_allocator_type + > elements_type; + + template + inline dynamic_internal_node(Alloc const&) {} + + void apply_visitor(dynamic_visitor & v) { v(*this); } + void apply_visitor(dynamic_visitor & v) const { v(*this); } + + elements_type elements; +}; + +template +struct dynamic_leaf + : public dynamic_node +{ + typedef typename Allocators::leaf_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef detail::varray< + Value, + Parameters::max_elements + 1, + elements_allocator_type + > elements_type; + + template + inline dynamic_leaf(Alloc const&) {} + + void apply_visitor(dynamic_visitor & v) { v(*this); } + void apply_visitor(dynamic_visitor & v) const { v(*this); } + + elements_type elements; +}; + +// nodes traits + +template +struct node +{ + typedef dynamic_node type; +}; + +template +struct internal_node +{ + typedef dynamic_internal_node type; +}; + +template +struct leaf +{ + typedef dynamic_leaf type; +}; + +template +struct visitor +{ + typedef dynamic_visitor type; +}; + +// elements derived type +template +struct container_from_elements_type, NewValue> +{ + typedef detail::varray type; +}; + +// allocators + +template +class allocators + : public Allocator::template rebind< + typename internal_node< + Value, Parameters, Box, + allocators, + node_d_mem_static_tag + >::type + >::other + , public Allocator::template rebind< + typename leaf< + Value, Parameters, Box, + allocators, + node_d_mem_static_tag + >::type + >::other +{ +public: + typedef typename Allocator::size_type size_type; + + typedef typename Allocator::template rebind< + typename node::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node::type + >::other internal_node_allocator_type; + + typedef typename Allocator::template rebind< + typename leaf::type + >::other leaf_allocator_type; + + inline allocators() + : internal_node_allocator_type() + , leaf_allocator_type() + {} + + inline explicit allocators(Allocator 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())) + {} + + 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 + 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_NODE_DEFAULT_STATIC_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp b/include/boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp new file mode 100644 index 000000000..b3331e9c8 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/node_s_mem_dynamic.hpp @@ -0,0 +1,249 @@ +// Boost.Geometry Index +// +// R-tree nodes based on Boost.Variant, storing std::vectors +// +// 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_NODE_DEFAULT_VARIANT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_VARIANT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes default types + +template +struct static_internal_node +{ + typedef typename Allocators::node_allocator_type::template rebind< + rtree::ptr_pair + >::other elements_allocator_type; + + typedef boost::container::vector< + rtree::ptr_pair, + elements_allocator_type + > elements_type; + + template + inline static_internal_node(Al const& al) + : elements(al) + {} + + elements_type elements; +}; + +template +struct static_leaf +{ + typedef typename Allocators::node_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef boost::container::vector< + Value, + elements_allocator_type + > elements_type; + + template + inline static_leaf(Al const& al) + : elements(al) + {} + + elements_type elements; +}; + +// nodes traits + +template +struct node +{ + typedef boost::variant< + static_leaf, + static_internal_node + > type; +}; + +template +struct internal_node +{ + typedef static_internal_node type; +}; + +template +struct leaf +{ + typedef static_leaf type; +}; + +// visitor traits + +template +struct visitor +{ + typedef static_visitor<> type; +}; + +// allocators + +template +class allocators + : public Allocator::template rebind< + typename node, node_s_mem_dynamic_tag>::type + >::other +{ +public: + typedef typename Allocator::size_type size_type; + + typedef typename Allocator::template rebind< + typename node::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename node::type + >::other node_allocator_type; + + inline allocators() + : node_allocator_type() + {} + + inline explicit allocators(Allocator const& alloc) + : node_allocator_type(alloc) + {} + + inline allocators(BOOST_FWD_REF(allocators) a) + : node_allocator_type(boost::move(a.node_allocator())) + {} + + void swap(allocators & a) + { + boost::swap(node_allocator(), a.node_allocator()); + } + + bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); } + template + 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 +struct create_static_node +{ + template + static inline VariantPtr apply(AllocNode & alloc_node) + { + typedef boost::container::allocator_traits Al; + typedef typename Al::pointer P; + + P p = Al::allocate(alloc_node, 1); + + if ( 0 == p ) + throw std::bad_alloc(); + + auto_deallocator deallocator(alloc_node, p); + + Al::construct(alloc_node, boost::addressof(*p), Node(alloc_node)); // implicit cast to Variant + + deallocator.release(); + return p; + } +}; + +// destroy_node_variant + +template +struct destroy_static_node +{ + template + static inline void apply(AllocNode & alloc_node, VariantPtr n) + { + typedef boost::container::allocator_traits Al; + + Al::destroy(alloc_node, boost::addressof(*n)); + Al::deallocate(alloc_node, n, 1); + } +}; + +// create_node + +template +struct create_node< + Allocators, + static_internal_node +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_internal_node + >::apply(allocators.node_allocator()); + } +}; + +template +struct create_node< + Allocators, + static_leaf +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_leaf + >::apply(allocators.node_allocator()); + } +}; + +// destroy_node + +template +struct destroy_node< + Allocators, + static_internal_node +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_static_node< + static_internal_node + >::apply(allocators.node_allocator(), n); + } +}; + +template +struct destroy_node< + Allocators, + static_leaf +> +{ + static inline void apply(Allocators & allocators, typename Allocators::node_pointer n) + { + destroy_static_node< + static_leaf + >::apply(allocators.node_allocator(), n); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_VARIANT_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp b/include/boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp new file mode 100644 index 000000000..252db0c82 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/node_s_mem_static.hpp @@ -0,0 +1,177 @@ +// Boost.Geometry Index +// +// R-tree nodes based on Boost.Variant, storing static-size containers +// +// 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_NODE_DEFAULT_STATIC_VARIANT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_VARIANT_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes default types + +template +struct static_internal_node +{ + typedef typename Allocators::node_allocator_type::template rebind< + rtree::ptr_pair + >::other elements_allocator_type; + + typedef detail::varray< + rtree::ptr_pair, + Parameters::max_elements + 1, + elements_allocator_type + > elements_type; + + template + inline static_internal_node(Alloc const&) {} + + elements_type elements; +}; + +template +struct static_leaf +{ + typedef typename Allocators::node_allocator_type::template rebind< + Value + >::other elements_allocator_type; + + typedef detail::varray< + Value, + Parameters::max_elements + 1, + elements_allocator_type + > elements_type; + + template + inline static_leaf(Alloc const&) {} + + elements_type elements; +}; + +// nodes traits + +template +struct node +{ + typedef boost::variant< + static_leaf, + static_internal_node + > type; +}; + +template +struct internal_node +{ + typedef static_internal_node type; +}; + +template +struct leaf +{ + typedef static_leaf type; +}; + +// visitor traits + +template +struct visitor +{ + typedef static_visitor<> type; +}; + +// allocators + +template +struct allocators + : public Allocator::template rebind< + typename node, node_s_mem_static_tag>::type + >::other +{ +public: + typedef typename Allocator::size_type size_type; + + typedef typename Allocator::template rebind< + typename node::type + >::other::pointer node_pointer; + + typedef typename Allocator::template rebind< + typename internal_node::type + >::other::pointer internal_node_pointer; + + typedef typename Allocator::template rebind< + typename node::type + >::other node_allocator_type; + + inline allocators() + : node_allocator_type() + {} + + inline explicit allocators(Allocator const& alloc) + : node_allocator_type(alloc) + {} + + inline allocators(BOOST_FWD_REF(allocators) a) + : node_allocator_type(boost::move(a.node_allocator())) + {} + + void swap(allocators & a) + { + boost::swap(node_allocator(), a.node_allocator()); + } + + bool operator==(allocators const& a) const { return node_allocator() == a.node_allocator(); } + template + 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 + +template +struct create_node< + Allocators, + static_internal_node +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_internal_node + >::template apply(allocators.node_allocator()); + } +}; + +template +struct create_node< + Allocators, + static_leaf +> +{ + static inline typename Allocators::node_pointer + apply(Allocators & allocators) + { + return create_static_node< + typename Allocators::node_pointer, + static_leaf + >::template apply(allocators.node_allocator()); + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_NODE_DEFAULT_STATIC_VARIANT_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/pairs.hpp b/include/boost/geometry/index/detail/rtree/node/pairs.hpp new file mode 100644 index 000000000..8cdbdd131 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/pairs.hpp @@ -0,0 +1,69 @@ +// 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 + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template +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 inline +ptr_pair +make_ptr_pair(First const& f, Pointer s) +{ + return ptr_pair(f, s); +} + +template +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 inline +exclusive_ptr_pair +make_exclusive_ptr_pair(First const& f, Pointer s) +{ + return exclusive_ptr_pair(f, s); +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_PAIRS_HPP diff --git a/include/boost/geometry/index/detail/rtree/node/static_visitor.hpp b/include/boost/geometry/index/detail/rtree/node/static_visitor.hpp new file mode 100644 index 000000000..9b74b1e41 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/node/static_visitor.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry Index +// +// R-tree nodes static visitor related code +// +// 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_STATIC_VISITOR_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_STATIC_VISITOR_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// nodes variants forward declarations + +template +struct static_internal_node; + +template +struct static_leaf; + +// nodes conversion + +template +inline V & get( + boost::variant< + static_leaf, + static_internal_node + > & v) +{ + return boost::get(v); +} + +// apply visitor + +template +inline void apply_visitor(Visitor & v, + boost::variant< + static_leaf, + static_internal_node + > & n) +{ + boost::apply_visitor(v, n); +} + +template +inline void apply_visitor(Visitor & v, + boost::variant< + static_leaf, + static_internal_node + > const& n) +{ + boost::apply_visitor(v, n); +} + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_NODE_STATIC_VISITOR_HPP diff --git a/include/boost/geometry/index/detail/rtree/options.hpp b/include/boost/geometry/index/detail/rtree/options.hpp new file mode 100644 index 000000000..b1bb60df1 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/options.hpp @@ -0,0 +1,155 @@ +// Boost.Geometry Index +// +// R-tree options, algorithms, parameters +// +// 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_OPTIONS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP + +#include + +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_d_mem_dynamic_tag {}; +struct node_d_mem_static_tag {}; +struct node_s_mem_dynamic_tag {}; +struct node_s_mem_static_tag {}; + +template +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 +struct options_type +{ + // TODO: awulkiew - use static assert +}; + +template +struct options_type< index::linear > +{ + typedef options< + index::linear, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + linear_tag, + node_d_mem_static_tag + > type; +}; + +template +struct options_type< index::quadratic > +{ + typedef options< + index::quadratic, + insert_default_tag, + choose_by_content_diff_tag, + split_default_tag, + quadratic_tag, + node_d_mem_static_tag + > type; +}; + +template +struct options_type< index::rstar > +{ + typedef options< + index::rstar, + insert_reinsert_tag, + choose_by_overlap_diff_tag, + split_default_tag, + rstar_tag, + node_d_mem_static_tag + > type; +}; + +//template +//struct options_type< kmeans > +//{ +// typedef options< +// kmeans, +// insert_default_tag, +// choose_by_content_diff_tag, // change it? +// split_kmeans_tag, +// int, // dummy tag - not used for now +// node_d_mem_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_d_mem_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_d_mem_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_d_mem_dynamic_tag + > type; +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_OPTIONS_HPP diff --git a/include/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp b/include/boost/geometry/index/detail/rtree/quadratic/quadratic.hpp new file mode 100644 index 000000000..837ddbeec --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/quadratic/quadratic.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 + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_QUADRATIC_HPP diff --git a/include/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp b/include/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp new file mode 100644 index 000000000..15ae3fa44 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/quadratic/redistribute_elements.hpp @@ -0,0 +1,293 @@ +// Boost.Geometry Index +// +// R-tree quadratic 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_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_QUADRATIC_REDISTRIBUTE_ELEMENTS_HPP + +#include + +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace quadratic { + +template +struct pick_seeds +{ + typedef typename Elements::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_type; + typedef Box box_type; + typedef typename index::detail::default_content_result::type content_type; + + static inline void apply(Elements const& elements, + Parameters const& parameters, + Translator const& tr, + size_t & seed1, + size_t & seed2) + { + 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; + geometry::convert(ind1, enlarged_box); + geometry::expand(enlarged_box, ind2); + + content_type free_content = (index::detail::content(enlarged_box) - index::detail::content(ind1)) - index::detail::content(ind2); + + if ( greatest_free_content < free_content ) + { + greatest_free_content = free_content; + seed1 = i; + seed2 = j; + } + } + } + + BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(parameters) + } +}; + +} // namespace quadratic + +template +struct redistribute_elements +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename index::detail::default_content_result::type content_type; + + template + 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::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename rtree::element_indexable_type::type indexable_type; + typedef typename index::detail::traits::coordinate_type::type coordinate_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 + elements_type elements_copy(elements1); // MAY THROW, STRONG (alloc, copy) + elements_type elements_backup(elements1); // MAY THROW, STRONG (alloc, copy) + + // calculate initial seeds + size_t seed1 = 0; + size_t seed2 = 0; + quadratic::pick_seeds< + elements_type, + parameters_type, + Translator, + Box + >::apply(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"); + + 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 + geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1); + geometry::convert(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 elements_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 elements_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; + } + } + catch(...) + { + //elements_copy.clear(); + elements1.clear(); + elements2.clear(); + + rtree::destroy_elements::apply(elements_backup, allocators); + //elements_backup.clear(); + + throw; // RETHROW, BASIC + } + } + + // TODO: awulkiew - change following function to static member of the pick_next class? + + template + 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::type element_type; + typedef typename rtree::element_indexable_type::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 diff --git a/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp b/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp new file mode 100644 index 000000000..20e953dff --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/rstar/choose_next_node.hpp @@ -0,0 +1,246 @@ +// Boost.Geometry Index +// +// R-tree R*-tree next node choosing 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_CHOOSE_NEXT_NODE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_CHOOSE_NEXT_NODE_HPP + +#include + +#include + +#include +#include +#include + +#include +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +template +class choose_next_node +{ + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename rtree::elements_type::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::type content_type; + +public: + template + 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); + + // children are leafs + if ( node_relative_level <= 1 ) + { + if ( 0 < parameters.get_overlap_cost_threshold() && + parameters.get_overlap_cost_threshold() < children.size() ) + return choose_by_nearly_minimum_overlap_cost(children, indexable, parameters.get_overlap_cost_threshold()); + else + return choose_by_minimum_overlap_cost(children, indexable); + } + // children are internal nodes + else + return choose_by_minimum_content_cost(children, indexable); + + BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(parameters) + } + +private: + template + static inline size_t choose_by_minimum_overlap_cost(children_type const& children, + Indexable const& indexable) + { + size_t children_count = children.size(); + + // 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::max)(); + content_type smallest_content_diff = (std::numeric_limits::max)(); + content_type smallest_content = (std::numeric_limits::max)(); + + // for each child node + for (size_t i = 0 ; i < 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); + + // calculate content and content diff + content_type content = index::detail::content(ch_i.first); + content_type content_diff = index::detail::content(box_exp) - content; + + content_type overlap = 0; + content_type overlap_exp = 0; + + // calculate overlap + for ( size_t j = 0 ; j < children_count ; ++j ) + { + if ( i != j ) + { + child_type const& ch_j = children[j]; + + overlap += index::detail::intersection_content(ch_i.first, ch_j.first); + overlap_exp += index::detail::intersection_content(box_exp, ch_j.first); + } + } + + content_type overlap_diff = overlap_exp - overlap; + + // 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 + static inline size_t choose_by_nearly_minimum_overlap_cost(children_type const& children, + Indexable const& indexable, + size_t overlap_cost_threshold) + { + const size_t children_count = children.size(); + + // create container of children sorted by content enlargement needed to include the new value + std::vector< boost::tuple > sorted_children(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); + + sorted_children[i] = boost::make_tuple(i, content_diff, content); + } + + // sort by content_diff + std::sort(sorted_children.begin(), sorted_children.end(), content_diff_less); + + BOOST_GEOMETRY_INDEX_ASSERT(overlap_cost_threshold <= children_count, "there are not enough children"); + + // for overlap_cost_threshold child nodes find the one with smallest overlap value + size_t choosen_index = 0; + content_type smallest_overlap_diff = (std::numeric_limits::max)(); + + // for each node + for (size_t i = 0 ; i < overlap_cost_threshold ; ++i ) + { + size_t child_index = boost::get<0>(sorted_children[i]); + + typedef typename children_type::value_type child_type; + child_type const& ch_i = children[child_index]; + + Box box_exp(ch_i.first); + // calculate expanded box of child node ch_i + geometry::expand(box_exp, indexable); + + content_type overlap = 0; + content_type overlap_exp = 0; + + // calculate overlap + for ( size_t j = 0 ; j < children_count ; ++j ) + { + if ( child_index != j ) + { + child_type const& ch_j = children[j]; + + overlap += index::detail::intersection_content(ch_i.first, ch_j.first); + overlap_exp += index::detail::intersection_content(box_exp, ch_j.first); + } + } + + content_type overlap_diff = overlap_exp - overlap; + + // update result + if ( overlap_diff < smallest_overlap_diff ) + { + smallest_overlap_diff = overlap_diff; + choosen_index = child_index; + } + } + + return choosen_index; + } + + static inline bool content_diff_less(boost::tuple const& p1, boost::tuple 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 + 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::max)(); + content_type smallest_content = (std::numeric_limits::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 diff --git a/include/boost/geometry/index/detail/rtree/rstar/insert.hpp b/include/boost/geometry/index/detail/rtree/rstar/insert.hpp new file mode 100644 index 000000000..896286be0 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/rstar/insert.hpp @@ -0,0 +1,542 @@ +// Boost.Geometry Index +// +// R-tree R*-tree insert 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_INSERT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +namespace rstar { + +template +class remove_elements_to_reinsert +{ +public: + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename Options::parameters_type parameters_type; + typedef typename Allocators::internal_node_pointer internal_node_pointer; + + template + 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::type elements_type; + typedef typename elements_type::value_type element_type; + typedef typename geometry::point_type::type point_type; + // TODO: awulkiew - change second point_type to the point type of the Indexable? + typedef typename geometry::default_distance_result::type distance_type; + + elements_type & elements = rtree::elements(n); + + const size_t elements_count = parameters.get_max_elements() + 1; + const size_t reinserted_elements_count = parameters.get_reinserted_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 + >::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); // 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) + } + + 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) + } + } + catch(...) + { + elements.clear(); + + for ( typename sorted_elements_type::iterator it = sorted_elements.begin() ; + it != sorted_elements.end() ; ++it ) + { + destroy_element::apply(it->second, allocators); + } + + throw; // RETHROW + } + + BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(parameters) + } + +private: + template + static inline bool distances_asc( + std::pair const& d1, + std::pair const& d2) + { + return d1.first < d2.first; + } + + template + static inline bool distances_dsc( + std::pair const& d1, + std::pair const& d2) + { + return d1.first > d2.first; + } +}; + +template +struct level_insert_elements_type +{ + typedef typename rtree::elements_type< + typename rtree::internal_node::type + >::type type; +}; + +template +struct level_insert_elements_type<0, Value, Value, Options, Box, Allocators> +{ + typedef typename rtree::elements_type< + typename rtree::leaf::type + >::type type; +}; + +template +struct level_insert_base + : public detail::insert +{ + typedef detail::insert base; + typedef typename base::node node; + typedef typename base::internal_node internal_node; + typedef typename base::leaf leaf; + + typedef typename level_insert_elements_type::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; + + inline level_insert_base(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t relative_level) + : base(root, leafs_level, element, parameters, translator, allocators, relative_level) + , result_relative_level(0) + {} + + template + 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::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(*base::m_root_node), "node should be the root node"); + base::split(n); // MAY THROW (V, E: alloc, copy, N: alloc) + } + } + } + + template + 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 + inline void recalculate_aabb_if_necessary(Node &n) const + { + if ( !result_elements.empty() && !base::m_traverse_data.current_is_root() ) + { + // calulate node's new box + base::m_traverse_data.current_element().first = + elements_box(rtree::elements(n).begin(), rtree::elements(n).end(), base::m_translator); + } + } + + size_t result_relative_level; + result_elements_type result_elements; +}; + +template +struct level_insert + : public level_insert_base +{ + typedef level_insert_base 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; + + inline level_insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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"); + + try + { + // push new child node + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy) + } + catch(...) + { + // NOTE: exception-safety + // if the insert fails above, the element won't be stored in the tree, so delete it + + rtree::visitors::destroy del_v(base::m_element.second, base::m_allocators); + rtree::apply_visitor(del_v, *base::m_element.second); + + throw; // RETHROW + } + + // 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 +struct level_insert + : public level_insert_base +{ + typedef level_insert_base 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; + + inline level_insert(node_pointer & root, + size_t & leafs_level, + Value const& v, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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::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 +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; + + inline level_insert(node_pointer & root, + size_t & leafs_level, + Value const& v, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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::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 +class insert + : public rtree::visitor::type +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename Allocators::node_pointer node_pointer; + +public: + inline insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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 & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n)) + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get(*m_root), "current node should be the root"); + + 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) + } + } + + inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(n)) + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get(*m_root), "current node should be the root"); + + 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"); + } + +private: + template + 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); + + try + { + rtree::apply_visitor(lins_v, *m_root); // MAY THROW (V, E: alloc, copy, N: alloc) + } + catch(...) + { + ++it; + for ( ; it != elements.rend() ; ++it) + rtree::destroy_element::apply(*it, m_allocators); + throw; // RETHROW + } + + 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_t & m_leafs_level; + Element const& m_element; + + parameters_type const& m_parameters; + Translator const& m_translator; + + size_t m_relative_level; + + Allocators & m_allocators; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_INSERT_HPP diff --git a/include/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp b/include/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp new file mode 100644 index 000000000..08cd51dbf --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/rstar/redistribute_elements.hpp @@ -0,0 +1,407 @@ +// Boost.Geometry Index +// +// R-tree R*-tree 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_RSTAR_REDISTRIBUTE_ELEMENTS_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP + +#include +#include +#include + +#include +#include +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +namespace rstar { + +template +class element_axis_corner_less +{ +public: + element_axis_corner_less(Translator const& tr) + : m_tr(tr) + {} + + bool operator()(Element const& e1, Element const& e2) const + { + return index::detail::get(rtree::element_indexable(e1, m_tr)) + < index::detail::get(rtree::element_indexable(e2, m_tr)); + } + +private: + Translator const& m_tr; +}; + +template +struct choose_split_axis_and_index_for_corner +{ + typedef typename index::detail::default_margin_result::type margin_type; + typedef typename index::detail::default_content_result::type content_type; + + template + 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; + + 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) + + // sort elements + element_axis_corner_less elements_less(translator); + std::sort(elements_copy.begin(), elements_copy.end(), elements_less); // MAY THROW, BASIC (copy) + + // init outputs + choosen_index = parameters.get_min_elements(); + sum_of_margins = 0; + smallest_overlap = (std::numeric_limits::max)(); + smallest_content = (std::numeric_limits::max)(); + + // calculate sum of margins for all distributions + size_t index_last = parameters.get_max_elements() - parameters.get_min_elements() + 2; + for ( size_t i = parameters.get_min_elements() ; 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(elements_copy.begin(), elements_copy.begin() + i, translator); + Box box2 = rtree::elements_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); + + if ( ovl < smallest_overlap || (ovl == smallest_overlap && con <= smallest_content) ) + { + choosen_index = i; + smallest_overlap = ovl; + smallest_content = con; + } + } + + BOOST_GEOMETRY_INDEX_DETAIL_USE_PARAM(parameters) + } +}; + +template +struct choose_split_axis_and_index_for_axis +{ + //BOOST_STATIC_ASSERT(0); +}; + +template +struct choose_split_axis_and_index_for_axis +{ + typedef typename index::detail::default_margin_result::type margin_type; + typedef typename index::detail::default_content_result::type content_type; + + template + 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::max)(); + content_type con1 = (std::numeric_limits::max)(); + + choose_split_axis_and_index_for_corner:: + 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::max)(); + content_type con2 = (std::numeric_limits::max)(); + + choose_split_axis_and_index_for_corner:: + 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 +struct choose_split_axis_and_index_for_axis +{ + typedef typename index::detail::default_margin_result::type margin_type; + typedef typename index::detail::default_content_result::type content_type; + + template + 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:: + apply(elements, choosen_index, + sum_of_margins, smallest_overlap, smallest_content, + parameters, translator); // MAY THROW, STRONG + + choosen_corner = min_corner; + } +}; + +template +struct choose_split_axis_and_index +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + typedef typename index::detail::default_margin_result::type margin_type; + typedef typename index::detail::default_content_result::type content_type; + + template + 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::type element_indexable_type; + + choose_split_axis_and_index:: + 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::max)(); + content_type content_val = (std::numeric_limits::max)(); + + choose_split_axis_and_index_for_axis< + Parameters, + Box, + Dimension - 1, + typename index::detail::traits::tag::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 +struct choose_split_axis_and_index +{ + typedef typename index::detail::default_margin_result::type margin_type; + typedef typename index::detail::default_content_result::type content_type; + + template + 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::type element_indexable_type; + + choosen_axis = 0; + + choose_split_axis_and_index_for_axis< + Parameters, + Box, + 0, + typename index::detail::traits::tag::type + >::apply(elements, choosen_corner, choosen_index, smallest_sum_of_margins, smallest_overlap, smallest_content, parameters, translator); // MAY THROW + } +}; + +template +struct partial_sort +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + template + static inline void apply(Elements & elements, const size_t axis, const size_t index, Translator const& tr) + { + if ( axis < Dimension - 1 ) + { + partial_sort::apply(elements, axis, index, tr); // MAY THROW, BASIC (copy) + } + else + { + BOOST_GEOMETRY_INDEX_ASSERT(axis == Dimension - 1, "unexpected axis value"); + + typedef typename Elements::value_type element_type; + element_axis_corner_less less(tr); + std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) + } + } +}; + +template +struct partial_sort +{ + template + static inline void apply(Elements & elements, + const size_t BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(axis), + const size_t index, + Translator const& tr) + { + BOOST_GEOMETRY_INDEX_ASSERT(axis == 0, "unexpected axis value"); + + typedef typename Elements::value_type element_type; + element_axis_corner_less less(tr); + std::partial_sort(elements.begin(), elements.begin() + index, elements.end(), less); // MAY THROW, BASIC (copy) + } +}; + +} // namespace rstar + +template +struct redistribute_elements +{ + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename Options::parameters_type parameters_type; + + static const size_t dimension = index::detail::traits::dimension::value; + + typedef typename index::detail::default_margin_result::type margin_type; + typedef typename index::detail::default_content_result::type content_type; + + template + 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::type elements_type; + + elements_type & elements1 = rtree::elements(n); + elements_type & elements2 = rtree::elements(second_node); + + 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::max)(); + content_type smallest_overlap = (std::numeric_limits::max)(); + content_type smallest_content = (std::numeric_limits::max)(); + + rstar::choose_split_axis_and_index< + typename Options::parameters_type, + Box, + index::detail::traits::dimension::value + >::apply(elements1, + 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 < index::detail::traits::dimension::value, "unexpected value"); + BOOST_GEOMETRY_INDEX_ASSERT(split_corner == static_cast(min_corner) || split_corner == static_cast(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"); + + // copy original elements + elements_type elements_copy(elements1); // MAY THROW, STRONG + elements_type elements_backup(elements1); // MAY THROW, STRONG + + // TODO: awulkiew - check if std::partial_sort produces the same result as std::sort + if ( split_corner == static_cast(min_corner) ) + rstar::partial_sort + ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy) + else + rstar::partial_sort + ::apply(elements_copy, split_axis, split_index, translator); // MAY THROW, BASIC (copy) + + 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(elements1.begin(), elements1.end(), translator); + box2 = rtree::elements_box(elements2.begin(), elements2.end(), translator); + } + catch(...) + { + //elements_copy.clear(); + elements1.clear(); + elements2.clear(); + + rtree::destroy_elements::apply(elements_backup, allocators); + //elements_backup.clear(); + + throw; // RETHROW, BASIC + } + } +}; + +}} // namespace detail::rtree + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_REDISTRIBUTE_ELEMENTS_HPP diff --git a/include/boost/geometry/index/detail/rtree/rstar/rstar.hpp b/include/boost/geometry/index/detail/rtree/rstar/rstar.hpp new file mode 100644 index 000000000..ed3959c89 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/rstar/rstar.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 +#include +#include + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_RSTAR_RSTAR_HPP diff --git a/include/boost/geometry/index/detail/rtree/visitors/are_boxes_ok.hpp b/include/boost/geometry/index/detail/rtree/visitors/are_boxes_ok.hpp new file mode 100644 index 000000000..7c5470155 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/are_boxes_ok.hpp @@ -0,0 +1,144 @@ +// Boost.Geometry Index +// +// R-tree boxes 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_VISITORS_ARE_BOXES_OK_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ARE_BOXES_OK_HPP + +#include +#include + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +namespace visitors { + +template +class are_boxes_ok + : public rtree::visitor::type +{ + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::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::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; + geometry::convert(elements.front().first, box_exp); + for( typename elements_type::const_iterator it = elements.begin() + 1; + it != elements.end() ; ++it) + { + geometry::expand(box_exp, it->first); + } + + 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::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; + geometry::convert(m_tr(elements.front()), box_exp); + for(typename elements_type::const_iterator it = elements.begin() + 1; + it != elements.end() ; ++it) + { + geometry::expand(box_exp, m_tr(*it)); + } + + 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 + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_DEBUG_INTERFACE +#error "To use are_boxes_ok BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_DEBUG_INTERFACE should be defined before including the rtree" +#endif + +template +bool are_boxes_ok(index::rtree const& tree, + bool exact_match = true) +{ + typedef index::rtree rt; + + detail::rtree::visitors::are_boxes_ok< + typename rt::value_type, + typename rt::options_type, + typename rt::translator_type, + typename rt::box_type, + typename rt::allocators_type + > v(tree.translator(), exact_match); + + tree.apply_visitor(v); + + return v.result; +} + +}}}}} // namespace boost::geometry::index::detail::rtree + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ARE_BOXES_OK_HPP diff --git a/include/boost/geometry/index/detail/rtree/visitors/are_levels_ok.hpp b/include/boost/geometry/index/detail/rtree/visitors/are_levels_ok.hpp new file mode 100644 index 000000000..f0d2c0823 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/are_levels_ok.hpp @@ -0,0 +1,114 @@ +// 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_VISITORS_ARE_LEVELS_OK_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ARE_LEVELS_OK_HPP + +#include + +namespace boost { namespace geometry { namespace index { namespace detail { namespace rtree { + +namespace visitors { + +template +class are_levels_ok + : public rtree::visitor::type +{ + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + +public: + inline are_levels_ok(Translator const& tr) + : result(true), m_tr(tr), m_leafs_level((std::numeric_limits::max)()), m_current_level(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type::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::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::max)() ) + { + m_leafs_level = m_current_level; + } + else if ( m_leafs_level != m_current_level ) + { + result = false; + } + } + + bool result; + +private: + Translator const& m_tr; + size_t m_leafs_level; + size_t m_current_level; +}; + +} // namespace visitors + +#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_DEBUG_INTERFACE +#error "To use are_levels_ok() BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_DEBUG_INTERFACE should be defined before including the rtree" +#endif + +template +bool are_levels_ok(index::rtree const& tree) +{ + typedef index::rtree rt; + + detail::rtree::visitors::are_levels_ok< + typename rt::value_type, + typename rt::options_type, + typename rt::translator_type, + typename rt::box_type, + typename rt::allocators_type + > v(tree.translator()); + + tree.apply_visitor(v); + + return v.result; +} + +}}}}} // namespace boost::geometry::index::detail::rtree + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_ARE_LEVELS_OK_HPP diff --git a/include/boost/geometry/index/detail/rtree/visitors/children_box.hpp b/include/boost/geometry/index/detail/rtree/visitors/children_box.hpp new file mode 100644 index 000000000..93726063b --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/children_box.hpp @@ -0,0 +1,55 @@ +// Boost.Geometry Index +// +// R-tree node children box calculating 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_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 +class children_box + : public rtree::visitor::type +{ + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::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::type elements_type; + elements_type const& elements = rtree::elements(n); + + m_result = rtree::elements_box(elements.begin(), elements.end(), m_tr); + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type::type elements_type; + elements_type const& elements = rtree::elements(n); + + m_result = rtree::elements_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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/copy.hpp b/include/boost/geometry/index/detail/rtree/visitors/copy.hpp new file mode 100644 index 000000000..8fc25ac80 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/copy.hpp @@ -0,0 +1,92 @@ +// Boost.Geometry Index +// +// R-tree deep copying 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_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 +class copy + : public rtree::visitor::type +{ +public: + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef rtree::node_auto_ptr node_auto_ptr; + 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::apply(m_allocators); // MAY THROW, STRONG (N: alloc) + node_auto_ptr new_node(raw_new_node, m_allocators); + + typedef typename rtree::elements_type::type elements_type; + elements_type & elements = rtree::elements(n); + + elements_type & elements_dst = rtree::elements(rtree::get(*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 + node_auto_ptr 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::apply(m_allocators); // MAY THROW, STRONG (N: alloc) + node_auto_ptr new_node(raw_new_node, m_allocators); + + typedef typename rtree::elements_type::type elements_type; + elements_type & elements = rtree::elements(l); + + elements_type & elements_dst = rtree::elements(rtree::get(*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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/count.hpp b/include/boost/geometry/index/detail/rtree/visitors/count.hpp new file mode 100644 index 000000000..203422f33 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/count.hpp @@ -0,0 +1,118 @@ +// Boost.Geometry Index +// +// R-tree count 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_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 +struct count + : public rtree::visitor::type +{ + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + inline count(Indexable const& i, Translator const& t) + : indexable(i), tr(t), found_count(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type::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(indexable, it->first) ) + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type::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 ( geometry::equals(indexable, tr(*it)) ) + { + ++found_count; + } + } + } + + Indexable const& indexable; + Translator const& tr; + typename Allocators::size_type found_count; +}; + +template +struct count + : public rtree::visitor::type +{ + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + inline count(Value const& v, Translator const& t) + : value(v), tr(t), found_count(0) + {} + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type::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(tr(value), it->first) ) + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type::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 ( tr.equals(value, *it) ) + { + ++found_count; + } + } + } + + Value const& value; + 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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/destroy.hpp b/include/boost/geometry/index/detail/rtree/visitors/destroy.hpp new file mode 100644 index 000000000..62722b97a --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/destroy.hpp @@ -0,0 +1,70 @@ +// Boost.Geometry Index +// +// R-tree destroying 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_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 +class destroy + : public rtree::visitor::type +{ +public: + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::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(*m_current_node), "invalid pointers"); + + node_pointer node_to_destroy = m_current_node; + + typedef typename rtree::elements_type::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::apply(m_allocators, node_to_destroy); + } + + inline void operator()(leaf & BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(l)) + { + BOOST_GEOMETRY_INDEX_ASSERT(&l == &rtree::get(*m_current_node), "invalid pointers"); + + rtree::destroy_node::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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/gl_draw.hpp b/include/boost/geometry/index/detail/rtree/visitors/gl_draw.hpp new file mode 100644 index 000000000..9a3c47f7b --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/gl_draw.hpp @@ -0,0 +1,221 @@ +// 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_VISITORS_GL_DRAW_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_GL_DRAW_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +namespace dispatch { + +template +struct gl_draw_point +{}; + +template +struct gl_draw_point +{ + static inline void apply(Point const& p, typename index::detail::traits::coordinate_type::type z) + { + glBegin(GL_POINT); + glVertex3f(geometry::get<0>(p), geometry::get<1>(p), z); + glEnd(); + } +}; + +template +struct gl_draw_box +{}; + +template +struct gl_draw_box +{ + static inline void apply(Box const& b, typename index::detail::traits::coordinate_type::type z) + { + glBegin(GL_LINE_LOOP); + glVertex3f(geometry::get(b), geometry::get(b), z); + glVertex3f(geometry::get(b), geometry::get(b), z); + glVertex3f(geometry::get(b), geometry::get(b), z); + glVertex3f(geometry::get(b), geometry::get(b), z); + glEnd(); + } +}; + +template +struct gl_draw_indexable +{ +}; + +template +struct gl_draw_indexable +{ + static const size_t dimension = index::detail::traits::dimension::value; + + static inline void apply(Indexable const& i, typename index::detail::traits::coordinate_type::type z) + { + gl_draw_box::apply(i, z); + } +}; + +template +struct gl_draw_indexable +{ + static const size_t dimension = index::detail::traits::dimension::value; + + static inline void apply(Indexable const& i, typename index::detail::traits::coordinate_type::type z) + { + gl_draw_point::apply(i, z); + } +}; + +} // namespace dispatch + +namespace detail { + +template +inline void gl_draw_indexable(Indexable const& i, typename index::detail::traits::coordinate_type::type z) +{ + dispatch::gl_draw_indexable< + Indexable, + typename index::detail::traits::tag::type + >::apply(i, z); +} + +} // namespace detail + +template +struct gl_draw : public rtree::visitor::type +{ + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + inline gl_draw(Translator const& t, + size_t level_first = 0, + size_t level_last = (std::numeric_limits::max)(), + typename index::detail::traits::coordinate_type::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::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::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::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::gl_draw_indexable(tr(*it), level_rel * z_mul); + } + } + } + + Translator const& tr; + size_t level_f; + size_t level_l; + typename index::detail::traits::coordinate_type::type z_mul; + + size_t level; +}; + +}}} // namespace detail::rtree::visitors + +template +void gl_draw(rtree const& tree, + size_t level_first = 0, + size_t level_last = (std::numeric_limits::max)(), + typename index::detail::traits::coordinate_type< + typename rtree::box_type + >::type z_coord_level_multiplier = 1 + ) +{ + typedef rtree rtree_type; + + typedef typename rtree_type::value_type value_type; + typedef typename rtree_type::options_type options_type; + typedef typename rtree_type::translator_type translator_type; + typedef typename rtree_type::box_type box_type; + typedef typename rtree_type::allocators_type allocators_type; + + if ( !tree.empty() ) + { + glColor3f(0.75f, 0.75f, 0.75f); + detail::rtree::visitors::detail::gl_draw_indexable(tree.bounds(), 0); + } + + detail::rtree::visitors::gl_draw + gl_draw_v(tree.translator(), level_first, level_last, z_coord_level_multiplier); + + tree.apply_visitor(gl_draw_v); +} + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_GL_DRAW_HPP diff --git a/include/boost/geometry/index/detail/rtree/visitors/insert.hpp b/include/boost/geometry/index/detail/rtree/visitors/insert.hpp new file mode 100644 index 000000000..0ba54d675 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/insert.hpp @@ -0,0 +1,511 @@ +// Boost.Geometry Index +// +// R-tree inserting 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_VISITORS_INSERT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_INSERT_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { + +// Default choose_next_node +template +class choose_next_node; + +template +class choose_next_node +{ +public: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef typename rtree::elements_type::type children_type; + + typedef typename index::detail::default_content_result::type content_type; + + template + 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::max)(); + content_type smallest_content = (std::numeric_limits::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 +struct redistribute_elements +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_REDISTRIBUTE_TAG_TYPE, + (redistribute_elements)); +}; + +// ----------------------------------------------------------------------- // + +// Split algorithm +template +class split +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_SPLIT_TAG_TYPE, + (split)); +}; + +// Default split algorithm +template +class split +{ +protected: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef rtree::node_auto_ptr node_auto_ptr; + +public: + typedef index::detail::varray< + typename rtree::elements_type::type::value_type, + 1 + > nodes_container_type; + + template + 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 ptr for automatic destruction on exception + node_auto_ptr second_node(rtree::create_node::apply(allocators), allocators); // MAY THROW, STRONG (N: alloc) + // create reference to the newly created node + Node & n2 = rtree::get(*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 +struct insert_traverse_data +{ + typedef typename rtree::elements_type::type elements_type; + typedef typename elements_type::value_type element_type; + + insert_traverse_data() + : parent(0), current_child_index(0), current_level(0) + {} + + void move_to_next_level(InternalNodePtr new_parent, size_t 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; + size_t current_child_index; + size_t current_level; +}; + +// Default insert visitor +template +class insert + : public rtree::visitor::type +{ +protected: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef rtree::node_auto_ptr node_auto_ptr; + typedef typename Allocators::node_pointer node_pointer; + typedef typename Allocators::internal_node_pointer internal_node_pointer; + + inline insert(node_pointer & root, + size_t & leafs_level, + Element const& element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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 + } + + template + inline void traverse(Visitor & visitor, internal_node & n) + { + // choose next node + size_t choosen_node_index = rtree::choose_next_node:: + 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, + 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 + inline void post_traverse(Node &n) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_traverse_data.current_is_root() || + &n == &rtree::get(*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() ) + { + split(n); // MAY THROW (V, E: alloc, copy, N:alloc) + } + } + + template + 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 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 + inline void split(Node & n) const + { + typedef rtree::split 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::pairs or Values) + // and translator + allocators + // where node_elements_count + additional_elements > node_max_elements_count + // What with elements other than std::pair ? + // Implement template struct node_element_type or something like that + + // for exception safety + node_auto_ptr additional_node_ptr(additional_nodes[0].second, m_allocators); + + // 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(*m_root_node), "node should be the root"); + + // create new root and add nodes + node_auto_ptr new_root(rtree::create_node::apply(m_allocators), m_allocators); // MAY THROW, STRONG (N:alloc) + + try { + rtree::elements(rtree::get(*new_root)).push_back(rtree::make_ptr_pair(n_box, m_root_node)); // MAY THROW, STRONG (E:alloc, copy) + rtree::elements(rtree::get(*new_root)).push_back(additional_nodes[0]); // MAY THROW, STRONG (E:alloc, copy) + } catch (...) { + // clear new root to not delete in the ~node_auto_ptr() potentially stored old root node + rtree::elements(rtree::get(*new_root)).clear(); + throw; // RETHROW + } + + 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; + parameters_type const& m_parameters; + Translator const& m_translator; + const size_t m_relative_level; + const size_t m_level; + + node_pointer & m_root_node; + size_t & m_leafs_level; + + // traversing input parameters + insert_traverse_data m_traverse_data; + + Allocators & m_allocators; +}; + +} // namespace detail + +// Insert visitor forward declaration +template +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 +class insert + : public detail::insert +{ +public: + typedef detail::insert 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; + + inline insert(node_pointer & root, + size_t & leafs_level, + Element & element, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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"); + + try + { + // push new child node + rtree::elements(n).push_back(base::m_element); // MAY THROW, STRONG (E: alloc, copy) + } + catch(...) + { + // if the insert fails above, the element won't be stored in the tree + + rtree::visitors::destroy del_v(base::m_element.second, base::m_allocators); + rtree::apply_visitor(del_v, *base::m_element.second); + + throw; // RETHROW + } + } + + 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 +class insert + : public detail::insert +{ +public: + typedef detail::insert 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; + + inline insert(node_pointer & root, + size_t & leafs_level, + Value const& value, + parameters_type const& parameters, + Translator const& translator, + Allocators & allocators, + size_t 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::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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp b/include/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp new file mode 100644 index 000000000..6d21afd99 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/is_leaf.hpp @@ -0,0 +1,41 @@ +// Boost.Geometry Index +// +// R-tree leaf node checking 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_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 +struct is_leaf : public rtree::visitor::type +{ + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + 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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/nearest_query.hpp b/include/boost/geometry/index/detail/rtree/visitors/nearest_query.hpp new file mode 100644 index 000000000..43a808f5d --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/nearest_query.hpp @@ -0,0 +1,338 @@ +// Boost.Geometry Index +// +// R-tree k nearest neighbour query 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_VISITORS_NEAREST_QUERY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_NEAREST_QUERY_HPP + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +// TODO: awulkiew - maby it's a good idea to check if curr_mindist < comp_mindist and then check predicates +// in store() or break store to 2 functions e.g. should_store() and store() +// - well not with this algorithm of storing k-th neighbor + +//template +//struct nearest_query_result_one +//{ +//public: +// typedef typename geometry::default_distance_result< +// Point, +// typename translator::indexable_type::type +// >::type distance_type; +// +// inline nearest_query_result_one(Value & value) +// : m_value(value) +// , m_comp_dist((std::numeric_limits::max)()) +// {} +// +// inline void store(Value const& val, distance_type const& curr_comp_dist) +// { +// if ( curr_comp_dist < m_comp_dist ) +// { +// m_comp_dist = curr_comp_dist; +// m_value = val; +// } +// } +// +// inline bool is_comparable_distance_valid() const +// { +// return m_comp_dist < (std::numeric_limits::max)(); +// } +// +// inline distance_type comparable_distance() const +// { +// return m_comp_dist; +// } +// +// inline size_t finish() +// { +// return is_comparable_distance_valid() ? 1 : 0; +// } +// +//private: +// Value & m_value; +// distance_type m_comp_dist; +//}; + +template +struct nearest_query_result_k +{ +public: + typedef typename geometry::default_distance_result< + Point, + typename indexable_type::type + >::type distance_type; + + inline explicit nearest_query_result_k(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 is_comparable_distance_valid() const + { + return m_neighbors.size() == m_count; + } + + inline distance_type comparable_distance() const + { + // smallest 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::max)() + : m_neighbors.front().first; + } + + inline size_t finish() + { + typedef typename std::vector< std::pair >::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 const& p1, + std::pair const& p2) + { + return p1.first < p2.first; + } + + size_t m_count; + OutIt m_out_it; + + std::vector< std::pair > m_neighbors; + distance_type m_biggest_comp_dist; +}; + +// TODO: awulkiew - add additional pruning before adding nodes to the ABL + +template < + typename Value, + typename Options, + typename Translator, + typename Box, + typename Allocators, + typename DistancesPredicates, + typename Predicates, + typename Result +> +class nearest_query + : public rtree::visitor::type +{ +public: + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef index::detail::distances_calc node_distances_calc; + typedef typename node_distances_calc::result_type node_distances_type; + typedef index::detail::distances_predicates_check node_distances_predicates_check; + + typedef index::detail::distances_calc< + DistancesPredicates, + typename indexable_type::type, + index::detail::value_tag + > value_distances_calc; + typedef typename value_distances_calc::result_type value_distances_type; + typedef index::detail::distances_predicates_check< + DistancesPredicates, + typename indexable_type::type, + index::detail::value_tag + > value_distances_predicates_check; + + static const unsigned predicates_len = index::detail::predicates_length::value; + + inline nearest_query(parameters_type const& parameters, Translator const& translator, DistancesPredicates const& dist_pred, Predicates const& pred, Result & r) + : m_parameters(parameters), m_translator(translator) + , m_dist_pred(dist_pred), m_pred(pred) + , m_result(r) + {} + + //TODO: awulkiew - consider this approach: store one, global vector of active branches, add branches only if mindist is ok + + inline void operator()(internal_node const& n) + { + typedef typename rtree::elements_type::type elements_type; + + // array of active nodes + typename index::detail::rtree::container_from_elements_type< + elements_type, + std::pair + >::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(m_pred, 0, it->first) ) + { + // calculate node's distance(s) for distance predicate + node_distances_type node_dist_data = node_distances_calc::apply(m_dist_pred, it->first); + + // TODO: awulkiew - consider at first calculating near distance only, + // comparing it with m_result.comparable_distance if it's valid, + // after that calculate the rest of distances and check predicates + + // if current node is further than found neighbors - don't analyze it + if ( m_result.is_comparable_distance_valid() && + is_node_prunable(m_result.comparable_distance(), node_dist_data) ) + { + continue; + } + + // if current node distance(s) meets distance predicate + if ( node_distances_predicates_check::apply(m_dist_pred, node_dist_data) ) + { + // add current node's data into the list + active_branch_list.push_back( std::make_pair(node_dist_data, 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 ( size_t i = 0 ;; ++i ) + { + // prune nodes + prune_nodes(active_branch_list); + + if ( active_branch_list.size() <= i ) + break; + + rtree::apply_visitor(*this, *active_branch_list[i].second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type::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(m_pred, *it, m_translator(*it)) ) + { + // calculate values distance for distance predicate + value_distances_type distances = value_distances_calc::apply(m_dist_pred, m_translator(*it)); + + // TODO: awulkiew - consider at first calculating point relation distance only, + // comparing it with m_result.comparable_distance if it's valid, + // after that calculate the rest of distances and check predicates + + // if distance meets distance predicate + if ( value_distances_predicates_check::apply(m_dist_pred, distances) ) + { + typedef typename index::detail::point_relation::type point_relation_type; + typedef typename index::detail::relation::tag point_relation_tag; + + // store value + m_result.store( + *it, + index::detail::cdist_value + ::template get(distances) + ); + } + } + } + } + +private: + template + inline void prune_nodes(ActiveBranchList & abl) const + { + // if some value were found + if ( m_result.is_comparable_distance_valid() ) + { + // prune if box's mindist is further than value's mindist + while ( !abl.empty() && + is_node_prunable(m_result.comparable_distance(), abl.back().first) ) + { + abl.pop_back(); + } + } + } + + static inline bool abl_less( + std::pair const& p1, + std::pair const& p2) + { + return index::detail::cdist_value + ::template get(p1.first) + < index::detail::cdist_value + ::template get(p2.first); + } + + template + static inline bool is_node_prunable(Distance const& smallest_dist, node_distances_type const& d) + { + return smallest_dist + < index::detail::cdist_value + ::template get(d); + } + + parameters_type const& m_parameters; + Translator const& m_translator; + + DistancesPredicates m_dist_pred; + Predicates m_pred; + + Result & m_result; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_NEAREST_QUERY_HPP diff --git a/include/boost/geometry/index/detail/rtree/visitors/print.hpp b/include/boost/geometry/index/detail/rtree/visitors/print.hpp new file mode 100644 index 000000000..0d989df02 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/print.hpp @@ -0,0 +1,197 @@ +// 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_VISITORS_PRINT_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_PRINT_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +namespace dispatch { + +template +struct print_point +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + static inline void apply(std::ostream & os, Point const& p) + { + print_point::apply(os, p); + + os << ", " << geometry::get(p); + } +}; + +template +struct print_point +{ + static inline void apply(std::ostream & os, Point const& p) + { + os << geometry::get<0>(p); + } +}; + +template +struct print_corner +{ + BOOST_STATIC_ASSERT(0 < Dimension); + + static inline void apply(std::ostream & os, Box const& b) + { + print_corner::apply(os, b); + + os << ", " << geometry::get(b); + } +}; + +template +struct print_corner +{ + static inline void apply(std::ostream & os, Box const& b) + { + os << geometry::get(b); + } +}; + +template +struct print_indexable +{ +}; + +template +struct print_indexable +{ + static const size_t dimension = index::detail::traits::dimension::value; + + static inline void apply(std::ostream &os, Indexable const& i) + { + os << '('; + print_corner::apply(os, i); + os << ")x("; + print_corner::apply(os, i); + os << ')'; + } +}; + +template +struct print_indexable +{ + static const size_t dimension = index::detail::traits::dimension::value; + + static inline void apply(std::ostream &os, Indexable const& i) + { + os << '('; + print_point::apply(os, i); + os << ')'; + } +}; + +} // namespace dispatch + +namespace detail { + +template +inline void print_indexable(std::ostream & os, Indexable const& i) +{ + dispatch::print_indexable< + Indexable, + typename geometry::traits::tag::type + >::apply(os, i); +} + +} // namespace detail + +template +struct print : public rtree::visitor::type +{ + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::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::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::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::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::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 detail::rtree::visitors + +template +std::ostream & operator<<(std::ostream & os, rtree const& tree) +{ + typedef rtree rtree_type; + typedef typename rtree_type::value_type value_type; + typedef typename rtree_type::options_type options_type; + typedef typename rtree_type::translator_type translator_type; + typedef typename rtree_type::box_type box_type; + typedef typename rtree_type::allocators_type allocators_type; + detail::rtree::visitors::print print_v(os, tree.translator()); + tree.apply_visitor(print_v); + return os; +} + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_PRINT_HPP diff --git a/include/boost/geometry/index/detail/rtree/visitors/remove.hpp b/include/boost/geometry/index/detail/rtree/visitors/remove.hpp new file mode 100644 index 000000000..a827db088 --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/remove.hpp @@ -0,0 +1,311 @@ +// Boost.Geometry Index +// +// R-tree removing 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_VISITORS_REMOVE_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_REMOVE_HPP + +#include + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { namespace rtree { namespace visitors { + +// Default remove algorithm +template +class remove + : public rtree::visitor::type +{ + typedef typename Options::parameters_type parameters_type; + + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + typedef rtree::node_auto_ptr node_auto_ptr; + typedef typename Allocators::node_pointer node_pointer; + typedef typename Allocators::internal_node_pointer internal_node_pointer; + +public: + inline remove(node_pointer & root, + size_t & 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::type children_type; + children_type & children = rtree::elements(n); + + // traverse children which boxes intersects value's box + size_t child_node_index = 0; + for ( ; child_node_index < children.size() ; ++child_node_index ) + { + if ( geometry::covered_by(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::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_t 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 + 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(elements.begin(), elements.end(), m_translator); + } + // n is root node + else + { + BOOST_GEOMETRY_INDEX_ASSERT(&n == &rtree::get(*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 + if ( rtree::elements(n).size() == 1 ) + { + node_pointer root_to_destroy = m_root_node; + m_root_node = rtree::elements(n)[0].second; + --m_leafs_level; + + rtree::destroy_node::apply(m_allocators, root_to_destroy); + } + } + } + } + + inline void operator()(leaf & n) + { + typedef typename rtree::elements_type::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 ) + { + // 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::elements_box(elements.begin(), elements.end(), m_translator); + } + } + } + + bool is_value_removed() const + { + return m_is_value_removed; + } + +private: + + typedef std::vector< std::pair > UnderflowNodes; + + void traverse_apply_visitor(internal_node &n, size_t choosen_node_index) + { + // save previous traverse inputs and set new ones + internal_node_pointer parent_bckup = m_parent; + size_t current_child_index_bckup = m_current_child_index; + size_t 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::type & elements, + typename rtree::elements_type::type::iterator underfl_el_it, + size_t 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) + + try + { + rtree::move_from_back(elements, underfl_el_it); // MAY THROW (E: copy) + elements.pop_back(); + } + catch(...) + { + m_underflowed_nodes.pop_back(); + throw; // RETHROW + } + + // calc underflow + return elements.size() < m_parameters.get_min_elements(); + } + + void reinsert_removed_nodes_elements() + { + typename UnderflowNodes::reverse_iterator it = m_underflowed_nodes.rbegin(); + + try + { + // reinsert elements from removed nodes + // begin with levels closer to the root + for ( ; it != m_underflowed_nodes.rend() ; ++it ) + { + is_leaf ilv; + rtree::apply_visitor(ilv, *it->second); + if ( ilv.result ) + { + reinsert_node_elements(rtree::get(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc) + + rtree::destroy_node::apply(m_allocators, it->second); + } + else + { + reinsert_node_elements(rtree::get(*it->second), it->first); // MAY THROW (V, E: alloc, copy, N: alloc) + + rtree::destroy_node::apply(m_allocators, it->second); + } + } + + //m_underflowed_nodes.clear(); + } + catch(...) + { + // destroy current and remaining nodes + for ( ; it != m_underflowed_nodes.rend() ; ++it ) + { + node_auto_ptr dummy(it->second, m_allocators); + } + + //m_underflowed_nodes.clear(); + + throw; // RETHROW + } + } + + template + void reinsert_node_elements(Node &n, size_t node_relative_level) + { + typedef typename rtree::elements_type::type elements_type; + elements_type & elements = rtree::elements(n); + + typename elements_type::iterator it = elements.begin(); + 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) + } + } + catch(...) + { + ++it; + rtree::destroy_elements + ::apply(it, elements.end(), m_allocators); + elements.clear(); + throw; // RETHROW + } + } + + Value const& m_value; + parameters_type const& m_parameters; + Translator const& m_translator; + Allocators & m_allocators; + + node_pointer & m_root_node; + size_t & m_leafs_level; + + bool m_is_value_removed; + UnderflowNodes m_underflowed_nodes; + + // traversing input parameters + internal_node_pointer m_parent; + size_t m_current_child_index; + size_t 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 diff --git a/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp new file mode 100644 index 000000000..3a15f04bd --- /dev/null +++ b/include/boost/geometry/index/detail/rtree/visitors/spatial_query.hpp @@ -0,0 +1,80 @@ +// Boost.Geometry Index +// +// R-tree spatial query 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_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 +struct spatial_query + : public rtree::visitor::type +{ + typedef typename rtree::node::type node; + typedef typename rtree::internal_node::type internal_node; + typedef typename rtree::leaf::type leaf; + + static const unsigned predicates_len = index::detail::predicates_length::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::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(pred, 0, it->first) ) + rtree::apply_visitor(*this, *it->second); + } + } + + inline void operator()(leaf const& n) + { + typedef typename rtree::elements_type::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(pred, *it, tr(*it)) ) + { + out_iter = *it; + ++out_iter; + + ++found_count; + } + } + } + + Translator const& tr; + + Predicates pred; + + OutIter out_iter; + size_t found_count; +}; + +}}} // namespace detail::rtree::visitors + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_RTREE_VISITORS_SPATIAL_QUERY_HPP diff --git a/include/boost/geometry/index/detail/tags.hpp b/include/boost/geometry/index/detail/tags.hpp new file mode 100644 index 000000000..e1a1716be --- /dev/null +++ b/include/boost/geometry/index/detail/tags.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 diff --git a/include/boost/geometry/index/detail/translator.hpp b/include/boost/geometry/index/detail/translator.hpp new file mode 100644 index 000000000..f377c720a --- /dev/null +++ b/include/boost/geometry/index/detail/translator.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 +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 + result_type operator()(Value const& value) const + { + return IndexableGetter::operator()(value); + } + + template + bool equals(Value const& v1, Value const& v2) const + { + return EqualTo::operator()(v1, v2); + } +}; + +template +struct result_type +{ + typedef typename IndexableGetter::result_type type; +}; + +template +struct indexable_type +{ + typedef typename boost::remove_const< + typename boost::remove_reference< + typename result_type::type + >::type + >::type type; +}; + +} // namespace detail + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_TRANSLATOR_HPP diff --git a/include/boost/geometry/index/detail/tuples.hpp b/include/boost/geometry/index/detail/tuples.hpp new file mode 100644 index 000000000..28e347bed --- /dev/null +++ b/include/boost/geometry/index/detail/tuples.hpp @@ -0,0 +1,201 @@ +// 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 +#include + +// TODO move this to index/tuples and separate algorithms + +namespace boost { namespace geometry { namespace index { namespace detail { + +namespace tuples { + +// find_index + +namespace detail { + +template +struct find_index; + +template +struct find_index_impl +{ + static const size_t value = find_index::value; +}; + +template +struct find_index_impl +{ + static const size_t value = N - 1; +}; + +template +struct find_index_impl +{ + BOOST_MPL_ASSERT_MSG( + (false), + ELEMENT_NOT_FOUND, + (find_index_impl)); +}; + +template +struct find_index_impl +{ + static const size_t value = 0; +}; + +template +struct find_index +{ + static const size_t value = + find_index_impl< + Tuple, + El, + N, + typename boost::tuples::element::type + >::value; +}; + +} // namespace detail + +template +struct find_index +{ + static const size_t value = + detail::find_index< + Tuple, + El, + boost::tuples::length::value + >::value; +}; + +// has + +namespace detail { + +template +struct has +{ + static const bool value + = boost::is_same< + typename boost::tuples::element::type, + El + >::value + || has::value; +}; + +template +struct has +{ + static const bool value + = boost::is_same< + typename boost::tuples::element<0, Tuple>::type, + El + >::value; +}; + +} // namespace detail + +template +struct has +{ + static const bool value + = detail::has< + Tuple, + El, + boost::tuples::length::value + >::value; +}; + +// add + +template +struct add +{ + BOOST_MPL_ASSERT_MSG( + (false), + NOT_IMPLEMENTED_FOR_THIS_TUPLE_TYPE, + (add)); +}; + +template +struct add, T> +{ + typedef boost::tuple type; +}; + +template +struct add, T> +{ + typedef boost::tuple type; +}; + +// add_if + +template +struct add_if +{ + typedef Tuple type; +}; + +template +struct add_if +{ + typedef typename add::type type; +}; + +// add_unique + +template +struct add_unique +{ + typedef typename add_if< + Tuple, + El, + !has::value + >::type type; +}; + +template +struct push_back_impl +{ + typedef + boost::tuples::cons< + typename boost::tuples::element::type, + typename push_back_impl::type + > type; + + static type apply(Tuple const& tup, T const& t) + { + return + type( + boost::get(tup), + push_back_impl::apply(tup, t) + ); + } +}; + +template +struct push_back_impl +{ + typedef boost::tuples::cons 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 diff --git a/include/boost/geometry/index/detail/varray.hpp b/include/boost/geometry/index/detail/varray.hpp new file mode 100644 index 000000000..0cbec3702 --- /dev/null +++ b/include/boost/geometry/index/detail/varray.hpp @@ -0,0 +1,881 @@ +// 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_VARRAY_HPP +#define BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { namespace geometry { namespace index { namespace detail { + +template +struct varray_default_alloc +{ + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef V * pointer; + typedef const V * const_pointer; +}; + +template > +class varray +{ + BOOST_MPL_ASSERT_MSG( + (0 < Capacity), + INVALID_CAPACITY, + (varray)); + + BOOST_COPYABLE_AND_MOVABLE(varray) + +public: + typedef Value value_type; + typedef Value& reference; + typedef Value const& const_reference; + typedef typename Al::size_type size_type; + typedef typename Al::difference_type difference_type; + typedef typename Al::pointer pointer; + typedef typename Al::const_pointer const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef boost::reverse_iterator reverse_iterator; + typedef boost::reverse_iterator const_reverse_iterator; + + // nothrow + varray() + : m_size(0) + {} + + // strong + explicit varray(size_type count) + : m_size(0) + { + resize(count); // may throw + } + + // strong + varray(size_type count, value_type const& value) + : m_size(0) + { + resize(count, value); // may throw + } + + // strong + varray(varray const& other) + : m_size(other.m_size) + { + this->uninitialized_copy(other.begin(), other.end(), this->begin()); // may throw + } + + // strong + varray(BOOST_RV_REF(varray) other) + : m_size(other.m_size) + { + this->uninitialized_move(other.begin(), other.end(), this->begin()); // may throw + } + + // strong + template + varray(Iterator first, Iterator last) + : m_size(0) + { + assign(first, last); // may throw + } + + // basic + varray & operator=(BOOST_COPY_ASSIGN_REF(varray) other) + { + assign(other.begin(), other.end()); // may throw + + return *this; + } + + // basic + varray & operator=(BOOST_RV_REF(varray) other) + { + assign(other.begin(), other.end()); // may throw + + return *this; + } + + // nothrow + ~varray() + { + this->destroy(this->begin(), this->end()); + } + + // strong + void resize(size_type count) + { + if ( count < m_size ) + { + this->destroy(this->begin() + count, this->end()); + } + else + { + check_capacity(count); + + this->construct(this->end(), this->begin() + count); // may throw + } + m_size = count; // update end + } + + // strong + void resize(size_type count, value_type const& value) + { + if ( count < m_size ) + { + this->destroy(this->begin() + count, this->end()); + } + else + { + check_capacity(count); + + std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw + } + m_size = count; // update end + } + + // nothrow + void reserve(size_type count) + { + check_capacity(count); + } + + // strong + void push_back(value_type const& value) + { + check_capacity(m_size + 1); + + this->uninitialized_fill(this->end(), value); // may throw + ++m_size; // update end + } + + void push_back(BOOST_RV_REF(value_type) value) + { + check_capacity(m_size + 1); + + this->uninitialized_fill(this->end(), value); // may throw + ++m_size; // update end + } + + // nothrow + void pop_back() + { + check_empty(); + + //--m_size; // update end + //this->destroy(this->end()); + + // safer and more intuitive version + this->destroy(this->end() - 1); + --m_size; // update end + } + + // basic + void insert(iterator position, value_type const& value) + { + check_iterator_end_eq(position); + check_capacity(m_size + 1); + + if ( position == this->end() ) + { + this->uninitialized_fill(position, value); // may throw + ++m_size; // update end + } + else + { + // TODO - should following lines check for exception and revert to the old size? + + this->uninitialized_fill(this->end(), *(this->end() - 1)); // may throw + ++m_size; // update end + this->move_backward(position, this->end() - 2, this->end() - 1); // may throw + this->fill(position, value); // may throw + } + } + + // basic + void insert(iterator position, size_type count, value_type const& value) + { + check_iterator_end_eq(position); + check_capacity(m_size + count); + + if ( position == this->end() ) + { + std::uninitialized_fill(position, position + count, value); // may throw + m_size += count; // update end + } + else + { + difference_type to_move = std::distance(position, this->end()); + + // TODO - should following lines check for exception and revert to the old size? + + if ( count < static_cast(to_move) ) + { + this->uninitialized_copy(this->end() - count, this->end(), this->end()); // may throw + m_size += count; // update end + this->move_backward(position, position + to_move - count, this->end() - count); // may throw + std::fill_n(position, count, value); // may throw + } + else + { + std::uninitialized_fill(this->end(), position + count, value); // may throw + m_size += count - to_move; // update end + this->uninitialized_copy(position, position + to_move, position + count); // may throw + m_size += to_move; // update end + std::fill_n(position, to_move, value); // may throw + } + } + } + + // basic + template + void insert(iterator position, Iterator first, Iterator last) + { + typedef typename boost::iterator_traversal::type traversal; + this->insert_dispatch(position, first, last, traversal()); + } + + // basic + void erase(iterator position) + { + check_iterator_end_neq(position); + + this->move(position + 1, this->end(), position); // may throw + this->destroy(this->end() - 1); + --m_size; + } + + // basic + void erase(iterator first, iterator last) + { + check_iterator_end_eq(first); + check_iterator_end_eq(last); + + difference_type n = std::distance(first, last); + BOOST_ASSERT_MSG(0 <= n, "invalid range"); + + this->move(last, this->end(), first); // may throw + this->destroy(this->end() - n, this->end()); + m_size -= n; + } + + // basic + template + void assign(Iterator first, Iterator last) + { + typedef typename boost::iterator_traversal::type traversal; + this->assign_dispatch(first, last, traversal()); // may throw + } + + // basic + void assign(size_type count, value_type const& value) + { + if ( count < m_size ) + { + std::fill_n(this->begin(), count, value); + this->destroy(this->begin() + count, this->end()); + } + else + { + check_capacity(count); + + std::fill_n(this->begin(), m_size, value); + std::uninitialized_fill(this->end(), this->begin() + count, value); // may throw + } + m_size = count; // update end + } + + // nothrow + void clear() + { + this->destroy(this->begin(), this->end()); + m_size = 0; // update end + } + + // strong + Value & at(size_type i) + { + if ( m_size <= i ) + throw std::out_of_range("index out of bounds"); + return *(this->begin() + i); + } + + // strong + Value const& at(size_type i) const + { + if ( m_size <= i ) + throw std::out_of_range("index out of bounds"); + return *(this->begin() + i); + } + + // nothrow + Value & operator[](size_type i) + { + BOOST_ASSERT_MSG(i < m_size, "index out of bounds"); + return *(this->begin() + i); + } + + // nothrow + Value const& operator[](size_type i) const + { + BOOST_ASSERT_MSG(i < m_size, "index out of bounds"); + return *(this->begin() + i); + } + + // nothrow + Value & front() + { + check_empty(); + return *(this->begin()); + } + + // nothrow + Value const& front() const + { + check_empty(); + return *(this->begin()); + } + + // nothrow + Value & back() + { + check_empty(); + return *(this->end() - 1); + } + + // nothrow + Value const& back() const + { + check_empty(); + return *(this->end() - 1); + } + + // nothrow + Value * data() { return this->ptr(); } + const Value * data() const { return this->ptr(); } + + // nothrow + iterator begin() { return this->ptr(); } + const_iterator begin() const { return this->ptr(); } + const_iterator cbegin() const { return this->ptr(); } + iterator end() { return this->begin() + m_size; } + const_iterator end() const { return this->begin() + m_size; } + const_iterator cend() const { return this->cbegin() + m_size; } + // nothrow + reverse_iterator rbegin() { return reverse_iterator(this->end()); } + const_reverse_iterator rbegin() const { return reverse_iterator(this->end()); } + const_reverse_iterator crbegin() const { return reverse_iterator(this->end()); } + reverse_iterator rend() { return reverse_iterator(this->begin()); } + const_reverse_iterator rend() const { return reverse_iterator(this->begin()); } + const_reverse_iterator crend() const { return reverse_iterator(this->begin()); } + + // nothrow + static size_type capacity() { return Capacity; } + static size_type max_size() { return Capacity; } + size_type size() const { return m_size; } + bool empty() const { return 0 == m_size; } + +private: + + // insert + + template + void insert_dispatch(iterator position, Iterator first, Iterator last, boost::random_access_traversal_tag const&) + { + check_iterator_end_eq(position); + + difference_type count = std::distance(first, last); + + check_capacity(m_size + count); + + if ( position == this->end() ) + { + this->uninitialized_copy(first, last, position); // may throw + m_size += count; // update end + } + else + { + this->insert_in_the_middle(position, first, last, count); // may throw + } + } + + template + void insert_dispatch(iterator position, Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + check_iterator_end_eq(position); + + if ( position == this->end() ) + { + std::pair copy_data = + this->uninitialized_copy_checked(first, last, position, std::distance(position, this->begin() + Capacity)); // may throw + + check_capacity(copy_data.first ? m_size + copy_data.second : Capacity + 1); + + m_size += copy_data.second; + } + else + { + difference_type count = std::distance(first, last); + + check_capacity(m_size + count); + + this->insert_in_the_middle(position, first, last, count); // may throw + } + } + + template + void insert_in_the_middle(iterator position, Iterator first, Iterator last, difference_type count) + { + difference_type to_move = std::distance(position, this->end()); + + // TODO - should following lines check for exception and revert to the old size? + + if ( count < to_move ) + { + this->uninitialized_copy(this->end() - count, this->end(), this->end()); // may throw + m_size += count; // update end + this->move_backward(position, position + to_move - count, this->end() - count); // may throw + this->copy(first, last, position); // may throw + } + else + { + Iterator middle_iter = first; + std::advance(middle_iter, to_move); + + this->uninitialized_copy(middle_iter, last, this->end()); // may throw + m_size += count - to_move; // update end + this->uninitialized_copy(position, position + to_move, position + count); // may throw + m_size += to_move; // update end + this->copy(first, middle_iter, position) ; // may throw + } + } + + // assign + + template + void assign_dispatch(Iterator first, Iterator last, boost::random_access_traversal_tag const& /*not_random_access*/) + { + size_type s = std::distance(first, last); + + check_capacity(s); + + if ( m_size <= s ) + { + this->copy(first, first + m_size, this->begin()); // may throw + // TODO - perform uninitialized_copy first? + this->uninitialized_copy(first + m_size, last, this->end()); // may throw + } + else + { + this->copy(first, last, this->begin()); // may throw + this->destroy(this->begin() + s, this->end()); + } + m_size = s; // update end + } + + template + void assign_dispatch(Iterator first, Iterator last, Traversal const& /*not_random_access*/) + { + size_type s = 0; + iterator it = this->begin(); + + for ( ; it != this->end() && first != last ; ++it, ++first, ++s ) + *it = *first; // may throw + + this->destroy(it, this->end()); + + std::pair copy_data = + this->uninitialized_copy_checked(first, last, it, std::distance(it, this->begin() + Capacity)); // may throw + s += copy_data.second; + + check_capacity(copy_data.first ? s : Capacity + 1); + + m_size = s; // update end + } + + // uninitialized_copy_checked + + template + std::pair uninitialized_copy_checked(Iterator first, Iterator last, iterator dest, size_type max_count) + { + size_type count = 0; + iterator it = dest; + try + { + for ( ; first != last ; ++it, ++first, ++count ) + { + if ( max_count <= count ) + return std::make_pair(false, count); + + this->uninitialized_fill(it, *first); // may throw + } + } + catch(...) + { + this->destroy(dest, it); + throw; + } + return std::make_pair(true, count); + } + + // copy + + template + void copy(Iterator first, Iterator last, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_assign, + mpl::or_< + is_same, + is_same + >, + mpl::or_< + is_same, + is_same + > + >::type + use_memcpy; + + this->copy_dispatch(first, last, dst, use_memcpy()); // may throw + } + + void copy_dispatch(const value_type * first, const value_type * last, value_type * dst, + boost::mpl::bool_ const& /*use_memcpy*/) + { + ::memmove(dst, first, sizeof(value_type) * std::distance(first, last)); + } + + template + void copy_dispatch(Iterator first, Iterator last, iterator dst, + boost::mpl::bool_ const& /*use_memcpy*/) + { + std::copy(first, last, dst); // may throw + } + + // uninitialized_copy + + template + void uninitialized_copy(Iterator first, Iterator last, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_copy, + mpl::or_< + is_same, + is_same + >, + mpl::or_< + is_same, + is_same + > + >::type + use_memcpy; + + this->uninitialized_copy_dispatch(first, last, dst, use_memcpy()); // may throw + } + + void uninitialized_copy_dispatch(const value_type * first, const value_type * last, value_type * dst, + boost::mpl::bool_ const& /*use_memcpy*/) + { + ::memcpy(dst, first, sizeof(value_type) * std::distance(first, last)); + } + + template + void uninitialized_copy_dispatch(Iterator first, Iterator last, iterator dst, + boost::mpl::bool_ const& /*use_memcpy*/) + { + std::uninitialized_copy(first, last, dst); // may throw + } + + // uninitialized_fill + + template + void uninitialized_fill(iterator dst, V const& v) + { + typedef typename + mpl::and_< + has_trivial_copy, + is_same + >::type + use_memcpy; + + uninitialized_fill_dispatch(dst, v, use_memcpy()); // may throw + } + + void uninitialized_fill_dispatch(iterator dst, value_type const& v, + boost::mpl::bool_ const& /*use_memcpy*/) + { + // TODO - check if value_type has operator& defined and call this version only if it hasn't + const value_type * vptr = &v; + ::memcpy(&(*dst), vptr, sizeof(value_type)); + } + + template + void uninitialized_fill_dispatch(iterator dst, V const& v, + boost::mpl::bool_ const& /*use_memcpy*/) + { + new (&(*dst)) value_type(v); // may throw + } + + template + void uninitialized_fill(iterator dst, BOOST_RV_REF(V) v) + { + // TODO optimized version if has_trivial_move + new (&(*dst)) value_type(v); // may throw + } + + // move + + template + void move(Iterator first, Iterator last, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_assign, + mpl::or_< + is_same, + is_same + >, + mpl::or_< + is_same, + is_same + > + >::type + use_memcpy; + + this->move_dispatch(first, last, dst, use_memcpy()); // may throw + } + + void move_dispatch(const value_type * first, const value_type * last, value_type * dst, + boost::mpl::bool_ const& /*use_mem*/) + { + ::memmove(dst, first, sizeof(value_type) * std::distance(first, last)); + } + + template + void move_dispatch(Iterator first, Iterator last, iterator dst, + boost::mpl::bool_ const& /*use_mem*/) + { + std::copy(first, last, dst); // may throw + } + + // move_backward + + void move_backward(iterator first, iterator last, iterator dst) + { + typedef typename + mpl::and_< + has_trivial_assign, + mpl::or_< + is_same, + is_same + > + >::type + use_memcpy; + + this->move_backward_dispatch(first, last, dst, use_memcpy()); // may throw + } + + void move_backward_dispatch(value_type * first, value_type * last, value_type * dst, + boost::mpl::bool_ const& /*has_trivial_assign*/) + { + difference_type n = std::distance(first, last); + ::memmove(dst - n, first, sizeof(value_type) * n); + } + + void move_backward_dispatch(iterator first, iterator last, iterator dst, + boost::mpl::bool_ const& /*has_trivial_assign*/) + { + std::copy_backward(first, last, dst); // may throw + } + + // uninitialized_fill + + template + void fill(iterator dst, V const& v) + { + fill_dispatch(dst, v, has_trivial_assign()); // may throw + } + + void fill_dispatch(iterator ptr, value_type const& v, + boost::true_type const& /*has_trivial_assign*/) + { + // TODO - check if value_type has operator& defined and call this version only if it hasn't + const value_type * vptr = &v; + ::memcpy(&(*ptr), vptr, sizeof(value_type)); + } + + template + void fill_dispatch(iterator ptr, V const& v, + boost::false_type const& /*has_trivial_assign*/) + { + *ptr = v; // may throw + } + + // destroy + + void destroy(iterator first, iterator last) + { + this->destroy_dispatch(first, last, has_trivial_destructor()); + } + + void destroy_dispatch(iterator /*first*/, iterator /*last*/, + boost::true_type const& /*has_trivial_destructor*/) + {} + + void destroy_dispatch(iterator first, iterator last, + boost::false_type const& /*has_trivial_destructor*/) + { + for ( ; first != last ; ++first ) + first->~value_type(); + } + + // destroy + + void destroy(iterator it) + { + this->destroy_dispatch(it, has_trivial_destructor()); + } + + void destroy_dispatch(iterator /*ptr*/, + boost::true_type const& /*has_trivial_destructor*/) + {} + + void destroy_dispatch(iterator ptr, + boost::false_type const& /*has_trivial_destructor*/) + { + ptr->~value_type(); + } + + // uninitialized_move + + template + void uninitialized_move(Iterator first, Iterator last, iterator dst) + { + iterator o = dst; + try + { + for (; first != last; ++first, ++o ) + new (boost::addressof(*o)) value_type(boost::move(*first)); + } + catch(...) + { + destroy(dst, o); + throw; + } + } + + // construct + + void construct(iterator first, iterator last) + { + this->construct_dispatch(first, last, has_trivial_constructor()); // may throw + } + + void construct_dispatch(iterator /*first*/, iterator /*last*/, + boost::true_type const& /*has_trivial_constructor*/) + {} + + void construct_dispatch(iterator first, iterator last, + boost::false_type const& /*has_trivial_constructor*/) + { + iterator it = first; + try + { + for ( ; it != last ; ++it ) + new (&(*it)) value_type(); // may throw + } + catch(...) + { + this->destroy(first, it); + throw; + } + } + + void check_capacity(size_type BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM(s)) const + { + BOOST_ASSERT_MSG(s <= Capacity, "size can't exceed the capacity"); + //if ( Capacity < s ) throw std::bad_alloc(); + } + + void check_empty() const + { + BOOST_ASSERT_MSG(0 < m_size, "the container is empty"); + } + + void check_iterator_end_neq(const_iterator position) const + { + BOOST_ASSERT_MSG(this->begin() <= position && position < this->end(), "iterator out of bounds"); + + /*BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM( + difference_type dist = std::distance(this->begin(), position); + ) + BOOST_ASSERT_MSG( + 0 <= dist && + ( sizeof(dist) <= sizeof(m_size) ? + (static_cast(dist) < m_size) : + ( dist < static_cast(m_size)) + ), "invalid iterator" + );*/ + } + + void check_iterator_end_eq(const_iterator position) const + { + BOOST_ASSERT_MSG(this->begin() <= position && position <= this->end(), "iterator out of bounds"); + + /*BOOST_GEOMETRY_INDEX_ASSERT_UNUSED_PARAM( + difference_type dist = std::distance(this->begin(), position); + ) + BOOST_ASSERT_MSG( + 0 <= dist && + ( sizeof(dist) <= sizeof(m_size) ? + (static_cast(dist) <= m_size) : + ( dist <= static_cast(m_size)) + ), "invalid iterator" + );*/ + } + + pointer ptr() + { + return pointer(static_cast(m_storage.address())); + } + + const_pointer ptr() const + { + return const_pointer(static_cast(m_storage.address())); + } + + boost::aligned_storage::value> m_storage; + size_type m_size; +}; + +}}}} // namespace boost::geometry::index::detail + +#endif // BOOST_GEOMETRY_INDEX_DETAIL_VARRAY_HPP diff --git a/include/boost/geometry/index/distance_predicates.hpp b/include/boost/geometry/index/distance_predicates.hpp new file mode 100644 index 000000000..142108eb5 --- /dev/null +++ b/include/boost/geometry/index/distance_predicates.hpp @@ -0,0 +1,200 @@ +// 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 + +/*! +\defgroup nearest_relations Nearest relations (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +// relations generators + +/*! +\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 +detail::to_nearest to_nearest(T const& v) +{ + return detail::to_nearest(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 +detail::to_centroid to_centroid(T const& v) +{ + return detail::to_centroid(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 +detail::to_furthest to_furthest(T const& v) +{ + return detail::to_furthest(v); +} + +// 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 +//inline detail::unbounded +//unbounded(PointRelation const& pr) +//{ +// return detail::unbounded(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 +//inline detail::min_bounded +//min_bounded(PointRelation const& pr, MinRelation const& minr) +//{ +// return detail::min_bounded(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 +//inline detail::max_bounded +//max_bounded(PointRelation const& pr, MaxRelation const& maxr) +//{ +// return detail::max_bounded(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 +//inline detail::bounded +//bounded(PointRelation const& pr, MinRelation const& minr, MaxRelation const& maxr) +//{ +// return detail::bounded(pr, minr, maxr); +//} + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_DISTANCE_PREDICATES_HPP diff --git a/include/boost/geometry/index/equal_to.hpp b/include/boost/geometry/index/equal_to.hpp new file mode 100644 index 000000000..3cec22ec8 --- /dev/null +++ b/include/boost/geometry/index/equal_to.hpp @@ -0,0 +1,178 @@ +// 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_EQUAL_TO_HPP +#define BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template +struct equals +{ + static bool apply(Geometry const& g1, Geometry const& g2) + { + return geometry::equals(g1, g2); + } +}; + +template +struct equals +{ + static bool apply(T const& v1, T const& v2) + { + return v1 == v2; + } +}; + +template +struct tuple_equals +{ + inline static bool apply(Tuple const& t1, Tuple const& t2) + { + typedef typename boost::tuples::element::type T; + return + equals< + T, typename geometry::traits::tag::type + >::apply(boost::get(t1), boost::get(t2)) + && + tuple_equals::apply(t1, t2); + } +}; + +template +struct tuple_equals +{ + inline static bool apply(Tuple const&, Tuple const&) + { + return true; + } +}; + +} // namespace detail + +/*! +\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 and boost::tuple<...>. + +\tparam Value The type of objects which are compared by this function object. +*/ +template +struct equal_to +{ + typedef bool result_type; + bool operator()(Value const& l, Value const& r) const + { + return detail::equals::type>::apply(l ,r); + } +}; + +/*! +\brief The function object comparing Values. + +This specialization compares values of type std::pair. +It compares pairs' first values, then second values. + +\tparam T1 The first type. +\tparam T2 The second type. +*/ +template +struct equal_to< std::pair > +{ + typedef bool result_type; + bool operator()(std::pair const& l, std::pair const& r) const + { + typedef detail::equals::type> equals1; + typedef detail::equals::type> equals2; + + return equals1::apply(l.first, r.first) && equals2::apply(l.second, r.second); + } +}; + +/*! +\brief The function object comparing Values. + +This specialization compares values of type boost::tuple<...>. +It compares values stored in tuple in range [0, length>::value). +*/ +template +struct equal_to< boost::tuple > +{ + typedef boost::tuple value_type; + + typedef bool result_type; + bool operator()(value_type const& l, value_type const& r) const + { + return detail::tuple_equals< + value_type, 0, boost::tuples::length::value + >::apply(l ,r); + } +}; + +}}} // namespace boost::geometry::index + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template +struct std_tuple_equals +{ + inline static bool apply(Tuple const& t1, Tuple const& t2) + { + typedef typename std::tuple_element::type T; + return + equals< + T, typename geometry::traits::tag::type + >::apply(std::get(t1), std::get(t2)) + && + std_tuple_equals::apply(t1, t2); + } +}; + +template +struct std_tuple_equals +{ + inline static bool apply(Tuple const&, Tuple const&) + { + return true; + } +}; + +} // namespace detail + +template +struct equal_to< std::tuple > +{ + typedef std::tuple value_type; + + typedef bool result_type; + bool operator()(value_type const& l, value_type const& r) const + { + return detail::std_tuple_equals< + value_type, 0, std::tuple_size::value + >::apply(l ,r); + } +}; + +}}} // namespace boost::geometry::index + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // BOOST_GEOMETRY_INDEX_EQUAL_TO_HPP diff --git a/include/boost/geometry/index/indexable.hpp b/include/boost/geometry/index/indexable.hpp new file mode 100644 index 000000000..53f9a64f5 --- /dev/null +++ b/include/boost/geometry/index/indexable.hpp @@ -0,0 +1,140 @@ +// 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_INDEXABLE_HPP +#define BOOST_GEOMETRY_INDEX_INDEXABLE_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +namespace detail { + +template +struct is_indexable_impl { static const bool value = false; }; + +template +struct is_indexable_impl { static const bool value = true; }; + +template +struct is_indexable_impl { static const bool value = true; }; + +template +struct is_indexable +{ + static const bool value = + is_indexable_impl::type>::value; +}; + +} // 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 and boost::tuple. + +\tparam Value The Value type which may be translated directly to the Indexable. +*/ +template +struct indexable +{ + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable::value), + NOT_VALID_INDEXABLE_TYPE, + (Value) + ); + + typedef Value const& result_type; + result_type operator()(Value const& v) const + { + return v; + } +}; + +/*! +\brief The function object extracting Indexable from Value. + +This specialization translates from std::pair. + +\tparam Indexable The Indexable type. +\tparam T2 The second type. +*/ +template +struct indexable< std::pair > +{ + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable::value), + NOT_VALID_INDEXABLE_TYPE, + (Indexable) + ); + + typedef Indexable const& result_type; + result_type operator()(std::pair const& v) const + { + return v.first; + } +}; + +/*! +\brief The function object extracting Indexable from Value. + +This specialization translates from boost::tuple. + +\tparam Indexable The Indexable type. +*/ +template +struct indexable< boost::tuple > +{ + typedef boost::tuple value_type; + + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable::value), + NOT_VALID_INDEXABLE_TYPE, + (Indexable) + ); + + typedef Indexable const& result_type; + result_type operator()(value_type const& v) const + { + return boost::get<0>(v); + } +}; + +}}} // namespace boost::geometry::index + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include + +namespace boost { namespace geometry { namespace index { + +template +struct indexable< std::tuple > +{ + typedef std::tuple value_type; + + BOOST_MPL_ASSERT_MSG( + (detail::is_indexable::value), + NOT_VALID_INDEXABLE_TYPE, + (Indexable) + ); + + typedef Indexable const& result_type; + result_type operator()(value_type const& v) const + { + return std::get<0>(v); + } +}; + +}}} // namespace boost::geometry::index + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // BOOST_GEOMETRY_INDEX_INDEXABLE_HPP diff --git a/include/boost/geometry/index/inserter.hpp b/include/boost/geometry/index/inserter.hpp new file mode 100644 index 000000000..7c489bc3f --- /dev/null +++ b/include/boost/geometry/index/inserter.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 + +/*! +\defgroup inserters Inserters (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +template +class insert_iterator : + public std::iterator +{ +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 +insert_iterator inserter(Container & c) +{ + return insert_iterator(c); +} + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_INSERTER_HPP diff --git a/include/boost/geometry/index/parameters.hpp b/include/boost/geometry/index/parameters.hpp new file mode 100644 index 000000000..9af868428 --- /dev/null +++ b/include/boost/geometry/index/parameters.hpp @@ -0,0 +1,204 @@ +// Boost.Geometry Index +// +// R-tree algorithms parameters +// +// 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_PARAMETERS_HPP +#define BOOST_GEOMETRY_INDEX_PARAMETERS_HPP + +#include + +namespace boost { namespace geometry { namespace index { + +// TODO: awulkiew - implement those: +//if ( m_min_elems_per_node < 1 ) +// m_min_elems_per_node = 1; +//if ( m_max_elems_per_node < 2 ) +// m_max_elems_per_node = 2; + +/*! +\brief Linear r-tree creation algorithm parameters. + +\tparam MaxElements Maximum number of elements in nodes. +\tparam MinElements Minimum number of elements in nodes. +*/ +template +struct 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. +*/ +template +struct 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; } +}; + +namespace detail { + +template +struct default_rstar_reinserted_elements_s +{ + static const size_t value = (MaxElements * 3) / 10; +}; + +} // namespace detail + +/*! +\brief R*-tree creation algorithm parameters. + +\tparam MaxElements Maximum number of elements in nodes. +\tparam MinElements Minimum number of elements in nodes. +\tparam OverlapCostThreshold The number of leaf node children elements above which + nearly minimum overlap cost is calculated instead of minimum + overlap cost. If 0 minimum overlap cost is always calculated. +\tparam ReinsertedElements Number of elements reinserted by forced reinsertions algorithm. +*/ +template ::value + > +struct rstar +{ + static const size_t max_elements = MaxElements; + static const size_t min_elements = MinElements; + static const size_t overlap_cost_threshold = OverlapCostThreshold; + static const size_t reinserted_elements = ReinsertedElements; + + static size_t get_max_elements() { return MaxElements; } + static size_t get_min_elements() { return MinElements; } + static size_t get_overlap_cost_threshold() { return OverlapCostThreshold; } + static size_t get_reinserted_elements() { return ReinsertedElements; } +}; + +//template +//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. + */ + dynamic_linear(size_t max_elements, size_t min_elements) + : m_max_elements(max_elements) + , m_min_elements(min_elements) + {} + + 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. + */ + dynamic_quadratic(size_t max_elements, size_t min_elements) + : m_max_elements(max_elements) + , m_min_elements(min_elements) + {} + + 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; +}; + +namespace detail { + +inline size_t default_rstar_reinserted_elements_d() +{ + return (std::numeric_limits::max)(); +}; + +} // namespace detail + +/*! +\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. + \param overlap_cost_threshold The number of leaf node children elements above which + nearly minimum overlap cost is calculated instead of minimum + overlap cost. If 0 minimum overlap cost is always calculated. + \param reinserted_elements Number of elements reinserted by forced reinsertions algorithm. + */ + dynamic_rstar(size_t max_elements, + size_t min_elements, + size_t overlap_cost_threshold = 0, + size_t reinserted_elements = detail::default_rstar_reinserted_elements_d()) + : m_max_elements(max_elements) + , m_min_elements(min_elements) + , m_overlap_cost_threshold(overlap_cost_threshold) + , m_reinserted_elements( + detail::default_rstar_reinserted_elements_d() == reinserted_elements ? + (max_elements * 3) / 10 : + reinserted_elements + ) + {} + + size_t get_max_elements() const { return m_max_elements; } + size_t get_min_elements() const { return m_min_elements; } + size_t get_overlap_cost_threshold() const { return m_overlap_cost_threshold; } + size_t get_reinserted_elements() const { return m_reinserted_elements; } + +private: + size_t m_max_elements; + size_t m_min_elements; + size_t m_overlap_cost_threshold; + size_t m_reinserted_elements; +}; + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_PARAMETERS_HPP diff --git a/include/boost/geometry/index/predicates.hpp b/include/boost/geometry/index/predicates.hpp new file mode 100644 index 000000000..4b111201c --- /dev/null +++ b/include/boost/geometry/index/predicates.hpp @@ -0,0 +1,373 @@ +// Boost.Geometry Index +// +// Spatial query predicates +// +// 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_PREDICATES_HPP +#define BOOST_GEOMETRY_INDEX_PREDICATES_HPP + +#include +#include +#include + +// TODO: awulkiew - temporary +#include + +#include +#include + +/*! +\defgroup predicates Predicates (boost::geometry::index::) +*/ + +namespace boost { namespace geometry { namespace index { + +/*! +\brief Generate \c covered_by() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if bg::covered_by(Indexable, Geometry) +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 +inline detail::covered_by covered_by(Geometry const& g) +{ + return detail::covered_by(g); +} + +/*! +\brief Generate \c disjoint() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if bg::disjoint(Indexable, Geometry) +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 +inline detail::disjoint disjoint(Geometry const& g) +{ + return detail::disjoint(g); +} + +/*! +\brief Generate \c intersects() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if bg::intersects(Indexable, Geometry) +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 +inline detail::intersects intersects(Geometry const& g) +{ + return detail::intersects(g); +} + +/*! +\brief Generate \c overlaps() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if bg::overlaps(Indexable, Geometry) +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 +inline detail::overlaps overlaps(Geometry const& g) +{ + return detail::overlaps(g); +} + +//*! +//\brief Generate \c touches() predicate. +// +//Generate a predicate defining Value and Geometry relationship. +//Value will be returned by the query if bg::touches(Indexable, Geometry) +//returns true. +// +//\ingroup predicates +// +//\tparam Geometry The Geometry type. +// +//\param g The Geometry object. +//*/ +//template +//inline detail::touches touches(Geometry const& g) +//{ +// return detail::touches(g); +//} + +/*! +\brief Generate \c within() predicate. + +Generate a predicate defining Value and Geometry relationship. +Value will be returned by the query if bg::within(Indexable, Geometry) +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 +inline detail::within within(Geometry const& g) +{ + return detail::within(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 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 +inline detail::satisfies satisfies(UnaryPredicate const& pred) +{ + return detail::satisfies(pred); +} + +/*! +\brief Generate nearest() predicate. + +When nearest predicate is passed to the query, k-nearest neighbour search will be performed. + +The simplest way of defining the knn query is passing a \c Point to which \c Values must be closest. + +It is possible to define how distance between values and query Point is calculated. This is done by passing PointRelation. +It can be generated by following functions: +\li \c boost::geometry::index::to_nearest() - default, +\li \c boost::geometry::index::to_centroid(), +\li \c boost::geometry::index::to_furthest(). + +\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(bgi::to_centroid(pt), 5) && bgi::within(box), std::back_inserter(result)); +\endverbatim + +\warning +Only one \c nearest() predicate may be used in a query. + +\ingroup predicates + +\param point_relation The point or relation describing how the distance will be calculated. +\param k The maximum number of values to return. +*/ +template inline +detail::nearest +nearest(PointOrRelation const& point_relation, unsigned k) +{ + return detail::nearest(point_relation, k); +} + +namespace detail { + +// operator! generators + +template +not_covered_by +operator!(covered_by const& p) +{ + return not_covered_by(p.geometry); +} + +template +covered_by +operator!(not_covered_by const& p) +{ + return covered_by(p.geometry); +} + +template +not_disjoint +operator!(disjoint const& p) +{ + return not_disjoint(p.geometry); +} + +template +disjoint +operator!(not_disjoint const& p) +{ + return disjoint(p.geometry); +} + +template +not_intersects +operator!(intersects const& p) +{ + return not_intersects(p.geometry); +} + +template +intersects +operator!(not_intersects const& p) +{ + return intersects(p.geometry); +} + +template +not_overlaps +operator!(overlaps const& p) +{ + return not_overlaps(p.geometry); +} + +template +overlaps +operator!(not_overlaps const& p) +{ + return overlaps(p.geometry); +} + +//template +//not_touches +//operator!(touches const& p) +//{ +// return not_touches(p.geometry); +//} +// +//template +//touches +//operator!(not_touches const& p) +//{ +// return touches(p.geometry); +//} + +template +not_within +operator!(within const& p) +{ + return not_within(p.geometry); +} + +template +within +operator!(not_within const& p) +{ + return within(p.geometry); +} + +// operator&& generators + +template inline +boost::tuples::cons< + Pred1, + boost::tuples::cons +> +operator&&(Pred1 const& p1, Pred2 const& p2) +{ + /*typedef typename boost::mpl::if_c::value, Pred1, Pred1 const&>::type stored1; + typedef typename boost::mpl::if_c::value, Pred2, Pred2 const&>::type stored2;*/ + namespace bt = boost::tuples; + + return + bt::cons< Pred1, bt::cons > + ( p1, bt::cons(p2, bt::null_type()) ); +} + +template inline +typename tuples::push_back_impl< + boost::tuples::cons, + Pred, + 0, + boost::tuples::length >::value +>::type +operator&&(boost::tuples::cons const& t, Pred const& p) +{ + //typedef typename boost::mpl::if_c::value, Pred, Pred const&>::type stored; + namespace bt = boost::tuples; + + return + tuples::push_back_impl< + bt::cons, Pred, 0, bt::length< bt::cons >::value + >::apply(t, p); +} + +} // namespace detail + +}}} // namespace boost::geometry::index + +#endif // BOOST_GEOMETRY_INDEX_PREDICATES_HPP diff --git a/include/boost/geometry/index/rtree.hpp b/include/boost/geometry/index/rtree.hpp new file mode 100644 index 000000000..058ce7c0a --- /dev/null +++ b/include/boost/geometry/index/rtree.hpp @@ -0,0 +1,1469 @@ +// Boost.Geometry Index +// +// R-tree implementation +// +// 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_RTREE_HPP +#define BOOST_GEOMETRY_INDEX_RTREE_HPP + +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +//#include + +#include + +// TODO change the name to bounding_tree + +/*! +\defgroup rtree_functions Functions related to the rtree +*/ + +namespace boost { namespace geometry { namespace index { + +/*! +\brief The R-tree spatial index. + +This is self-balancing spatial index capable to store various types of Values and balancing algorithms. + +\par Parameters +The user must pass a type defining the Parameters which will +be used in rtree creation process. This type is used e.g. to specify balancing algorithm +with specific parameters like min and max number of elements in node. + +\par +Predefined algorithms with compile-time parameters are: +\li boost::geometry::index::linear, + \li boost::geometry::index::quadratic, + \li boost::geometry::index::rstar. + +\par +Predefined algorithms with run-time parameters are: + \li \c boost::geometry::index::dynamic_linear, + \li \c boost::geometry::index::dynamic_quadratic, + \li \c boost::geometry::index::dynamic_rstar. + +\par Translator +The Translator translates from Value to Indexable each time r-tree requires it. Which means that this +operation is done for each Value access. Therefore the Translator should return the Indexable by +const reference instead of a value. Default translator can translate all types adapted to Point +or Box concepts (called Indexables). It also handles std::pair and +boost::tuple. For example, if std::pair is stored in the +container, the default translator translates from std::pair const& to Box const&. + +\tparam Value The type of objects stored in the container. +\tparam Parameters Compile-time parameters. +\tparam IndexableGetter The function object extracting Indexable from Value. +\tparam EqualTo The function object comparing objects of type Value. +\tparam Allocator The allocator used to allocate/deallocate memory, construct/destroy nodes and Values. +*/ +template < + typename Value, + typename Parameters, + typename IndexableGetter = index::indexable, + typename EqualTo = index::equal_to, + typename Allocator = std::allocator +> +class rtree +{ + BOOST_COPYABLE_AND_MOVABLE(rtree) + +public: + /*! \brief The type of Value stored in the container. */ + typedef Value value_type; + /*! \brief R-tree parameters type. */ + typedef Parameters parameters_type; + /*! \brief The type of allocator used by the container. */ + typedef Allocator allocator_type; + /*! \brief Unsigned integral type used by the container. */ + typedef typename allocator_type::size_type size_type; + /*! \brief The function object extracting Indexable from Value. */ + typedef IndexableGetter indexable_getter; + /*! \brief The function object comparing objects of type Value. */ + typedef EqualTo value_equal; + + // TODO: SHOULD THIS TYPE BE REMOVED? + /*! \brief The Indexable type to which Value is translated. */ + typedef typename index::detail::indexable_type< + detail::translator + >::type indexable_type; + + /*! \brief The Box type used by the R-tree. */ + typedef typename index::detail::default_box_type::type bounds_type; + +#if !defined(BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_DEBUG_INTERFACE) +private: +#endif + typedef detail::translator translator_type; + + typedef bounds_type box_type; + typedef typename detail::rtree::options_type::type options_type; + typedef typename options_type::node_tag node_tag; + typedef detail::rtree::allocators allocators_type; + + typedef typename detail::rtree::node::type node; + typedef typename detail::rtree::internal_node::type internal_node; + typedef typename detail::rtree::leaf::type leaf; + + typedef typename allocators_type::node_pointer node_pointer; + typedef ::boost::container::allocator_traits allocator_traits_type; + +public: + + /*! + \brief The constructor. + + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + + \par Throws + If allocator default constructor throws. + */ + inline explicit rtree(parameters_type const& parameters = parameters_type(), + indexable_getter const& getter = indexable_getter(), + value_equal const& equal = value_equal()) + : m_members(getter, equal, parameters) + {} + + /*! + \brief The constructor. + + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + \param allocator The allocator object. + + \par Throws + If allocator copy constructor throws. + */ + inline rtree(parameters_type const& parameters, + indexable_getter const& getter, + value_equal const& equal, + allocator_type const& allocator) + : m_members(getter, equal, parameters, allocator) + {} + + /*! + \brief The constructor. + + \param first The beginning of the range of Values. + \param last The end of the range of Values. + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + \param allocator The allocator object. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When memory allocation for Node fails. + */ + template + inline rtree(Iterator first, Iterator last, + parameters_type const& parameters = parameters_type(), + indexable_getter const& getter = indexable_getter(), + value_equal const& equal = value_equal(), + allocator_type const& allocator = allocator_type()) + : m_members(getter, equal, parameters, allocator) + { + try + { + this->insert(first, last); + } + catch(...) + { + this->raw_destroy(*this); + throw; + } + } + + /*! + \brief The constructor. + + \param rng The range of Values. + \param parameters The parameters object. + \param getter The function object extracting Indexable from Value. + \param equal The function object comparing Values. + \param allocator The allocator object. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When memory allocation for Node fails. + */ + template + inline explicit rtree(Range const& rng, + parameters_type const& parameters = parameters_type(), + indexable_getter const& getter = indexable_getter(), + value_equal const& equal = value_equal(), + allocator_type const& allocator = allocator_type()) + : m_members(getter, equal, parameters, allocator) + { + try + { + this->insert(rng); + } + catch(...) + { + this->raw_destroy(*this); + throw; + } + } + + /*! + \brief The destructor. + + \par Throws + Nothing. + */ + inline ~rtree() + { + this->raw_destroy(*this); + } + + /*! + \brief The copy constructor. + + It uses parameters, translator and allocator from the source tree. + + \param src The rtree which content will be copied. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor throws. + \li If allocation throws. + \li When memory allocation for Node fails. + */ + inline rtree(rtree const& src) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), + allocator_traits_type::select_on_container_copy_construction(src.get_allocator())) + { + this->raw_copy(src, *this, false); + } + + /*! + \brief The copy constructor. + + It uses Parameters and translator from the source tree. + + \param src The rtree which content will be copied. + \param allocator The allocator which will be used. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor throws. + \li If allocation throws. + \li When memory allocation for Node fails. + */ + inline rtree(rtree const& src, allocator_type const& allocator) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), allocator) + { + this->raw_copy(src, *this, false); + } + + /*! + \brief The moving constructor. + + It uses parameters, translator and allocator from the source tree. + + \param src The rtree which content will be moved. + + \par Throws + Nothing. + */ + inline rtree(BOOST_RV_REF(rtree) src) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), + boost::move(src.m_members.allocators())) + { + boost::swap(m_members.values_count, src.m_members.values_count); + boost::swap(m_members.leafs_level, src.m_members.leafs_level); + boost::swap(m_members.root, src.m_members.root); + } + + /*! + \brief The moving constructor. + + It uses parameters and translator from the source tree. + + \param src The rtree which content will be moved. + \param allocator The allocator. + + \par Throws + \li If allocator copy constructor throws. + \li If Value copy constructor throws (only if allocators aren't equal). + \li If allocation throws (only if allocators aren't equal). + \li When memory allocation for Node fails (only if allocators aren't equal). + */ + inline rtree(BOOST_RV_REF(rtree) src, allocator_type const& allocator) + : m_members(src.m_members.indexable_getter(), + src.m_members.equal_to(), + src.m_members.parameters(), + boost::move(allocator)) + { + if ( src.m_members.allocators() == allocator ) + { + boost::swap(m_members.values_count, src.m_members.values_count); + boost::swap(m_members.leafs_level, src.m_members.leafs_level); + boost::swap(m_members.root, src.m_members.root); + } + else + { + this->raw_copy(src, *this, false); + } + } + + /*! + \brief The assignment operator. + + It uses parameters and translator from the source tree. + + \param src The rtree which content will be copied. + + \par Throws + \li If Value copy constructor throws. + \li If allocation throws. + \li When nodes allocation fails. + */ + inline rtree & operator=(BOOST_COPY_ASSIGN_REF(rtree) src) + { + if ( this == &src ) + return *this; + + typedef boost::mpl::bool_< + allocator_traits_type::propagate_on_container_copy_assignment::value + > propagate; + if ( propagate::value && !(m_members.allocators() == src.m_members.allocators()) ) + this->raw_destroy(*this); + assign_cond(m_members.allocators(), src.m_members.allocators(), propagate()); + + // It uses m_allocators + this->raw_copy(src, *this, true); + + return *this; + } + + /*! + \brief The moving assignment. + + It uses parameters and translator from the source tree. + + \param src The rtree which content will be moved. + + \par Throws + Only if allocators aren't equal. + \li If Value copy constructor throws. + \li If allocation throws. + \li When nodes allocation fails. + */ + inline rtree & operator=(BOOST_RV_REF(rtree) src) + { + if ( this == &src ) + return *this; + + if ( m_members.allocators() == src.m_members.allocators() ) + { + this->raw_destroy(*this); + + m_members.indexable_getter() = src.m_members.indexable_getter(); + m_members.equal_to() = src.m_members.equal_to(); + m_members.parameters() = src.m_members.parameters(); + + boost::swap(m_members.values_count, src.m_members.values_count); + boost::swap(m_members.leafs_level, src.m_members.leafs_level); + boost::swap(m_members.root, src.m_members.root); + + typedef boost::mpl::bool_< + allocator_traits_type::propagate_on_container_move_assignment::value + > propagate; + rtree::move_cond(m_members.allocators(), src.m_members.allocators(), propagate()); + } + else + { +// TODO - shouldn't here propagate_on_container_copy_assignment be checked like in operator=(const&)? + + // It uses m_allocators + this->raw_copy(src, *this, true); + } + + return *this; + } + + /*! + \brief Swaps contents of two rtrees. + + Parameters, translator and allocators are swapped as well. + + \param other The rtree which content will be swapped with this rtree content. + + \par Throws + If allocators swap throws. + */ + void swap(rtree & other) + { + boost::swap(m_members.indexable_getter(), other.m_members.indexable_getter()); + boost::swap(m_members.equal_to(), other.m_members.equal_to()); + boost::swap(m_members.parameters(), other.m_members.parameters()); + m_members.allocators().swap(other.m_members.allocators()); + + boost::swap(m_members.values_count, other.m_members.values_count); + boost::swap(m_members.leafs_level, other.m_members.leafs_level); + boost::swap(m_members.root, other.m_members.root); + } + + /*! + \brief Insert a value to the index. + + \param value The value which will be stored in the container. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When nodes allocation fails. + + \warning + This operation is not thread safe. If it throws, the R-tree may be left in an inconsistent state, + elements must not be inserted or removed, methods may return invalid data. + */ + inline void insert(value_type const& value) + { + if ( !m_members.root ) + this->raw_create(); + + this->raw_insert(value); + } + + /*! + \brief Insert a range of values to the index. + + \param first The beginning of the range of values. + \param last The end of the range of values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When nodes allocation fails. + + \warning + This operation is not thread safe. If it throws, the R-tree may be left in an inconsistent state, + elements must not be inserted or removed, methods may return invalid data. + */ + template + inline void insert(Iterator first, Iterator last) + { + if ( !m_members.root ) + this->raw_create(); + + for ( ; first != last ; ++first ) + this->raw_insert(*first); + } + + /*! + \brief Insert a range of values to the index. + + \param rng The range of values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When nodes allocation fails. + + \warning + This operation is not thread safe. If it throws, the R-tree may be left in an inconsistent state, + elements must not be inserted or removed, methods may return invalid data. + */ + template + inline void insert(Range const& rng) + { + if ( !m_members.root ) + this->raw_create(); + + typedef typename boost::range_const_iterator::type It; + for ( It it = boost::const_begin(rng); it != boost::const_end(rng) ; ++it ) + this->raw_insert(*it); + } + + /*! + \brief Remove a value from the container. + + In contrast to the \c std::set or std::map erase() method + this method removes only one value from the container. + + \param value The value which will be removed from the container. + + \return 1 if the value was removed, 0 otherwise. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When nodes allocation fails. + + \warning + This operation is not thread safe. If it throws, the R-tree may be left in an inconsistent state, + elements must not be inserted or removed, methods may return invalid data. + */ + inline size_type remove(value_type const& value) + { + return this->raw_remove(value); + } + + /*! + \brief Remove a range of values from the container. + + In contrast to the \c std::set or std::map erase() method + it doesn't take iterators pointing to values stored in this container. It removes values equal + to these passed as a range. Furthermore this method removes only one value for each one passed + in the range, not all equal values. + + \param first The beginning of the range of values. + \param last The end of the range of values. + + \return The number of removed values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When nodes allocation fails. + + \warning + This operation is not thread safe. If it throws, the R-tree may be left in an inconsistent state, + elements must not be inserted or removed, methods may return invalid data. + */ + template + inline size_type remove(Iterator first, Iterator last) + { + size_type result = 0; + for ( ; first != last ; ++first ) + result += this->raw_remove(*first); + return result; + } + + /*! + \brief Remove a range of values from the container. + + In contrast to the \c std::set or std::map erase() method + it removes values equal to these passed as a range. Furthermore, this method removes only + one value for each one passed in the range, not all equal values. + + \param rng The range of values. + + \return The number of removed values. + + \par Throws + \li If Value copy constructor or copy assignment throws. + \li If allocation throws. + \li When nodes allocation fails. + + \warning + This operation is not thread safe. If it throws, the R-tree may be left in an inconsistent state, + elements must not be inserted or removed, methods may return invalid data. + */ + template + inline size_type remove(Range const& rng) + { + size_type result = 0; + typedef typename boost::range_const_iterator::type It; + for ( It it = boost::const_begin(rng); it != boost::const_end(rng) ; ++it ) + result += this->raw_remove(*it); + return result; + } + + /*! + \brief Finds values meeting passed predicates e.g. nearest to some Point and/or intersecting some Box. + + This query function performs spatial and k-nearest neighbor searches. It allows to pass a set of predicates. + Values will be returned only if all predicates are met. + + Spatial predicates + + Spatial predicates may be generated by one of the functions listed below: + \li \c boost::geometry::index::covered_by(), + \li \c boost::geometry::index::disjoint(), + \li \c boost::geometry::index::intersects(), + \li \c boost::geometry::index::overlaps(), + \li \c boost::geometry::index::within(), + + It is possible to negate spatial predicates: + \li ! boost::geometry::index::covered_by(), + \li ! boost::geometry::index::disjoint(), + \li ! boost::geometry::index::intersects(), + \li ! boost::geometry::index::overlaps(), + \li ! boost::geometry::index::within() + + Satisfies predicate + + This is a special kind of predicate which allows to pass a user-defined function or function object which checks + if Value should be returned by the query. It's generated by: + \li \c boost::geometry::index::satisfies(). + + Nearest predicate + + If the nearest predicate is passed a k-nearest neighbor search will be performed. This query will result + in returning k values to the output iterator. Only one nearest predicate may be passed to the query. + It may be generated by: + \li \c boost::geometry::index::nearest(). + + Connecting predicates + + Predicates may be passed together connected with \c operator&&(). + + \par Example + \verbatim + // return elements intersecting box + tree.query(bgi::intersects(box), std::back_inserter(result)); + // return elements intersecting poly but not within box + tree.query(bgi::intersects(poly) && !bgi::within(box), std::back_inserter(result)); + // return elements overlapping box and meeting my_fun unary predicate + tree.query(bgi::overlaps(box) && bgi::satisfies(my_fun), std::back_inserter(result)); + // return 5 elements nearest to pt and elements are intersecting box + tree.query(bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result)); + // return 5 elements which centroids are nearest to pt and elements aren't within box + tree.query(bgi::nearest(bgi::to_centroid(pt), 5) && !bgi::within(box), std::back_inserter(result)); + \endverbatim + + \par Throws + If Value copy constructor or copy assignment throws. + + \warning + Only one \c nearest() perdicate may be passed to the query. + + \param predicates Predicates. + \param out_it The output iterator, e.g. generated by std::back_inserter(). + + \return The number of values found. + */ + template + size_type query(Predicates const& predicates, OutIter out_it) const + { + if ( !m_members.root ) + return 0; + + static const unsigned nearest_count = detail::predicates_count_nearest::value; + static const bool is_nearest = 0 < nearest_count; + BOOST_MPL_ASSERT_MSG((nearest_count <= 1), PASS_ONLY_ONE_NEAREST_PREDICATE, (Predicates)); + + return query_dispatch(predicates, out_it, boost::mpl::bool_()); + } + + /*! + \brief Returns the number of stored values. + + \return The number of stored values. + + \par Throws + Nothing. + */ + inline size_type size() const + { + return m_members.values_count; + } + + /*! + \brief Query if the container is empty. + + \return true if the container is empty. + + \par Throws + Nothing. + */ + inline bool empty() const + { + return 0 == m_members.values_count; + } + + /*! + \brief Removes all values stored in the container. + + \par Throws + Nothing. + */ + inline void clear() + { + this->raw_destroy(*this); + } + + /*! + \brief Returns the box able to contain all values stored in the container. + + Returns the box able to contain all values stored in the container. + If the container is empty the result of \c geometry::assign_inverse() is returned. + + \return The box able to contain all values stored in the container or an invalid box if + there are no values in the container. + + \par Throws + Nothing. + */ + inline bounds_type bounds() const + { + bounds_type result; + if ( !m_members.root ) + { + geometry::assign_inverse(result); + return result; + } + + detail::rtree::visitors::children_box + box_v(result, m_members.translator()); + detail::rtree::apply_visitor(box_v, *m_members.root); + + return result; + } + + /*! + \brief Count Values or Indexables stored in the container. + + For indexable_type it returns the number of values which indexables equals the parameter. + For value_type it returns the number of values which equals the parameter. + + \param vori The value or indexable which will be counted. + + \return The number of values found. + + \par Throws + Nothing. + */ + template + size_type count(ValueOrIndexable const& vori) const + { + if ( !m_members.root ) + return 0; + + detail::rtree::visitors::count + count_v(vori, m_members.translator()); + + detail::rtree::apply_visitor(count_v, *m_members.root); + + return count_v.found_count; + } + + /*! + \brief Returns parameters. + + \return The parameters object. + + \par Throws + Nothing. + */ + inline parameters_type parameters() const + { + return m_members.parameters(); + } + + /*! + \brief Returns function retrieving Indexable from Value. + + \return The indexable_getter object. + + \par Throws + Nothing. + */ + indexable_getter indexable_get() const + { + return m_members.indexable_getter(); + } + + /*! + \brief Returns function comparing Values + + \return The value_equal function. + + \par Throws + Nothing. + */ + value_equal value_eq() const + { + return m_members.equal_to(); + } + + /*! + \brief Returns allocator used by the rtree. + + \return The allocator. + + \par Throws + If allocator copy constructor throws. + */ + allocator_type get_allocator() const + { + return m_members.allocators().allocator(); + } + +#if !defined(BOOST_GEOMETRY_INDEX_DETAIL_ENABLE_DEBUG_INTERFACE) +private: +#endif + /*! + \brief Returns the translator object. + + \return The translator object. + + \par Throws + Nothing. + */ + inline translator_type translator() const + { + return m_members.translator(); + } + + /*! + \brief Apply a visitor to the nodes structure in order to perform some operator. + + This function is not a part of the 'official' interface. However it makes + possible e.g. to pass a visitor drawing the tree structure. + + \param visitor The visitor object. + + \par Throws + If Visitor::operator() throws. + */ + template + inline void apply_visitor(Visitor & visitor) const + { + if ( m_members.root ) + detail::rtree::apply_visitor(visitor, *m_members.root); + } + + /*! + \brief Returns the number of stored objects. Same as size(). + + This function is not a part of the 'official' interface. + + \return The number of stored objects. + + \par Throws + Nothing. + */ + inline size_type values_count() const + { + return m_members.values_count; + } + + /*! + \brief Returns the depth of the R-tree. + + This function is not a part of the 'official' interface. + + \return The depth of the R-tree. + + \par Throws + Nothing. + */ + inline size_type depth() const + { + return m_members.leafs_level; + } + +private: + /*! + \pre Root node must exist - m_root != 0. + + \brief Insert a value to the index. + + \param value The value which will be stored in the container. + + \par Exception-safety + basic + */ + inline void raw_insert(value_type const& value) + { + BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist"); + BOOST_GEOMETRY_INDEX_ASSERT(detail::is_valid(m_members.translator()(value)), "Indexable is invalid"); + + detail::rtree::visitors::insert< + value_type, + value_type, options_type, translator_type, box_type, allocators_type, + typename options_type::insert_tag + > insert_v(m_members.root, m_members.leafs_level, value, + m_members.parameters(), m_members.translator(), m_members.allocators()); + + detail::rtree::apply_visitor(insert_v, *m_members.root); + +// TODO +// Think about this: If exception is thrown, may the root be removed? +// Or it is just cleared? + +// TODO +// If exception is thrown, m_values_count may be invalid + ++m_members.values_count; + } + + /*! + \brief Remove the value from the container. + + \param value The value which will be removed from the container. + + \par Exception-safety + basic + */ + inline size_type raw_remove(value_type const& value) + { + // TODO: awulkiew - assert for correct value (indexable) ? + BOOST_GEOMETRY_INDEX_ASSERT(m_members.root, "The root must exist"); + + detail::rtree::visitors::remove< + value_type, options_type, translator_type, box_type, allocators_type + > remove_v(m_members.root, m_members.leafs_level, value, + m_members.parameters(), m_members.translator(), m_members.allocators()); + + detail::rtree::apply_visitor(remove_v, *m_members.root); + + // If exception is thrown, m_values_count may be invalid + + if ( remove_v.is_value_removed() ) + { + BOOST_GEOMETRY_INDEX_ASSERT(0 < m_members.values_count, "unexpected state"); + + --m_members.values_count; + + return 1; + } + + return 0; + } + + /*! + \brief Create an empty R-tree i.e. new empty root node and clear other attributes. + + \par Exception-safety + strong + */ + inline void raw_create() + { + BOOST_GEOMETRY_INDEX_ASSERT(0 == m_members.root, "the tree is already created"); + + m_members.root = detail::rtree::create_node::apply(m_members.allocators()); // MAY THROW (N: alloc) + m_members.values_count = 0; + m_members.leafs_level = 0; + } + + /*! + \brief Destroy the R-tree i.e. all nodes and clear attributes. + + \param t The container which is going to be destroyed. + + \par Exception-safety + nothrow + */ + inline void raw_destroy(rtree & t) + { + if ( t.m_members.root ) + { + detail::rtree::visitors::destroy + del_v(t.m_members.root, t.m_members.allocators()); + detail::rtree::apply_visitor(del_v, *t.m_members.root); + + t.m_members.root = 0; + } + t.m_members.values_count = 0; + t.m_members.leafs_level = 0; + } + + /*! + \brief Copy the R-tree i.e. whole nodes structure, values and other attributes. + It uses destination's allocators to create the new structure. + + \param src The source R-tree. + \param dst The destination R-tree. + \param copy_tr_and_params If true, translator and parameters will also be copied. + + \par Exception-safety + strong + */ + inline void raw_copy(rtree const& src, rtree & dst, bool copy_tr_and_params) const + { + detail::rtree::visitors::copy + copy_v(dst.m_members.allocators()); + + if ( src.m_members.root ) + detail::rtree::apply_visitor(copy_v, *src.m_members.root); // MAY THROW (V, E: alloc, copy, N: alloc) + + if ( copy_tr_and_params ) + { + dst.m_members.indexable_getter() = src.m_members.indexable_getter(); + dst.m_members.equal_to() = src.m_members.equal_to(); + dst.m_members.parameters() = src.m_members.parameters(); + } + + if ( dst.m_members.root ) + { + detail::rtree::visitors::destroy + del_v(dst.m_members.root, dst.m_members.allocators()); + detail::rtree::apply_visitor(del_v, *dst.m_members.root); + dst.m_members.root = 0; + } + + dst.m_members.root = copy_v.result; + dst.m_members.values_count = src.m_members.values_count; + dst.m_members.leafs_level = src.m_members.leafs_level; + } + + /*! + \brief Return values meeting predicates. + + \par Exception-safety + strong + */ + template + size_type query_dispatch(Predicates const& predicates, OutIter out_it, boost::mpl::bool_ const& /*is_nearest*/) const + { + detail::rtree::visitors::spatial_query + find_v(m_members.translator(), predicates, out_it); + + detail::rtree::apply_visitor(find_v, *m_members.root); + + return find_v.found_count; + } + + /*! + \brief Perform nearest neighbour search. + + \par Exception-safety + strong + */ + template + size_type query_dispatch(Predicates const& predicates, OutIter out_it, boost::mpl::bool_ const& /*is_nearest*/) const + { + static const unsigned nearest_index = detail::predicates_find_nearest::value; + typedef detail::predicates_element element_access; + typename element_access::type const& nearest_pred = element_access::get(predicates); + + return raw_nearest_k(nearest_pred.distance_predicates, nearest_pred.count, predicates, out_it); + } + + /*! + \brief Find k values meeting distances and spatial predicates. + + \par Exception-safety + strong + */ + template + inline size_type raw_nearest_k(DistancesPredicates const& dpred, size_t k, Predicates const& pred, OutIter out_it) const + { + typedef typename detail::point_relation::type point_relation; + typedef typename detail::relation::value_type point_type; + + typedef detail::rtree::visitors::nearest_query_result_k< + value_type, + translator_type, + point_type, + OutIter + > result_type; + + result_type result(k, out_it); + + detail::rtree::visitors::nearest_query< + value_type, + options_type, + translator_type, + box_type, + allocators_type, + DistancesPredicates, + Predicates, + result_type + > nearest_v(m_members.parameters(), m_members.translator(), dpred, pred, result); + + detail::rtree::apply_visitor(nearest_v, *m_members.root); + + return result.finish(); + } + + template + static inline void assign_cond(T &, T const&, boost::mpl::bool_ const&) {} + + template + static inline void assign_cond(T & l, T const& r, boost::mpl::bool_ const&) { l = r; } + + template + inline void move_cond(T &, T &, boost::mpl::bool_ const&) {} + + template + inline void move_cond(T & l, T & r, boost::mpl::bool_ const&) { l = ::boost::move(r); } + + struct members_holder + : public translator_type + , public Parameters + , public allocators_type + { + private: + members_holder(members_holder const&); + + public: + template + members_holder(IndGet const& ind_get, + ValEq const& val_eq, + Parameters const& parameters, + BOOST_FWD_REF(Alloc) alloc) + : translator_type(ind_get, val_eq) + , Parameters(parameters) + , allocators_type(boost::forward(alloc)) + , values_count(0) + , leafs_level(0) + , root(0) + {} + + template + members_holder(IndGet const& ind_get, + ValEq const& val_eq, + Parameters const& parameters) + : translator_type(ind_get, val_eq) + , Parameters(parameters) + , allocators_type() + , values_count(0) + , leafs_level(0) + , root(0) + {} + + translator_type const& translator() const { return *this; } + + IndexableGetter const& indexable_getter() const { return *this; } + IndexableGetter & indexable_getter() { return *this; } + EqualTo const& equal_to() const { return *this; } + EqualTo & equal_to() { return *this; } + Parameters const& parameters() const { return *this; } + Parameters & parameters() { return *this; } + allocators_type const& allocators() const { return *this; } + allocators_type & allocators() { return *this; } + + size_type values_count; + size_type leafs_level; + node_pointer root; + }; + + members_holder m_members; +}; + +/*! +\brief Insert a value to the index. + +It calls rtree::insert(value_type const&). + +\ingroup rtree_functions + +\param tree The spatial index. +\param v The value which will be stored in the index. +*/ +template +inline void insert(rtree & tree, Value const& v) +{ + tree.insert(v); +} + +/*! +\brief Insert a range of values to the index. + +It calls rtree::insert(Iterator, Iterator). + +\ingroup rtree_functions + +\param tree The spatial index. +\param first The beginning of the range of values. +\param last The end of the range of values. +*/ +template +inline void insert(rtree & tree, Iterator first, Iterator last) +{ + tree.insert(first, last); +} + +/*! +\brief Insert a range of values to the index. + +It calls rtree::insert(Range const&). + +\ingroup rtree_functions + +\param tree The spatial index. +\param rng The range of values. +*/ +template +inline void insert(rtree & tree, Range const& rng) +{ + tree.insert(rng); +} + +/*! +\brief Remove a value from the container. + +Remove a value from the container. In contrast to the \c std::set or std::map erase() method +this function removes only one value from the container. + +It calls rtree::remove(value_type const&). + +\ingroup rtree_functions + +\param tree The spatial index. +\param v The value which will be removed from the index. + +\return 1 if value was removed, 0 otherwise. +*/ +template +inline typename rtree::size_type +remove(rtree & tree, Value const& v) +{ + return tree.remove(v); +} + +/*! +\brief Remove a range of values from the container. + +Remove a range of values from the container. In contrast to the \c std::set or std::map erase() method +it doesn't take iterators pointing to values stored in this container. It removes values equal +to these passed as a range. Furthermore this function removes only one value for each one passed +in the range, not all equal values. + +It calls rtree::remove(Iterator, Iterator). + +\ingroup rtree_functions + +\param tree The spatial index. +\param first The beginning of the range of values. +\param last The end of the range of values. + +\return The number of removed values. +*/ +template +inline typename rtree::size_type +remove(rtree & tree, Iterator first, Iterator last) +{ + return tree.remove(first, last); +} + +/*! +\brief Remove a range of values from the container. + +Remove a range of values from the container. In contrast to the \c std::set or std::map erase() method +it removes values equal to these passed as a range. Furthermore this method removes only +one value for each one passed in the range, not all equal values. + +It calls rtree::remove(Range const&). + +\ingroup rtree_functions + +\param tree The spatial index. +\param rng The range of values. + +\return The number of removed values. +*/ +template +inline typename rtree::size_type +remove(rtree & tree, Range const& rng) +{ + return tree.remove(rng); +} + +/*! +\brief Finds values meeting passed predicates e.g. nearest to some Point and/or intersecting some Box. + +This query function performs spatial and k-nearest neighbor searches. It allows to pass a set of predicates. +Values will be returned only if all predicates are met. + +Spatial predicates + +Spatial predicates may be generated by one of the functions listed below: +\li \c boost::geometry::index::covered_by(), +\li \c boost::geometry::index::disjoint(), +\li \c boost::geometry::index::intersects(), +\li \c boost::geometry::index::overlaps(), +\li \c boost::geometry::index::within(), + +It is possible to negate spatial predicates: +\li ! boost::geometry::index::covered_by(), +\li ! boost::geometry::index::disjoint(), +\li ! boost::geometry::index::intersects(), +\li ! boost::geometry::index::overlaps(), +\li ! boost::geometry::index::within() + +Satisfies predicate + +This is a special kind of predicate which allows to pass a user-defined function or function object which checks +if Value should be returned by the query. It's generated by: +\li \c boost::geometry::index::satisfies(). + +Nearest predicate + +If the nearest predicate is passed a k-nearest neighbor search will be performed. This query will result +in returning k values to the output iterator. Only one nearest predicate may be passed to the query. +It may be generated by: +\li \c boost::geometry::index::nearest(). + +Connecting predicates + +Predicates may be passed together connected with \c operator&&(). + +\par Example +\verbatim +// return elements intersecting box +bgi::query(tree, bgi::intersects(box), std::back_inserter(result)); +// return elements intersecting poly but not within box +bgi::query(tree, bgi::intersects(poly) && !bgi::within(box), std::back_inserter(result)); +// return elements overlapping box and meeting my_fun value predicate +bgi::query(tree, bgi::overlaps(box) && bgi::satisfies(my_fun), std::back_inserter(result)); +// return 5 elements nearest to pt and elements are intersecting box +bgi::query(tree, bgi::nearest(pt, 5) && bgi::intersects(box), std::back_inserter(result)); +// return 5 elements which centroids are nearest to pt and elements aren't within box +bgi::query(tree, bgi::nearest(bgi::to_centroid(pt), 5) && !bgi::within(box), std::back_inserter(result)); +\endverbatim + +\par Throws +If Value copy constructor or copy assignment throws. + +\warning +Only one \c nearest() perdicate may be passed to the query. + +\ingroup rtree_functions + +\param tree The rtree. +\param predicates Predicates. +\param out_it The output iterator, e.g. generated by std::back_inserter(). + +\return The number of values found. +*/ +template inline +typename rtree::size_type +query(rtree const& tree, + Predicates const& predicates, + OutIter out_it) +{ + return tree.query(predicates, out_it); +} + +/*! +\brief Remove all values from the index. + +It calls \c rtree::clear(). + +\ingroup rtree_functions + +\param tree The spatial index. +*/ +template +inline void clear(rtree & tree) +{ + return tree.clear(); +} + +/*! +\brief Get the number of values stored in the index. + +It calls \c rtree::size(). + +\ingroup rtree_functions + +\param tree The spatial index. + +\return The number of values stored in the index. +*/ +template +inline size_t size(rtree const& tree) +{ + return tree.size(); +} + +/*! +\brief Query if there are no values stored in the index. + +It calls \c rtree::empty(). + +\ingroup rtree_functions + +\param tree The spatial index. + +\return true if there are no values in the index. +*/ +template +inline bool empty(rtree const& tree) +{ + return tree.bounds(); +} + +/*! +\brief Get the box containing all stored values or an invalid box if the index has no values. + +It calls \c rtree::envelope(). + +\ingroup rtree_functions + +\param tree The spatial index. + +\return The box containing all stored values or an invalid box. +*/ +template +inline typename rtree::bounds_type +bounds(rtree const& tree) +{ + return tree.bounds(); +} + +/*! +\brief Exchanges the contents of the container with those of other. + +It calls \c rtree::swap(). + +\ingroup rtree_functions + +\param l The first rtree. +\param r The second rtree. +*/ +template +inline void swap(rtree & l, + rtree & r) +{ + return l.swap(r); +} + +}}} // namespace boost::geometry::index + +#include + +#endif // BOOST_GEOMETRY_INDEX_RTREE_HPP