// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2018, 2019 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP #define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace line_interpolate { struct convert_and_push_back { template inline void apply(Point const& p, Range& range) { typename boost::range_value::type p2; geometry::detail::conversion::convert_point_to_point(p, p2); range::push_back(range, p2); } }; struct convert_and_assign { template inline void apply(Point1 const& p1, Point2& p2) { geometry::detail::conversion::convert_point_to_point(p1, p2); } }; /*! \brief Internal, calculates interpolation point of a linestring using iterator pairs and specified strategy */ template struct interpolate_range { template < typename Range, typename Distance, typename PointLike, typename Strategy > static inline void apply(Range const& range, Distance const& max_distance, PointLike & pointlike, Strategy const& strategy) { Policy policy; typedef typename boost::range_iterator::type iterator_t; typedef typename boost::range_value::type point_t; iterator_t it = boost::begin(range); iterator_t end = boost::end(range); if (it == end) // empty(range) { BOOST_THROW_EXCEPTION(empty_input_exception()); return; } if (max_distance <= 0) //non positive distance { policy.apply(*it, pointlike); return; } iterator_t prev = it++; Distance repeated_distance = max_distance; Distance prev_distance = 0; Distance current_distance = 0; point_t start_p = *prev; for ( ; it != end ; ++it) { Distance dist = strategy.get_distance_pp_strategy().apply(*prev, *it); current_distance = prev_distance + dist; while (current_distance >= repeated_distance) { point_t p; Distance diff_distance = current_distance - prev_distance; BOOST_ASSERT(diff_distance != Distance(0)); strategy.apply(start_p, *it, (repeated_distance - prev_distance)/diff_distance, p, diff_distance); policy.apply(p, pointlike); if (boost::is_same::value) { return; } start_p = p; prev_distance = repeated_distance; repeated_distance += max_distance; } prev_distance = current_distance; prev = it; start_p = *prev; } // case when max_distance is larger than linestring's length // return the last point in range (range is not empty) if (repeated_distance == max_distance) { policy.apply(*(end-1), pointlike); } } }; template struct interpolate_segment { template static inline void apply(Segment const& segment, Distance const& max_distance, Pointlike & point, Strategy const& strategy) { interpolate_range().apply(segment_view(segment), max_distance, point, strategy); } }; }} // namespace detail::line_interpolate #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Pointlike, typename Tag1 = typename tag::type, typename Tag2 = typename tag::type > struct line_interpolate { BOOST_MPL_ASSERT_MSG ( false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE , (types) ); }; template struct line_interpolate : detail::line_interpolate::interpolate_range < detail::line_interpolate::convert_and_assign > {}; template struct line_interpolate : detail::line_interpolate::interpolate_range < detail::line_interpolate::convert_and_push_back > {}; template struct line_interpolate : detail::line_interpolate::interpolate_segment < detail::line_interpolate::convert_and_assign > {}; template struct line_interpolate : detail::line_interpolate::interpolate_segment < detail::line_interpolate::convert_and_push_back > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct line_interpolate { template < typename Geometry, typename Distance, typename Pointlike, typename Strategy > static inline void apply(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, Strategy const& strategy) { dispatch::line_interpolate::apply(geometry, max_distance, pointlike, strategy); } template static inline void apply(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, default_strategy) { typedef typename strategy::line_interpolate::services::default_strategy < typename cs_tag::type >::type strategy_type; dispatch::line_interpolate::apply(geometry, max_distance, pointlike, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template struct line_interpolate { template static inline void apply(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, Strategy const& strategy) { return resolve_strategy::line_interpolate::apply(geometry, max_distance, pointlike, strategy); } }; template struct line_interpolate > { template struct visitor: boost::static_visitor { Pointlike const& m_pointlike; Strategy const& m_strategy; visitor(Pointlike const& pointlike, Strategy const& strategy) : m_pointlike(pointlike) , m_strategy(strategy) {} template void operator()(Geometry const& geometry, Distance const& max_distance) const { line_interpolate::apply(geometry, max_distance, m_pointlike, m_strategy); } }; template static inline void apply(boost::variant const& geometry, double const& max_distance, Pointlike & pointlike, Strategy const& strategy) { boost::apply_visitor( visitor(pointlike, strategy), geometry, max_distance ); } }; } // namespace resolve_variant /*! \brief Returns one or more points interpolated along a LineString \brief_strategy \ingroup line_interpolate \tparam Geometry Any type fulfilling a LineString concept \tparam Distance A numerical distance measure \tparam Pointlike Any type fulfilling Point or Multipoint concept \tparam Strategy A type fulfilling a LineInterpolatePointStrategy concept \param geometry Input geometry \param max_distance Distance threshold (in units depending on coordinate system) representing the spacing between the points \param pointlike Output: either a Point (exactly one point will be constructed) or a MultiPoint (depending on the max_distance one or more points will be constructed) \param strategy line_interpolate strategy to be used for interpolation of points \qbk{[include reference/algorithms/line_interpolate.qbk]} \qbk{distinguish,with strategy} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_line_interpolate_cartesian Cartesian] \* [link geometry.reference.strategies.strategy_line_interpolate_spherical Spherical] \* [link geometry.reference.strategies.strategy_line_interpolate_geographic Geographic] [heading Example] [line_interpolate_strategy] [line_interpolate_strategy_output] [heading See also] \* [link geometry.reference.algorithms.densify densify] } */ template < typename Geometry, typename Distance, typename Pointlike, typename Strategy > inline void line_interpolate(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, Strategy const& strategy) { concepts::check(); // detail::throw_on_empty_input(geometry); return resolve_variant::line_interpolate ::apply(geometry, max_distance, pointlike, strategy); } /*! \brief Returns one or more points interpolated along a LineString. \ingroup line_interpolate \tparam Geometry Any type fulfilling a LineString concept \tparam Distance A numerical distance measure \tparam Pointlike Any type fulfilling Point or Multipoint concept \param geometry Input geometry \param max_distance Distance threshold (in units depending on coordinate system) representing the spacing between the points \param pointlike Output: either a Point (exactly one point will be constructed) or a MultiPoint (depending on the max_distance one or more points will be constructed) \qbk{[include reference/algorithms/line_interpolate.qbk] [heading Example] [line_interpolate] [line_interpolate_output] [heading See also] \* [link geometry.reference.algorithms.densify densify] } */ template inline void line_interpolate(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike) { concepts::check(); // detail::throw_on_empty_input(geometry); return resolve_variant::line_interpolate ::apply(geometry, max_distance, pointlike, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP