]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/algorithms/detail/overlay/overlay.hpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / overlay / overlay.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
11fdf7f2 4// Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland
7c673cae 5
b32b8144
FG
6// This file was modified by Oracle on 2015, 2017.
7// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
7c673cae
FG
8
9// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
b32b8144 10// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7c673cae
FG
11
12// Use, modification and distribution is subject to the Boost Software License,
13// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
14// http://www.boost.org/LICENSE_1_0.txt)
15
16#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
17#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
18
19
20#include <deque>
21#include <map>
22
23#include <boost/range.hpp>
24#include <boost/mpl/assert.hpp>
25
26
27#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
28#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
29#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
30#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
b32b8144
FG
31#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
32#include <boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp>
7c673cae
FG
33#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
34#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
35#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
b32b8144 36#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
7c673cae
FG
37#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
38
39#include <boost/geometry/algorithms/detail/recalculate.hpp>
40
41#include <boost/geometry/algorithms/is_empty.hpp>
42#include <boost/geometry/algorithms/reverse.hpp>
43
44#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
45#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
46#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
47#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
48#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
49
50#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
51
11fdf7f2 52#include <boost/geometry/util/condition.hpp>
7c673cae
FG
53
54#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
55# include <boost/geometry/io/dsv/write.hpp>
56#endif
57
58
59namespace boost { namespace geometry
60{
61
62
63#ifndef DOXYGEN_NO_DETAIL
64namespace detail { namespace overlay
65{
66
67
68//! Default visitor for overlay, doing nothing
69struct overlay_null_visitor
70{
71 void print(char const* ) {}
72
73 template <typename Turns>
74 void print(char const* , Turns const& , int) {}
75
76 template <typename Turns>
77 void print(char const* , Turns const& , int , int ) {}
78
79 template <typename Turns>
80 void visit_turns(int , Turns const& ) {}
81
82 template <typename Clusters, typename Turns>
83 void visit_clusters(Clusters const& , Turns const& ) {}
84
85 template <typename Turns, typename Turn, typename Operation>
86 void visit_traverse(Turns const& , Turn const& , Operation const& , char const*)
87 {}
88
89 template <typename Turns, typename Turn, typename Operation>
90 void visit_traverse_reject(Turns const& , Turn const& , Operation const& , traverse_error_type )
91 {}
11fdf7f2
TL
92
93 template <typename Rings>
94 void visit_generated_rings(Rings const& )
95 {}
7c673cae
FG
96};
97
b32b8144
FG
98template
99<
100 overlay_type OverlayType,
101 typename TurnInfoMap,
102 typename Turns,
103 typename Clusters
104>
105inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters)
7c673cae
FG
106{
107 typedef typename boost::range_value<Turns>::type turn_type;
b32b8144 108 typedef typename turn_type::turn_operation_type turn_operation_type;
7c673cae
FG
109 typedef typename turn_type::container_type container_type;
110
b32b8144
FG
111 static const operation_type target_operation
112 = operation_from_overlay<OverlayType>::value;
113 static const operation_type opposite_operation
114 = target_operation == operation_union
115 ? operation_intersection
116 : operation_union;
117
7c673cae
FG
118 for (typename boost::range_iterator<Turns const>::type
119 it = boost::begin(turns);
120 it != boost::end(turns);
121 ++it)
122 {
b32b8144 123 turn_type const& turn = *it;
7c673cae 124
b32b8144
FG
125 bool cluster_checked = false;
126 bool has_blocked = false;
7c673cae
FG
127
128 for (typename boost::range_iterator<container_type const>::type
b32b8144
FG
129 op_it = boost::begin(turn.operations);
130 op_it != boost::end(turn.operations);
7c673cae
FG
131 ++op_it)
132 {
b32b8144 133 turn_operation_type const& op = *op_it;
7c673cae
FG
134 ring_identifier const ring_id
135 (
b32b8144
FG
136 op.seg_id.source_index,
137 op.seg_id.multi_index,
138 op.seg_id.ring_index
7c673cae 139 );
b32b8144
FG
140
141 if (! is_self_turn<OverlayType>(turn)
142 && (
11fdf7f2 143 (BOOST_GEOMETRY_CONDITION(target_operation == operation_union)
b32b8144 144 && op.enriched.count_left > 0)
11fdf7f2 145 || (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)
b32b8144
FG
146 && op.enriched.count_right <= 2)))
147 {
148 // Avoid including untraversed rings which have polygons on
149 // their left side (union) or not two on their right side (int)
150 // This can only be done for non-self-turns because of count
151 // information
152 turn_info_map[ring_id].has_blocked_turn = true;
153 continue;
154 }
155
156 if (turn.any_blocked())
157 {
158 turn_info_map[ring_id].has_blocked_turn = true;
159 }
160 if (turn_info_map[ring_id].has_traversed_turn
161 || turn_info_map[ring_id].has_blocked_turn)
162 {
163 continue;
164 }
165
166 // Check information in colocated turns
167 if (! cluster_checked && turn.is_clustered())
168 {
169 check_colocation(has_blocked, turn.cluster_id, turns, clusters);
170 cluster_checked = true;
171 }
172
173 // Block rings where any other turn is blocked,
174 // and (with exceptions): i for union and u for intersection
175 // Exceptions: don't block self-uu for intersection
176 // don't block self-ii for union
177 // don't block (for union) i/u if there is an self-ii too
178 if (has_blocked
179 || (op.operation == opposite_operation
180 && ! turn.has_colocated_both
181 && ! (turn.both(opposite_operation)
182 && is_self_turn<OverlayType>(turn))))
183 {
184 turn_info_map[ring_id].has_blocked_turn = true;
185 }
7c673cae
FG
186 }
187 }
188}
189
7c673cae
FG
190template
191<
192 typename GeometryOut, overlay_type OverlayType, bool ReverseOut,
193 typename Geometry1, typename Geometry2,
b32b8144 194 typename OutputIterator, typename Strategy
7c673cae
FG
195>
196inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
197 Geometry2 const& geometry2,
b32b8144 198 OutputIterator out, Strategy const& strategy)
7c673cae
FG
199{
200 typedef std::deque
201 <
202 typename geometry::ring_type<GeometryOut>::type
203 > ring_container_type;
204
b32b8144
FG
205 typedef typename geometry::point_type<Geometry1>::type point_type1;
206
207 typedef ring_properties
208 <
209 point_type1,
210 typename Strategy::template area_strategy
211 <
212 point_type1
11fdf7f2 213 >::type::template result_type<point_type1>::type
b32b8144 214 > properties;
7c673cae
FG
215
216// Silence warning C4127: conditional expression is constant
217#if defined(_MSC_VER)
218#pragma warning(push)
219#pragma warning(disable : 4127)
220#endif
221
222 // Union: return either of them
223 // Intersection: return nothing
224 // Difference: return first of them
225 if (OverlayType == overlay_intersection
226 || (OverlayType == overlay_difference && geometry::is_empty(geometry1)))
227 {
228 return out;
229 }
230
231#if defined(_MSC_VER)
232#pragma warning(pop)
233#endif
234
235
236 std::map<ring_identifier, ring_turn_info> empty;
237 std::map<ring_identifier, properties> all_of_one_of_them;
238
b32b8144 239 select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
7c673cae 240 ring_container_type rings;
11fdf7f2 241 assign_parents<OverlayType>(geometry1, geometry2, rings, all_of_one_of_them, strategy);
b32b8144
FG
242 return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out,
243 strategy.template get_area_strategy<point_type1>());
7c673cae
FG
244}
245
246
247template
248<
249 typename Geometry1, typename Geometry2,
250 bool Reverse1, bool Reverse2, bool ReverseOut,
251 typename GeometryOut,
252 overlay_type OverlayType
253>
254struct overlay
255{
256 template <typename RobustPolicy, typename OutputIterator, typename Strategy, typename Visitor>
257 static inline OutputIterator apply(
258 Geometry1 const& geometry1, Geometry2 const& geometry2,
259 RobustPolicy const& robust_policy,
260 OutputIterator out,
b32b8144 261 Strategy const& strategy,
7c673cae
FG
262 Visitor& visitor)
263 {
264 bool const is_empty1 = geometry::is_empty(geometry1);
265 bool const is_empty2 = geometry::is_empty(geometry2);
266
267 if (is_empty1 && is_empty2)
268 {
269 return out;
270 }
271
272 if (is_empty1 || is_empty2)
273 {
274 return return_if_one_input_is_empty
275 <
276 GeometryOut, OverlayType, ReverseOut
b32b8144 277 >(geometry1, geometry2, out, strategy);
7c673cae
FG
278 }
279
280 typedef typename geometry::point_type<GeometryOut>::type point_type;
281 typedef detail::overlay::traversal_turn_info
282 <
283 point_type,
284 typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
285 > turn_info;
286 typedef std::deque<turn_info> turn_container_type;
287
288 typedef std::deque
289 <
290 typename geometry::ring_type<GeometryOut>::type
291 > ring_container_type;
292
293 // Define the clusters, mapping cluster_id -> turns
294 typedef std::map
295 <
296 signed_size_type,
297 cluster_info
298 > cluster_type;
299
300 turn_container_type turns;
301
302#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
303std::cout << "get turns" << std::endl;
304#endif
305 detail::get_turns::no_interrupt_policy policy;
306 geometry::get_turns
307 <
308 Reverse1, Reverse2,
309 detail::overlay::assign_null_policy
b32b8144 310 >(geometry1, geometry2, strategy, robust_policy, turns, policy);
7c673cae
FG
311
312 visitor.visit_turns(1, turns);
313
11fdf7f2 314#if ! defined(BOOST_GEOMETRY_NO_SELF_TURNS)
b32b8144
FG
315 if (needs_self_turns<Geometry1>::apply(geometry1))
316 {
317 self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
318 strategy, robust_policy, turns, policy, 0);
319 }
320 if (needs_self_turns<Geometry2>::apply(geometry2))
321 {
322 self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
323 strategy, robust_policy, turns, policy, 1);
324 }
325#endif
326
327
7c673cae
FG
328#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
329std::cout << "enrich" << std::endl;
330#endif
b32b8144 331 typename Strategy::side_strategy_type side_strategy = strategy.get_side_strategy();
7c673cae 332 cluster_type clusters;
b32b8144 333 std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
7c673cae
FG
334
335 geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(turns,
336 clusters, geometry1, geometry2,
337 robust_policy,
338 side_strategy);
339
340 visitor.visit_turns(2, turns);
341
342 visitor.visit_clusters(clusters, turns);
343
344#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
345std::cout << "traverse" << std::endl;
346#endif
347 // Traverse through intersection/turn points and create rings of them.
348 // Note that these rings are always in clockwise order, even in CCW polygons,
349 // and are marked as "to be reversed" below
350 ring_container_type rings;
351 traverse<Reverse1, Reverse2, Geometry1, Geometry2, OverlayType>::apply
352 (
353 geometry1, geometry2,
b32b8144 354 strategy,
7c673cae
FG
355 robust_policy,
356 turns, rings,
b32b8144 357 turn_info_per_ring,
7c673cae
FG
358 clusters,
359 visitor
360 );
b32b8144 361 visitor.visit_turns(3, turns);
7c673cae 362
b32b8144
FG
363 get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters);
364
365 typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type;
7c673cae
FG
366
367 typedef ring_properties
b32b8144
FG
368 <
369 point_type,
11fdf7f2 370 typename area_strategy_type::template result_type<point_type>::type
b32b8144 371 > properties;
7c673cae
FG
372
373 // Select all rings which are NOT touched by any intersection point
374 std::map<ring_identifier, properties> selected_ring_properties;
375 select_rings<OverlayType>(geometry1, geometry2, turn_info_per_ring,
b32b8144 376 selected_ring_properties, strategy);
7c673cae
FG
377
378 // Add rings created during traversal
b32b8144 379 area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
7c673cae
FG
380 {
381 ring_identifier id(2, 0, -1);
382 for (typename boost::range_iterator<ring_container_type>::type
383 it = boost::begin(rings);
384 it != boost::end(rings);
385 ++it)
386 {
b32b8144 387 selected_ring_properties[id] = properties(*it, area_strategy);
7c673cae
FG
388 selected_ring_properties[id].reversed = ReverseOut;
389 id.multi_index++;
390 }
391 }
392
11fdf7f2
TL
393 assign_parents<OverlayType>(geometry1, geometry2,
394 rings, selected_ring_properties, strategy);
b32b8144
FG
395
396 // NOTE: There is no need to check result area for union because
397 // as long as the polygons in the input are valid the resulting
398 // polygons should be valid as well.
399 // By default the area is checked (this is old behavior) however this
400 // can be changed with #define. This may be important in non-cartesian CSes.
401 // The result may be too big, so the area is negative. In this case either
402 // it can be returned or an exception can be thrown.
403 return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out,
404 area_strategy,
405 OverlayType == overlay_union ?
406#if defined(BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION)
407 add_rings_throw_if_reversed
408#elif defined(BOOST_GEOMETRY_UNION_RETURN_INVALID)
409 add_rings_add_unordered
410#else
411 add_rings_ignore_unordered
412#endif
413 : add_rings_ignore_unordered);
7c673cae
FG
414 }
415
416 template <typename RobustPolicy, typename OutputIterator, typename Strategy>
417 static inline OutputIterator apply(
418 Geometry1 const& geometry1, Geometry2 const& geometry2,
419 RobustPolicy const& robust_policy,
420 OutputIterator out,
421 Strategy const& strategy)
422 {
423 overlay_null_visitor visitor;
424 return apply(geometry1, geometry2, robust_policy, out, strategy, visitor);
425 }
426};
427
428
429}} // namespace detail::overlay
430#endif // DOXYGEN_NO_DETAIL
431
432
433}} // namespace boost::geometry
434
435
436#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP