copy_segments.hpp 11 KB

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