simplify.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2015 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/core/ignore_unused.hpp>
  14. #include <boost/range.hpp>
  15. #include <boost/variant/apply_visitor.hpp>
  16. #include <boost/variant/static_visitor.hpp>
  17. #include <boost/variant/variant_fwd.hpp>
  18. #include <boost/geometry/core/cs.hpp>
  19. #include <boost/geometry/core/closure.hpp>
  20. #include <boost/geometry/core/exterior_ring.hpp>
  21. #include <boost/geometry/core/interior_rings.hpp>
  22. #include <boost/geometry/core/mutable_range.hpp>
  23. #include <boost/geometry/core/tags.hpp>
  24. #include <boost/geometry/geometries/concepts/check.hpp>
  25. #include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
  26. #include <boost/geometry/strategies/concepts/simplify_concept.hpp>
  27. #include <boost/geometry/strategies/default_strategy.hpp>
  28. #include <boost/geometry/strategies/distance.hpp>
  29. #include <boost/geometry/algorithms/clear.hpp>
  30. #include <boost/geometry/algorithms/convert.hpp>
  31. #include <boost/geometry/algorithms/not_implemented.hpp>
  32. #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp>
  33. namespace boost { namespace geometry
  34. {
  35. #ifndef DOXYGEN_NO_DETAIL
  36. namespace detail { namespace simplify
  37. {
  38. struct simplify_range_insert
  39. {
  40. template<typename Range, typename Strategy, typename OutputIterator, typename Distance>
  41. static inline void apply(Range const& range, OutputIterator out,
  42. Distance const& max_distance, Strategy const& strategy)
  43. {
  44. boost::ignore_unused(strategy);
  45. if (boost::size(range) <= 2 || max_distance < 0)
  46. {
  47. std::copy(boost::begin(range), boost::end(range), out);
  48. }
  49. else
  50. {
  51. strategy.apply(range, out, max_distance);
  52. }
  53. }
  54. };
  55. struct simplify_copy
  56. {
  57. template <typename Range, typename Strategy, typename Distance>
  58. static inline void apply(Range const& range, Range& out,
  59. Distance const& , Strategy const& )
  60. {
  61. std::copy
  62. (
  63. boost::begin(range), boost::end(range), geometry::range::back_inserter(out)
  64. );
  65. }
  66. };
  67. template<std::size_t Minimum>
  68. struct simplify_range
  69. {
  70. template <typename Range, typename Strategy, typename Distance>
  71. static inline void apply(Range const& range, Range& out,
  72. Distance const& max_distance, Strategy const& strategy)
  73. {
  74. // Call do_container for a linestring / ring
  75. /* For a RING:
  76. The first/last point (the closing point of the ring) should maybe
  77. be excluded because it lies on a line with second/one but last.
  78. Here it is never excluded.
  79. Note also that, especially if max_distance is too large,
  80. the output ring might be self intersecting while the input ring is
  81. not, although chances are low in normal polygons
  82. Finally the inputring might have 3 (open) or 4 (closed) points (=correct),
  83. the output < 3 or 4(=wrong)
  84. */
  85. if (boost::size(range) <= int(Minimum) || max_distance < 0.0)
  86. {
  87. simplify_copy::apply(range, out, max_distance, strategy);
  88. }
  89. else
  90. {
  91. simplify_range_insert::apply
  92. (
  93. range, geometry::range::back_inserter(out), max_distance, strategy
  94. );
  95. }
  96. }
  97. };
  98. struct simplify_polygon
  99. {
  100. private:
  101. template
  102. <
  103. std::size_t Minimum,
  104. typename IteratorIn,
  105. typename IteratorOut,
  106. typename Distance,
  107. typename Strategy
  108. >
  109. static inline void iterate(IteratorIn begin, IteratorIn end,
  110. IteratorOut it_out,
  111. Distance const& max_distance, Strategy const& strategy)
  112. {
  113. for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out)
  114. {
  115. simplify_range<Minimum>::apply(*it_in, *it_out, max_distance, strategy);
  116. }
  117. }
  118. template
  119. <
  120. std::size_t Minimum,
  121. typename InteriorRingsIn,
  122. typename InteriorRingsOut,
  123. typename Distance,
  124. typename Strategy
  125. >
  126. static inline void apply_interior_rings(
  127. InteriorRingsIn const& interior_rings_in,
  128. InteriorRingsOut& interior_rings_out,
  129. Distance const& max_distance, Strategy const& strategy)
  130. {
  131. traits::resize<InteriorRingsOut>::apply(interior_rings_out,
  132. boost::size(interior_rings_in));
  133. iterate<Minimum>(
  134. boost::begin(interior_rings_in), boost::end(interior_rings_in),
  135. boost::begin(interior_rings_out),
  136. max_distance, strategy);
  137. }
  138. public:
  139. template <typename Polygon, typename Strategy, typename Distance>
  140. static inline void apply(Polygon const& poly_in, Polygon& poly_out,
  141. Distance const& max_distance, Strategy const& strategy)
  142. {
  143. std::size_t const minimum = core_detail::closure::minimum_ring_size
  144. <
  145. geometry::closure<Polygon>::value
  146. >::value;
  147. // Note that if there are inner rings, and distance is too large,
  148. // they might intersect with the outer ring in the output,
  149. // while it didn't in the input.
  150. simplify_range<minimum>::apply(exterior_ring(poly_in),
  151. exterior_ring(poly_out),
  152. max_distance, strategy);
  153. apply_interior_rings<minimum>(interior_rings(poly_in),
  154. interior_rings(poly_out),
  155. max_distance, strategy);
  156. }
  157. };
  158. template<typename Policy>
  159. struct simplify_multi
  160. {
  161. template <typename MultiGeometry, typename Strategy, typename Distance>
  162. static inline void apply(MultiGeometry const& multi, MultiGeometry& out,
  163. Distance const& max_distance, Strategy const& strategy)
  164. {
  165. traits::resize<MultiGeometry>::apply(out, boost::size(multi));
  166. typename boost::range_iterator<MultiGeometry>::type it_out
  167. = boost::begin(out);
  168. for (typename boost::range_iterator<MultiGeometry const>::type
  169. it_in = boost::begin(multi);
  170. it_in != boost::end(multi);
  171. ++it_in, ++it_out)
  172. {
  173. Policy::apply(*it_in, *it_out, max_distance, strategy);
  174. }
  175. }
  176. };
  177. }} // namespace detail::simplify
  178. #endif // DOXYGEN_NO_DETAIL
  179. #ifndef DOXYGEN_NO_DISPATCH
  180. namespace dispatch
  181. {
  182. template
  183. <
  184. typename Geometry,
  185. typename Tag = typename tag<Geometry>::type
  186. >
  187. struct simplify: not_implemented<Tag>
  188. {};
  189. template <typename Point>
  190. struct simplify<Point, point_tag>
  191. {
  192. template <typename Distance, typename Strategy>
  193. static inline void apply(Point const& point, Point& out,
  194. Distance const& , Strategy const& )
  195. {
  196. geometry::convert(point, out);
  197. }
  198. };
  199. template <typename Linestring>
  200. struct simplify<Linestring, linestring_tag>
  201. : detail::simplify::simplify_range<2>
  202. {};
  203. template <typename Ring>
  204. struct simplify<Ring, ring_tag>
  205. : detail::simplify::simplify_range
  206. <
  207. core_detail::closure::minimum_ring_size
  208. <
  209. geometry::closure<Ring>::value
  210. >::value
  211. >
  212. {};
  213. template <typename Polygon>
  214. struct simplify<Polygon, polygon_tag>
  215. : detail::simplify::simplify_polygon
  216. {};
  217. template
  218. <
  219. typename Geometry,
  220. typename Tag = typename tag<Geometry>::type
  221. >
  222. struct simplify_insert: not_implemented<Tag>
  223. {};
  224. template <typename Linestring>
  225. struct simplify_insert<Linestring, linestring_tag>
  226. : detail::simplify::simplify_range_insert
  227. {};
  228. template <typename Ring>
  229. struct simplify_insert<Ring, ring_tag>
  230. : detail::simplify::simplify_range_insert
  231. {};
  232. template <typename MultiPoint>
  233. struct simplify<MultiPoint, multi_point_tag>
  234. : detail::simplify::simplify_copy
  235. {};
  236. template <typename MultiLinestring>
  237. struct simplify<MultiLinestring, multi_linestring_tag>
  238. : detail::simplify::simplify_multi<detail::simplify::simplify_range<2> >
  239. {};
  240. template <typename MultiPolygon>
  241. struct simplify<MultiPolygon, multi_polygon_tag>
  242. : detail::simplify::simplify_multi<detail::simplify::simplify_polygon>
  243. {};
  244. } // namespace dispatch
  245. #endif // DOXYGEN_NO_DISPATCH
  246. namespace resolve_strategy
  247. {
  248. struct simplify
  249. {
  250. template <typename Geometry, typename Distance, typename Strategy>
  251. static inline void apply(Geometry const& geometry,
  252. Geometry& out,
  253. Distance const& max_distance,
  254. Strategy const& strategy)
  255. {
  256. dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
  257. }
  258. template <typename Geometry, typename Distance>
  259. static inline void apply(Geometry const& geometry,
  260. Geometry& out,
  261. Distance const& max_distance,
  262. default_strategy)
  263. {
  264. typedef typename point_type<Geometry>::type point_type;
  265. typedef typename strategy::distance::services::default_strategy
  266. <
  267. point_tag, segment_tag, point_type
  268. >::type ds_strategy_type;
  269. typedef strategy::simplify::douglas_peucker
  270. <
  271. point_type, ds_strategy_type
  272. > strategy_type;
  273. BOOST_CONCEPT_ASSERT(
  274. (concept::SimplifyStrategy<strategy_type, point_type>)
  275. );
  276. apply(geometry, out, max_distance, strategy_type());
  277. }
  278. };
  279. struct simplify_insert
  280. {
  281. template
  282. <
  283. typename Geometry,
  284. typename OutputIterator,
  285. typename Distance,
  286. typename Strategy
  287. >
  288. static inline void apply(Geometry const& geometry,
  289. OutputIterator& out,
  290. Distance const& max_distance,
  291. Strategy const& strategy)
  292. {
  293. dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy);
  294. }
  295. template <typename Geometry, typename OutputIterator, typename Distance>
  296. static inline void apply(Geometry const& geometry,
  297. OutputIterator& out,
  298. Distance const& max_distance,
  299. default_strategy)
  300. {
  301. typedef typename point_type<Geometry>::type point_type;
  302. typedef typename strategy::distance::services::default_strategy
  303. <
  304. point_tag, segment_tag, point_type
  305. >::type ds_strategy_type;
  306. typedef strategy::simplify::douglas_peucker
  307. <
  308. point_type, ds_strategy_type
  309. > strategy_type;
  310. BOOST_CONCEPT_ASSERT(
  311. (concept::SimplifyStrategy<strategy_type, point_type>)
  312. );
  313. apply(geometry, out, max_distance, strategy_type());
  314. }
  315. };
  316. } // namespace resolve_strategy
  317. namespace resolve_variant {
  318. template <typename Geometry>
  319. struct simplify
  320. {
  321. template <typename Distance, typename Strategy>
  322. static inline void apply(Geometry const& geometry,
  323. Geometry& out,
  324. Distance const& max_distance,
  325. Strategy const& strategy)
  326. {
  327. resolve_strategy::simplify::apply(geometry, out, max_distance, strategy);
  328. }
  329. };
  330. template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
  331. struct simplify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
  332. {
  333. template <typename Distance, typename Strategy>
  334. struct visitor: boost::static_visitor<void>
  335. {
  336. Distance const& m_max_distance;
  337. Strategy const& m_strategy;
  338. visitor(Distance const& max_distance, Strategy const& strategy)
  339. : m_max_distance(max_distance)
  340. , m_strategy(strategy)
  341. {}
  342. template <typename Geometry>
  343. void operator()(Geometry const& geometry, Geometry& out) const
  344. {
  345. simplify<Geometry>::apply(geometry, out, m_max_distance, m_strategy);
  346. }
  347. };
  348. template <typename Distance, typename Strategy>
  349. static inline void
  350. apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
  351. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out,
  352. Distance const& max_distance,
  353. Strategy const& strategy)
  354. {
  355. boost::apply_visitor(
  356. visitor<Distance, Strategy>(max_distance, strategy),
  357. geometry,
  358. out
  359. );
  360. }
  361. };
  362. } // namespace resolve_variant
  363. /*!
  364. \brief Simplify a geometry using a specified strategy
  365. \ingroup simplify
  366. \tparam Geometry \tparam_geometry
  367. \tparam Distance A numerical distance measure
  368. \tparam Strategy A type fulfilling a SimplifyStrategy concept
  369. \param strategy A strategy to calculate simplification
  370. \param geometry input geometry, to be simplified
  371. \param out output geometry, simplified version of the input geometry
  372. \param max_distance distance (in units of input coordinates) of a vertex
  373. to other segments to be removed
  374. \param strategy simplify strategy to be used for simplification, might
  375. include point-distance strategy
  376. \image html svg_simplify_country.png "The image below presents the simplified country"
  377. \qbk{distinguish,with strategy}
  378. */
  379. template<typename Geometry, typename Distance, typename Strategy>
  380. inline void simplify(Geometry const& geometry, Geometry& out,
  381. Distance const& max_distance, Strategy const& strategy)
  382. {
  383. concept::check<Geometry>();
  384. geometry::clear(out);
  385. resolve_variant::simplify<Geometry>::apply(geometry, out, max_distance, strategy);
  386. }
  387. /*!
  388. \brief Simplify a geometry
  389. \ingroup simplify
  390. \tparam Geometry \tparam_geometry
  391. \tparam Distance \tparam_numeric
  392. \note This version of simplify simplifies a geometry using the default
  393. strategy (Douglas Peucker),
  394. \param geometry input geometry, to be simplified
  395. \param out output geometry, simplified version of the input geometry
  396. \param max_distance distance (in units of input coordinates) of a vertex
  397. to other segments to be removed
  398. \qbk{[include reference/algorithms/simplify.qbk]}
  399. */
  400. template<typename Geometry, typename Distance>
  401. inline void simplify(Geometry const& geometry, Geometry& out,
  402. Distance const& max_distance)
  403. {
  404. concept::check<Geometry>();
  405. geometry::simplify(geometry, out, max_distance, default_strategy());
  406. }
  407. #ifndef DOXYGEN_NO_DETAIL
  408. namespace detail { namespace simplify
  409. {
  410. /*!
  411. \brief Simplify a geometry, using an output iterator
  412. and a specified strategy
  413. \ingroup simplify
  414. \tparam Geometry \tparam_geometry
  415. \param geometry input geometry, to be simplified
  416. \param out output iterator, outputs all simplified points
  417. \param max_distance distance (in units of input coordinates) of a vertex
  418. to other segments to be removed
  419. \param strategy simplify strategy to be used for simplification,
  420. might include point-distance strategy
  421. \qbk{distinguish,with strategy}
  422. \qbk{[include reference/algorithms/simplify.qbk]}
  423. */
  424. template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy>
  425. inline void simplify_insert(Geometry const& geometry, OutputIterator out,
  426. Distance const& max_distance, Strategy const& strategy)
  427. {
  428. concept::check<Geometry const>();
  429. resolve_strategy::simplify_insert::apply(geometry, out, max_distance, strategy);
  430. }
  431. /*!
  432. \brief Simplify a geometry, using an output iterator
  433. \ingroup simplify
  434. \tparam Geometry \tparam_geometry
  435. \param geometry input geometry, to be simplified
  436. \param out output iterator, outputs all simplified points
  437. \param max_distance distance (in units of input coordinates) of a vertex
  438. to other segments to be removed
  439. \qbk{[include reference/algorithms/simplify_insert.qbk]}
  440. */
  441. template<typename Geometry, typename OutputIterator, typename Distance>
  442. inline void simplify_insert(Geometry const& geometry, OutputIterator out,
  443. Distance const& max_distance)
  444. {
  445. // Concept: output point type = point type of input geometry
  446. concept::check<Geometry const>();
  447. concept::check<typename point_type<Geometry>::type>();
  448. simplify_insert(geometry, out, max_distance, default_strategy());
  449. }
  450. }} // namespace detail::simplify
  451. #endif // DOXYGEN_NO_DETAIL
  452. }} // namespace boost::geometry
  453. #endif // BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP