densify.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. // Boost.Geometry
  2. // Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
  3. // Copyright (c) 2017-2023, Oracle and/or its affiliates.
  4. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  5. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  6. // Licensed under the Boost Software License version 1.0.
  7. // http://www.boost.org/users/license.html
  8. #ifndef BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
  9. #define BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
  10. #include <boost/range/size.hpp>
  11. #include <boost/range/value_type.hpp>
  12. #include <boost/throw_exception.hpp>
  13. #include <boost/geometry/algorithms/clear.hpp>
  14. #include <boost/geometry/algorithms/convert.hpp>
  15. #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
  16. #include <boost/geometry/algorithms/detail/visit.hpp>
  17. #include <boost/geometry/algorithms/not_implemented.hpp>
  18. #include <boost/geometry/core/closure.hpp>
  19. #include <boost/geometry/core/exception.hpp>
  20. #include <boost/geometry/core/tag.hpp>
  21. #include <boost/geometry/core/tags.hpp>
  22. #include <boost/geometry/core/visit.hpp>
  23. #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
  24. #include <boost/geometry/strategies/default_strategy.hpp>
  25. #include <boost/geometry/strategies/densify/cartesian.hpp>
  26. #include <boost/geometry/strategies/densify/geographic.hpp>
  27. #include <boost/geometry/strategies/densify/spherical.hpp>
  28. #include <boost/geometry/strategies/detail.hpp>
  29. #include <boost/geometry/util/constexpr.hpp>
  30. #include <boost/geometry/util/range.hpp>
  31. namespace boost { namespace geometry
  32. {
  33. #ifndef DOXYGEN_NO_DETAIL
  34. namespace detail { namespace densify
  35. {
  36. template <typename Range>
  37. struct push_back_policy
  38. {
  39. typedef typename boost::range_value<Range>::type point_type;
  40. inline explicit push_back_policy(Range & rng)
  41. : m_rng(rng)
  42. {}
  43. inline void apply(point_type const& p)
  44. {
  45. range::push_back(m_rng, p);
  46. }
  47. private:
  48. Range & m_rng;
  49. };
  50. template <typename Range, typename Point>
  51. inline void convert_and_push_back(Range & range, Point const& p)
  52. {
  53. typename boost::range_value<Range>::type p2;
  54. geometry::detail::conversion::convert_point_to_point(p, p2);
  55. range::push_back(range, p2);
  56. }
  57. template <bool AppendLastPoint = true>
  58. struct densify_range
  59. {
  60. template <typename FwdRng, typename MutRng, typename T, typename Strategies>
  61. static inline void apply(FwdRng const& rng, MutRng & rng_out,
  62. T const& len, Strategies const& strategies)
  63. {
  64. typedef typename boost::range_value<FwdRng>::type point_t;
  65. auto it = boost::begin(rng);
  66. auto const end = boost::end(rng);
  67. if (it == end) // empty(rng)
  68. {
  69. return;
  70. }
  71. auto strategy = strategies.densify(rng);
  72. push_back_policy<MutRng> policy(rng_out);
  73. auto prev = it;
  74. for ( ++it ; it != end ; prev = it++)
  75. {
  76. point_t const& p0 = *prev;
  77. point_t const& p1 = *it;
  78. convert_and_push_back(rng_out, p0);
  79. strategy.apply(p0, p1, policy, len);
  80. }
  81. if BOOST_GEOMETRY_CONSTEXPR (AppendLastPoint)
  82. {
  83. convert_and_push_back(rng_out, *prev); // back(rng)
  84. }
  85. }
  86. };
  87. template <bool IsClosed1, bool IsClosed2> // false, X
  88. struct densify_ring
  89. {
  90. template <typename Geometry, typename GeometryOut, typename T, typename Strategies>
  91. static inline void apply(Geometry const& ring, GeometryOut & ring_out,
  92. T const& len, Strategies const& strategies)
  93. {
  94. geometry::detail::densify::densify_range<true>
  95. ::apply(ring, ring_out, len, strategies);
  96. if (boost::size(ring) <= 1)
  97. return;
  98. auto const& p0 = range::back(ring);
  99. auto const& p1 = range::front(ring);
  100. auto strategy = strategies.densify(ring);
  101. push_back_policy<GeometryOut> policy(ring_out);
  102. strategy.apply(p0, p1, policy, len);
  103. if BOOST_GEOMETRY_CONSTEXPR (IsClosed2)
  104. {
  105. convert_and_push_back(ring_out, p1);
  106. }
  107. }
  108. };
  109. template <>
  110. struct densify_ring<true, true>
  111. : densify_range<true>
  112. {};
  113. template <>
  114. struct densify_ring<true, false>
  115. : densify_range<false>
  116. {};
  117. struct densify_convert
  118. {
  119. template <typename GeometryIn, typename GeometryOut, typename T, typename Strategy>
  120. static void apply(GeometryIn const& in, GeometryOut &out,
  121. T const& , Strategy const& )
  122. {
  123. geometry::convert(in, out);
  124. }
  125. };
  126. }} // namespace detail::densify
  127. #endif // DOXYGEN_NO_DETAIL
  128. #ifndef DOXYGEN_NO_DISPATCH
  129. namespace dispatch
  130. {
  131. template
  132. <
  133. typename Geometry,
  134. typename GeometryOut,
  135. typename Tag1 = typename tag<Geometry>::type,
  136. typename Tag2 = typename tag<GeometryOut>::type
  137. >
  138. struct densify
  139. : not_implemented<Tag1, Tag2>
  140. {};
  141. template <typename Geometry, typename GeometryOut>
  142. struct densify<Geometry, GeometryOut, point_tag, point_tag>
  143. : geometry::detail::densify::densify_convert
  144. {};
  145. template <typename Geometry, typename GeometryOut>
  146. struct densify<Geometry, GeometryOut, segment_tag, segment_tag>
  147. : geometry::detail::densify::densify_convert
  148. {};
  149. template <typename Geometry, typename GeometryOut>
  150. struct densify<Geometry, GeometryOut, box_tag, box_tag>
  151. : geometry::detail::densify::densify_convert
  152. {};
  153. template <typename Geometry, typename GeometryOut>
  154. struct densify<Geometry, GeometryOut, multi_point_tag, multi_point_tag>
  155. : geometry::detail::densify::densify_convert
  156. {};
  157. template <typename Geometry, typename GeometryOut>
  158. struct densify<Geometry, GeometryOut, linestring_tag, linestring_tag>
  159. : geometry::detail::densify::densify_range<>
  160. {};
  161. template <typename Geometry, typename GeometryOut>
  162. struct densify<Geometry, GeometryOut, multi_linestring_tag, multi_linestring_tag>
  163. {
  164. template <typename T, typename Strategy>
  165. static void apply(Geometry const& mls, GeometryOut & mls_out,
  166. T const& len, Strategy const& strategy)
  167. {
  168. std::size_t count = boost::size(mls);
  169. range::resize(mls_out, count);
  170. for (std::size_t i = 0 ; i < count ; ++i)
  171. {
  172. geometry::detail::densify::densify_range<>
  173. ::apply(range::at(mls, i), range::at(mls_out, i),
  174. len, strategy);
  175. }
  176. }
  177. };
  178. template <typename Geometry, typename GeometryOut>
  179. struct densify<Geometry, GeometryOut, ring_tag, ring_tag>
  180. : geometry::detail::densify::densify_ring
  181. <
  182. geometry::closure<Geometry>::value != geometry::open,
  183. geometry::closure<GeometryOut>::value != geometry::open
  184. >
  185. {};
  186. template <typename Geometry, typename GeometryOut>
  187. struct densify<Geometry, GeometryOut, polygon_tag, polygon_tag>
  188. {
  189. template <typename T, typename Strategy>
  190. static void apply(Geometry const& poly, GeometryOut & poly_out,
  191. T const& len, Strategy const& strategy)
  192. {
  193. apply_ring(exterior_ring(poly), exterior_ring(poly_out),
  194. len, strategy);
  195. std::size_t count = boost::size(interior_rings(poly));
  196. range::resize(interior_rings(poly_out), count);
  197. for (std::size_t i = 0 ; i < count ; ++i)
  198. {
  199. apply_ring(range::at(interior_rings(poly), i),
  200. range::at(interior_rings(poly_out), i),
  201. len, strategy);
  202. }
  203. }
  204. template <typename Ring, typename RingOut, typename T, typename Strategy>
  205. static void apply_ring(Ring const& ring, RingOut & ring_out,
  206. T const& len, Strategy const& strategy)
  207. {
  208. densify<Ring, RingOut, ring_tag, ring_tag>
  209. ::apply(ring, ring_out, len, strategy);
  210. }
  211. };
  212. template <typename Geometry, typename GeometryOut>
  213. struct densify<Geometry, GeometryOut, multi_polygon_tag, multi_polygon_tag>
  214. {
  215. template <typename T, typename Strategy>
  216. static void apply(Geometry const& mpoly, GeometryOut & mpoly_out,
  217. T const& len, Strategy const& strategy)
  218. {
  219. std::size_t count = boost::size(mpoly);
  220. range::resize(mpoly_out, count);
  221. for (std::size_t i = 0 ; i < count ; ++i)
  222. {
  223. apply_poly(range::at(mpoly, i),
  224. range::at(mpoly_out, i),
  225. len, strategy);
  226. }
  227. }
  228. template <typename Poly, typename PolyOut, typename T, typename Strategy>
  229. static void apply_poly(Poly const& poly, PolyOut & poly_out,
  230. T const& len, Strategy const& strategy)
  231. {
  232. densify<Poly, PolyOut, polygon_tag, polygon_tag>::
  233. apply(poly, poly_out, len, strategy);
  234. }
  235. };
  236. } // namespace dispatch
  237. #endif // DOXYGEN_NO_DISPATCH
  238. namespace resolve_strategy
  239. {
  240. template
  241. <
  242. typename Strategies,
  243. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
  244. >
  245. struct densify
  246. {
  247. template <typename Geometry, typename Distance>
  248. static inline void apply(Geometry const& geometry,
  249. Geometry& out,
  250. Distance const& max_distance,
  251. Strategies const& strategies)
  252. {
  253. dispatch::densify
  254. <
  255. Geometry, Geometry
  256. >::apply(geometry, out, max_distance, strategies);
  257. }
  258. };
  259. template <typename Strategy>
  260. struct densify<Strategy, false>
  261. {
  262. template <typename Geometry, typename Distance>
  263. static inline void apply(Geometry const& geometry,
  264. Geometry& out,
  265. Distance const& max_distance,
  266. Strategy const& strategy)
  267. {
  268. using strategies::densify::services::strategy_converter;
  269. dispatch::densify
  270. <
  271. Geometry, Geometry
  272. >::apply(geometry, out, max_distance,
  273. strategy_converter<Strategy>::get(strategy));
  274. }
  275. };
  276. template <>
  277. struct densify<default_strategy, false>
  278. {
  279. template <typename Geometry, typename Distance>
  280. static inline void apply(Geometry const& geometry,
  281. Geometry& out,
  282. Distance const& max_distance,
  283. default_strategy const&)
  284. {
  285. typedef typename strategies::densify::services::default_strategy
  286. <
  287. Geometry
  288. >::type strategies_type;
  289. dispatch::densify
  290. <
  291. Geometry, Geometry
  292. >::apply(geometry, out, max_distance, strategies_type());
  293. }
  294. };
  295. } // namespace resolve_strategy
  296. namespace resolve_dynamic {
  297. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  298. struct densify
  299. {
  300. template <typename Distance, typename Strategy>
  301. static inline void apply(Geometry const& geometry,
  302. Geometry& out,
  303. Distance const& max_distance,
  304. Strategy const& strategy)
  305. {
  306. resolve_strategy::densify
  307. <
  308. Strategy
  309. >::apply(geometry, out, max_distance, strategy);
  310. }
  311. };
  312. template <typename Geometry>
  313. struct densify<Geometry, dynamic_geometry_tag>
  314. {
  315. template <typename Distance, typename Strategy>
  316. static inline void
  317. apply(Geometry const& geometry,
  318. Geometry& out,
  319. Distance const& max_distance,
  320. Strategy const& strategy)
  321. {
  322. traits::visit<Geometry>::apply([&](auto const& g)
  323. {
  324. using geom_t = util::remove_cref_t<decltype(g)>;
  325. geom_t o;
  326. densify<geom_t>::apply(g, o, max_distance, strategy);
  327. out = std::move(o);
  328. }, geometry);
  329. }
  330. };
  331. template <typename Geometry>
  332. struct densify<Geometry, geometry_collection_tag>
  333. {
  334. template <typename Distance, typename Strategy>
  335. static inline void
  336. apply(Geometry const& geometry,
  337. Geometry& out,
  338. Distance const& max_distance,
  339. Strategy const& strategy)
  340. {
  341. detail::visit_breadth_first([&](auto const& g)
  342. {
  343. using geom_t = util::remove_cref_t<decltype(g)>;
  344. geom_t o;
  345. densify<geom_t>::apply(g, o, max_distance, strategy);
  346. traits::emplace_back<Geometry>::apply(out, std::move(o));
  347. return true;
  348. }, geometry);
  349. }
  350. };
  351. } // namespace resolve_dynamic
  352. /*!
  353. \brief Densify a geometry using a specified strategy
  354. \ingroup densify
  355. \tparam Geometry \tparam_geometry
  356. \tparam Distance A numerical distance measure
  357. \tparam Strategy A type fulfilling a DensifyStrategy concept
  358. \param geometry Input geometry, to be densified
  359. \param out Output geometry, densified version of the input geometry
  360. \param max_distance Distance threshold (in units depending on strategy)
  361. \param strategy Densify strategy to be used for densification
  362. \qbk{distinguish,with strategy}
  363. \qbk{[include reference/algorithms/densify.qbk]}
  364. \qbk{
  365. [heading Available Strategies]
  366. \* [link geometry.reference.strategies.strategy_densify_cartesian Cartesian]
  367. \* [link geometry.reference.strategies.strategy_densify_spherical Spherical]
  368. \* [link geometry.reference.strategies.strategy_densify_geographic Geographic]
  369. [heading Example]
  370. [densify_strategy]
  371. [densify_strategy_output]
  372. [heading See also]
  373. \* [link geometry.reference.algorithms.line_interpolate line_interpolate]
  374. }
  375. */
  376. template <typename Geometry, typename Distance, typename Strategy>
  377. inline void densify(Geometry const& geometry,
  378. Geometry& out,
  379. Distance const& max_distance,
  380. Strategy const& strategy)
  381. {
  382. concepts::check<Geometry>();
  383. if (max_distance <= Distance(0))
  384. {
  385. BOOST_THROW_EXCEPTION(geometry::invalid_input_exception());
  386. }
  387. geometry::clear(out);
  388. resolve_dynamic::densify
  389. <
  390. Geometry
  391. >::apply(geometry, out, max_distance, strategy);
  392. }
  393. /*!
  394. \brief Densify a geometry
  395. \ingroup densify
  396. \tparam Geometry \tparam_geometry
  397. \tparam Distance A numerical distance measure
  398. \param geometry Input geometry, to be densified
  399. \param out Output geometry, densified version of the input geometry
  400. \param max_distance Distance threshold (in units depending on coordinate system)
  401. \qbk{[include reference/algorithms/densify.qbk]}
  402. \qbk{
  403. [heading Example]
  404. [densify]
  405. [densify_output]
  406. [heading See also]
  407. \* [link geometry.reference.algorithms.line_interpolate line_interpolate]
  408. }
  409. */
  410. template <typename Geometry, typename Distance>
  411. inline void densify(Geometry const& geometry,
  412. Geometry& out,
  413. Distance const& max_distance)
  414. {
  415. densify(geometry, out, max_distance, default_strategy());
  416. }
  417. }} // namespace boost::geometry
  418. #endif // BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP