// 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 #include #include #include #include #include #include #include #include #include #include #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 closest_points { struct point_to_point { template 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 static inline void apply(Point const& point, Segment const& segment, OutputSegment& shortest_seg, Strategies const& strategies) { point_type_t 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 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 class point_to_range { public: template 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 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 struct point_to_ring { template 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::value >::apply(point, ring, shortest_seg, strategies); } } }; template class point_to_polygon { template 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; 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; 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::apply(point, interior_rings(polygon), shortest_seg, strategies); } }; template < typename MultiGeometry, bool CheckCoveredBy = std::is_same < tag_t, 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; closest_points::creturn_t 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 struct point_to_multigeometry { 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 struct closest_points < P1, P2, point_tag, point_tag, false > : detail::closest_points::point_to_point {}; template struct closest_points < Point, Linestring, point_tag, linestring_tag, false > : detail::closest_points::point_to_range {}; template struct closest_points < Point, Ring, point_tag, ring_tag, false > : detail::closest_points::point_to_ring < closure::value > {}; template struct closest_points < Point, Polygon, point_tag, polygon_tag, false > : detail::closest_points::point_to_polygon < closure::value > {}; template struct closest_points < Point, Segment, point_tag, segment_tag, false > : detail::closest_points::point_to_segment {}; /* template struct closest_points < Point, Box, point_tag, box_tag, strategy_tag_distance_point_box, false > : detail::closest_points::point_to_box {}; */ template struct closest_points < Point, MultiPoint, point_tag, multi_point_tag, false > : detail::closest_points::point_to_multigeometry {}; template struct closest_points < Point, MultiLinestring, point_tag, multi_linestring_tag, false > : detail::closest_points::point_to_multigeometry {}; template struct closest_points < Point, MultiPolygon, point_tag, multi_polygon_tag, false > : detail::closest_points::point_to_multigeometry {}; template struct closest_points < Point, Linear, point_tag, linear_tag, false > : closest_points < Point, Linear, point_tag, tag_t, false > {}; template struct closest_points < Point, Areal, point_tag, areal_tag, false > : closest_points < Point, Areal, point_tag, tag_t, false > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP