]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/algorithms/detail/overlay/follow.hpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / overlay / follow.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
5
6 // This file was modified by Oracle on 2014, 2017.
7 // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
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_FOLLOW_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
17
18 #include <cstddef>
19
20 #include <boost/range.hpp>
21 #include <boost/mpl/assert.hpp>
22
23 #include <boost/geometry/algorithms/detail/point_on_border.hpp>
24 #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
25 #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
26 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
27
28 #include <boost/geometry/algorithms/covered_by.hpp>
29 #include <boost/geometry/algorithms/clear.hpp>
30 #include <boost/geometry/algorithms/detail/relate/turns.hpp>
31
32
33 namespace boost { namespace geometry
34 {
35
36
37 #ifndef DOXYGEN_NO_DETAIL
38 namespace detail { namespace overlay
39 {
40
41 namespace following
42 {
43
44 template <typename Turn, typename Operation>
45 static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
46 {
47 // (Blocked means: blocked for polygon/polygon intersection, because
48 // they are reversed. But for polygon/line it is similar to continue)
49 return op.operation == operation_intersection
50 || op.operation == operation_continue
51 || op.operation == operation_blocked
52 ;
53 }
54
55 template
56 <
57 typename Turn,
58 typename Operation,
59 typename LineString,
60 typename Polygon,
61 typename PtInPolyStrategy
62 >
63 static inline bool last_covered_by(Turn const& /*turn*/, Operation const& op,
64 LineString const& linestring, Polygon const& polygon,
65 PtInPolyStrategy const& strategy)
66 {
67 return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
68 }
69
70
71 template
72 <
73 typename Turn,
74 typename Operation,
75 typename LineString,
76 typename Polygon,
77 typename PtInPolyStrategy
78 >
79 static inline bool is_leaving(Turn const& turn, Operation const& op,
80 bool entered, bool first,
81 LineString const& linestring, Polygon const& polygon,
82 PtInPolyStrategy const& strategy)
83 {
84 if (op.operation == operation_union)
85 {
86 return entered
87 || turn.method == method_crosses
88 || (first && last_covered_by(turn, op, linestring, polygon, strategy))
89 ;
90 }
91 return false;
92 }
93
94
95 template
96 <
97 typename Turn,
98 typename Operation,
99 typename LineString,
100 typename Polygon,
101 typename PtInPolyStrategy
102 >
103 static inline bool is_staying_inside(Turn const& turn, Operation const& op,
104 bool entered, bool first,
105 LineString const& linestring, Polygon const& polygon,
106 PtInPolyStrategy const& strategy)
107 {
108 if (turn.method == method_crosses)
109 {
110 // The normal case, this is completely covered with entering/leaving
111 // so stay out of this time consuming "covered_by"
112 return false;
113 }
114
115 if (is_entering(turn, op))
116 {
117 return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy));
118 }
119
120 return false;
121 }
122
123 template
124 <
125 typename Turn,
126 typename Operation,
127 typename Linestring,
128 typename Polygon,
129 typename PtInPolyStrategy
130 >
131 static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
132 Linestring const& linestring, Polygon const& polygon,
133 PtInPolyStrategy const& strategy)
134 {
135 if (first && (turn.method == method_collinear || turn.method == method_equal))
136 {
137 return last_covered_by(turn, op, linestring, polygon, strategy);
138 }
139 return false;
140 }
141
142
143 // Template specialization structure to call the right actions for the right type
144 template <overlay_type OverlayType, bool RemoveSpikes = true>
145 struct action_selector
146 {
147 // If you get here the overlay type is not intersection or difference
148 // BOOST_MPL_ASSERT(false);
149 };
150
151 // Specialization for intersection, containing the implementation
152 template <bool RemoveSpikes>
153 struct action_selector<overlay_intersection, RemoveSpikes>
154 {
155 template
156 <
157 typename OutputIterator,
158 typename LineStringOut,
159 typename LineString,
160 typename Point,
161 typename Operation,
162 typename SideStrategy,
163 typename RobustPolicy
164 >
165 static inline void enter(LineStringOut& current_piece,
166 LineString const& ,
167 segment_identifier& segment_id,
168 signed_size_type , Point const& point,
169 Operation const& operation,
170 SideStrategy const& ,
171 RobustPolicy const& ,
172 OutputIterator& )
173 {
174 // On enter, append the intersection point and remember starting point
175 // TODO: we don't check on spikes for linestrings (?). Consider this.
176 detail::overlay::append_no_duplicates(current_piece, point);
177 segment_id = operation.seg_id;
178 }
179
180 template
181 <
182 typename OutputIterator,
183 typename LineStringOut,
184 typename LineString,
185 typename Point,
186 typename Operation,
187 typename SideStrategy,
188 typename RobustPolicy
189 >
190 static inline void leave(LineStringOut& current_piece,
191 LineString const& linestring,
192 segment_identifier& segment_id,
193 signed_size_type index, Point const& point,
194 Operation const& ,
195 SideStrategy const& strategy,
196 RobustPolicy const& robust_policy,
197 OutputIterator& out)
198 {
199 // On leave, copy all segments from starting point, append the intersection point
200 // and add the output piece
201 detail::copy_segments::copy_segments_linestring
202 <
203 false, RemoveSpikes
204 >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
205 detail::overlay::append_no_duplicates(current_piece, point);
206 if (::boost::size(current_piece) > 1)
207 {
208 *out++ = current_piece;
209 }
210
211 geometry::clear(current_piece);
212 }
213
214 template
215 <
216 typename OutputIterator,
217 typename LineStringOut,
218 typename LineString,
219 typename Point,
220 typename Operation
221 >
222 static inline void isolated_point(LineStringOut&,
223 LineString const&,
224 segment_identifier&,
225 signed_size_type, Point const& point,
226 Operation const& , OutputIterator& out)
227 {
228 LineStringOut isolated_point_ls;
229 geometry::append(isolated_point_ls, point);
230
231 #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
232 geometry::append(isolated_point_ls, point);
233 #endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS
234
235 *out++ = isolated_point_ls;
236 }
237
238 static inline bool is_entered(bool entered)
239 {
240 return entered;
241 }
242
243 static inline bool included(int inside_value)
244 {
245 return inside_value >= 0; // covered_by
246 }
247
248 };
249
250 // Specialization for difference, which reverses these actions
251 template <bool RemoveSpikes>
252 struct action_selector<overlay_difference, RemoveSpikes>
253 {
254 typedef action_selector<overlay_intersection, RemoveSpikes> normal_action;
255
256 template
257 <
258 typename OutputIterator,
259 typename LineStringOut,
260 typename LineString,
261 typename Point,
262 typename Operation,
263 typename SideStrategy,
264 typename RobustPolicy
265 >
266 static inline void enter(LineStringOut& current_piece,
267 LineString const& linestring,
268 segment_identifier& segment_id,
269 signed_size_type index, Point const& point,
270 Operation const& operation,
271 SideStrategy const& strategy,
272 RobustPolicy const& robust_policy,
273 OutputIterator& out)
274 {
275 normal_action::leave(current_piece, linestring, segment_id, index,
276 point, operation, strategy, robust_policy, out);
277 }
278
279 template
280 <
281 typename OutputIterator,
282 typename LineStringOut,
283 typename LineString,
284 typename Point,
285 typename Operation,
286 typename SideStrategy,
287 typename RobustPolicy
288 >
289 static inline void leave(LineStringOut& current_piece,
290 LineString const& linestring,
291 segment_identifier& segment_id,
292 signed_size_type index, Point const& point,
293 Operation const& operation,
294 SideStrategy const& strategy,
295 RobustPolicy const& robust_policy,
296 OutputIterator& out)
297 {
298 normal_action::enter(current_piece, linestring, segment_id, index,
299 point, operation, strategy, robust_policy, out);
300 }
301
302 template
303 <
304 typename OutputIterator,
305 typename LineStringOut,
306 typename LineString,
307 typename Point,
308 typename Operation
309 >
310 static inline void isolated_point(LineStringOut&,
311 LineString const&,
312 segment_identifier&,
313 signed_size_type, Point const&,
314 Operation const&, OutputIterator&)
315 {
316 }
317
318 static inline bool is_entered(bool entered)
319 {
320 return ! normal_action::is_entered(entered);
321 }
322
323 static inline bool included(int inside_value)
324 {
325 return ! normal_action::included(inside_value);
326 }
327
328 };
329
330 }
331
332 /*!
333 \brief Follows a linestring from intersection point to intersection point, outputting which
334 is inside, or outside, a ring or polygon
335 \ingroup overlay
336 */
337 template
338 <
339 typename LineStringOut,
340 typename LineString,
341 typename Polygon,
342 overlay_type OverlayType,
343 bool RemoveSpikes = true
344 >
345 class follow
346 {
347
348 #ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
349 template <typename Turn>
350 struct sort_on_segment
351 {
352 // In case of turn point at the same location, we want to have continue/blocked LAST
353 // because that should be followed (intersection) or skipped (difference).
354 inline int operation_order(Turn const& turn) const
355 {
356 operation_type const& operation = turn.operations[0].operation;
357 switch(operation)
358 {
359 case operation_opposite : return 0;
360 case operation_none : return 0;
361 case operation_union : return 1;
362 case operation_intersection : return 2;
363 case operation_blocked : return 3;
364 case operation_continue : return 4;
365 }
366 return -1;
367 };
368
369 inline bool use_operation(Turn const& left, Turn const& right) const
370 {
371 // If they are the same, OK.
372 return operation_order(left) < operation_order(right);
373 }
374
375 inline bool use_distance(Turn const& left, Turn const& right) const
376 {
377 return left.operations[0].fraction == right.operations[0].fraction
378 ? use_operation(left, right)
379 : left.operations[0].fraction < right.operations[0].fraction
380 ;
381 }
382
383 inline bool operator()(Turn const& left, Turn const& right) const
384 {
385 segment_identifier const& sl = left.operations[0].seg_id;
386 segment_identifier const& sr = right.operations[0].seg_id;
387
388 return sl == sr
389 ? use_distance(left, right)
390 : sl < sr
391 ;
392
393 }
394 };
395 #endif // BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
396
397
398 public :
399
400 static inline bool included(int inside_value)
401 {
402 return following::action_selector
403 <
404 OverlayType, RemoveSpikes
405 >::included(inside_value);
406 }
407
408 template
409 <
410 typename Turns,
411 typename OutputIterator,
412 typename RobustPolicy,
413 typename Strategy
414 >
415 static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
416 detail::overlay::operation_type , // TODO: this parameter might be redundant
417 Turns& turns,
418 RobustPolicy const& robust_policy,
419 OutputIterator out,
420 Strategy const& strategy)
421 {
422 typedef typename boost::range_iterator<Turns>::type turn_iterator;
423 typedef typename boost::range_value<Turns>::type turn_type;
424 typedef typename boost::range_iterator
425 <
426 typename turn_type::container_type
427 >::type turn_operation_iterator_type;
428
429 typedef following::action_selector<OverlayType, RemoveSpikes> action;
430
431 typename Strategy::template point_in_geometry_strategy
432 <
433 LineString, Polygon
434 >::type const pt_in_poly_strategy
435 = strategy.template get_point_in_geometry_strategy<LineString, Polygon>();
436
437 // Sort intersection points on segments-along-linestring, and distance
438 // (like in enrich is done for poly/poly)
439 // sort turns by Linear seg_id, then by fraction, then
440 // for same ring id: x, u, i, c
441 // for different ring id: c, i, u, x
442 #ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR
443 std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
444 #else
445 typedef relate::turns::less<0, relate::turns::less_op_linear_areal_single<0> > turn_less;
446 std::sort(boost::begin(turns), boost::end(turns), turn_less());
447 #endif
448
449 LineStringOut current_piece;
450 geometry::segment_identifier current_segment_id(0, -1, -1, -1);
451
452 // Iterate through all intersection points (they are ordered along the line)
453 bool entered = false;
454 bool first = true;
455 for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
456 {
457 turn_operation_iterator_type iit = boost::begin(it->operations);
458
459 if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
460 {
461 debug_traverse(*it, *iit, "-> Was entered");
462 entered = true;
463 }
464
465 if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
466 {
467 debug_traverse(*it, *iit, "-> Staying inside");
468
469 entered = true;
470 }
471 else if (following::is_entering(*it, *iit))
472 {
473 debug_traverse(*it, *iit, "-> Entering");
474
475 entered = true;
476 action::enter(current_piece, linestring, current_segment_id,
477 iit->seg_id.segment_index, it->point, *iit,
478 strategy, robust_policy,
479 out);
480 }
481 else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
482 {
483 debug_traverse(*it, *iit, "-> Leaving");
484
485 entered = false;
486 action::leave(current_piece, linestring, current_segment_id,
487 iit->seg_id.segment_index, it->point, *iit,
488 strategy, robust_policy,
489 out);
490 }
491 first = false;
492 }
493
494 if (action::is_entered(entered))
495 {
496 detail::copy_segments::copy_segments_linestring
497 <
498 false, RemoveSpikes
499 >::apply(linestring,
500 current_segment_id,
501 static_cast<signed_size_type>(boost::size(linestring) - 1),
502 strategy, robust_policy,
503 current_piece);
504 }
505
506 // Output the last one, if applicable
507 if (::boost::size(current_piece) > 1)
508 {
509 *out++ = current_piece;
510 }
511 return out;
512 }
513
514 };
515
516
517 }} // namespace detail::overlay
518 #endif // DOXYGEN_NO_DETAIL
519
520
521 }} // namespace boost::geometry
522
523
524 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP