1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2018, 2019 Oracle and/or its affiliates.
5 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
6 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8 // Use, modification and distribution is subject to the Boost Software License,
9 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
12 #ifndef BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
13 #define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
17 #include <boost/range/begin.hpp>
18 #include <boost/range/end.hpp>
19 #include <boost/range/iterator.hpp>
20 #include <boost/range/value_type.hpp>
22 #include <boost/geometry/core/cs.hpp>
23 #include <boost/geometry/core/closure.hpp>
24 #include <boost/geometry/core/tags.hpp>
26 #include <boost/geometry/geometries/concepts/check.hpp>
28 #include <boost/geometry/algorithms/assign.hpp>
29 #include <boost/geometry/algorithms/length.hpp>
30 #include <boost/geometry/strategies/default_strategy.hpp>
31 #include <boost/geometry/strategies/line_interpolate.hpp>
33 namespace boost { namespace geometry
37 #ifndef DOXYGEN_NO_DETAIL
38 namespace detail { namespace line_interpolate
41 struct convert_and_push_back
43 template <typename Range, typename Point>
44 inline void apply(Point const& p, Range& range)
46 typename boost::range_value<Range>::type p2;
47 geometry::detail::conversion::convert_point_to_point(p, p2);
48 range::push_back(range, p2);
52 struct convert_and_assign
54 template <typename Point1, typename Point2>
55 inline void apply(Point1 const& p1, Point2& p2)
57 geometry::detail::conversion::convert_point_to_point(p1, p2);
64 \brief Internal, calculates interpolation point of a linestring using iterator pairs and
67 template <typename Policy>
68 struct interpolate_range
77 static inline void apply(Range const& range,
78 Distance const& max_distance,
79 PointLike & pointlike,
80 Strategy const& strategy)
84 typedef typename boost::range_iterator<Range const>::type iterator_t;
85 typedef typename boost::range_value<Range const>::type point_t;
87 iterator_t it = boost::begin(range);
88 iterator_t end = boost::end(range);
90 if (it == end) // empty(range)
92 BOOST_THROW_EXCEPTION(empty_input_exception());
95 if (max_distance <= 0) //non positive distance
97 policy.apply(*it, pointlike);
101 iterator_t prev = it++;
102 Distance repeated_distance = max_distance;
103 Distance prev_distance = 0;
104 Distance current_distance = 0;
105 point_t start_p = *prev;
107 for ( ; it != end ; ++it)
109 Distance dist = strategy.get_distance_pp_strategy().apply(*prev, *it);
110 current_distance = prev_distance + dist;
112 while (current_distance >= repeated_distance)
115 Distance diff_distance = current_distance - prev_distance;
116 BOOST_ASSERT(diff_distance != Distance(0));
117 strategy.apply(start_p, *it,
118 (repeated_distance - prev_distance)/diff_distance,
121 policy.apply(p, pointlike);
122 if (boost::is_same<PointLike, point_t>::value)
127 prev_distance = repeated_distance;
128 repeated_distance += max_distance;
130 prev_distance = current_distance;
135 // case when max_distance is larger than linestring's length
136 // return the last point in range (range is not empty)
137 if (repeated_distance == max_distance)
139 policy.apply(*(end-1), pointlike);
144 template <typename Policy>
145 struct interpolate_segment
147 template <typename Segment, typename Distance, typename Pointlike, typename Strategy>
148 static inline void apply(Segment const& segment,
149 Distance const& max_distance,
151 Strategy const& strategy)
153 interpolate_range<Policy>().apply(segment_view<Segment>(segment),
154 max_distance, point, strategy);
158 }} // namespace detail::line_interpolate
159 #endif // DOXYGEN_NO_DETAIL
162 #ifndef DOXYGEN_NO_DISPATCH
171 typename Tag1 = typename tag<Geometry>::type,
172 typename Tag2 = typename tag<Pointlike>::type
174 struct line_interpolate
178 false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
184 template <typename Geometry, typename Pointlike>
185 struct line_interpolate<Geometry, Pointlike, linestring_tag, point_tag>
186 : detail::line_interpolate::interpolate_range
188 detail::line_interpolate::convert_and_assign
192 template <typename Geometry, typename Pointlike>
193 struct line_interpolate<Geometry, Pointlike, linestring_tag, multi_point_tag>
194 : detail::line_interpolate::interpolate_range
196 detail::line_interpolate::convert_and_push_back
200 template <typename Geometry, typename Pointlike>
201 struct line_interpolate<Geometry, Pointlike, segment_tag, point_tag>
202 : detail::line_interpolate::interpolate_segment
204 detail::line_interpolate::convert_and_assign
208 template <typename Geometry, typename Pointlike>
209 struct line_interpolate<Geometry, Pointlike, segment_tag, multi_point_tag>
210 : detail::line_interpolate::interpolate_segment
212 detail::line_interpolate::convert_and_push_back
216 } // namespace dispatch
217 #endif // DOXYGEN_NO_DISPATCH
220 namespace resolve_strategy {
222 struct line_interpolate
231 static inline void apply(Geometry const& geometry,
232 Distance const& max_distance,
233 Pointlike & pointlike,
234 Strategy const& strategy)
236 dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry,
242 template <typename Geometry, typename Distance, typename Pointlike>
243 static inline void apply(Geometry const& geometry,
244 Distance const& max_distance,
245 Pointlike & pointlike,
248 typedef typename strategy::line_interpolate::services::default_strategy
250 typename cs_tag<Geometry>::type
251 >::type strategy_type;
253 dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry,
260 } // namespace resolve_strategy
263 namespace resolve_variant {
265 template <typename Geometry>
266 struct line_interpolate
268 template <typename Distance, typename Pointlike, typename Strategy>
269 static inline void apply(Geometry const& geometry,
270 Distance const& max_distance,
271 Pointlike & pointlike,
272 Strategy const& strategy)
274 return resolve_strategy::line_interpolate::apply(geometry,
281 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
282 struct line_interpolate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
284 template <typename Pointlike, typename Strategy>
285 struct visitor: boost::static_visitor<void>
287 Pointlike const& m_pointlike;
288 Strategy const& m_strategy;
290 visitor(Pointlike const& pointlike, Strategy const& strategy)
291 : m_pointlike(pointlike)
292 , m_strategy(strategy)
295 template <typename Geometry, typename Distance>
296 void operator()(Geometry const& geometry, Distance const& max_distance) const
298 line_interpolate<Geometry>::apply(geometry, max_distance,
299 m_pointlike, m_strategy);
303 template <typename Distance, typename Pointlike, typename Strategy>
305 apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
306 double const& max_distance,
307 Pointlike & pointlike,
308 Strategy const& strategy)
310 boost::apply_visitor(
311 visitor<Pointlike, Strategy>(pointlike, strategy),
318 } // namespace resolve_variant
321 \brief Returns one or more points interpolated along a LineString \brief_strategy
322 \ingroup line_interpolate
323 \tparam Geometry Any type fulfilling a LineString concept
324 \tparam Distance A numerical distance measure
325 \tparam Pointlike Any type fulfilling Point or Multipoint concept
326 \tparam Strategy A type fulfilling a LineInterpolatePointStrategy concept
327 \param geometry Input geometry
328 \param max_distance Distance threshold (in units depending on coordinate system)
329 representing the spacing between the points
330 \param pointlike Output: either a Point (exactly one point will be constructed) or
331 a MultiPoint (depending on the max_distance one or more points will be constructed)
332 \param strategy line_interpolate strategy to be used for interpolation of
335 \qbk{[include reference/algorithms/line_interpolate.qbk]}
337 \qbk{distinguish,with strategy}
340 [heading Available Strategies]
341 \* [link geometry.reference.strategies.strategy_line_interpolate_cartesian Cartesian]
342 \* [link geometry.reference.strategies.strategy_line_interpolate_spherical Spherical]
343 \* [link geometry.reference.strategies.strategy_line_interpolate_geographic Geographic]
346 [line_interpolate_strategy]
347 [line_interpolate_strategy_output]
350 \* [link geometry.reference.algorithms.densify densify]
360 inline void line_interpolate(Geometry const& geometry,
361 Distance const& max_distance,
362 Pointlike & pointlike,
363 Strategy const& strategy)
365 concepts::check<Geometry const>();
367 // detail::throw_on_empty_input(geometry);
369 return resolve_variant::line_interpolate<Geometry>
370 ::apply(geometry, max_distance, pointlike, strategy);
375 \brief Returns one or more points interpolated along a LineString.
376 \ingroup line_interpolate
377 \tparam Geometry Any type fulfilling a LineString concept
378 \tparam Distance A numerical distance measure
379 \tparam Pointlike Any type fulfilling Point or Multipoint concept
380 \param geometry Input geometry
381 \param max_distance Distance threshold (in units depending on coordinate system)
382 representing the spacing between the points
383 \param pointlike Output: either a Point (exactly one point will be constructed) or
384 a MultiPoint (depending on the max_distance one or more points will be constructed)
386 \qbk{[include reference/algorithms/line_interpolate.qbk]
390 [line_interpolate_output]
393 \* [link geometry.reference.algorithms.densify densify]
396 template<typename Geometry, typename Distance, typename Pointlike>
397 inline void line_interpolate(Geometry const& geometry,
398 Distance const& max_distance,
399 Pointlike & pointlike)
401 concepts::check<Geometry const>();
403 // detail::throw_on_empty_input(geometry);
405 return resolve_variant::line_interpolate<Geometry>
406 ::apply(geometry, max_distance, pointlike, default_strategy());
409 }} // namespace boost::geometry
411 #endif // BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP