line_interpolate.hpp 14 KB

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