line_interpolate.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2018, 2019 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 <boost/range/begin.hpp>
  12. #include <boost/range/end.hpp>
  13. #include <boost/range/iterator.hpp>
  14. #include <boost/range/value_type.hpp>
  15. #include <boost/geometry/core/cs.hpp>
  16. #include <boost/geometry/core/closure.hpp>
  17. #include <boost/geometry/core/tags.hpp>
  18. #include <boost/geometry/geometries/concepts/check.hpp>
  19. #include <boost/geometry/algorithms/assign.hpp>
  20. #include <boost/geometry/algorithms/length.hpp>
  21. #include <boost/geometry/strategies/default_strategy.hpp>
  22. #include <boost/geometry/strategies/line_interpolate.hpp>
  23. namespace boost { namespace geometry
  24. {
  25. #ifndef DOXYGEN_NO_DETAIL
  26. namespace detail { namespace line_interpolate
  27. {
  28. struct convert_and_push_back
  29. {
  30. template <typename Range, typename Point>
  31. inline void apply(Point const& p, Range& range)
  32. {
  33. typename boost::range_value<Range>::type p2;
  34. geometry::detail::conversion::convert_point_to_point(p, p2);
  35. range::push_back(range, p2);
  36. }
  37. };
  38. struct convert_and_assign
  39. {
  40. template <typename Point1, typename Point2>
  41. inline void apply(Point1 const& p1, Point2& p2)
  42. {
  43. geometry::detail::conversion::convert_point_to_point(p1, p2);
  44. }
  45. };
  46. /*!
  47. \brief Internal, calculates interpolation point of a linestring using iterator pairs and
  48. specified strategy
  49. */
  50. template <typename Policy>
  51. struct interpolate_range
  52. {
  53. template
  54. <
  55. typename Range,
  56. typename Distance,
  57. typename PointLike,
  58. typename Strategy
  59. >
  60. static inline void apply(Range const& range,
  61. Distance const& max_distance,
  62. PointLike & pointlike,
  63. Strategy const& strategy)
  64. {
  65. Policy policy;
  66. typedef typename boost::range_iterator<Range const>::type iterator_t;
  67. typedef typename boost::range_value<Range const>::type point_t;
  68. iterator_t it = boost::begin(range);
  69. iterator_t end = boost::end(range);
  70. if (it == end) // empty(range)
  71. {
  72. BOOST_THROW_EXCEPTION(empty_input_exception());
  73. return;
  74. }
  75. if (max_distance <= 0) //non positive distance
  76. {
  77. policy.apply(*it, pointlike);
  78. return;
  79. }
  80. iterator_t prev = it++;
  81. Distance repeated_distance = max_distance;
  82. Distance prev_distance = 0;
  83. Distance current_distance = 0;
  84. point_t start_p = *prev;
  85. for ( ; it != end ; ++it)
  86. {
  87. Distance dist = strategy.get_distance_pp_strategy().apply(*prev, *it);
  88. current_distance = prev_distance + dist;
  89. while (current_distance >= repeated_distance)
  90. {
  91. point_t p;
  92. Distance diff_distance = current_distance - prev_distance;
  93. BOOST_ASSERT(diff_distance != Distance(0));
  94. strategy.apply(start_p, *it,
  95. (repeated_distance - prev_distance)/diff_distance,
  96. p,
  97. diff_distance);
  98. policy.apply(p, pointlike);
  99. if (boost::is_same<PointLike, point_t>::value)
  100. {
  101. return;
  102. }
  103. start_p = p;
  104. prev_distance = repeated_distance;
  105. repeated_distance += max_distance;
  106. }
  107. prev_distance = current_distance;
  108. prev = it;
  109. start_p = *prev;
  110. }
  111. // case when max_distance is larger than linestring's length
  112. // return the last point in range (range is not empty)
  113. if (repeated_distance == max_distance)
  114. {
  115. policy.apply(*(end-1), pointlike);
  116. }
  117. }
  118. };
  119. template <typename Policy>
  120. struct interpolate_segment
  121. {
  122. template <typename Segment, typename Distance, typename Pointlike, typename Strategy>
  123. static inline void apply(Segment const& segment,
  124. Distance const& max_distance,
  125. Pointlike & point,
  126. Strategy const& strategy)
  127. {
  128. interpolate_range<Policy>().apply(segment_view<Segment>(segment),
  129. max_distance, point, strategy);
  130. }
  131. };
  132. }} // namespace detail::line_interpolate
  133. #endif // DOXYGEN_NO_DETAIL
  134. #ifndef DOXYGEN_NO_DISPATCH
  135. namespace dispatch
  136. {
  137. template
  138. <
  139. typename Geometry,
  140. typename Pointlike,
  141. typename Tag1 = typename tag<Geometry>::type,
  142. typename Tag2 = typename tag<Pointlike>::type
  143. >
  144. struct line_interpolate
  145. {
  146. BOOST_MPL_ASSERT_MSG
  147. (
  148. false, NOT_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
  149. , (types<Geometry>)
  150. );
  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