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