]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
20effc67 | 3 | // Copyright (c) 2018-2020 Oracle and/or its affiliates. |
92f5a8d4 TL |
4 | |
5 | // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle | |
6 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
7 | ||
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) | |
11 | ||
12 | #ifndef BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP | |
13 | #define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP | |
14 | ||
15 | #include <iterator> | |
20effc67 | 16 | #include <type_traits> |
92f5a8d4 TL |
17 | |
18 | #include <boost/range/begin.hpp> | |
19 | #include <boost/range/end.hpp> | |
20 | #include <boost/range/iterator.hpp> | |
21 | #include <boost/range/value_type.hpp> | |
22 | ||
23 | #include <boost/geometry/core/cs.hpp> | |
24 | #include <boost/geometry/core/closure.hpp> | |
20effc67 | 25 | #include <boost/geometry/core/static_assert.hpp> |
92f5a8d4 TL |
26 | #include <boost/geometry/core/tags.hpp> |
27 | ||
28 | #include <boost/geometry/geometries/concepts/check.hpp> | |
29 | ||
30 | #include <boost/geometry/algorithms/assign.hpp> | |
31 | #include <boost/geometry/algorithms/length.hpp> | |
32 | #include <boost/geometry/strategies/default_strategy.hpp> | |
33 | #include <boost/geometry/strategies/line_interpolate.hpp> | |
34 | ||
35 | namespace boost { namespace geometry | |
36 | { | |
37 | ||
38 | ||
39 | #ifndef DOXYGEN_NO_DETAIL | |
40 | namespace detail { namespace line_interpolate | |
41 | { | |
42 | ||
43 | struct convert_and_push_back | |
44 | { | |
45 | template <typename Range, typename Point> | |
46 | inline void apply(Point const& p, Range& range) | |
47 | { | |
48 | typename boost::range_value<Range>::type p2; | |
49 | geometry::detail::conversion::convert_point_to_point(p, p2); | |
50 | range::push_back(range, p2); | |
51 | } | |
52 | }; | |
53 | ||
54 | struct convert_and_assign | |
55 | { | |
56 | template <typename Point1, typename Point2> | |
57 | inline void apply(Point1 const& p1, Point2& p2) | |
58 | { | |
59 | geometry::detail::conversion::convert_point_to_point(p1, p2); | |
60 | } | |
61 | ||
62 | }; | |
63 | ||
64 | ||
65 | /*! | |
66 | \brief Internal, calculates interpolation point of a linestring using iterator pairs and | |
67 | specified strategy | |
68 | */ | |
69 | template <typename Policy> | |
70 | struct interpolate_range | |
71 | { | |
72 | template | |
73 | < | |
74 | typename Range, | |
75 | typename Distance, | |
76 | typename PointLike, | |
77 | typename Strategy | |
78 | > | |
79 | static inline void apply(Range const& range, | |
80 | Distance const& max_distance, | |
81 | PointLike & pointlike, | |
82 | Strategy const& strategy) | |
83 | { | |
84 | Policy policy; | |
85 | ||
86 | typedef typename boost::range_iterator<Range const>::type iterator_t; | |
87 | typedef typename boost::range_value<Range const>::type point_t; | |
88 | ||
89 | iterator_t it = boost::begin(range); | |
90 | iterator_t end = boost::end(range); | |
91 | ||
92 | if (it == end) // empty(range) | |
93 | { | |
94 | BOOST_THROW_EXCEPTION(empty_input_exception()); | |
95 | return; | |
96 | } | |
97 | if (max_distance <= 0) //non positive distance | |
98 | { | |
99 | policy.apply(*it, pointlike); | |
100 | return; | |
101 | } | |
102 | ||
103 | iterator_t prev = it++; | |
104 | Distance repeated_distance = max_distance; | |
105 | Distance prev_distance = 0; | |
106 | Distance current_distance = 0; | |
107 | point_t start_p = *prev; | |
108 | ||
109 | for ( ; it != end ; ++it) | |
110 | { | |
111 | Distance dist = strategy.get_distance_pp_strategy().apply(*prev, *it); | |
112 | current_distance = prev_distance + dist; | |
113 | ||
114 | while (current_distance >= repeated_distance) | |
115 | { | |
116 | point_t p; | |
117 | Distance diff_distance = current_distance - prev_distance; | |
118 | BOOST_ASSERT(diff_distance != Distance(0)); | |
119 | strategy.apply(start_p, *it, | |
120 | (repeated_distance - prev_distance)/diff_distance, | |
121 | p, | |
122 | diff_distance); | |
123 | policy.apply(p, pointlike); | |
20effc67 | 124 | if (std::is_same<PointLike, point_t>::value) |
92f5a8d4 TL |
125 | { |
126 | return; | |
127 | } | |
128 | start_p = p; | |
129 | prev_distance = repeated_distance; | |
130 | repeated_distance += max_distance; | |
131 | } | |
132 | prev_distance = current_distance; | |
133 | prev = it; | |
134 | start_p = *prev; | |
135 | } | |
136 | ||
137 | // case when max_distance is larger than linestring's length | |
138 | // return the last point in range (range is not empty) | |
139 | if (repeated_distance == max_distance) | |
140 | { | |
141 | policy.apply(*(end-1), pointlike); | |
142 | } | |
143 | } | |
144 | }; | |
145 | ||
146 | template <typename Policy> | |
147 | struct interpolate_segment | |
148 | { | |
149 | template <typename Segment, typename Distance, typename Pointlike, typename Strategy> | |
150 | static inline void apply(Segment const& segment, | |
151 | Distance const& max_distance, | |
152 | Pointlike & point, | |
153 | Strategy const& strategy) | |
154 | { | |
155 | interpolate_range<Policy>().apply(segment_view<Segment>(segment), | |
156 | max_distance, point, strategy); | |
157 | } | |
158 | }; | |
159 | ||
160 | }} // namespace detail::line_interpolate | |
161 | #endif // DOXYGEN_NO_DETAIL | |
162 | ||
163 | ||
164 | #ifndef DOXYGEN_NO_DISPATCH | |
165 | namespace dispatch | |
166 | { | |
167 | ||
168 | ||
169 | template | |
170 | < | |
171 | typename Geometry, | |
172 | typename Pointlike, | |
173 | typename Tag1 = typename tag<Geometry>::type, | |
174 | typename Tag2 = typename tag<Pointlike>::type | |
175 | > | |
176 | struct line_interpolate | |
177 | { | |
20effc67 TL |
178 | BOOST_GEOMETRY_STATIC_ASSERT_FALSE( |
179 | "Not implemented for this Geometry type.", | |
180 | Geometry, Pointlike); | |
92f5a8d4 TL |
181 | }; |
182 | ||
183 | ||
184 | template <typename Geometry, typename Pointlike> | |
185 | struct line_interpolate<Geometry, Pointlike, linestring_tag, point_tag> | |
186 | : detail::line_interpolate::interpolate_range | |
187 | < | |
188 | detail::line_interpolate::convert_and_assign | |
189 | > | |
190 | {}; | |
191 | ||
192 | template <typename Geometry, typename Pointlike> | |
193 | struct line_interpolate<Geometry, Pointlike, linestring_tag, multi_point_tag> | |
194 | : detail::line_interpolate::interpolate_range | |
195 | < | |
196 | detail::line_interpolate::convert_and_push_back | |
197 | > | |
198 | {}; | |
199 | ||
200 | template <typename Geometry, typename Pointlike> | |
201 | struct line_interpolate<Geometry, Pointlike, segment_tag, point_tag> | |
202 | : detail::line_interpolate::interpolate_segment | |
203 | < | |
204 | detail::line_interpolate::convert_and_assign | |
205 | > | |
206 | {}; | |
207 | ||
208 | template <typename Geometry, typename Pointlike> | |
209 | struct line_interpolate<Geometry, Pointlike, segment_tag, multi_point_tag> | |
210 | : detail::line_interpolate::interpolate_segment | |
211 | < | |
212 | detail::line_interpolate::convert_and_push_back | |
213 | > | |
214 | {}; | |
215 | ||
216 | } // namespace dispatch | |
217 | #endif // DOXYGEN_NO_DISPATCH | |
218 | ||
219 | ||
220 | namespace resolve_strategy { | |
221 | ||
222 | struct line_interpolate | |
223 | { | |
224 | template | |
225 | < | |
226 | typename Geometry, | |
227 | typename Distance, | |
228 | typename Pointlike, | |
229 | typename Strategy | |
230 | > | |
231 | static inline void apply(Geometry const& geometry, | |
232 | Distance const& max_distance, | |
233 | Pointlike & pointlike, | |
234 | Strategy const& strategy) | |
235 | { | |
236 | dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry, | |
237 | max_distance, | |
238 | pointlike, | |
239 | strategy); | |
240 | } | |
241 | ||
242 | template <typename Geometry, typename Distance, typename Pointlike> | |
243 | static inline void apply(Geometry const& geometry, | |
244 | Distance const& max_distance, | |
245 | Pointlike & pointlike, | |
246 | default_strategy) | |
247 | { | |
248 | typedef typename strategy::line_interpolate::services::default_strategy | |
249 | < | |
250 | typename cs_tag<Geometry>::type | |
251 | >::type strategy_type; | |
252 | ||
253 | dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry, | |
254 | max_distance, | |
255 | pointlike, | |
256 | strategy_type()); | |
257 | } | |
258 | }; | |
259 | ||
260 | } // namespace resolve_strategy | |
261 | ||
262 | ||
263 | namespace resolve_variant { | |
264 | ||
265 | template <typename Geometry> | |
266 | struct line_interpolate | |
267 | { | |
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) | |
273 | { | |
274 | return resolve_strategy::line_interpolate::apply(geometry, | |
275 | max_distance, | |
276 | pointlike, | |
277 | strategy); | |
278 | } | |
279 | }; | |
280 | ||
281 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
282 | struct line_interpolate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
283 | { | |
284 | template <typename Pointlike, typename Strategy> | |
285 | struct visitor: boost::static_visitor<void> | |
286 | { | |
287 | Pointlike const& m_pointlike; | |
288 | Strategy const& m_strategy; | |
289 | ||
290 | visitor(Pointlike const& pointlike, Strategy const& strategy) | |
291 | : m_pointlike(pointlike) | |
292 | , m_strategy(strategy) | |
293 | {} | |
294 | ||
295 | template <typename Geometry, typename Distance> | |
296 | void operator()(Geometry const& geometry, Distance const& max_distance) const | |
297 | { | |
298 | line_interpolate<Geometry>::apply(geometry, max_distance, | |
299 | m_pointlike, m_strategy); | |
300 | } | |
301 | }; | |
302 | ||
303 | template <typename Distance, typename Pointlike, typename Strategy> | |
304 | static inline void | |
305 | apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, | |
306 | double const& max_distance, | |
307 | Pointlike & pointlike, | |
308 | Strategy const& strategy) | |
309 | { | |
310 | boost::apply_visitor( | |
311 | visitor<Pointlike, Strategy>(pointlike, strategy), | |
312 | geometry, | |
313 | max_distance | |
314 | ); | |
315 | } | |
316 | }; | |
317 | ||
318 | } // namespace resolve_variant | |
319 | ||
320 | /*! | |
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 | |
333 | points | |
334 | ||
335 | \qbk{[include reference/algorithms/line_interpolate.qbk]} | |
336 | ||
337 | \qbk{distinguish,with strategy} | |
338 | ||
339 | \qbk{ | |
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] | |
344 | ||
345 | [heading Example] | |
346 | [line_interpolate_strategy] | |
347 | [line_interpolate_strategy_output] | |
348 | ||
349 | [heading See also] | |
350 | \* [link geometry.reference.algorithms.densify densify] | |
351 | } | |
352 | */ | |
353 | template | |
354 | < | |
355 | typename Geometry, | |
356 | typename Distance, | |
357 | typename Pointlike, | |
358 | typename Strategy | |
359 | > | |
360 | inline void line_interpolate(Geometry const& geometry, | |
361 | Distance const& max_distance, | |
362 | Pointlike & pointlike, | |
363 | Strategy const& strategy) | |
364 | { | |
365 | concepts::check<Geometry const>(); | |
366 | ||
367 | // detail::throw_on_empty_input(geometry); | |
368 | ||
369 | return resolve_variant::line_interpolate<Geometry> | |
370 | ::apply(geometry, max_distance, pointlike, strategy); | |
371 | } | |
372 | ||
373 | ||
374 | /*! | |
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) | |
385 | ||
386 | \qbk{[include reference/algorithms/line_interpolate.qbk] | |
387 | ||
388 | [heading Example] | |
389 | [line_interpolate] | |
390 | [line_interpolate_output] | |
391 | ||
392 | [heading See also] | |
393 | \* [link geometry.reference.algorithms.densify densify] | |
394 | } | |
395 | */ | |
396 | template<typename Geometry, typename Distance, typename Pointlike> | |
397 | inline void line_interpolate(Geometry const& geometry, | |
398 | Distance const& max_distance, | |
399 | Pointlike & pointlike) | |
400 | { | |
401 | concepts::check<Geometry const>(); | |
402 | ||
403 | // detail::throw_on_empty_input(geometry); | |
404 | ||
405 | return resolve_variant::line_interpolate<Geometry> | |
406 | ::apply(geometry, max_distance, pointlike, default_strategy()); | |
407 | } | |
408 | ||
409 | }} // namespace boost::geometry | |
410 | ||
411 | #endif // BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP |