summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp
diff options
context:
space:
mode:
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.hpp456
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