diff options
Diffstat (limited to 'boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp')
-rw-r--r-- | boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp b/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp new file mode 100644 index 0000000000..5771858518 --- /dev/null +++ b/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp @@ -0,0 +1,456 @@ +// Boost.Geometry + +// Copyright (c) 2021-2023, Oracle and/or its affiliates. + +// Contributed and/or modified by Vissarion Fysikopoulos, 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_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP + +#include <iterator> +#include <type_traits> + +#include <boost/core/ignore_unused.hpp> +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> +#include <boost/range/size.hpp> +#include <boost/range/value_type.hpp> + +#include <boost/geometry/algorithms/assign.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/closest_points/utilities.hpp> +#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> +#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> +#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp> +#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> +#include <boost/geometry/algorithms/dispatch/closest_points.hpp> +#include <boost/geometry/algorithms/dispatch/distance.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/radian_access.hpp> +#include <boost/geometry/core/tag.hpp> +#include <boost/geometry/core/tags.hpp> + +#include <boost/geometry/strategies/distance.hpp> +#include <boost/geometry/strategies/relate/services.hpp> +#include <boost/geometry/strategies/tags.hpp> + +#include <boost/geometry/util/math.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace closest_points +{ + +struct point_to_point +{ + template <typename P1, typename P2, typename Segment, typename Strategies> + static inline void apply(P1 const& p1, P2 const& p2, + Segment& shortest_seg, Strategies const&) + { + set_segment_from_points::apply(p1, p2, shortest_seg); + } +}; + +struct point_to_segment +{ + template <typename Point, typename Segment, typename OutputSegment, typename Strategies> + static inline void apply(Point const& point, Segment const& segment, + OutputSegment& shortest_seg, Strategies const& strategies) + { + 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(strategies); + + auto closest_point = strategies.closest_points(point, segment) + .apply(point, p[0], p[1]); + + set_segment_from_points::apply(point, closest_point, shortest_seg); + } +}; + +/* +struct point_to_box +{ + template<typename Point, typename Box, typename Strategies> +static inline auto apply(Point const& point, Box const& box, + Strategies const& strategies) + { + boost::ignore_unused(strategies); + return strategies.closest_points(point, box).apply(point, box); + } +}; +*/ + +template <closure_selector Closure> +class point_to_range +{ +public: + + template <typename Point, typename Range, typename Segment, typename Strategies> + static inline void apply(Point const& point, Range const& range, + Segment& shortest_seg, + Strategies const& strategies) + { + using point_to_point_range = detail::closest_feature::point_to_point_range + < + Point, Range, Closure + >; + + if (boost::size(range) == 0) + { + set_segment_from_points::apply(point, point, shortest_seg); + return; + } + + closest_points::creturn_t<Point, Range, Strategies> cd_min; + + auto comparable_distance = strategy::distance::services::get_comparable + < + decltype(strategies.distance(point, range)) + >::apply(strategies.distance(point, range)); + + auto closest_segment = point_to_point_range::apply(point, + boost::begin(range), + boost::end(range), + comparable_distance, + cd_min); + + auto closest_point = strategies.closest_points(point, range) + .apply(point, *closest_segment.first, *closest_segment.second); + + set_segment_from_points::apply(point, closest_point, shortest_seg); + } +}; + + +template<closure_selector Closure> +struct point_to_ring +{ + template <typename Point, typename Ring, typename Segment, typename Strategies> + static inline auto apply(Point const& point, + Ring const& ring, + Segment& shortest_seg, + Strategies const& strategies) + { + if (within::within_point_geometry(point, ring, strategies)) + { + set_segment_from_points::apply(point, point, shortest_seg); + } + else + { + point_to_range + < + closure<Ring>::value + >::apply(point, ring, shortest_seg, strategies); + } + + } +}; + + +template <closure_selector Closure> +class point_to_polygon +{ + template <typename Polygon> + struct distance_to_interior_rings + { + template + < + typename Point, + typename InteriorRingIterator, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + InteriorRingIterator first, + InteriorRingIterator last, + Segment& shortest_seg, + Strategies const& strategies) + { + using per_ring = point_to_range<Closure>; + + for (InteriorRingIterator it = first; it != last; ++it) + { + if (within::within_point_geometry(point, *it, strategies)) + { + // the point is inside a polygon hole, so its distance + // to the polygon is its distance to the polygon's + // hole boundary + per_ring::apply(point, *it, shortest_seg, strategies); + return; + } + } + set_segment_from_points::apply(point, point, shortest_seg); + } + + template + < + typename Point, + typename InteriorRings, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, InteriorRings const& interior_rings, + Segment& shortest_seg, Strategies const& strategies) + { + apply(point, + boost::begin(interior_rings), + boost::end(interior_rings), + shortest_seg, + strategies); + } + }; + + +public: + template + < + typename Point, + typename Polygon, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + Polygon const& polygon, + Segment& shortest_seg, + Strategies const& strategies) + { + using per_ring = point_to_range<Closure>; + + if (! within::covered_by_point_geometry(point, exterior_ring(polygon), + strategies)) + { + // the point is outside the exterior ring, so its distance + // to the polygon is its distance to the polygon's exterior ring + per_ring::apply(point, exterior_ring(polygon), shortest_seg, strategies); + return; + } + + // Check interior rings + distance_to_interior_rings<Polygon>::apply(point, + interior_rings(polygon), + shortest_seg, + strategies); + } +}; + + +template +< + typename MultiGeometry, + bool CheckCoveredBy = std::is_same + < + typename tag<MultiGeometry>::type, multi_polygon_tag + >::value +> +class point_to_multigeometry +{ +private: + using geometry_to_range = detail::closest_feature::geometry_to_range; + +public: + + template + < + typename Point, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + MultiGeometry const& multigeometry, + Segment& shortest_seg, + Strategies const& strategies) + { + using selector_type = distance::iterator_selector<MultiGeometry const>; + + closest_points::creturn_t<Point, MultiGeometry, Strategies> cd; + + auto comparable_distance = strategy::distance::services::get_comparable + < + decltype(strategies.distance(point, multigeometry)) + >::apply(strategies.distance(point, multigeometry)); + + typename selector_type::iterator_type it_min + = geometry_to_range::apply(point, + selector_type::begin(multigeometry), + selector_type::end(multigeometry), + comparable_distance, + cd); + + dispatch::closest_points + < + Point, + typename std::iterator_traits + < + typename selector_type::iterator_type + >::value_type + >::apply(point, *it_min, shortest_seg, strategies); + } +}; + + +// this is called only for multipolygons, hence the change in the +// template parameter name MultiGeometry to MultiPolygon +template <typename MultiPolygon> +struct point_to_multigeometry<MultiPolygon, true> +{ + template + < + typename Point, + typename Segment, + typename Strategies + > + static inline void apply(Point const& point, + MultiPolygon const& multipolygon, + Segment& shortest_seg, + Strategies const& strategies) + { + if (within::covered_by_point_geometry(point, multipolygon, strategies)) + { + set_segment_from_points::apply(point, point, shortest_seg); + return; + } + + return point_to_multigeometry + < + MultiPolygon, false + >::apply(point, multipolygon, shortest_seg, strategies); + } +}; + + +}} // namespace detail::closest_points +#endif // DOXYGEN_NO_DETAIL + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template <typename P1, typename P2> +struct closest_points + < + P1, P2, point_tag, point_tag, false + > : detail::closest_points::point_to_point +{}; + + +template <typename Point, typename Linestring> +struct closest_points + < + Point, Linestring, point_tag, linestring_tag, false + > : detail::closest_points::point_to_range<closed> +{}; + + +template <typename Point, typename Ring> +struct closest_points + < + Point, Ring, point_tag, ring_tag, false + > : detail::closest_points::point_to_ring + < + closure<Ring>::value + > +{}; + + +template <typename Point, typename Polygon> +struct closest_points + < + Point, Polygon, point_tag, polygon_tag, false + > : detail::closest_points::point_to_polygon + < + closure<Polygon>::value + > +{}; + + +template <typename Point, typename Segment> +struct closest_points + < + Point, Segment, point_tag, segment_tag, false + > : detail::closest_points::point_to_segment +{}; + +/* +template <typename Point, typename Box> +struct closest_points + < + Point, Box, point_tag, box_tag, + strategy_tag_distance_point_box, false + > : detail::closest_points::point_to_box<Point, Box> +{}; +*/ + +template<typename Point, typename MultiPoint> +struct closest_points + < + Point, MultiPoint, point_tag, multi_point_tag, false + > : detail::closest_points::point_to_multigeometry<MultiPoint> +{}; + + +template<typename Point, typename MultiLinestring> +struct closest_points + < + Point, MultiLinestring, point_tag, multi_linestring_tag, false + > : detail::closest_points::point_to_multigeometry<MultiLinestring> +{}; + + +template<typename Point, typename MultiPolygon> +struct closest_points + < + Point, MultiPolygon, point_tag, multi_polygon_tag, false + > : detail::closest_points::point_to_multigeometry<MultiPolygon> +{}; + + +template <typename Point, typename Linear> +struct closest_points + < + Point, Linear, point_tag, linear_tag, false + > : closest_points + < + Point, Linear, + point_tag, typename tag<Linear>::type, false + > +{}; + + +template <typename Point, typename Areal> +struct closest_points + < + Point, Areal, point_tag, areal_tag, false + > : closest_points + < + Point, Areal, + point_tag, typename tag<Areal>::type, false + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP |