densify.hpp 12 KB

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