line_interpolate.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2018-2020 Oracle and/or its affiliates.
  3. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  4. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
  10. #include <iterator>
  11. #include <type_traits>
  12. #include <boost/range/begin.hpp>
  13. #include <boost/range/end.hpp>
  14. #include <boost/range/iterator.hpp>
  15. #include <boost/range/value_type.hpp>
  16. #include <boost/geometry/core/cs.hpp>
  17. #include <boost/geometry/core/closure.hpp>
  18. #include <boost/geometry/core/static_assert.hpp>
  19. #include <boost/geometry/core/tags.hpp>
  20. #include <boost/geometry/geometries/concepts/check.hpp>
  21. #include <boost/geometry/algorithms/assign.hpp>
  22. #include <boost/geometry/algorithms/length.hpp>
  23. #include <boost/geometry/strategies/default_strategy.hpp>
  24. #include <boost/geometry/strategies/line_interpolate.hpp>
  25. namespace boost { namespace geometry
  26. {
  27. #ifndef DOXYGEN_NO_DETAIL
  28. namespace detail { namespace line_interpolate
  29. {
  30. struct convert_and_push_back
  31. {
  32. template <typename Range, typename Point>
  33. inline void apply(Point const& p, Range& range)
  34. {
  35. typename boost::range_value<Range>::type p2;
  36. geometry::detail::conversion::convert_point_to_point(p, p2);
  37. range::push_back(range, p2);
  38. }
  39. };
  40. struct convert_and_assign
  41. {
  42. template <typename Point1, typename Point2>
  43. inline void apply(Point1 const& p1, Point2& p2)
  44. {
  45. geometry::detail::conversion::convert_point_to_point(p1, p2);
  46. }
  47. };
  48. /*!
  49. \brief Internal, calculates interpolation point of a linestring using iterator pairs and
  50. specified strategy
  51. */
  52. template <typename Policy>
  53. struct interpolate_range
  54. {
  55. template
  56. <
  57. typename Range,
  58. typename Distance,
  59. typename PointLike,
  60. typename Strategy
  61. >
  62. static inline void apply(Range const& range,
  63. Distance const& max_distance,
  64. PointLike & pointlike,
  65. Strategy const& strategy)
  66. {
  67. Policy policy;
  68. typedef typename boost::range_iterator<Range const>::type iterator_t;
  69. typedef typename boost::range_value<Range const>::type point_t;
  70. iterator_t it = boost::begin(range);
  71. iterator_t end = boost::end(range);
  72. if (it == end) // empty(range)
  73. {
  74. BOOST_THROW_EXCEPTION(empty_input_exception());
  75. return;
  76. }
  77. if (max_distance <= 0) //non positive distance
  78. {
  79. policy.apply(*it, pointlike);
  80. return;
  81. }
  82. iterator_t prev = it++;
  83. Distance repeated_distance = max_distance;
  84. Distance prev_distance = 0;
  85. Distance current_distance = 0;
  86. point_t start_p = *prev;
  87. for ( ; it != end ; ++it)
  88. {
  89. Distance dist = strategy.get_distance_pp_strategy().apply(*prev, *it);
  90. current_distance = prev_distance + dist;
  91. while (current_distance >= repeated_distance)
  92. {
  93. point_t p;
  94. Distance diff_distance = current_distance - prev_distance;
  95. BOOST_ASSERT(diff_distance != Distance(0));
  96. strategy.apply(start_p, *it,
  97. (repeated_distance - prev_distance)/diff_distance,
  98. p,
  99. diff_distance);
  100. policy.apply(p, pointlike);
  101. if (std::is_same<PointLike, point_t>::value)
  102. {
  103. return;
  104. }
  105. start_p = p;
  106. prev_distance = repeated_distance;
  107. repeated_distance += max_distance;
  108. }
  109. prev_distance = current_distance;
  110. prev = it;
  111. start_p = *prev;
  112. }
  113. // case when max_distance is larger than linestring's length
  114. // return the last point in range (range is not empty)
  115. if (repeated_distance == max_distance)
  116. {
  117. policy.apply(*(end-1), pointlike);
  118. }
  119. }
  120. };
  121. template <typename Policy>
  122. struct interpolate_segment
  123. {
  124. template <typename Segment, typename Distance, typename Pointlike, typename Strategy>
  125. static inline void apply(Segment const& segment,
  126. Distance const& max_distance,
  127. Pointlike & point,
  128. Strategy const& strategy)
  129. {
  130. interpolate_range<Policy>().apply(segment_view<Segment>(segment),
  131. max_distance, point, strategy);
  132. }
  133. };
  134. }} // namespace detail::line_interpolate
  135. #endif // DOXYGEN_NO_DETAIL
  136. #ifndef DOXYGEN_NO_DISPATCH
  137. namespace dispatch
  138. {
  139. template
  140. <
  141. typename Geometry,
  142. typename Pointlike,
  143. typename Tag1 = typename tag<Geometry>::type,
  144. typename Tag2 = typename tag<Pointlike>::type
  145. >
  146. struct line_interpolate
  147. {
  148. BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
  149. "Not implemented for this Geometry type.",
  150. Geometry, Pointlike);
  151. };
  152. template <typename Geometry, typename Pointlike>
  153. struct line_interpolate<Geometry, Pointlike, linestring_tag, point_tag>
  154. : detail::line_interpolate::interpolate_range
  155. <
  156. detail::line_interpolate::convert_and_assign
  157. >
  158. {};
  159. template <typename Geometry, typename Pointlike>
  160. struct line_interpolate<Geometry, Pointlike, linestring_tag, multi_point_tag>
  161. : detail::line_interpolate::interpolate_range
  162. <
  163. detail::line_interpolate::convert_and_push_back
  164. >
  165. {};
  166. template <typename Geometry, typename Pointlike>
  167. struct line_interpolate<Geometry, Pointlike, segment_tag, point_tag>
  168. : detail::line_interpolate::interpolate_segment
  169. <
  170. detail::line_interpolate::convert_and_assign
  171. >
  172. {};
  173. template <typename Geometry, typename Pointlike>
  174. struct line_interpolate<Geometry, Pointlike, segment_tag, multi_point_tag>
  175. : detail::line_interpolate::interpolate_segment
  176. <
  177. detail::line_interpolate::convert_and_push_back
  178. >
  179. {};
  180. } // namespace dispatch
  181. #endif // DOXYGEN_NO_DISPATCH
  182. namespace resolve_strategy {
  183. struct line_interpolate
  184. {
  185. template
  186. <
  187. typename Geometry,
  188. typename Distance,
  189. typename Pointlike,
  190. typename Strategy
  191. >
  192. static inline void apply(Geometry const& geometry,
  193. Distance const& max_distance,
  194. Pointlike & pointlike,
  195. Strategy const& strategy)
  196. {
  197. dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry,
  198. max_distance,
  199. pointlike,
  200. strategy);
  201. }
  202. template <typename Geometry, typename Distance, typename Pointlike>
  203. static inline void apply(Geometry const& geometry,
  204. Distance const& max_distance,
  205. Pointlike & pointlike,
  206. default_strategy)
  207. {
  208. typedef typename strategy::line_interpolate::services::default_strategy
  209. <
  210. typename cs_tag<Geometry>::type
  211. >::type strategy_type;
  212. dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry,
  213. max_distance,
  214. pointlike,
  215. strategy_type());
  216. }
  217. };
  218. } // namespace resolve_strategy
  219. namespace resolve_variant {
  220. template <typename Geometry>
  221. struct line_interpolate
  222. {
  223. template <typename Distance, typename Pointlike, typename Strategy>
  224. static inline void apply(Geometry const& geometry,
  225. Distance const& max_distance,
  226. Pointlike & pointlike,
  227. Strategy const& strategy)
  228. {
  229. return resolve_strategy::line_interpolate::apply(geometry,
  230. max_distance,
  231. pointlike,
  232. strategy);
  233. }
  234. };
  235. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  236. struct line_interpolate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  237. {
  238. template <typename Pointlike, typename Strategy>
  239. struct visitor: boost::static_visitor<void>
  240. {
  241. Pointlike const& m_pointlike;
  242. Strategy const& m_strategy;
  243. visitor(Pointlike const& pointlike, Strategy const& strategy)
  244. : m_pointlike(pointlike)
  245. , m_strategy(strategy)
  246. {}
  247. template <typename Geometry, typename Distance>
  248. void operator()(Geometry const& geometry, Distance const& max_distance) const
  249. {
  250. line_interpolate<Geometry>::apply(geometry, max_distance,
  251. m_pointlike, m_strategy);
  252. }
  253. };
  254. template <typename Distance, typename Pointlike, typename Strategy>
  255. static inline void
  256. apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
  257. double const& max_distance,
  258. Pointlike & pointlike,
  259. Strategy const& strategy)
  260. {
  261. boost::apply_visitor(
  262. visitor<Pointlike, Strategy>(pointlike, strategy),
  263. geometry,
  264. max_distance
  265. );
  266. }
  267. };
  268. } // namespace resolve_variant
  269. /*!
  270. \brief Returns one or more points interpolated along a LineString \brief_strategy
  271. \ingroup line_interpolate
  272. \tparam Geometry Any type fulfilling a LineString concept
  273. \tparam Distance A numerical distance measure
  274. \tparam Pointlike Any type fulfilling Point or Multipoint concept
  275. \tparam Strategy A type fulfilling a LineInterpolatePointStrategy concept
  276. \param geometry Input geometry
  277. \param max_distance Distance threshold (in units depending on coordinate system)
  278. representing the spacing between the points
  279. \param pointlike Output: either a Point (exactly one point will be constructed) or
  280. a MultiPoint (depending on the max_distance one or more points will be constructed)
  281. \param strategy line_interpolate strategy to be used for interpolation of
  282. points
  283. \qbk{[include reference/algorithms/line_interpolate.qbk]}
  284. \qbk{distinguish,with strategy}
  285. \qbk{
  286. [heading Available Strategies]
  287. \* [link geometry.reference.strategies.strategy_line_interpolate_cartesian Cartesian]
  288. \* [link geometry.reference.strategies.strategy_line_interpolate_spherical Spherical]
  289. \* [link geometry.reference.strategies.strategy_line_interpolate_geographic Geographic]
  290. [heading Example]
  291. [line_interpolate_strategy]
  292. [line_interpolate_strategy_output]
  293. [heading See also]
  294. \* [link geometry.reference.algorithms.densify densify]
  295. }
  296. */
  297. template
  298. <
  299. typename Geometry,
  300. typename Distance,
  301. typename Pointlike,
  302. typename Strategy
  303. >
  304. inline void line_interpolate(Geometry const& geometry,
  305. Distance const& max_distance,
  306. Pointlike & pointlike,
  307. Strategy const& strategy)
  308. {
  309. concepts::check<Geometry const>();
  310. // detail::throw_on_empty_input(geometry);
  311. return resolve_variant::line_interpolate<Geometry>
  312. ::apply(geometry, max_distance, pointlike, strategy);
  313. }
  314. /*!
  315. \brief Returns one or more points interpolated along a LineString.
  316. \ingroup line_interpolate
  317. \tparam Geometry Any type fulfilling a LineString concept
  318. \tparam Distance A numerical distance measure
  319. \tparam Pointlike Any type fulfilling Point or Multipoint concept
  320. \param geometry Input geometry
  321. \param max_distance Distance threshold (in units depending on coordinate system)
  322. representing the spacing between the points
  323. \param pointlike Output: either a Point (exactly one point will be constructed) or
  324. a MultiPoint (depending on the max_distance one or more points will be constructed)
  325. \qbk{[include reference/algorithms/line_interpolate.qbk]
  326. [heading Example]
  327. [line_interpolate]
  328. [line_interpolate_output]
  329. [heading See also]
  330. \* [link geometry.reference.algorithms.densify densify]
  331. }
  332. */
  333. template<typename Geometry, typename Distance, typename Pointlike>
  334. inline void line_interpolate(Geometry const& geometry,
  335. Distance const& max_distance,
  336. Pointlike & pointlike)
  337. {
  338. concepts::check<Geometry const>();
  339. // detail::throw_on_empty_input(geometry);
  340. return resolve_variant::line_interpolate<Geometry>
  341. ::apply(geometry, max_distance, pointlike, default_strategy());
  342. }
  343. }} // namespace boost::geometry
  344. #endif // BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP