]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / overlay / traversal_ring_creator.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
20effc67
TL
5// This file was modified by Oracle on 2017-2020.
6// Modifications copyright (c) 2017-2020, Oracle and/or its affiliates.
b32b8144
FG
7// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8
7c673cae
FG
9// Use, modification and distribution is subject to the Boost Software License,
10// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11// http://www.boost.org/LICENSE_1_0.txt)
12
13#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP
14#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP
15
16#include <cstddef>
17
20effc67 18#include <boost/range/value_type.hpp>
7c673cae 19
92f5a8d4 20#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
7c673cae
FG
21#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
22#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
23#include <boost/geometry/algorithms/detail/overlay/traversal.hpp>
24#include <boost/geometry/algorithms/num_points.hpp>
25#include <boost/geometry/core/access.hpp>
26#include <boost/geometry/core/assert.hpp>
27#include <boost/geometry/core/closure.hpp>
28
29namespace boost { namespace geometry
30{
31
32#ifndef DOXYGEN_NO_DETAIL
33namespace detail { namespace overlay
34{
35
36
37template
38<
39 bool Reverse1,
40 bool Reverse2,
41 overlay_type OverlayType,
42 typename Geometry1,
43 typename Geometry2,
44 typename Turns,
b32b8144 45 typename TurnInfoMap,
7c673cae 46 typename Clusters,
1e59de90 47 typename Strategy,
7c673cae
FG
48 typename RobustPolicy,
49 typename Visitor,
50 typename Backtrack
51>
52struct traversal_ring_creator
53{
b32b8144
FG
54 typedef traversal
55 <
56 Reverse1, Reverse2, OverlayType,
57 Geometry1, Geometry2, Turns, Clusters,
1e59de90
TL
58 RobustPolicy,
59 decltype(std::declval<Strategy>().side()),
b32b8144
FG
60 Visitor
61 > traversal_type;
7c673cae
FG
62
63 typedef typename boost::range_value<Turns>::type turn_type;
64 typedef typename turn_type::turn_operation_type turn_operation_type;
65
66 static const operation_type target_operation
67 = operation_from_overlay<OverlayType>::value;
68
69 inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2,
b32b8144
FG
70 Turns& turns, TurnInfoMap& turn_info_map,
71 Clusters const& clusters,
1e59de90 72 Strategy const& strategy,
7c673cae 73 RobustPolicy const& robust_policy, Visitor& visitor)
b32b8144 74 : m_trav(geometry1, geometry2, turns, clusters,
1e59de90 75 robust_policy, strategy.side(), visitor)
7c673cae
FG
76 , m_geometry1(geometry1)
77 , m_geometry2(geometry2)
78 , m_turns(turns)
b32b8144 79 , m_turn_info_map(turn_info_map)
7c673cae 80 , m_clusters(clusters)
1e59de90 81 , m_strategy(strategy)
7c673cae
FG
82 , m_robust_policy(robust_policy)
83 , m_visitor(visitor)
7c673cae 84 {
7c673cae
FG
85 }
86
87 template <typename Ring>
88 inline traverse_error_type travel_to_next_turn(signed_size_type start_turn_index,
89 int start_op_index,
90 signed_size_type& turn_index,
91 int& op_index,
92 Ring& current_ring,
93 bool is_start)
94 {
95 int const previous_op_index = op_index;
96 signed_size_type const previous_turn_index = turn_index;
97 turn_type& previous_turn = m_turns[turn_index];
98 turn_operation_type& previous_op = previous_turn.operations[op_index];
99 segment_identifier previous_seg_id;
100
101 signed_size_type to_vertex_index = -1;
102 if (! m_trav.select_turn_from_enriched(turn_index, previous_seg_id,
103 to_vertex_index, start_turn_index, start_op_index,
104 previous_turn, previous_op, is_start))
105 {
106 return is_start
107 ? traverse_error_no_next_ip_at_start
108 : traverse_error_no_next_ip;
109 }
110 if (to_vertex_index >= 0)
111 {
112 if (previous_op.seg_id.source_index == 0)
113 {
114 geometry::copy_segments<Reverse1>(m_geometry1,
115 previous_op.seg_id, to_vertex_index,
1e59de90 116 m_strategy, m_robust_policy, current_ring);
7c673cae
FG
117 }
118 else
119 {
120 geometry::copy_segments<Reverse2>(m_geometry2,
121 previous_op.seg_id, to_vertex_index,
1e59de90 122 m_strategy, m_robust_policy, current_ring);
7c673cae
FG
123 }
124 }
125
126 if (m_turns[turn_index].discarded)
127 {
128 return is_start
129 ? traverse_error_dead_end_at_start
130 : traverse_error_dead_end;
131 }
132
133 if (is_start)
134 {
135 // Register the start
136 previous_op.visited.set_started();
137 m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start");
138 }
139
b32b8144
FG
140 if (! m_trav.select_turn(start_turn_index, start_op_index,
141 turn_index, op_index,
7c673cae 142 previous_op_index, previous_turn_index, previous_seg_id,
92f5a8d4 143 is_start, current_ring.size() > 1))
7c673cae
FG
144 {
145 return is_start
146 ? traverse_error_no_next_ip_at_start
147 : traverse_error_no_next_ip;
148 }
149
150 {
151 // Check operation (TODO: this might be redundant or should be catched before)
152 const turn_type& current_turn = m_turns[turn_index];
153 const turn_operation_type& op = current_turn.operations[op_index];
154 if (op.visited.finalized()
155 || m_trav.is_visited(current_turn, op, turn_index, op_index))
156 {
157 return traverse_error_visit_again;
158 }
159 }
160
161 // Update registration and append point
162 turn_type& current_turn = m_turns[turn_index];
163 turn_operation_type& op = current_turn.operations[op_index];
11fdf7f2 164 detail::overlay::append_no_collinear(current_ring, current_turn.point,
1e59de90 165 m_strategy, m_robust_policy);
7c673cae
FG
166
167 // Register the visit
168 m_trav.set_visited(current_turn, op);
169 m_visitor.visit_traverse(m_turns, current_turn, op, "Visit");
170
171 return traverse_error_none;
172 }
173
174 template <typename Ring>
175 inline traverse_error_type traverse(Ring& ring,
176 signed_size_type start_turn_index, int start_op_index)
177 {
178 turn_type const& start_turn = m_turns[start_turn_index];
179 turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
180
11fdf7f2 181 detail::overlay::append_no_collinear(ring, start_turn.point,
1e59de90 182 m_strategy, m_robust_policy);
7c673cae
FG
183
184 signed_size_type current_turn_index = start_turn_index;
185 int current_op_index = start_op_index;
186
187 traverse_error_type error = travel_to_next_turn(start_turn_index,
188 start_op_index,
189 current_turn_index, current_op_index,
190 ring, true);
191
192 if (error != traverse_error_none)
193 {
194 // This is not necessarily a problem, it happens for clustered turns
195 // which are "build in" or otherwise point inwards
196 return error;
197 }
198
199 if (current_turn_index == start_turn_index)
200 {
201 start_op.visited.set_finished();
202 m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish");
203 return traverse_error_none;
204 }
205
b32b8144
FG
206 if (start_turn.is_clustered())
207 {
92f5a8d4
TL
208 turn_type& turn = m_turns[current_turn_index];
209 turn_operation_type& op = turn.operations[current_op_index];
210 if (turn.cluster_id == start_turn.cluster_id
211 && op.enriched.get_next_turn_index() == start_turn_index)
b32b8144 212 {
b32b8144
FG
213 op.visited.set_finished();
214 m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish (cluster)");
215 return traverse_error_none;
216 }
217 }
218
7c673cae
FG
219 std::size_t const max_iterations = 2 + 2 * m_turns.size();
220 for (std::size_t i = 0; i <= max_iterations; i++)
221 {
222 // We assume clockwise polygons only, non self-intersecting, closed.
223 // However, the input might be different, and checking validity
224 // is up to the library user.
225
226 // Therefore we make here some sanity checks. If the input
227 // violates the assumptions, the output polygon will not be correct
228 // but the routine will stop and output the current polygon, and
229 // will continue with the next one.
230
231 // Below three reasons to stop.
232 error = travel_to_next_turn(start_turn_index, start_op_index,
233 current_turn_index, current_op_index,
234 ring, false);
235
236 if (error != traverse_error_none)
237 {
238 return error;
239 }
240
241 if (current_turn_index == start_turn_index
242 && current_op_index == start_op_index)
243 {
244 start_op.visited.set_finished();
245 m_visitor.visit_traverse(m_turns, start_turn, start_op, "Finish");
246 return traverse_error_none;
247 }
248 }
249
250 return traverse_error_endless_loop;
251 }
252
253 template <typename Rings>
254 void traverse_with_operation(turn_type const& start_turn,
255 std::size_t turn_index, int op_index,
256 Rings& rings, std::size_t& finalized_ring_size,
257 typename Backtrack::state_type& state)
258 {
259 typedef typename boost::range_value<Rings>::type ring_type;
260
261 turn_operation_type const& start_op = start_turn.operations[op_index];
262
263 if (! start_op.visited.none()
264 || ! start_op.enriched.startable
265 || start_op.visited.rejected()
266 || ! (start_op.operation == target_operation
267 || start_op.operation == detail::overlay::operation_continue))
268 {
269 return;
270 }
271
272 ring_type ring;
273 traverse_error_type traverse_error = traverse(ring, turn_index, op_index);
274
275 if (traverse_error == traverse_error_none)
276 {
277 std::size_t const min_num_points
278 = core_detail::closure::minimum_ring_size
279 <
280 geometry::closure<ring_type>::value
281 >::value;
282
283 if (geometry::num_points(ring) >= min_num_points)
284 {
1e59de90 285 clean_closing_dups_and_spikes(ring, m_strategy, m_robust_policy);
7c673cae
FG
286 rings.push_back(ring);
287
b32b8144 288 m_trav.finalize_visit_info(m_turn_info_map);
7c673cae
FG
289 finalized_ring_size++;
290 }
291 }
292 else
293 {
1e59de90
TL
294 Backtrack::apply(finalized_ring_size,
295 rings, ring, m_turns, start_turn,
296 m_turns[turn_index].operations[op_index],
297 traverse_error,
298 m_geometry1, m_geometry2,
299 m_strategy, m_robust_policy,
300 state, m_visitor);
7c673cae
FG
301 }
302 }
303
92f5a8d4
TL
304 int get_operation_index(turn_type const& turn) const
305 {
306 // When starting with a continue operation, the one
307 // with the smallest (for intersection) or largest (for union)
308 // remaining distance (#8310b)
309 // Also to avoid skipping a turn in between, which can happen
310 // in rare cases (e.g. #130)
311 static const bool is_union
312 = operation_from_overlay<OverlayType>::value == operation_union;
313
314 turn_operation_type const& op0 = turn.operations[0];
315 turn_operation_type const& op1 = turn.operations[1];
316 return op0.remaining_distance <= op1.remaining_distance
317 ? (is_union ? 1 : 0)
318 : (is_union ? 0 : 1);
319 }
320
7c673cae
FG
321 template <typename Rings>
322 void iterate(Rings& rings, std::size_t& finalized_ring_size,
b32b8144 323 typename Backtrack::state_type& state)
7c673cae 324 {
7c673cae
FG
325 for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
326 {
b32b8144 327 turn_type const& turn = m_turns[turn_index];
7c673cae 328
b32b8144 329 if (turn.discarded || turn.blocked())
7c673cae
FG
330 {
331 // Skip discarded and blocked turns
332 continue;
333 }
7c673cae 334
b32b8144 335 if (turn.both(operation_continue))
7c673cae 336 {
92f5a8d4
TL
337 traverse_with_operation(turn, turn_index,
338 get_operation_index(turn),
7c673cae
FG
339 rings, finalized_ring_size, state);
340 }
b32b8144
FG
341 else
342 {
343 for (int op_index = 0; op_index < 2; op_index++)
344 {
345 traverse_with_operation(turn, turn_index, op_index,
346 rings, finalized_ring_size, state);
347 }
348 }
7c673cae
FG
349 }
350 }
351
11fdf7f2
TL
352 template <typename Rings>
353 void iterate_with_preference(std::size_t phase,
354 Rings& rings, std::size_t& finalized_ring_size,
355 typename Backtrack::state_type& state)
356 {
357 for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
358 {
359 turn_type const& turn = m_turns[turn_index];
360
361 if (turn.discarded || turn.blocked())
362 {
363 // Skip discarded and blocked turns
364 continue;
365 }
366
367 turn_operation_type const& op0 = turn.operations[0];
368 turn_operation_type const& op1 = turn.operations[1];
369
370 if (phase == 0)
371 {
372 if (! op0.enriched.prefer_start && ! op1.enriched.prefer_start)
373 {
374 // Not preferred, take next one
375 continue;
376 }
377 }
378
379 if (turn.both(operation_continue))
380 {
92f5a8d4
TL
381 traverse_with_operation(turn, turn_index,
382 get_operation_index(turn),
11fdf7f2
TL
383 rings, finalized_ring_size, state);
384 }
385 else
386 {
387 bool const forward = op0.enriched.prefer_start;
388
389 int op_index = forward ? 0 : 1;
390 int const increment = forward ? 1 : -1;
391
392 for (int i = 0; i < 2; i++, op_index += increment)
393 {
394 traverse_with_operation(turn, turn_index, op_index,
395 rings, finalized_ring_size, state);
396 }
397 }
398 }
399 }
400
7c673cae
FG
401private:
402 traversal_type m_trav;
403
404 Geometry1 const& m_geometry1;
405 Geometry2 const& m_geometry2;
406 Turns& m_turns;
b32b8144 407 TurnInfoMap& m_turn_info_map; // contains turn-info information per ring
7c673cae 408 Clusters const& m_clusters;
1e59de90 409 Strategy const& m_strategy;
7c673cae
FG
410 RobustPolicy const& m_robust_policy;
411 Visitor& m_visitor;
7c673cae
FG
412};
413
414}} // namespace detail::overlay
415#endif // DOXYGEN_NO_DETAIL
416
417}} // namespace boost::geometry
418
419#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP