simplify.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  5. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  6. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP
  12. #include <cstddef>
  13. #include <boost/range.hpp>
  14. #include <boost/typeof/typeof.hpp>
  15. #include <boost/geometry/core/cs.hpp>
  16. #include <boost/geometry/core/closure.hpp>
  17. #include <boost/geometry/core/ring_type.hpp>
  18. #include <boost/geometry/core/exterior_ring.hpp>
  19. #include <boost/geometry/core/interior_rings.hpp>
  20. #include <boost/geometry/core/mutable_range.hpp>
  21. #include <boost/geometry/geometries/concepts/check.hpp>
  22. #include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
  23. #include <boost/geometry/strategies/concepts/simplify_concept.hpp>
  24. #include <boost/geometry/algorithms/clear.hpp>
  25. #include <boost/geometry/algorithms/convert.hpp>
  26. #include <boost/geometry/algorithms/not_implemented.hpp>
  27. #include <boost/geometry/algorithms/num_interior_rings.hpp>
  28. namespace boost { namespace geometry
  29. {
  30. #ifndef DOXYGEN_NO_DETAIL
  31. namespace detail { namespace simplify
  32. {
  33. struct simplify_range_insert
  34. {
  35. template<typename Range, typename Strategy, typename OutputIterator, typename Distance>
  36. static inline void apply(Range const& range, OutputIterator out,
  37. Distance const& max_distance, Strategy const& strategy)
  38. {
  39. if (boost::size(range) <= 2 || max_distance < 0)
  40. {
  41. std::copy(boost::begin(range), boost::end(range), out);
  42. }
  43. else
  44. {
  45. strategy.apply(range, out, max_distance);
  46. }
  47. }
  48. };
  49. struct simplify_copy
  50. {
  51. template <typename Range, typename Strategy, typename Distance>
  52. static inline void apply(Range const& range, Range& out,
  53. Distance const& , Strategy const& )
  54. {
  55. std::copy
  56. (
  57. boost::begin(range), boost::end(range), std::back_inserter(out)
  58. );
  59. }
  60. };
  61. template<std::size_t Minimum>
  62. struct simplify_range
  63. {
  64. template <typename Range, typename Strategy, typename Distance>
  65. static inline void apply(Range const& range, Range& out,
  66. Distance const& max_distance, Strategy const& strategy)
  67. {
  68. // Call do_container for a linestring / ring
  69. /* For a RING:
  70. The first/last point (the closing point of the ring) should maybe
  71. be excluded because it lies on a line with second/one but last.
  72. Here it is never excluded.
  73. Note also that, especially if max_distance is too large,
  74. the output ring might be self intersecting while the input ring is
  75. not, although chances are low in normal polygons
  76. Finally the inputring might have 3 (open) or 4 (closed) points (=correct),
  77. the output < 3 or 4(=wrong)
  78. */
  79. if (boost::size(range) <= int(Minimum) || max_distance < 0.0)
  80. {
  81. simplify_copy::apply(range, out, max_distance, strategy);
  82. }
  83. else
  84. {
  85. simplify_range_insert::apply
  86. (
  87. range, std::back_inserter(out), max_distance, strategy
  88. );
  89. }
  90. }
  91. };
  92. struct simplify_polygon
  93. {
  94. template <typename Polygon, typename Strategy, typename Distance>
  95. static inline void apply(Polygon const& poly_in, Polygon& poly_out,
  96. Distance const& max_distance, Strategy const& strategy)
  97. {
  98. typedef typename ring_type<Polygon>::type ring_type;
  99. int const Minimum = core_detail::closure::minimum_ring_size
  100. <
  101. geometry::closure<Polygon>::value
  102. >::value;
  103. // Note that if there are inner rings, and distance is too large,
  104. // they might intersect with the outer ring in the output,
  105. // while it didn't in the input.
  106. simplify_range<Minimum>::apply(exterior_ring(poly_in),
  107. exterior_ring(poly_out),
  108. max_distance, strategy);
  109. traits::resize
  110. <
  111. typename boost::remove_reference
  112. <
  113. typename traits::interior_mutable_type<Polygon>::type
  114. >::type
  115. >::apply(interior_rings(poly_out), num_interior_rings(poly_in));
  116. typename interior_return_type<Polygon const>::type rings_in
  117. = interior_rings(poly_in);
  118. typename interior_return_type<Polygon>::type rings_out
  119. = interior_rings(poly_out);
  120. BOOST_AUTO_TPL(it_out, boost::begin(rings_out));
  121. for (BOOST_AUTO_TPL(it_in, boost::begin(rings_in));
  122. it_in != boost::end(rings_in);
  123. ++it_in, ++it_out)
  124. {
  125. simplify_range<Minimum>::apply(*it_in, *it_out, max_distance, strategy);
  126. }
  127. }
  128. };
  129. }} // namespace detail::simplify
  130. #endif // DOXYGEN_NO_DETAIL
  131. #ifndef DOXYGEN_NO_DISPATCH
  132. namespace dispatch
  133. {
  134. template
  135. <
  136. typename Geometry,
  137. typename Tag = typename tag<Geometry>::type
  138. >
  139. struct simplify: not_implemented<Tag>
  140. {};
  141. template <typename Point>
  142. struct simplify<Point, point_tag>
  143. {
  144. template <typename Distance, typename Strategy>
  145. static inline void apply(Point const& point, Point& out,
  146. Distance const& , Strategy const& )
  147. {
  148. geometry::convert(point, out);
  149. }
  150. };
  151. template <typename Linestring>
  152. struct simplify<Linestring, linestring_tag>
  153. : detail::simplify::simplify_range<2>
  154. {};
  155. template <typename Ring>
  156. struct simplify<Ring, ring_tag>
  157. : detail::simplify::simplify_range
  158. <
  159. core_detail::closure::minimum_ring_size
  160. <
  161. geometry::closure<Ring>::value
  162. >::value
  163. >
  164. {};
  165. template <typename Polygon>
  166. struct simplify<Polygon, polygon_tag>
  167. : detail::simplify::simplify_polygon
  168. {};
  169. template
  170. <
  171. typename Geometry,
  172. typename Tag = typename tag<Geometry>::type
  173. >
  174. struct simplify_insert: not_implemented<Tag>
  175. {};
  176. template <typename Linestring>
  177. struct simplify_insert<Linestring, linestring_tag>
  178. : detail::simplify::simplify_range_insert
  179. {};
  180. template <typename Ring>
  181. struct simplify_insert<Ring, ring_tag>
  182. : detail::simplify::simplify_range_insert
  183. {};
  184. } // namespace dispatch
  185. #endif // DOXYGEN_NO_DISPATCH
  186. /*!
  187. \brief Simplify a geometry using a specified strategy
  188. \ingroup simplify
  189. \tparam Geometry \tparam_geometry
  190. \tparam Distance A numerical distance measure
  191. \tparam Strategy A type fulfilling a SimplifyStrategy concept
  192. \param strategy A strategy to calculate simplification
  193. \param geometry input geometry, to be simplified
  194. \param out output geometry, simplified version of the input geometry
  195. \param max_distance distance (in units of input coordinates) of a vertex
  196. to other segments to be removed
  197. \param strategy simplify strategy to be used for simplification, might
  198. include point-distance strategy
  199. \image html svg_simplify_country.png "The image below presents the simplified country"
  200. \qbk{distinguish,with strategy}
  201. */
  202. template<typename Geometry, typename Distance, typename Strategy>
  203. inline void simplify(Geometry const& geometry, Geometry& out,
  204. Distance const& max_distance, Strategy const& strategy)
  205. {
  206. concept::check<Geometry>();
  207. BOOST_CONCEPT_ASSERT(
  208. (concept::SimplifyStrategy<Strategy, typename point_type<Geometry>::type>)
  209. );
  210. geometry::clear(out);
  211. dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
  212. }
  213. /*!
  214. \brief Simplify a geometry
  215. \ingroup simplify
  216. \tparam Geometry \tparam_geometry
  217. \tparam Distance \tparam_numeric
  218. \note This version of simplify simplifies a geometry using the default
  219. strategy (Douglas Peucker),
  220. \param geometry input geometry, to be simplified
  221. \param out output geometry, simplified version of the input geometry
  222. \param max_distance distance (in units of input coordinates) of a vertex
  223. to other segments to be removed
  224. \qbk{[include reference/algorithms/simplify.qbk]}
  225. */
  226. template<typename Geometry, typename Distance>
  227. inline void simplify(Geometry const& geometry, Geometry& out,
  228. Distance const& max_distance)
  229. {
  230. concept::check<Geometry>();
  231. typedef typename point_type<Geometry>::type point_type;
  232. typedef typename strategy::distance::services::default_strategy
  233. <
  234. segment_tag, point_type
  235. >::type ds_strategy_type;
  236. typedef strategy::simplify::douglas_peucker
  237. <
  238. point_type, ds_strategy_type
  239. > strategy_type;
  240. simplify(geometry, out, max_distance, strategy_type());
  241. }
  242. #ifndef DOXYGEN_NO_DETAIL
  243. namespace detail { namespace simplify
  244. {
  245. /*!
  246. \brief Simplify a geometry, using an output iterator
  247. and a specified strategy
  248. \ingroup simplify
  249. \tparam Geometry \tparam_geometry
  250. \param geometry input geometry, to be simplified
  251. \param out output iterator, outputs all simplified points
  252. \param max_distance distance (in units of input coordinates) of a vertex
  253. to other segments to be removed
  254. \param strategy simplify strategy to be used for simplification,
  255. might include point-distance strategy
  256. \qbk{distinguish,with strategy}
  257. \qbk{[include reference/algorithms/simplify.qbk]}
  258. */
  259. template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy>
  260. inline void simplify_insert(Geometry const& geometry, OutputIterator out,
  261. Distance const& max_distance, Strategy const& strategy)
  262. {
  263. concept::check<Geometry const>();
  264. BOOST_CONCEPT_ASSERT(
  265. (concept::SimplifyStrategy<Strategy, typename point_type<Geometry>::type>)
  266. );
  267. dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy);
  268. }
  269. /*!
  270. \brief Simplify a geometry, using an output iterator
  271. \ingroup simplify
  272. \tparam Geometry \tparam_geometry
  273. \param geometry input geometry, to be simplified
  274. \param out output iterator, outputs all simplified points
  275. \param max_distance distance (in units of input coordinates) of a vertex
  276. to other segments to be removed
  277. \qbk{[include reference/algorithms/simplify_insert.qbk]}
  278. */
  279. template<typename Geometry, typename OutputIterator, typename Distance>
  280. inline void simplify_insert(Geometry const& geometry, OutputIterator out,
  281. Distance const& max_distance)
  282. {
  283. typedef typename point_type<Geometry>::type point_type;
  284. // Concept: output point type = point type of input geometry
  285. concept::check<Geometry const>();
  286. concept::check<point_type>();
  287. typedef typename strategy::distance::services::default_strategy
  288. <
  289. segment_tag, point_type
  290. >::type ds_strategy_type;
  291. typedef strategy::simplify::douglas_peucker
  292. <
  293. point_type, ds_strategy_type
  294. > strategy_type;
  295. dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy_type());
  296. }
  297. }} // namespace detail::simplify
  298. #endif // DOXYGEN_NO_DETAIL
  299. }} // namespace boost::geometry
  300. #endif // BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP