correct_closure.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Boost.Geometry
  2. // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2020-2023.
  4. // Modifications copyright (c) 2020-2023 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  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_CORRECT_CLOSURE_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
  12. #include <boost/geometry/algorithms/detail/multi_modify.hpp>
  13. #include <boost/geometry/algorithms/disjoint.hpp>
  14. #include <boost/geometry/core/closure.hpp>
  15. #include <boost/geometry/core/exterior_ring.hpp>
  16. #include <boost/geometry/core/interior_rings.hpp>
  17. #include <boost/geometry/core/tags.hpp>
  18. #include <boost/geometry/geometries/adapted/boost_variant.hpp>
  19. #include <boost/geometry/geometries/concepts/check.hpp>
  20. #include <boost/geometry/util/range.hpp>
  21. #include <boost/range/size.hpp>
  22. namespace boost { namespace geometry
  23. {
  24. // Silence warning C4127: conditional expression is constant
  25. #if defined(_MSC_VER)
  26. #pragma warning(push)
  27. #pragma warning(disable : 4127)
  28. #endif
  29. #ifndef DOXYGEN_NO_DETAIL
  30. namespace detail { namespace correct_closure
  31. {
  32. struct nop
  33. {
  34. template <typename Geometry>
  35. static inline void apply(Geometry& )
  36. {}
  37. };
  38. // Close a ring, if not closed, or open it
  39. struct close_or_open_ring
  40. {
  41. template <typename Ring>
  42. static inline void apply(Ring& r)
  43. {
  44. auto size = boost::size(r);
  45. if (size <= 2)
  46. {
  47. return;
  48. }
  49. // TODO: This requires relate(pt, pt) strategy
  50. bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1));
  51. closure_selector const closure = geometry::closure<Ring>::value;
  52. if (disjoint && closure == closed)
  53. {
  54. // Close it by adding first point
  55. geometry::append(r, *boost::begin(r));
  56. }
  57. else if (! disjoint && closure == open)
  58. {
  59. // Open it by removing last point
  60. range::resize(r, size - 1);
  61. }
  62. }
  63. };
  64. // Close/open exterior ring and all its interior rings
  65. struct close_or_open_polygon
  66. {
  67. template <typename Polygon>
  68. static inline void apply(Polygon& poly)
  69. {
  70. close_or_open_ring::apply(exterior_ring(poly));
  71. auto&& rings = interior_rings(poly);
  72. auto const end = boost::end(rings);
  73. for (auto it = boost::begin(rings); it != end; ++it)
  74. {
  75. close_or_open_ring::apply(*it);
  76. }
  77. }
  78. };
  79. }} // namespace detail::correct_closure
  80. #endif // DOXYGEN_NO_DETAIL
  81. #ifndef DOXYGEN_NO_DISPATCH
  82. namespace dispatch
  83. {
  84. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  85. struct correct_closure: not_implemented<Tag>
  86. {};
  87. template <typename Point>
  88. struct correct_closure<Point, point_tag>
  89. : detail::correct_closure::nop
  90. {};
  91. template <typename LineString>
  92. struct correct_closure<LineString, linestring_tag>
  93. : detail::correct_closure::nop
  94. {};
  95. template <typename Segment>
  96. struct correct_closure<Segment, segment_tag>
  97. : detail::correct_closure::nop
  98. {};
  99. template <typename Box>
  100. struct correct_closure<Box, box_tag>
  101. : detail::correct_closure::nop
  102. {};
  103. template <typename Ring>
  104. struct correct_closure<Ring, ring_tag>
  105. : detail::correct_closure::close_or_open_ring
  106. {};
  107. template <typename Polygon>
  108. struct correct_closure<Polygon, polygon_tag>
  109. : detail::correct_closure::close_or_open_polygon
  110. {};
  111. template <typename MultiPoint>
  112. struct correct_closure<MultiPoint, multi_point_tag>
  113. : detail::correct_closure::nop
  114. {};
  115. template <typename MultiLineString>
  116. struct correct_closure<MultiLineString, multi_linestring_tag>
  117. : detail::correct_closure::nop
  118. {};
  119. template <typename Geometry>
  120. struct correct_closure<Geometry, multi_polygon_tag>
  121. : detail::multi_modify
  122. <
  123. detail::correct_closure::close_or_open_polygon
  124. >
  125. {};
  126. } // namespace dispatch
  127. #endif // DOXYGEN_NO_DISPATCH
  128. namespace resolve_variant
  129. {
  130. template <typename Geometry, typename Tag = typename tag<Geometry>::type>
  131. struct correct_closure
  132. {
  133. static inline void apply(Geometry& geometry)
  134. {
  135. concepts::check<Geometry const>();
  136. dispatch::correct_closure<Geometry>::apply(geometry);
  137. }
  138. };
  139. template <typename Geometry>
  140. struct correct_closure<Geometry, dynamic_geometry_tag>
  141. {
  142. static void apply(Geometry& geometry)
  143. {
  144. traits::visit<Geometry>::apply([](auto & g)
  145. {
  146. correct_closure<util::remove_cref_t<decltype(g)>>::apply(g);
  147. }, geometry);
  148. }
  149. };
  150. template <typename Geometry>
  151. struct correct_closure<Geometry, geometry_collection_tag>
  152. {
  153. static void apply(Geometry& geometry)
  154. {
  155. detail::visit_breadth_first([](auto & g)
  156. {
  157. correct_closure<util::remove_cref_t<decltype(g)>>::apply(g);
  158. return true;
  159. }, geometry);
  160. }
  161. };
  162. } // namespace resolve_variant
  163. // TODO: This algorithm should use relate(pt, pt) strategy
  164. /*!
  165. \brief Closes or opens a geometry, according to its type
  166. \details Corrects a geometry w.r.t. closure points to all rings which do not
  167. have a closing point and are typed as they should have one, the first point
  168. is appended.
  169. \ingroup correct_closure
  170. \tparam Geometry \tparam_geometry
  171. \param geometry \param_geometry which will be corrected if necessary
  172. */
  173. template <typename Geometry>
  174. inline void correct_closure(Geometry& geometry)
  175. {
  176. resolve_variant::correct_closure<Geometry>::apply(geometry);
  177. }
  178. #if defined(_MSC_VER)
  179. #pragma warning(pop)
  180. #endif
  181. }} // namespace boost::geometry
  182. #endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP