correct.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
  6. // This file was modified by Oracle on 2017-2023.
  7. // Modifications copyright (c) 2017-2023 Oracle and/or its affiliates.
  8. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  10. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
  11. // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
  12. // Use, modification and distribution is subject to the Boost Software License,
  13. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  14. // http://www.boost.org/LICENSE_1_0.txt)
  15. #ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP
  16. #define BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP
  17. #include <algorithm>
  18. #include <functional>
  19. #include <boost/range/begin.hpp>
  20. #include <boost/range/end.hpp>
  21. #include <boost/geometry/algorithms/area.hpp>
  22. #include <boost/geometry/algorithms/correct_closure.hpp>
  23. #include <boost/geometry/algorithms/detail/multi_modify.hpp>
  24. #include <boost/geometry/algorithms/detail/visit.hpp>
  25. #include <boost/geometry/core/exterior_ring.hpp>
  26. #include <boost/geometry/core/interior_rings.hpp>
  27. #include <boost/geometry/core/tags.hpp>
  28. #include <boost/geometry/core/visit.hpp>
  29. #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
  30. #include <boost/geometry/geometries/concepts/check.hpp>
  31. #include <boost/geometry/strategies/area/cartesian.hpp>
  32. #include <boost/geometry/strategies/area/geographic.hpp>
  33. #include <boost/geometry/strategies/area/spherical.hpp>
  34. #include <boost/geometry/strategies/detail.hpp>
  35. #include <boost/geometry/util/algorithm.hpp>
  36. namespace boost { namespace geometry
  37. {
  38. // Silence warning C4127: conditional expression is constant
  39. #if defined(_MSC_VER)
  40. #pragma warning(push)
  41. #pragma warning(disable : 4127)
  42. #endif
  43. #ifndef DOXYGEN_NO_DETAIL
  44. namespace detail { namespace correct
  45. {
  46. struct correct_nop
  47. {
  48. template <typename Geometry, typename Strategy>
  49. static inline void apply(Geometry& , Strategy const& )
  50. {}
  51. };
  52. // Correct a box: make min/max correct
  53. struct correct_box
  54. {
  55. template <typename Box, typename Strategy>
  56. static inline void apply(Box& box, Strategy const& )
  57. {
  58. using coordinate_type = typename geometry::coordinate_type<Box>::type;
  59. // Currently only for Cartesian coordinates
  60. // (or spherical without crossing dateline)
  61. // Future version: adapt using strategies
  62. detail::for_each_dimension<Box>([&](auto dimension)
  63. {
  64. if (get<min_corner, dimension>(box) > get<max_corner, dimension>(box))
  65. {
  66. // Swap the coordinates
  67. coordinate_type max_value = get<min_corner, dimension>(box);
  68. coordinate_type min_value = get<max_corner, dimension>(box);
  69. set<min_corner, dimension>(box, min_value);
  70. set<max_corner, dimension>(box, max_value);
  71. }
  72. });
  73. }
  74. };
  75. // Close a ring, if not closed
  76. template <typename Predicate = std::less<>>
  77. struct correct_ring
  78. {
  79. template <typename Ring, typename Strategy>
  80. static inline void apply(Ring& r, Strategy const& strategy)
  81. {
  82. // Correct closure if necessary
  83. detail::correct_closure::close_or_open_ring::apply(r);
  84. // NOTE: calculate_point_order should probably be used here instead.
  85. // Check area
  86. using area_t = typename area_result<Ring, Strategy>::type;
  87. area_t const zero = 0;
  88. if (Predicate()(detail::area::ring_area::apply(r, strategy), zero))
  89. {
  90. std::reverse(boost::begin(r), boost::end(r));
  91. }
  92. }
  93. };
  94. // Correct a polygon: normalizes all rings, sets outer ring clockwise, sets all
  95. // inner rings counter clockwise (or vice versa depending on orientation)
  96. struct correct_polygon
  97. {
  98. template <typename Polygon, typename Strategy>
  99. static inline void apply(Polygon& poly, Strategy const& strategy)
  100. {
  101. correct_ring<std::less<>>::apply(exterior_ring(poly), strategy);
  102. auto&& rings = interior_rings(poly);
  103. auto const end = boost::end(rings);
  104. for (auto it = boost::begin(rings); it != end; ++it)
  105. {
  106. correct_ring<std::greater<>>::apply(*it, strategy);
  107. }
  108. }
  109. };
  110. }} // namespace detail::correct
  111. #endif // DOXYGEN_NO_DETAIL
  112. #ifndef DOXYGEN_NO_DISPATCH
  113. namespace dispatch
  114. {
  115. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  116. struct correct: not_implemented<Tag>
  117. {};
  118. template <typename Point>
  119. struct correct<Point, point_tag>
  120. : detail::correct::correct_nop
  121. {};
  122. template <typename LineString>
  123. struct correct<LineString, linestring_tag>
  124. : detail::correct::correct_nop
  125. {};
  126. template <typename Segment>
  127. struct correct<Segment, segment_tag>
  128. : detail::correct::correct_nop
  129. {};
  130. template <typename Box>
  131. struct correct<Box, box_tag>
  132. : detail::correct::correct_box
  133. {};
  134. template <typename Ring>
  135. struct correct<Ring, ring_tag>
  136. : detail::correct::correct_ring<>
  137. {};
  138. template <typename Polygon>
  139. struct correct<Polygon, polygon_tag>
  140. : detail::correct::correct_polygon
  141. {};
  142. template <typename MultiPoint>
  143. struct correct<MultiPoint, multi_point_tag>
  144. : detail::correct::correct_nop
  145. {};
  146. template <typename MultiLineString>
  147. struct correct<MultiLineString, multi_linestring_tag>
  148. : detail::correct::correct_nop
  149. {};
  150. template <typename Geometry>
  151. struct correct<Geometry, multi_polygon_tag>
  152. : detail::multi_modify<detail::correct::correct_polygon>
  153. {};
  154. } // namespace dispatch
  155. #endif // DOXYGEN_NO_DISPATCH
  156. namespace resolve_strategy
  157. {
  158. template
  159. <
  160. typename Strategy,
  161. bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
  162. >
  163. struct correct
  164. {
  165. template <typename Geometry>
  166. static inline void apply(Geometry& geometry, Strategy const& strategy)
  167. {
  168. dispatch::correct<Geometry>::apply(geometry, strategy);
  169. }
  170. };
  171. template <typename Strategy>
  172. struct correct<Strategy, false>
  173. {
  174. template <typename Geometry>
  175. static inline void apply(Geometry& geometry, Strategy const& strategy)
  176. {
  177. // NOTE: calculate_point_order strategy should probably be used here instead.
  178. using geometry::strategies::area::services::strategy_converter;
  179. dispatch::correct<Geometry>::apply(geometry, strategy_converter<Strategy>::get(strategy));
  180. }
  181. };
  182. template <>
  183. struct correct<default_strategy, false>
  184. {
  185. template <typename Geometry>
  186. static inline void apply(Geometry& geometry, default_strategy const& )
  187. {
  188. // NOTE: calculate_point_order strategy should probably be used here instead.
  189. using strategy_type = typename strategies::area::services::default_strategy
  190. <
  191. Geometry
  192. >::type;
  193. dispatch::correct<Geometry>::apply(geometry, strategy_type());
  194. }
  195. };
  196. } // namespace resolve_strategy
  197. namespace resolve_dynamic
  198. {
  199. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  200. struct correct
  201. {
  202. template <typename Strategy>
  203. static inline void apply(Geometry& geometry, Strategy const& strategy)
  204. {
  205. concepts::check<Geometry>();
  206. resolve_strategy::correct<Strategy>::apply(geometry, strategy);
  207. }
  208. };
  209. template <typename Geometry>
  210. struct correct<Geometry, dynamic_geometry_tag>
  211. {
  212. template <typename Strategy>
  213. static inline void apply(Geometry& geometry, Strategy const& strategy)
  214. {
  215. traits::visit<Geometry>::apply([&](auto & g)
  216. {
  217. correct<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
  218. }, geometry);
  219. }
  220. };
  221. template <typename Geometry>
  222. struct correct<Geometry, geometry_collection_tag>
  223. {
  224. template <typename Strategy>
  225. static inline void apply(Geometry& geometry, Strategy const& strategy)
  226. {
  227. detail::visit_breadth_first([&](auto & g)
  228. {
  229. correct<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
  230. return true;
  231. }, geometry);
  232. }
  233. };
  234. } // namespace resolve_dynamic
  235. /*!
  236. \brief Corrects a geometry
  237. \details Corrects a geometry: all rings which are wrongly oriented with respect
  238. to their expected orientation are reversed. To all rings which do not have a
  239. closing point and are typed as they should have one, the first point is
  240. appended. Also boxes can be corrected.
  241. \ingroup correct
  242. \tparam Geometry \tparam_geometry
  243. \param geometry \param_geometry which will be corrected if necessary
  244. \qbk{[include reference/algorithms/correct.qbk]}
  245. */
  246. template <typename Geometry>
  247. inline void correct(Geometry& geometry)
  248. {
  249. resolve_dynamic::correct<Geometry>::apply(geometry, default_strategy());
  250. }
  251. /*!
  252. \brief Corrects a geometry
  253. \details Corrects a geometry: all rings which are wrongly oriented with respect
  254. to their expected orientation are reversed. To all rings which do not have a
  255. closing point and are typed as they should have one, the first point is
  256. appended. Also boxes can be corrected.
  257. \ingroup correct
  258. \tparam Geometry \tparam_geometry
  259. \tparam Strategy \tparam_strategy{Area}
  260. \param geometry \param_geometry which will be corrected if necessary
  261. \param strategy \param_strategy{area}
  262. \qbk{distinguish,with strategy}
  263. \qbk{[include reference/algorithms/correct.qbk]}
  264. */
  265. template <typename Geometry, typename Strategy>
  266. inline void correct(Geometry& geometry, Strategy const& strategy)
  267. {
  268. resolve_dynamic::correct<Geometry>::apply(geometry, strategy);
  269. }
  270. #if defined(_MSC_VER)
  271. #pragma warning(pop)
  272. #endif
  273. }} // namespace boost::geometry
  274. #endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP