copy_segments.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
  4. // This file was modified by Oracle on 2014-2021.
  5. // Modifications copyright (c) 2014-2021 Oracle and/or its affiliates.
  6. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  7. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  8. // Use, modification and distribution is subject to the Boost Software License,
  9. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
  12. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
  13. #include <array>
  14. #include <type_traits>
  15. #include <vector>
  16. #include <boost/range/begin.hpp>
  17. #include <boost/range/end.hpp>
  18. #include <boost/range/size.hpp>
  19. #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
  20. #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
  21. #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
  22. #include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
  23. #include <boost/geometry/algorithms/not_implemented.hpp>
  24. #include <boost/geometry/core/assert.hpp>
  25. #include <boost/geometry/core/exterior_ring.hpp>
  26. #include <boost/geometry/core/interior_rings.hpp>
  27. #include <boost/geometry/core/ring_type.hpp>
  28. #include <boost/geometry/core/tags.hpp>
  29. #include <boost/geometry/geometries/concepts/check.hpp>
  30. #include <boost/geometry/iterators/ever_circling_iterator.hpp>
  31. #include <boost/geometry/util/range.hpp>
  32. #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
  33. namespace boost { namespace geometry
  34. {
  35. #ifndef DOXYGEN_NO_DETAIL
  36. namespace detail { namespace copy_segments
  37. {
  38. template <bool Reverse>
  39. struct copy_segments_ring
  40. {
  41. template
  42. <
  43. typename Ring,
  44. typename SegmentIdentifier,
  45. typename Strategy,
  46. typename RobustPolicy,
  47. typename RangeOut
  48. >
  49. static inline void apply(Ring const& ring,
  50. SegmentIdentifier const& seg_id,
  51. signed_size_type to_index,
  52. Strategy const& strategy,
  53. RobustPolicy const& robust_policy,
  54. RangeOut& current_output)
  55. {
  56. using view_type = detail::closed_clockwise_view
  57. <
  58. Ring const,
  59. closure<Ring>::value,
  60. Reverse ? counterclockwise : clockwise
  61. >;
  62. using iterator = typename boost::range_iterator<view_type const>::type;
  63. using ec_iterator = geometry::ever_circling_iterator<iterator>;
  64. view_type view(ring);
  65. // The problem: sometimes we want to from "3" to "2"
  66. // -> end = "3" -> end == begin
  67. // This is not convenient with iterators.
  68. // So we use the ever-circling iterator and determine when to step out
  69. signed_size_type const from_index = seg_id.segment_index + 1;
  70. // Sanity check
  71. BOOST_GEOMETRY_ASSERT(from_index < static_cast<signed_size_type>(boost::size(view)));
  72. ec_iterator it(boost::begin(view), boost::end(view),
  73. boost::begin(view) + from_index);
  74. // [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK
  75. // [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK
  76. // [1..1], travel the whole ring round
  77. signed_size_type const count = from_index <= to_index
  78. ? to_index - from_index + 1
  79. : static_cast<signed_size_type>(boost::size(view))
  80. - from_index + to_index + 1;
  81. for (signed_size_type i = 0; i < count; ++i, ++it)
  82. {
  83. detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy);
  84. }
  85. }
  86. };
  87. template <bool Reverse, bool RemoveSpikes = true>
  88. class copy_segments_linestring
  89. {
  90. private:
  91. // remove spikes
  92. template <typename RangeOut, typename Point, typename Strategy, typename RobustPolicy>
  93. static inline void append_to_output(RangeOut& current_output,
  94. Point const& point,
  95. Strategy const& strategy,
  96. RobustPolicy const& robust_policy,
  97. std::true_type const&)
  98. {
  99. detail::overlay::append_no_dups_or_spikes(current_output, point,
  100. strategy,
  101. robust_policy);
  102. }
  103. // keep spikes
  104. template <typename RangeOut, typename Point, typename Strategy, typename RobustPolicy>
  105. static inline void append_to_output(RangeOut& current_output,
  106. Point const& point,
  107. Strategy const& strategy,
  108. RobustPolicy const&,
  109. std::false_type const&)
  110. {
  111. detail::overlay::append_no_duplicates(current_output, point, strategy);
  112. }
  113. public:
  114. template
  115. <
  116. typename LineString,
  117. typename SegmentIdentifier,
  118. typename SideStrategy,
  119. typename RobustPolicy,
  120. typename RangeOut
  121. >
  122. static inline void apply(LineString const& ls,
  123. SegmentIdentifier const& seg_id,
  124. signed_size_type to_index,
  125. SideStrategy const& strategy,
  126. RobustPolicy const& robust_policy,
  127. RangeOut& current_output)
  128. {
  129. signed_size_type const from_index = seg_id.segment_index + 1;
  130. // Sanity check
  131. if ( from_index > to_index
  132. || from_index < 0
  133. || to_index >= static_cast<signed_size_type>(boost::size(ls)) )
  134. {
  135. return;
  136. }
  137. signed_size_type const count = to_index - from_index + 1;
  138. auto it = boost::begin(ls) + from_index;
  139. for (signed_size_type i = 0; i < count; ++i, ++it)
  140. {
  141. append_to_output(current_output, *it, strategy, robust_policy,
  142. std::integral_constant<bool, RemoveSpikes>());
  143. }
  144. }
  145. };
  146. template <bool Reverse>
  147. struct copy_segments_polygon
  148. {
  149. template
  150. <
  151. typename Polygon,
  152. typename SegmentIdentifier,
  153. typename SideStrategy,
  154. typename RobustPolicy,
  155. typename RangeOut
  156. >
  157. static inline void apply(Polygon const& polygon,
  158. SegmentIdentifier const& seg_id,
  159. signed_size_type to_index,
  160. SideStrategy const& strategy,
  161. RobustPolicy const& robust_policy,
  162. RangeOut& current_output)
  163. {
  164. // Call ring-version with the right ring
  165. copy_segments_ring<Reverse>::apply
  166. (
  167. seg_id.ring_index < 0
  168. ? geometry::exterior_ring(polygon)
  169. : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
  170. seg_id, to_index,
  171. strategy,
  172. robust_policy,
  173. current_output
  174. );
  175. }
  176. };
  177. template <bool Reverse>
  178. struct copy_segments_box
  179. {
  180. template
  181. <
  182. typename Box,
  183. typename SegmentIdentifier,
  184. typename SideStrategy,
  185. typename RobustPolicy,
  186. typename RangeOut
  187. >
  188. static inline void apply(Box const& box,
  189. SegmentIdentifier const& seg_id,
  190. signed_size_type to_index,
  191. SideStrategy const& strategy,
  192. RobustPolicy const& robust_policy,
  193. RangeOut& current_output)
  194. {
  195. signed_size_type index = seg_id.segment_index + 1;
  196. BOOST_GEOMETRY_ASSERT(index < 5);
  197. signed_size_type const count = index <= to_index
  198. ? to_index - index + 1
  199. : 5 - index + to_index + 1;
  200. // Create array of points, the fifth one closes it
  201. std::array<typename point_type<Box>::type, 5> bp;
  202. assign_box_corners_oriented<Reverse>(box, bp);
  203. bp[4] = bp[0];
  204. // (possibly cyclic) copy to output
  205. // (see comments in ring-version)
  206. for (signed_size_type i = 0; i < count; i++, index++)
  207. {
  208. detail::overlay::append_no_dups_or_spikes(current_output,
  209. bp[index % 5], strategy, robust_policy);
  210. }
  211. }
  212. };
  213. template<typename Policy>
  214. struct copy_segments_multi
  215. {
  216. template
  217. <
  218. typename MultiGeometry,
  219. typename SegmentIdentifier,
  220. typename SideStrategy,
  221. typename RobustPolicy,
  222. typename RangeOut
  223. >
  224. static inline void apply(MultiGeometry const& multi_geometry,
  225. SegmentIdentifier const& seg_id,
  226. signed_size_type to_index,
  227. SideStrategy const& strategy,
  228. RobustPolicy const& robust_policy,
  229. RangeOut& current_output)
  230. {
  231. BOOST_GEOMETRY_ASSERT
  232. (
  233. seg_id.multi_index >= 0
  234. && static_cast<std::size_t>(seg_id.multi_index) < boost::size(multi_geometry)
  235. );
  236. // Call the single-version
  237. Policy::apply(range::at(multi_geometry, seg_id.multi_index),
  238. seg_id, to_index,
  239. strategy,
  240. robust_policy,
  241. current_output);
  242. }
  243. };
  244. }} // namespace detail::copy_segments
  245. #endif // DOXYGEN_NO_DETAIL
  246. #ifndef DOXYGEN_NO_DISPATCH
  247. namespace dispatch
  248. {
  249. template
  250. <
  251. typename Tag,
  252. bool Reverse
  253. >
  254. struct copy_segments : not_implemented<Tag>
  255. {};
  256. template <bool Reverse>
  257. struct copy_segments<ring_tag, Reverse>
  258. : detail::copy_segments::copy_segments_ring<Reverse>
  259. {};
  260. template <bool Reverse>
  261. struct copy_segments<linestring_tag, Reverse>
  262. : detail::copy_segments::copy_segments_linestring<Reverse>
  263. {};
  264. template <bool Reverse>
  265. struct copy_segments<polygon_tag, Reverse>
  266. : detail::copy_segments::copy_segments_polygon<Reverse>
  267. {};
  268. template <bool Reverse>
  269. struct copy_segments<box_tag, Reverse>
  270. : detail::copy_segments::copy_segments_box<Reverse>
  271. {};
  272. template<bool Reverse>
  273. struct copy_segments<multi_polygon_tag, Reverse>
  274. : detail::copy_segments::copy_segments_multi
  275. <
  276. detail::copy_segments::copy_segments_polygon<Reverse>
  277. >
  278. {};
  279. } // namespace dispatch
  280. #endif // DOXYGEN_NO_DISPATCH
  281. /*!
  282. \brief Copy segments from a geometry, starting with the specified segment (seg_id)
  283. until the specified index (to_index)
  284. \ingroup overlay
  285. */
  286. template
  287. <
  288. bool Reverse,
  289. typename Geometry,
  290. typename SegmentIdentifier,
  291. typename SideStrategy,
  292. typename RobustPolicy,
  293. typename RangeOut
  294. >
  295. inline void copy_segments(Geometry const& geometry,
  296. SegmentIdentifier const& seg_id,
  297. signed_size_type to_index,
  298. SideStrategy const& strategy,
  299. RobustPolicy const& robust_policy,
  300. RangeOut& range_out)
  301. {
  302. concepts::check<Geometry const>();
  303. dispatch::copy_segments
  304. <
  305. typename tag<Geometry>::type,
  306. Reverse
  307. >::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out);
  308. }
  309. }} // namespace boost::geometry
  310. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP