densify.hpp 15 KB

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