mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-02 21:02:13 +00:00
[algorithms][distance] re-factor point-to-geometry distance computations;
include in point_to_geometry.hpp implementation of point-to-multigeometry distance computations and dispatches; compute, whenever applicable, the closest feature of the goemetry to the point, and then compute the distance as the distance of this closest feature to the point; optimize the performance of point-to-ring and point-to-polygon by not computing both containment and distance to the boundary: compute the distance to the boundary only if the containment test fails;
This commit is contained in:
@@ -20,33 +20,32 @@
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
|
||||
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/closure.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
#include <boost/geometry/core/exterior_ring.hpp>
|
||||
#include <boost/geometry/core/interior_rings.hpp>
|
||||
#include <boost/geometry/core/interior_type.hpp>
|
||||
#include <boost/geometry/core/tag.hpp>
|
||||
#include <boost/geometry/core/tags.hpp>
|
||||
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/distance.hpp>
|
||||
#include <boost/geometry/strategies/tags.hpp>
|
||||
#include <boost/geometry/strategies/distance_comparable_to_regular.hpp>
|
||||
|
||||
#include <boost/geometry/views/closeable_view.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/within.hpp>
|
||||
#include <boost/geometry/algorithms/intersects.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp>
|
||||
#include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp>
|
||||
#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/dispatch/distance.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
@@ -63,7 +62,7 @@ struct point_to_point
|
||||
typename strategy::distance::services::return_type<Strategy, P1, P2>::type
|
||||
apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
|
||||
{
|
||||
boost::ignore_unused_variable_warning(strategy);
|
||||
boost::ignore_unused(strategy);
|
||||
return strategy.apply(p1, p2);
|
||||
}
|
||||
};
|
||||
@@ -84,12 +83,10 @@ private:
|
||||
Strategy
|
||||
>::type comparable_strategy;
|
||||
|
||||
typedef typename strategy::distance::services::return_type
|
||||
typedef detail::closest_feature::point_to_point_range
|
||||
<
|
||||
comparable_strategy,
|
||||
Point,
|
||||
typename boost::range_value<Range>::type
|
||||
>::type comparable_return_type;
|
||||
Point, Range, Closure, comparable_strategy
|
||||
> closest_feature_type;
|
||||
|
||||
public:
|
||||
typedef typename strategy::distance::services::return_type
|
||||
@@ -102,68 +99,24 @@ public:
|
||||
static inline return_type apply(Point const& point, Range const& range,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
comparable_strategy c_strategy =
|
||||
strategy::distance::services::get_comparable
|
||||
<
|
||||
Strategy
|
||||
>::apply(strategy);
|
||||
return_type const zero = return_type(0);
|
||||
|
||||
comparable_return_type const zero = comparable_return_type(0);
|
||||
|
||||
if (boost::size(range) == 0)
|
||||
if ( boost::size(range) == 0 )
|
||||
{
|
||||
return zero;
|
||||
}
|
||||
|
||||
typedef typename closeable_view<Range const, Closure>::type view_type;
|
||||
namespace sds = strategy::distance::services;
|
||||
|
||||
view_type view(range);
|
||||
typename closest_feature_type::return_type cf
|
||||
= closest_feature_type::apply(point,
|
||||
range,
|
||||
sds::get_comparable
|
||||
<
|
||||
Strategy
|
||||
>::apply(strategy));
|
||||
|
||||
// line of one point: return point distance
|
||||
typedef typename boost::range_iterator<view_type const>::type iterator_type;
|
||||
iterator_type it = boost::begin(view);
|
||||
iterator_type prev = it++;
|
||||
if (it == boost::end(view))
|
||||
{
|
||||
return strategy::distance::services::comparable_to_regular
|
||||
<
|
||||
comparable_strategy, Strategy, Point,
|
||||
typename boost::range_value<Range>::type
|
||||
>::apply( c_strategy.apply(point,
|
||||
*boost::begin(view),
|
||||
*boost::begin(view)) );
|
||||
}
|
||||
|
||||
// start with first segment distance
|
||||
comparable_return_type cd = c_strategy.apply(point, *prev, *it);
|
||||
|
||||
// check if other segments are closer
|
||||
for (++prev, ++it; it != boost::end(view); ++prev, ++it)
|
||||
{
|
||||
comparable_return_type cds = c_strategy.apply(point, *prev, *it);
|
||||
if (geometry::math::equals(cds, zero))
|
||||
{
|
||||
return strategy::distance::services::comparable_to_regular
|
||||
<
|
||||
comparable_strategy,
|
||||
Strategy,
|
||||
Point,
|
||||
typename boost::range_value<Range>::type
|
||||
>::apply(zero);
|
||||
}
|
||||
else if (cds < cd)
|
||||
{
|
||||
cd = cds;
|
||||
}
|
||||
}
|
||||
|
||||
return strategy::distance::services::comparable_to_regular
|
||||
<
|
||||
comparable_strategy,
|
||||
Strategy,
|
||||
Point,
|
||||
typename boost::range_value<Range>::type
|
||||
>::apply(cd);
|
||||
return strategy.apply(point, *cf.first, *cf.second);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -177,35 +130,28 @@ template
|
||||
>
|
||||
struct point_to_ring
|
||||
{
|
||||
typedef std::pair
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
typename strategy::distance::services::return_type
|
||||
<
|
||||
Strategy, Point, typename point_type<Ring>::type
|
||||
>::type,
|
||||
bool
|
||||
> distance_containment;
|
||||
Strategy, Point, typename point_type<Ring>::type
|
||||
>::type return_type;
|
||||
|
||||
static inline distance_containment apply(Point const& point,
|
||||
Ring const& ring,
|
||||
Strategy const& strategy)
|
||||
static inline return_type apply(Point const& point,
|
||||
Ring const& ring,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return distance_containment
|
||||
(
|
||||
point_to_range
|
||||
<
|
||||
Point,
|
||||
Ring,
|
||||
Closure,
|
||||
Strategy
|
||||
>::apply(point, ring, strategy),
|
||||
geometry::within(point, ring)
|
||||
);
|
||||
if ( geometry::within(point, ring) )
|
||||
{
|
||||
return return_type(0);
|
||||
}
|
||||
|
||||
return detail::distance::point_to_range
|
||||
<
|
||||
Point, Ring, closure<Ring>::value, Strategy
|
||||
>::apply(point, ring, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename Point,
|
||||
@@ -215,79 +161,150 @@ template
|
||||
>
|
||||
class point_to_polygon
|
||||
{
|
||||
public:
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
Strategy, Point, typename point_type<Polygon>::type
|
||||
>::type return_type;
|
||||
|
||||
private:
|
||||
typedef point_to_range
|
||||
<
|
||||
Point, typename ring_type<Polygon>::type, Closure, Strategy
|
||||
> per_ring;
|
||||
|
||||
struct distance_to_interior_rings
|
||||
{
|
||||
template <typename InteriorRingIterator>
|
||||
static inline return_type apply(Point const& point,
|
||||
InteriorRingIterator first,
|
||||
InteriorRingIterator beyond,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
for (InteriorRingIterator it = first; it != beyond; ++it)
|
||||
{
|
||||
if ( geometry::within(point, *it) )
|
||||
{
|
||||
// the point is inside a polygon hole, so its distance
|
||||
// to the polygon its distance to the polygon's
|
||||
// hole boundary
|
||||
return per_ring::apply(point, *it, strategy);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename InteriorRings>
|
||||
static inline return_type apply(Point const& point,
|
||||
InteriorRings const& interior_rings,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
return apply(point,
|
||||
boost::begin(interior_rings),
|
||||
boost::end(interior_rings),
|
||||
strategy);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
static inline return_type apply(Point const& point,
|
||||
Polygon const& polygon,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
if ( !geometry::within(point, exterior_ring(polygon)) )
|
||||
{
|
||||
// the point is outside the exterior ring, so its distance
|
||||
// to the polygon is its distance to the polygon's exterior ring
|
||||
return per_ring::apply(point, exterior_ring(polygon), strategy);
|
||||
}
|
||||
|
||||
// Check interior rings
|
||||
return distance_to_interior_rings::apply(point,
|
||||
interior_rings(polygon),
|
||||
strategy);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
typename Point,
|
||||
typename MultiGeometry,
|
||||
typename Strategy,
|
||||
bool CheckWithin = false
|
||||
>
|
||||
class point_to_multigeometry
|
||||
{
|
||||
private:
|
||||
typedef typename strategy::distance::services::comparable_type
|
||||
<
|
||||
Strategy
|
||||
>::type comparable_strategy;
|
||||
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
comparable_strategy, Point, typename point_type<Polygon>::type
|
||||
>::type comparable_return_type;
|
||||
|
||||
typedef std::pair
|
||||
<
|
||||
comparable_return_type, bool
|
||||
> comparable_distance_containment;
|
||||
|
||||
public:
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
Strategy, Point, typename point_type<Polygon>::type
|
||||
Strategy,
|
||||
Point,
|
||||
typename point_type<MultiGeometry>::type
|
||||
>::type return_type;
|
||||
typedef std::pair<return_type, bool> distance_containment;
|
||||
|
||||
static inline distance_containment apply(Point const& point,
|
||||
Polygon const& polygon,
|
||||
Strategy const& strategy)
|
||||
static inline return_type apply(Point const& point,
|
||||
MultiGeometry const& multigeometry,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
comparable_strategy c_strategy =
|
||||
strategy::distance::services::get_comparable
|
||||
<
|
||||
Strategy
|
||||
>::apply(strategy);
|
||||
typedef iterator_selector<MultiGeometry const> selector_type;
|
||||
|
||||
// Check distance to all rings
|
||||
typedef point_to_ring
|
||||
typedef detail::closest_feature::geometry_to_range point_to_range;
|
||||
|
||||
namespace sds = strategy::distance::services;
|
||||
|
||||
typename selector_type::iterator_type it_min
|
||||
= point_to_range::apply(point,
|
||||
selector_type::begin(multigeometry),
|
||||
selector_type::end(multigeometry),
|
||||
sds::get_comparable
|
||||
<
|
||||
Strategy
|
||||
>::apply(strategy));
|
||||
return dispatch::distance
|
||||
<
|
||||
Point,
|
||||
typename ring_type<Polygon>::type,
|
||||
Closure,
|
||||
comparable_strategy
|
||||
> per_ring;
|
||||
typename std::iterator_traits
|
||||
<
|
||||
typename selector_type::iterator_type
|
||||
>::value_type,
|
||||
Strategy
|
||||
>::apply(point, *it_min, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
comparable_distance_containment dc =
|
||||
per_ring::apply(point, exterior_ring(polygon), c_strategy);
|
||||
|
||||
typename interior_return_type<Polygon const>::type rings
|
||||
= interior_rings(polygon);
|
||||
for (typename boost::range_iterator
|
||||
<
|
||||
typename interior_type<Polygon const>::type const
|
||||
>::type it = boost::begin(rings);
|
||||
it != boost::end(rings); ++it)
|
||||
template <typename Point, typename MultiGeometry, typename Strategy>
|
||||
struct point_to_multigeometry<Point, MultiGeometry, Strategy, true>
|
||||
{
|
||||
public:
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
Strategy,
|
||||
Point,
|
||||
typename point_type<MultiGeometry>::type
|
||||
>::type return_type;
|
||||
|
||||
static inline return_type apply(Point const& point,
|
||||
MultiGeometry const& multigeometry,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
if ( geometry::within(point, multigeometry) )
|
||||
{
|
||||
comparable_distance_containment dcr =
|
||||
per_ring::apply(point, *it, c_strategy);
|
||||
if (dcr.first < dc.first)
|
||||
{
|
||||
dc.first = dcr.first;
|
||||
}
|
||||
// If it was inside, and also inside inner ring,
|
||||
// turn off the inside-flag, it is outside the polygon
|
||||
if (dc.second && dcr.second)
|
||||
{
|
||||
dc.second = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return_type rd = strategy::distance::services::comparable_to_regular
|
||||
return point_to_multigeometry
|
||||
<
|
||||
comparable_strategy, Strategy, Point, Polygon
|
||||
>::apply(dc.first);
|
||||
|
||||
return std::make_pair(rd, dc.second);
|
||||
Point, MultiGeometry, Strategy, false
|
||||
>::apply(point, multigeometry, strategy);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -307,111 +324,73 @@ namespace dispatch
|
||||
template <typename P1, typename P2, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
P1, P2, Strategy,
|
||||
point_tag, point_tag, strategy_tag_distance_point_point,
|
||||
false
|
||||
>
|
||||
: detail::distance::point_to_point<P1, P2, Strategy>
|
||||
P1, P2, Strategy, point_tag, point_tag,
|
||||
strategy_tag_distance_point_point, false
|
||||
> : detail::distance::point_to_point<P1, P2, Strategy>
|
||||
{};
|
||||
|
||||
|
||||
// Point-line version 2, where point-segment strategy is specified
|
||||
template <typename Point, typename Linestring, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, Linestring, Strategy,
|
||||
point_tag, linestring_tag, strategy_tag_distance_point_segment,
|
||||
false
|
||||
> : detail::distance::point_to_range<Point, Linestring, closed, Strategy>
|
||||
<
|
||||
Point, Linestring, Strategy, point_tag, linestring_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : detail::distance::point_to_range<Point, Linestring, closed, Strategy>
|
||||
{};
|
||||
|
||||
|
||||
// Point-ring , where point-segment strategy is specified
|
||||
template <typename Point, typename Ring, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, Ring, Strategy,
|
||||
point_tag, ring_tag, strategy_tag_distance_point_segment,
|
||||
false
|
||||
>
|
||||
{
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
Point, Ring, Strategy, point_tag, ring_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : detail::distance::point_to_ring
|
||||
<
|
||||
Strategy, Point, typename point_type<Ring>::type
|
||||
>::type return_type;
|
||||
|
||||
static inline return_type apply(Point const& point,
|
||||
Ring const& ring,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
std::pair<return_type, bool>
|
||||
dc = detail::distance::point_to_ring
|
||||
<
|
||||
Point, Ring,
|
||||
geometry::closure<Ring>::value,
|
||||
Strategy
|
||||
>::apply(point, ring, strategy);
|
||||
|
||||
return dc.second ? return_type(0) : dc.first;
|
||||
}
|
||||
};
|
||||
Point, Ring, closure<Ring>::value, Strategy
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
// Point-polygon , where point-segment strategy is specified
|
||||
template <typename Point, typename Polygon, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, Polygon, Strategy, point_tag, polygon_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
>
|
||||
{
|
||||
typedef typename strategy::distance::services::return_type
|
||||
<
|
||||
Point, Polygon, Strategy, point_tag, polygon_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : detail::distance::point_to_polygon
|
||||
<
|
||||
Strategy, Point, typename point_type<Polygon>::type
|
||||
>::type return_type;
|
||||
|
||||
static inline return_type apply(Point const& point,
|
||||
Polygon const& polygon,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
std::pair<return_type, bool>
|
||||
dc = detail::distance::point_to_polygon
|
||||
<
|
||||
Point, Polygon,
|
||||
geometry::closure<Polygon>::value,
|
||||
Strategy
|
||||
>::apply(point, polygon, strategy);
|
||||
|
||||
return dc.second ? return_type(0) : dc.first;
|
||||
}
|
||||
};
|
||||
Point, Polygon, closure<Polygon>::value, Strategy
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
// Point-segment version 2, with point-segment strategy
|
||||
template <typename Point, typename Segment, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, Segment, Strategy,
|
||||
point_tag, segment_tag, strategy_tag_distance_point_segment,
|
||||
false
|
||||
>
|
||||
<
|
||||
Point, Segment, Strategy, point_tag, segment_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
>
|
||||
{
|
||||
static inline typename return_type<Strategy, Point, typename point_type<Segment>::type>::type
|
||||
apply(Point const& point,
|
||||
Segment const& segment,
|
||||
Strategy const& strategy)
|
||||
static inline typename strategy::distance::services::return_type
|
||||
<
|
||||
Strategy, Point, typename point_type<Segment>::type
|
||||
>::type apply(Point const& point,
|
||||
Segment const& segment,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
typename point_type<Segment>::type p[2];
|
||||
geometry::detail::assign_point_from_index<0>(segment, p[0]);
|
||||
geometry::detail::assign_point_from_index<1>(segment, p[1]);
|
||||
|
||||
boost::ignore_unused_variable_warning(strategy);
|
||||
boost::ignore_unused(strategy);
|
||||
return strategy.apply(point, p[0], p[1]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Point, typename Box, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
@@ -425,12 +404,75 @@ struct distance
|
||||
>::type
|
||||
apply(Point const& point, Box const& box, Strategy const& strategy)
|
||||
{
|
||||
boost::ignore_unused_variable_warning(strategy);
|
||||
boost::ignore_unused(strategy);
|
||||
return strategy.apply(point, box);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Point, typename MultiPoint, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, MultiPoint, Strategy, point_tag, multi_point_tag,
|
||||
strategy_tag_distance_point_point, false
|
||||
> : detail::distance::point_to_multigeometry
|
||||
<
|
||||
Point, MultiPoint, Strategy
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
template<typename Point, typename MultiLinestring, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : detail::distance::point_to_multigeometry
|
||||
<
|
||||
Point, MultiLinestring, Strategy
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
template<typename Point, typename MultiPolygon, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : detail::distance::point_to_multigeometry
|
||||
<
|
||||
Point, MultiPolygon, Strategy, true
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Point, typename Linear, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, Linear, Strategy, point_tag, linear_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : distance
|
||||
<
|
||||
Point, Linear, Strategy,
|
||||
point_tag, typename tag<Linear>::type,
|
||||
strategy_tag_distance_point_segment, false
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Point, typename Areal, typename Strategy>
|
||||
struct distance
|
||||
<
|
||||
Point, Areal, Strategy, point_tag, areal_tag,
|
||||
strategy_tag_distance_point_segment, false
|
||||
> : distance
|
||||
<
|
||||
Point, Areal, Strategy,
|
||||
point_tag, typename tag<Areal>::type,
|
||||
strategy_tag_distance_point_segment, false
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
} // namespace dispatch
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
Reference in New Issue
Block a user