From 2ee9adef725cc1d95b18e3969198dc1ae7b1bc67 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sun, 25 Sep 2011 09:54:42 +0000 Subject: [PATCH] knn query distance predicates (first version) implemented [SVN r74558] --- .../extensions/index/distance_predicates.hpp | 78 +++---- .../index/rtree/distance_predicates.hpp | 190 ++++++++++++++---- .../geometry/extensions/index/rtree/rtree.hpp | 81 ++++++-- .../index/rtree/visitors/nearest.hpp | 71 ++++--- tests/additional_glut_vis.cpp | 70 +++++-- 5 files changed, 342 insertions(+), 148 deletions(-) diff --git a/include/boost/geometry/extensions/index/distance_predicates.hpp b/include/boost/geometry/extensions/index/distance_predicates.hpp index 7b771d610..65d1be779 100644 --- a/include/boost/geometry/extensions/index/distance_predicates.hpp +++ b/include/boost/geometry/extensions/index/distance_predicates.hpp @@ -10,6 +10,10 @@ #ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_DISTANCE_PREDICATES_HPP #define BOOST_GEOMETRY_EXTENSIONS_INDEX_DISTANCE_PREDICATES_HPP +#include +#include +#include + namespace boost { namespace geometry { namespace index { namespace detail { @@ -271,10 +275,10 @@ struct distance_calc< } }; -// distance_check +// distance_predicate_check -template -struct distance_check +template +struct distance_predicate_check { template static inline bool apply(Point const&, DistanceType const&) @@ -283,9 +287,10 @@ struct distance_check } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_unbounded, + Indexable, Tag> { template @@ -297,9 +302,10 @@ struct distance_check< } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_half_bounded, + Indexable, Tag> { template @@ -311,9 +317,10 @@ struct distance_check< } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_half_bounded, + Indexable, Tag> { template @@ -325,9 +332,10 @@ struct distance_check< } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_bounded, + Indexable, Tag> { template @@ -339,38 +347,34 @@ struct distance_check< } }; -// move distance_calc and distance_comp into geometry::index ? +// distance_point -// TODO: awulkiew - pruning for nodes! <- inside detail::rtree so NOT HERE -// if 0 < comp_near node is pruned if maxdist(point, node_box) < comp_near -// if comp_far < INF node is pruned if comp_far < min_dist(point, node_box) -// still nodes must be sorted by min_dist(point, node_box) +template +struct distance_point +{ + typedef Point type; +}; -// for values, proper distance values are calculated min, max or centroid -// and tested with comp_near and/or comp_far +template +struct distance_point< detail::distance_unbounded > +{ + typedef Point type; +}; -// + something in case of nodes -// additional calculation of maxdist in case of distance_between and -// distance_xxxxx +template +struct distance_point< detail::distance_half_bounded > +{ + typedef Point type; +}; + +template +struct distance_point< detail::distance_bounded > +{ + typedef Point type; +}; } // namespace detail -//template -//inline typename detail::distance_calc::distance_type -//distance_calc(PointData const& p, Indexable const& i) -//{ -// return detail::distance_calc -// ::apply(p, i); -//} -// -//template -//inline bool -//distance_comp(PointData const& p, DistanceType const& d) -//{ -// return detail::distance_comp -// ::apply(p, d); -//} - }}} // namespace boost::geometry::index #endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_DISTANCE_PREDICATES_HPP diff --git a/include/boost/geometry/extensions/index/rtree/distance_predicates.hpp b/include/boost/geometry/extensions/index/rtree/distance_predicates.hpp index 50d3fe6f5..3bb39c19c 100644 --- a/include/boost/geometry/extensions/index/rtree/distance_predicates.hpp +++ b/include/boost/geometry/extensions/index/rtree/distance_predicates.hpp @@ -11,6 +11,8 @@ #ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_DISTANCE_PREDICATES_HPP #define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_DISTANCE_PREDICATES_HPP +#include + namespace boost { namespace geometry { namespace index { namespace detail { @@ -26,7 +28,10 @@ struct node_distance_predicate_tag {}; // distance_calc template -struct distance_calc +struct distance_calc< + Point, + Indexable, + rtree::node_distance_predicate_tag> { typedef typename geometry::default_distance_result::type result_type; @@ -36,60 +41,85 @@ struct distance_calc } }; -// TODO - finish specializations for nodes - -template +template struct distance_calc< detail::distance_unbounded, Indexable, - Tag> + rtree::node_distance_predicate_tag> { - typedef typename distance_calc_impl::result_type result_type; + typedef typename geometry::default_distance_result::type result_type; static inline result_type apply( detail::distance_unbounded const& dx, Indexable const& i) { - return distance_calc_impl::apply(dx.point, i); + return index::comparable_distance_near(dx.point, i); } }; -template +template struct distance_calc< - detail::distance_half_bounded, + detail::distance_half_bounded, Indexable, - Tag> + rtree::node_distance_predicate_tag> { - typedef typename distance_calc_impl::result_type result_type; + typedef typename geometry::default_distance_result::type distance_type; + typedef std::pair result_type; static inline result_type apply( - detail::distance_half_bounded const& dx, + detail::distance_half_bounded const& dx, Indexable const& i) { - return distance_calc_impl::apply(dx.point, i); + return std::make_pair( + index::comparable_distance_near(dx.point, i), + index::comparable_distance_far(dx.point, i) + ); } }; -template +template +struct distance_calc< + detail::distance_half_bounded, + Indexable, + rtree::node_distance_predicate_tag> +{ + typedef typename geometry::default_distance_result::type result_type; + + static inline result_type apply( + detail::distance_half_bounded const& dx, + Indexable const& i) + { + return index::comparable_distance_near(dx.point, i); + } +}; + +template struct distance_calc< detail::distance_bounded, Indexable, - Tag> + rtree::node_distance_predicate_tag> { - typedef typename distance_calc_impl::result_type result_type; + typedef typename geometry::default_distance_result::type distance_type; + typedef std::pair result_type; static inline result_type apply( detail::distance_bounded const& dx, Indexable const& i) { - return distance_calc_impl::apply(dx.point, i); + return std::make_pair( + index::comparable_distance_near(dx.point, i), + index::comparable_distance_far(dx.point, i) + ); } }; -// distance_check +// distance_predicate_check -template -struct distance_check +template +struct distance_predicate_check< + Point, + Indexable, + rtree::node_distance_predicate_tag> { template static inline bool apply(Point const&, DistanceType const&) @@ -98,10 +128,11 @@ struct distance_check } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_unbounded, - Tag> + Indexable, + rtree::node_distance_predicate_tag> { template static inline bool apply( @@ -112,24 +143,26 @@ struct distance_check< } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_half_bounded, - Tag> + Indexable, + rtree::node_distance_predicate_tag> { template static inline bool apply( detail::distance_half_bounded const& dx, - DistanceType const& comparable_d) + DistanceType const& d) { - return dx.comparable_limit <= comparable_d; + return dx.comparable_limit <= d.second; } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_half_bounded, - Tag> + Indexable, + rtree::node_distance_predicate_tag> { template static inline bool apply( @@ -140,20 +173,105 @@ struct distance_check< } }; -template -struct distance_check< +template +struct distance_predicate_check< detail::distance_bounded, - Tag> + Indexable, + rtree::node_distance_predicate_tag> { template static inline bool apply( detail::distance_bounded const& dx, - DistanceType const& comparable_d) + DistanceType const& d) { - return dx.comparable_min <= comparable_d && comparable_d <= dx.comparable_max; + return dx.comparable_min <= d.second && d.first <= dx.comparable_max; } }; +// TODO implement alternative version for Indexable being a Point - don't need to calculate the distance 2x +// TODO explicitly define DistanceType ? + +namespace rtree +{ + +// distance less comparator + +template +struct distance_less +{ + template + inline bool operator()(DistanceType const& d1, DistanceType const& d2) + { + return d1 < d2; + } +}; + +template +struct distance_less< + detail::distance_half_bounded, + Indexable +> +{ + template + inline bool operator()(DistanceType const& d1, DistanceType const& d2) + { + return d1.first < d2.first; + } +}; + +template +struct distance_less< + detail::distance_bounded, + Indexable +> +{ + template + inline bool operator()(DistanceType const& d1, DistanceType const& d2) + { + return d1.first < d2.first; + } +}; + +// TODO distance_node_pruning_check + +template +struct distance_node_pruning_check +{ + template + static inline bool apply(SmallestDistanceType const& sd, NodeDistanceType const& nd) + { + return sd < nd; + } +}; + +template +struct distance_node_pruning_check< + detail::distance_half_bounded, + Indexable +> +{ + template + static inline bool apply(SmallestDistanceType const& sd, NodeDistanceType const& nd) + { + return sd < nd.first; + } +}; + +template +struct distance_node_pruning_check< + detail::distance_bounded, + Indexable +> +{ + template + static inline bool apply(SmallestDistanceType const& sd, NodeDistanceType const& nd) + { + return sd < nd.first; + } +}; + +} // namespace rtree + // move distance_calc and distance_comp into geometry::index ? // TODO: awulkiew - pruning for nodes! <- inside detail::rtree so NOT HERE diff --git a/include/boost/geometry/extensions/index/rtree/rtree.hpp b/include/boost/geometry/extensions/index/rtree/rtree.hpp index 2088782fd..eae2a9a08 100644 --- a/include/boost/geometry/extensions/index/rtree/rtree.hpp +++ b/include/boost/geometry/extensions/index/rtree/rtree.hpp @@ -40,6 +40,7 @@ namespace boost { namespace geometry { namespace index { // TODO copying +// TODO move extensional/debug visitors to the other folder template < typename Value, @@ -94,28 +95,28 @@ public: // TODO: awulkiew - change Point to Geometry? // return number of elements instead of bool? - template - inline size_t nearest(Point const& pt, value_type & v) const + template + inline size_t nearest(DistancePredicate const& p, value_type & v) const { - return nearest_one(pt, detail::empty(), v); + return nearest_one(p, detail::empty(), v); } - template - inline size_t nearest(Point const& pt, Predicates const& pred, value_type & v) const + template + inline size_t nearest(DistancePredicate const& p, Predicates const& pred, value_type & v) const { - return nearest_one(pt, pred, v); + return nearest_one(p, pred, v); } - template - inline size_t nearest(Point const& pt, size_t k, OutIter out_it) const + template + inline size_t nearest(DistancePredicate const& p, size_t k, OutIter out_it) const { - return nearest_k(pt, k, detail::empty(), out_it); + return nearest_k(p, k, detail::empty(), out_it); } - template - inline size_t nearest(Point const& pt, size_t k, Predicates const& pred, OutIter out_it) const + template + inline size_t nearest(DistancePredicate const& p, size_t k, Predicates const& pred, OutIter out_it) const { - return nearest_k(pt, k, pred, out_it); + return nearest_k(p, k, pred, out_it); } inline void insert(value_type const& value) @@ -187,28 +188,52 @@ public: } private: - template - inline size_t nearest_one(Point const& pt, Predicates const& pred, value_type & v) const + template + inline size_t nearest_one(DistancePredicate const& p, Predicates const& pred, value_type & v) const { - typedef detail::rtree::visitors::nearest_one result_type; + typedef detail::rtree::visitors::nearest_one< + value_type, + translator_type, + typename detail::distance_point::type + > result_type; + result_type result; - detail::rtree::visitors::nearest - nearest_v(m_translator, pt, pred, result); + detail::rtree::visitors::nearest< + value_type, + options_type, + translator_type, + box_type, + DistancePredicate, + Predicates, + result_type + > nearest_v(m_translator, p, pred, result); detail::rtree::apply_visitor(nearest_v, *m_root); return result.get(v); } - template - inline size_t nearest_k(Point const& pt, size_t k, Predicates const& pred, OutIter out_it) const + template + inline size_t nearest_k(DistancePredicate const& p, size_t k, Predicates const& pred, OutIter out_it) const { - typedef detail::rtree::visitors::nearest_k result_type; + typedef detail::rtree::visitors::nearest_k< + value_type, + translator_type, + typename detail::distance_point::type + > result_type; + result_type result(k); - detail::rtree::visitors::nearest - nearest_v(m_translator, pt, pred, result); + detail::rtree::visitors::nearest< + value_type, + options_type, + translator_type, + box_type, + DistancePredicate, + Predicates, + result_type + > nearest_v(m_translator, p, pred, result); detail::rtree::apply_visitor(nearest_v, *m_root); @@ -263,6 +288,18 @@ inline size_t nearest(rtree const& tree, Point const return tree.nearest(pt, k, pred, out_it); } +template +inline size_t size(rtree const& tree) +{ + return tree.size(); +} + +template +inline bool empty(rtree const& tree) +{ + return tree.empty(); +} + }}} // namespace boost::geometry::index #endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_HPP diff --git a/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp b/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp index c25c6e68d..c69a41717 100644 --- a/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp +++ b/include/boost/geometry/extensions/index/rtree/visitors/nearest.hpp @@ -10,11 +10,7 @@ #ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_VISITORS_NEAREST_HPP #define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_VISITORS_NEAREST_HPP -#include -#include -#include - -#include +#include #include @@ -134,7 +130,7 @@ template < typename Options, typename Translator, typename Box, - typename PointData, + typename DistancePredicate, typename Predicates, typename Result > @@ -147,10 +143,17 @@ public: typedef typename rtree::internal_node::type internal_node; typedef typename rtree::leaf::type leaf; - typedef typename geometry::default_distance_result::type node_distance_type; + typedef index::detail::distance_calc node_distance_calc; + typedef typename node_distance_calc::result_type node_distance_type; + typedef index::detail::distance_predicate_check node_distance_predicate_check; + typedef rtree::distance_less node_distance_less; - inline nearest(Translator const& t, PointData const& point_data, Predicates const& pr, Result & r) - : m_tr(t), m_point_data(point_data), m_pred(pr) + typedef index::detail::distance_calc value_distance_calc; + typedef typename value_distance_calc::result_type value_distance_type; + typedef index::detail::distance_predicate_check value_distance_predicate_check; + + inline nearest(Translator const& t, DistancePredicate const& dist_pred, Predicates const& pred, Result & r) + : m_tr(t), m_dist_pred(dist_pred), m_pred(pred) , m_result(r) {} @@ -159,11 +162,10 @@ public: inline void operator()(internal_node const& n) { // array of active nodes - /*index::pushable_array< + index::pushable_array< std::pair, Options::parameters_type::max_elements - > active_branch_list;*/ - std::vector< std::pair > active_branch_list; + > active_branch_list; typedef typename rtree::elements_type::type elements_type; elements_type const& elements = rtree::elements(n); @@ -172,14 +174,18 @@ public: for (typename elements_type::const_iterator it = elements.begin(); it != elements.end(); ++it) { + // if current node meets predicates if ( index::predicates_check(m_pred, it->first) ) { - active_branch_list.push_back( - std::make_pair( - index::comparable_distance_near(m_point_data, it->first), - it->second - ) - ); + // calculate node's distance(s) for distance predicate + node_distance_type node_dist_data = node_distance_calc::apply(m_dist_pred, it->first); + + // if current node distance(s) meets distance predicate + if ( node_distance_predicate_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) ); + } } } @@ -188,7 +194,7 @@ public: return; // sort array - std::sort(active_branch_list.begin(), active_branch_list.end(), abl_mindist_less); + std::sort(active_branch_list.begin(), active_branch_list.end(), node_distance_less()); // recursively visit nodes for ( size_t i = 0 ;; ++i ) @@ -212,25 +218,23 @@ public: for (typename elements_type::const_iterator it = elements.begin(); it != elements.end(); ++it) { + // if value meets predicates if ( index::predicates_check(m_pred, m_tr(*it)) ) { - // store value - m_result.store( - *it, - index::comparable_distance_near(m_point_data, m_tr(*it)) - ); + // calculate values distance for distance predicate + value_distance_type dist = value_distance_calc::apply(m_dist_pred, m_tr(*it)); + + // if distance meets distance predicate + if ( value_distance_predicate_check::apply(m_dist_pred, dist) ) + { + // store value + m_result.store(*it, dist); + } } } } private: - inline static bool abl_mindist_less( - std::pair const& p1, - std::pair const& p2) - { - return p1.first < p2.first; - } - template inline void prune_nodes(ActiveBranchList & abl) const { @@ -239,7 +243,8 @@ private: { // prune if box's mindist is further than value's mindist while ( !abl.empty() && - m_result.comparable_distance() < abl.back().first ) + distance_node_pruning_check + ::apply(m_result.comparable_distance(), abl.back().first) ) { abl.pop_back(); } @@ -247,7 +252,7 @@ private: } Translator const& m_tr; - PointData const& m_point_data; + DistancePredicate const& m_dist_pred; Predicates const& m_pred; Result & m_result; diff --git a/tests/additional_glut_vis.cpp b/tests/additional_glut_vis.cpp index 1a3c800a3..ddae78142 100644 --- a/tests/additional_glut_vis.cpp +++ b/tests/additional_glut_vis.cpp @@ -26,24 +26,51 @@ boost::geometry::index::rtree< boost::geometry::index::rstar<4, 2> > t; std::vector vect; -bool is_nearest = false; +size_t found_count = 0; P search_point; +float min_distance = 20; +float max_distance = 30; +size_t count = 10; std::vector nearest_boxes; +void draw_search_area() +{ + float x = boost::geometry::get<0>(search_point); + float y = boost::geometry::get<1>(search_point); + float z = t.depth(); + + // search point + glBegin(GL_TRIANGLES); + glVertex3f(x, y, z); + glVertex3f(x + 1, y, z); + glVertex3f(x + 1, y + 1, z); + glEnd(); + + // search min circle + + glBegin(GL_LINE_LOOP); + for(float a = 0 ; a < 3.14158f * 2 ; a += 3.14158f / 180) + glVertex3f(x + min_distance * ::cos(a), y + min_distance * ::sin(a), z); + glEnd(); + + // search max circle + + glBegin(GL_LINE_LOOP); + for(float a = 0 ; a < 3.14158f * 2 ; a += 3.14158f / 180) + glVertex3f(x + max_distance * ::cos(a), y + max_distance * ::sin(a), z); + glEnd(); +} + void render_scene(void) { glClear(GL_COLOR_BUFFER_BIT); boost::geometry::index::gl_draw(t); - if ( is_nearest ) + if ( found_count > 0 ) { glColor3f(1.0f, 0.5f, 0.0f); - glBegin(GL_TRIANGLES); - glVertex3f(boost::geometry::get<0>(search_point), boost::geometry::get<1>(search_point), t.depth()); - glVertex3f(boost::geometry::get<0>(search_point) + 1, boost::geometry::get<1>(search_point), t.depth()); - glVertex3f(boost::geometry::get<0>(search_point) + 1, boost::geometry::get<1>(search_point) + 1, t.depth()); - glEnd(); + draw_search_area(); for ( size_t i = 0 ; i < nearest_boxes.size() ; ++i ) boost::geometry::index::detail::rtree::visitors::detail::gl_draw_indexable(nearest_boxes[i], t.depth()); @@ -75,6 +102,9 @@ void resize(int w, int h) void mouse(int button, int state, int x, int y) { + namespace bg = boost::geometry; + namespace bgi = bg::index; + if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) { float x = ( rand() % 100 ); @@ -88,12 +118,12 @@ void mouse(int button, int state, int x, int y) vect.push_back(b); std::cout << "inserted: "; - boost::geometry::index::detail::rtree::visitors::detail::print_indexable(std::cout, b); + bgi::detail::rtree::visitors::detail::print_indexable(std::cout, b); std::cout << '\n'; std::cout << "\n" << t << "\n"; - std::cout << ( boost::geometry::index::are_boxes_ok(t) ? "boxes OK\n" : "WRONG BOXES!\n" ); - std::cout << ( boost::geometry::index::are_levels_ok(t) ? "levels OK\n" : "WRONG LEVELS!\n" ); + std::cout << ( bgi::are_boxes_ok(t) ? "boxes OK\n" : "WRONG BOXES!\n" ); + std::cout << ( bgi::are_levels_ok(t) ? "levels OK\n" : "WRONG LEVELS!\n" ); std::cout << "\n"; } else if ( button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN ) @@ -104,16 +134,16 @@ void mouse(int button, int state, int x, int y) size_t i = rand() % vect.size(); B b = vect[i]; - boost::geometry::index::remove(t, b); + bgi::remove(t, b); vect.erase(vect.begin() + i); std::cout << "removed: "; - boost::geometry::index::detail::rtree::visitors::detail::print_indexable(std::cout, b); + bgi::detail::rtree::visitors::detail::print_indexable(std::cout, b); std::cout << '\n'; std::cout << "\n" << t << "\n"; - std::cout << ( boost::geometry::index::are_boxes_ok(t) ? "boxes OK\n" : "WRONG BOXES!\n" ); - std::cout << ( boost::geometry::index::are_levels_ok(t) ? "levels OK\n" : "WRONG LEVELS!\n" ); + std::cout << ( bgi::are_boxes_ok(t) ? "boxes OK\n" : "WRONG BOXES!\n" ); + std::cout << ( bgi::are_levels_ok(t) ? "levels OK\n" : "WRONG LEVELS!\n" ); std::cout << "\n"; } else if ( button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN ) @@ -123,16 +153,16 @@ void mouse(int button, int state, int x, int y) search_point = P(x, y); nearest_boxes.clear(); - is_nearest = t.nearest(search_point, 3, std::back_inserter(nearest_boxes)); + found_count = t.nearest(bgi::distance_centroid(search_point, min_distance, max_distance), count, std::back_inserter(nearest_boxes)); - if ( is_nearest ) + if ( found_count > 0 ) { std::cout << "search point: "; - boost::geometry::index::detail::rtree::visitors::detail::print_indexable(std::cout, search_point); + bgi::detail::rtree::visitors::detail::print_indexable(std::cout, search_point); std::cout << "\nfound: "; for ( size_t i = 0 ; i < nearest_boxes.size() ; ++i ) { - boost::geometry::index::detail::rtree::visitors::detail::print_indexable(std::cout, nearest_boxes[i]); + bgi::detail::rtree::visitors::detail::print_indexable(std::cout, nearest_boxes[i]); std::cout << '\n'; } } @@ -140,8 +170,8 @@ void mouse(int button, int state, int x, int y) std::cout << "nearest not found\n"; std::cout << "\n" << t << "\n"; - std::cout << ( boost::geometry::index::are_boxes_ok(t) ? "boxes OK\n" : "WRONG BOXES!\n" ); - std::cout << ( boost::geometry::index::are_levels_ok(t) ? "levels OK\n" : "WRONG LEVELS!\n" ); + std::cout << ( bgi::are_boxes_ok(t) ? "boxes OK\n" : "WRONG BOXES!\n" ); + std::cout << ( bgi::are_levels_ok(t) ? "levels OK\n" : "WRONG LEVELS!\n" ); std::cout << "\n"; }