densify.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. // Boost.Geometry
  2. // Copyright (c) 2017-2018, 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/geometry/algorithms/clear.hpp>
  9. #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
  10. #include <boost/geometry/algorithms/not_implemented.hpp>
  11. #include <boost/geometry/core/closure.hpp>
  12. #include <boost/geometry/core/cs.hpp>
  13. #include <boost/geometry/core/exception.hpp>
  14. #include <boost/geometry/core/point_type.hpp>
  15. #include <boost/geometry/core/tag.hpp>
  16. #include <boost/geometry/core/tags.hpp>
  17. #include <boost/geometry/strategies/default_strategy.hpp>
  18. #include <boost/geometry/strategies/densify.hpp>
  19. #include <boost/geometry/util/condition.hpp>
  20. #include <boost/geometry/util/range.hpp>
  21. #include <boost/range/size.hpp>
  22. #include <boost/range/value_type.hpp>
  23. #include <boost/throw_exception.hpp>
  24. namespace boost { namespace geometry
  25. {
  26. #ifndef DOXYGEN_NO_DETAIL
  27. namespace detail { namespace densify
  28. {
  29. template <typename Range>
  30. struct push_back_policy
  31. {
  32. typedef typename boost::range_value<Range>::type point_type;
  33. inline explicit push_back_policy(Range & rng)
  34. : m_rng(rng)
  35. {}
  36. inline void apply(point_type const& p)
  37. {
  38. range::push_back(m_rng, p);
  39. }
  40. private:
  41. Range & m_rng;
  42. };
  43. template <typename Range, typename Point>
  44. inline void convert_and_push_back(Range & range, Point const& p)
  45. {
  46. typename boost::range_value<Range>::type p2;
  47. geometry::detail::conversion::convert_point_to_point(p, p2);
  48. range::push_back(range, p2);
  49. }
  50. template <bool AppendLastPoint = true>
  51. struct densify_range
  52. {
  53. template <typename FwdRng, typename MutRng, typename T, typename Strategy>
  54. static inline void apply(FwdRng const& rng, MutRng & rng_out,
  55. T const& len, Strategy const& strategy)
  56. {
  57. typedef typename boost::range_iterator<FwdRng const>::type iterator_t;
  58. typedef typename boost::range_value<FwdRng>::type point_t;
  59. iterator_t it = boost::begin(rng);
  60. iterator_t end = boost::end(rng);
  61. if (it == end) // empty(rng)
  62. {
  63. return;
  64. }
  65. push_back_policy<MutRng> policy(rng_out);
  66. iterator_t prev = it;
  67. for ( ++it ; it != end ; prev = it++)
  68. {
  69. point_t const& p0 = *prev;
  70. point_t const& p1 = *it;
  71. convert_and_push_back(rng_out, p0);
  72. strategy.apply(p0, p1, policy, len);
  73. }
  74. if (BOOST_GEOMETRY_CONDITION(AppendLastPoint))
  75. {
  76. convert_and_push_back(rng_out, *prev); // back(rng)
  77. }
  78. }
  79. };
  80. template <bool IsClosed1, bool IsClosed2> // false, X
  81. struct densify_ring
  82. {
  83. template <typename Geometry, typename GeometryOut, typename T, typename Strategy>
  84. static inline void apply(Geometry const& ring, GeometryOut & ring_out,
  85. T const& len, Strategy const& strategy)
  86. {
  87. geometry::detail::densify::densify_range<true>
  88. ::apply(ring, ring_out, len, strategy);
  89. if (boost::size(ring) <= 1)
  90. return;
  91. typedef typename point_type<Geometry>::type point_t;
  92. point_t const& p0 = range::back(ring);
  93. point_t const& p1 = range::front(ring);
  94. push_back_policy<GeometryOut> policy(ring_out);
  95. strategy.apply(p0, p1, policy, len);
  96. if (BOOST_GEOMETRY_CONDITION(IsClosed2))
  97. {
  98. convert_and_push_back(ring_out, p1);
  99. }
  100. }
  101. };
  102. template <>
  103. struct densify_ring<true, true>
  104. : densify_range<true>
  105. {};
  106. template <>
  107. struct densify_ring<true, false>
  108. : densify_range<false>
  109. {};
  110. }} // namespace detail::densify
  111. #endif // DOXYGEN_NO_DETAIL
  112. #ifndef DOXYGEN_NO_DISPATCH
  113. namespace dispatch
  114. {
  115. template
  116. <
  117. typename Geometry,
  118. typename GeometryOut,
  119. typename Tag1 = typename tag<Geometry>::type,
  120. typename Tag2 = typename tag<GeometryOut>::type
  121. >
  122. struct densify
  123. : not_implemented<Tag1, Tag2>
  124. {};
  125. template <typename Geometry, typename GeometryOut>
  126. struct densify<Geometry, GeometryOut, linestring_tag, linestring_tag>
  127. : geometry::detail::densify::densify_range<>
  128. {};
  129. template <typename Geometry, typename GeometryOut>
  130. struct densify<Geometry, GeometryOut, multi_linestring_tag, multi_linestring_tag>
  131. {
  132. template <typename T, typename Strategy>
  133. static void apply(Geometry const& mls, GeometryOut & mls_out,
  134. T const& len, Strategy const& strategy)
  135. {
  136. std::size_t count = boost::size(mls);
  137. range::resize(mls_out, count);
  138. for (std::size_t i = 0 ; i < count ; ++i)
  139. {
  140. geometry::detail::densify::densify_range<>
  141. ::apply(range::at(mls, i), range::at(mls_out, i),
  142. len, strategy);
  143. }
  144. }
  145. };
  146. template <typename Geometry, typename GeometryOut>
  147. struct densify<Geometry, GeometryOut, ring_tag, ring_tag>
  148. : geometry::detail::densify::densify_ring
  149. <
  150. geometry::closure<Geometry>::value != geometry::open,
  151. geometry::closure<GeometryOut>::value != geometry::open
  152. >
  153. {};
  154. template <typename Geometry, typename GeometryOut>
  155. struct densify<Geometry, GeometryOut, polygon_tag, polygon_tag>
  156. {
  157. template <typename T, typename Strategy>
  158. static void apply(Geometry const& poly, GeometryOut & poly_out,
  159. T const& len, Strategy const& strategy)
  160. {
  161. apply_ring(exterior_ring(poly), exterior_ring(poly_out),
  162. len, strategy);
  163. std::size_t count = boost::size(interior_rings(poly));
  164. range::resize(interior_rings(poly_out), count);
  165. for (std::size_t i = 0 ; i < count ; ++i)
  166. {
  167. apply_ring(range::at(interior_rings(poly), i),
  168. range::at(interior_rings(poly_out), i),
  169. len, strategy);
  170. }
  171. }
  172. template <typename Ring, typename RingOut, typename T, typename Strategy>
  173. static void apply_ring(Ring const& ring, RingOut & ring_out,
  174. T const& len, Strategy const& strategy)
  175. {
  176. densify<Ring, RingOut, ring_tag, ring_tag>
  177. ::apply(ring, ring_out, len, strategy);
  178. }
  179. };
  180. template <typename Geometry, typename GeometryOut>
  181. struct densify<Geometry, GeometryOut, multi_polygon_tag, multi_polygon_tag>
  182. {
  183. template <typename T, typename Strategy>
  184. static void apply(Geometry const& mpoly, GeometryOut & mpoly_out,
  185. T const& len, Strategy const& strategy)
  186. {
  187. std::size_t count = boost::size(mpoly);
  188. range::resize(mpoly_out, count);
  189. for (std::size_t i = 0 ; i < count ; ++i)
  190. {
  191. apply_poly(range::at(mpoly, i),
  192. range::at(mpoly_out, i),
  193. len, strategy);
  194. }
  195. }
  196. template <typename Poly, typename PolyOut, typename T, typename Strategy>
  197. static void apply_poly(Poly const& poly, PolyOut & poly_out,
  198. T const& len, Strategy const& strategy)
  199. {
  200. densify<Poly, PolyOut, polygon_tag, polygon_tag>::
  201. apply(poly, poly_out, len, strategy);
  202. }
  203. };
  204. } // namespace dispatch
  205. #endif // DOXYGEN_NO_DISPATCH
  206. namespace resolve_strategy
  207. {
  208. struct densify
  209. {
  210. template <typename Geometry, typename Distance, typename Strategy>
  211. static inline void apply(Geometry const& geometry,
  212. Geometry& out,
  213. Distance const& max_distance,
  214. Strategy const& strategy)
  215. {
  216. dispatch::densify<Geometry, Geometry>
  217. ::apply(geometry, out, max_distance, strategy);
  218. }
  219. template <typename Geometry, typename Distance>
  220. static inline void apply(Geometry const& geometry,
  221. Geometry& out,
  222. Distance const& max_distance,
  223. default_strategy)
  224. {
  225. typedef typename strategy::densify::services::default_strategy
  226. <
  227. typename cs_tag<Geometry>::type
  228. >::type strategy_type;
  229. /*BOOST_CONCEPT_ASSERT(
  230. (concepts::DensifyStrategy<strategy_type>)
  231. );*/
  232. apply(geometry, out, max_distance, strategy_type());
  233. }
  234. };
  235. } // namespace resolve_strategy
  236. namespace resolve_variant {
  237. template <typename Geometry>
  238. struct densify
  239. {
  240. template <typename Distance, typename Strategy>
  241. static inline void apply(Geometry const& geometry,
  242. Geometry& out,
  243. Distance const& max_distance,
  244. Strategy const& strategy)
  245. {
  246. resolve_strategy::densify::apply(geometry, out, max_distance, strategy);
  247. }
  248. };
  249. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  250. struct densify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  251. {
  252. template <typename Distance, typename Strategy>
  253. struct visitor: boost::static_visitor<void>
  254. {
  255. Distance const& m_max_distance;
  256. Strategy const& m_strategy;
  257. visitor(Distance const& max_distance, Strategy const& strategy)
  258. : m_max_distance(max_distance)
  259. , m_strategy(strategy)
  260. {}
  261. template <typename Geometry>
  262. void operator()(Geometry const& geometry, Geometry& out) const
  263. {
  264. densify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
  265. }
  266. };
  267. template <typename Distance, typename Strategy>
  268. static inline void
  269. apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
  270. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
  271. Distance const& max_distance,
  272. Strategy const& strategy)
  273. {
  274. boost::apply_visitor(
  275. visitor<Distance, Strategy>(max_distance, strategy),
  276. geometry,
  277. out
  278. );
  279. }
  280. };
  281. } // namespace resolve_variant
  282. /*!
  283. \brief Densify a geometry using a specified strategy
  284. \ingroup densify
  285. \tparam Geometry \tparam_geometry
  286. \tparam Distance A numerical distance measure
  287. \tparam Strategy A type fulfilling a DensifyStrategy concept
  288. \param geometry Input geometry, to be densified
  289. \param out Output geometry, densified version of the input geometry
  290. \param max_distance Distance threshold (in units depending on strategy)
  291. \param strategy Densify strategy to be used for densification
  292. \qbk{distinguish,with strategy}
  293. \qbk{[include reference/algorithms/densify.qbk]}
  294. \qbk{
  295. [heading Available Strategies]
  296. \* [link geometry.reference.strategies.strategy_densify_cartesian Cartesian]
  297. \* [link geometry.reference.strategies.strategy_densify_spherical Spherical]
  298. \* [link geometry.reference.strategies.strategy_densify_geographic Geographic]
  299. [heading Example]
  300. [densify_strategy]
  301. [densify_strategy_output]
  302. [heading See also]
  303. \* [link geometry.reference.algorithms.line_interpolate line_interpolate]
  304. }
  305. */
  306. template <typename Geometry, typename Distance, typename Strategy>
  307. inline void densify(Geometry const& geometry,
  308. Geometry& out,
  309. Distance const& max_distance,
  310. Strategy const& strategy)
  311. {
  312. concepts::check<Geometry>();
  313. if (max_distance <= Distance(0))
  314. {
  315. BOOST_THROW_EXCEPTION(geometry::invalid_input_exception());
  316. }
  317. geometry::clear(out);
  318. resolve_variant::densify
  319. <
  320. Geometry
  321. >::apply(geometry, out, max_distance, strategy);
  322. }
  323. /*!
  324. \brief Densify a geometry
  325. \ingroup densify
  326. \tparam Geometry \tparam_geometry
  327. \tparam Distance A numerical distance measure
  328. \param geometry Input geometry, to be densified
  329. \param out Output geometry, densified version of the input geometry
  330. \param max_distance Distance threshold (in units depending on coordinate system)
  331. \qbk{[include reference/algorithms/densify.qbk]}
  332. \qbk{
  333. [heading Example]
  334. [densify]
  335. [densify_output]
  336. [heading See also]
  337. \* [link geometry.reference.algorithms.line_interpolate line_interpolate]
  338. }
  339. */
  340. template <typename Geometry, typename Distance>
  341. inline void densify(Geometry const& geometry,
  342. Geometry& out,
  343. Distance const& max_distance)
  344. {
  345. densify(geometry, out, max_distance, default_strategy());
  346. }
  347. }} // namespace boost::geometry
  348. #endif // BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP