From 8553124d37d56dbb4b77d039b0be1cbecd1c47d8 Mon Sep 17 00:00:00 2001 From: Menelaos Karavelas Date: Thu, 8 May 2014 14:58:05 +0300 Subject: [PATCH] [distance] base cose for distance computations using the R-Tree --- .../distance/geometry_to_geometry_rtree.hpp | 338 ++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 include/boost/geometry/algorithms/detail/distance/geometry_to_geometry_rtree.hpp diff --git a/include/boost/geometry/algorithms/detail/distance/geometry_to_geometry_rtree.hpp b/include/boost/geometry/algorithms/detail/distance/geometry_to_geometry_rtree.hpp new file mode 100644 index 000000000..84030d77c --- /dev/null +++ b/include/boost/geometry/algorithms/detail/distance/geometry_to_geometry_rtree.hpp @@ -0,0 +1,338 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_GEOMETRY_RTREE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_GEOMETRY_RTREE_HPP + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace distance +{ + + + +template +< + typename RTreePoint, + typename Geometry, + typename Strategy +> +class point_range_to_geometry_rtree +{ +public: + typedef typename strategy::distance::services::comparable_type + < + Strategy + >::type comparable_strategy; + + typedef typename strategy::distance::services::return_type + < + Strategy, + RTreePoint, + typename point_type::type + >::type return_type; + +private: + typedef index::rtree > r_tree; + + // functor to evaluate minimum comparable distance + struct minimum_cdistance_evaluator + { + r_tree const& m_r_tree; + comparable_strategy const& m_cstrategy; + bool m_first; + return_type m_min_cd; + + minimum_cdistance_evaluator(r_tree const& r_tree, + comparable_strategy const& cstrategy) + : m_r_tree(r_tree), m_cstrategy(cstrategy), + m_first(true), m_min_cd() + {} + + template + inline void operator()(QueryGeometry const& query_geometry) + { + typename r_tree::value_type t_v; + std::size_t n = + m_r_tree.query(index::nearest(query_geometry, 1), &t_v); + + BOOST_ASSERT( n > 0 ); + + return_type cd = dispatch::distance + < + typename r_tree::value_type, + QueryGeometry, + comparable_strategy + >::apply(t_v, query_geometry, m_cstrategy); + + if ( m_first || cd < m_min_cd ) + { + m_first = false; + m_min_cd = cd; + } + } + }; + + + + // class to choose between for_each_point and for_each_segment + template ::type> + struct for_each_selector + { + typedef dispatch::for_each_segment type; + }; + + template + struct for_each_selector + { + typedef dispatch::for_each_point type; + }; + +public: + template + static inline return_type apply(PointIterator points_first, + PointIterator points_beyond, + Geometry const& geometry, + Strategy const& strategy) + { + BOOST_ASSERT( points_first != points_beyond ); + + if ( geometry::has_one_element(points_first, points_beyond) ) + { + return dispatch::distance + < + typename std::iterator_traits::value_type, + Geometry, + Strategy + >::apply(*points_first, geometry, strategy); + } + + // create -- packing algorithm + r_tree rt(points_first, points_beyond); + + minimum_cdistance_evaluator + functor(rt, + strategy::distance::services::get_comparable + < + Strategy + >::apply(strategy)); + + for_each_selector::type::apply(geometry, functor); + + return strategy::distance::services::comparable_to_regular + < + comparable_strategy, Strategy, RTreePoint, Geometry + >::apply(functor.m_min_cd); + } +}; + + + +template +< + typename Geometry1, + typename Geometry2, + typename Strategy +> +struct geometry_to_geometry_rtree +{ + // the following works with linear geometries seen as ranges of points + // + // we compute the r-tree for the points of one range and then, + // compute nearest points for the segments of the other, + // ... and ... + // vice versa. + + typedef typename strategy::distance::services::return_type + < + Strategy, + typename point_type::type, + typename point_type::type + >::type return_type; + + static inline return_type apply(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Strategy const& strategy, + bool check_intersection = true) + { + point_iterator first1 = points_begin(geometry1); + point_iterator beyond1 = points_end(geometry1); + point_iterator first2 = points_begin(geometry2); + point_iterator beyond2 = points_end(geometry2); + + if ( geometry::has_one_element(first1, beyond1) ) + { + return dispatch::distance + < + typename point_type::type, + Geometry2, + Strategy + >::apply(*first1, geometry2, strategy); + } + + if ( geometry::has_one_element(first2, beyond2) ) + { + return dispatch::distance + < + typename point_type::type, + Geometry1, + Strategy + >::apply(*first2, geometry1, strategy); + } + + if ( check_intersection && geometry::intersects(geometry1, geometry2) ) + { + return return_type(0); + } + + return_type cdist1 = point_range_to_geometry_rtree + < + typename point_type::type, + Geometry2, + Strategy + >::apply(first1, beyond1, geometry2, strategy); + + return_type cdist2 = point_range_to_geometry_rtree + < + typename point_type::type, + Geometry1, + Strategy + >::apply(first2, beyond2, geometry1, strategy); + + return (std::min)(cdist1, cdist2); + } +}; + + + + +}} // namespace detail::distance +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +struct distance + < + Linestring1, Linestring2, Strategy, + linestring_tag, linestring_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::geometry_to_geometry_rtree + < + Linestring1, Linestring2, Strategy + > +{}; + + + +template +struct distance + < + Linestring, Polygon, Strategy, + linestring_tag, polygon_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::geometry_to_geometry_rtree + < + Linestring, Polygon, Strategy + > +{}; + + + +template +struct distance + < + Linestring, Ring, Strategy, + linestring_tag, ring_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::geometry_to_geometry_rtree + < + Linestring, Ring, Strategy + > +{}; + + + +template +struct distance + < + Polygon1, Polygon2, Strategy, + polygon_tag, polygon_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::geometry_to_geometry_rtree + < + Polygon1, Polygon2, Strategy + > +{}; + + + +template +struct distance + < + Polygon, Ring, Strategy, + polygon_tag, ring_tag, + strategy_tag_distance_point_segment, false + > + : detail::distance::geometry_to_geometry_rtree + < + Polygon, Ring, Strategy + > +{}; + + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_GEOMETRY_RTREE_HPP