[distance] base cose for distance computations using the R-Tree

This commit is contained in:
Menelaos Karavelas
2014-05-08 14:58:05 +03:00
parent e1e227c022
commit 8553124d37

View File

@@ -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 <cstddef>
#include <algorithm>
#include <iterator>
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/iterators/point_iterator.hpp>
#include <boost/geometry/iterators/has_one_element.hpp>
#include <boost/geometry/algorithms/for_each.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/distance_comparable_to_regular.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/index/rtree.hpp>
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<Geometry>::type
>::type return_type;
private:
typedef index::rtree<RTreePoint, index::linear<8> > 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 <typename QueryGeometry>
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 <typename G, typename Tag = typename tag<G>::type>
struct for_each_selector
{
typedef dispatch::for_each_segment<G> type;
};
template <typename MultiPoint>
struct for_each_selector<MultiPoint, multi_point_tag>
{
typedef dispatch::for_each_point<MultiPoint> type;
};
public:
template <typename PointIterator>
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<PointIterator>::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<Geometry>::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<Geometry1>::type,
typename point_type<Geometry2>::type
>::type return_type;
static inline return_type apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy,
bool check_intersection = true)
{
point_iterator<Geometry1 const> first1 = points_begin(geometry1);
point_iterator<Geometry1 const> beyond1 = points_end(geometry1);
point_iterator<Geometry2 const> first2 = points_begin(geometry2);
point_iterator<Geometry2 const> beyond2 = points_end(geometry2);
if ( geometry::has_one_element(first1, beyond1) )
{
return dispatch::distance
<
typename point_type<Geometry1>::type,
Geometry2,
Strategy
>::apply(*first1, geometry2, strategy);
}
if ( geometry::has_one_element(first2, beyond2) )
{
return dispatch::distance
<
typename point_type<Geometry2>::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<Geometry1>::type,
Geometry2,
Strategy
>::apply(first1, beyond1, geometry2, strategy);
return_type cdist2 = point_range_to_geometry_rtree
<
typename point_type<Geometry2>::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 <typename Linestring1, typename Linestring2, typename Strategy>
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 <typename Linestring, typename Polygon, typename Strategy>
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 <typename Linestring, typename Ring, typename Strategy>
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 <typename Polygon1, typename Polygon2, typename Strategy>
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 <typename Polygon, typename Ring, typename Strategy>
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