1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland
6 // This file was modified by Oracle on 2015, 2017, 2019.
7 // Modifications copyright (c) 2015-2019, Oracle and/or its affiliates.
9 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
10 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
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)
16 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
17 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
23 #include <boost/range.hpp>
24 #include <boost/mpl/assert.hpp>
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>
31 #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
32 #include <boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp>
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>
36 #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
37 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
39 #include <boost/geometry/algorithms/detail/recalculate.hpp>
41 #include <boost/geometry/algorithms/is_empty.hpp>
42 #include <boost/geometry/algorithms/reverse.hpp>
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>
50 #include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
52 #include <boost/geometry/util/condition.hpp>
54 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
55 # include <boost/geometry/io/dsv/write.hpp>
59 namespace boost { namespace geometry
63 #ifndef DOXYGEN_NO_DETAIL
64 namespace detail { namespace overlay
68 //! Default visitor for overlay, doing nothing
69 struct overlay_null_visitor
71 void print(char const* ) {}
73 template <typename Turns>
74 void print(char const* , Turns const& , int) {}
76 template <typename Turns>
77 void print(char const* , Turns const& , int , int ) {}
79 template <typename Turns>
80 void visit_turns(int , Turns const& ) {}
82 template <typename Clusters, typename Turns>
83 void visit_clusters(Clusters const& , Turns const& ) {}
85 template <typename Turns, typename Turn, typename Operation>
86 void visit_traverse(Turns const& , Turn const& , Operation const& , char const*)
89 template <typename Turns, typename Turn, typename Operation>
90 void visit_traverse_reject(Turns const& , Turn const& , Operation const& , traverse_error_type )
93 template <typename Rings>
94 void visit_generated_rings(Rings const& )
100 overlay_type OverlayType,
101 typename TurnInfoMap,
105 inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters)
107 typedef typename boost::range_value<Turns>::type turn_type;
108 typedef typename turn_type::turn_operation_type turn_operation_type;
109 typedef typename turn_type::container_type container_type;
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
118 for (typename boost::range_iterator<Turns const>::type
119 it = boost::begin(turns);
120 it != boost::end(turns);
123 turn_type const& turn = *it;
125 bool cluster_checked = false;
126 bool has_blocked = false;
128 if (is_self_turn<OverlayType>(turn) && turn.discarded)
130 // Discarded self-turns don't count as traversed
134 for (typename boost::range_iterator<container_type const>::type
135 op_it = boost::begin(turn.operations);
136 op_it != boost::end(turn.operations);
139 turn_operation_type const& op = *op_it;
140 ring_identifier const ring_id
142 op.seg_id.source_index,
143 op.seg_id.multi_index,
147 if (! is_self_turn<OverlayType>(turn)
149 (BOOST_GEOMETRY_CONDITION(target_operation == operation_union)
150 && op.enriched.count_left > 0)
151 || (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)
152 && op.enriched.count_right <= 2)))
154 // Avoid including untraversed rings which have polygons on
155 // their left side (union) or not two on their right side (int)
156 // This can only be done for non-self-turns because of count
158 turn_info_map[ring_id].has_blocked_turn = true;
162 if (turn.any_blocked())
164 turn_info_map[ring_id].has_blocked_turn = true;
166 if (turn_info_map[ring_id].has_traversed_turn
167 || turn_info_map[ring_id].has_blocked_turn)
172 // Check information in colocated turns
173 if (! cluster_checked && turn.is_clustered())
175 check_colocation(has_blocked, turn.cluster_id, turns, clusters);
176 cluster_checked = true;
179 // Block rings where any other turn is blocked,
180 // and (with exceptions): i for union and u for intersection
181 // Exceptions: don't block self-uu for intersection
182 // don't block self-ii for union
183 // don't block (for union) i/u if there is an self-ii too
185 || (op.operation == opposite_operation
186 && ! turn.has_colocated_both
187 && ! (turn.both(opposite_operation)
188 && is_self_turn<OverlayType>(turn))))
190 turn_info_map[ring_id].has_blocked_turn = true;
198 typename GeometryOut, overlay_type OverlayType, bool ReverseOut,
199 typename Geometry1, typename Geometry2,
200 typename OutputIterator, typename Strategy
202 inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
203 Geometry2 const& geometry2,
204 OutputIterator out, Strategy const& strategy)
208 typename geometry::ring_type<GeometryOut>::type
209 > ring_container_type;
211 typedef typename geometry::point_type<Geometry1>::type point_type1;
213 typedef ring_properties
216 typename Strategy::template area_strategy
219 >::type::template result_type<point_type1>::type
222 // Silence warning C4127: conditional expression is constant
223 #if defined(_MSC_VER)
224 #pragma warning(push)
225 #pragma warning(disable : 4127)
228 // Union: return either of them
229 // Intersection: return nothing
230 // Difference: return first of them
231 if (OverlayType == overlay_intersection
232 || (OverlayType == overlay_difference && geometry::is_empty(geometry1)))
237 #if defined(_MSC_VER)
242 std::map<ring_identifier, ring_turn_info> empty;
243 std::map<ring_identifier, properties> all_of_one_of_them;
245 select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
246 ring_container_type rings;
247 assign_parents<OverlayType>(geometry1, geometry2, rings, all_of_one_of_them, strategy);
248 return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out,
249 strategy.template get_area_strategy<point_type1>());
255 typename Geometry1, typename Geometry2,
256 bool Reverse1, bool Reverse2, bool ReverseOut,
257 typename GeometryOut,
258 overlay_type OverlayType
262 template <typename RobustPolicy, typename OutputIterator, typename Strategy, typename Visitor>
263 static inline OutputIterator apply(
264 Geometry1 const& geometry1, Geometry2 const& geometry2,
265 RobustPolicy const& robust_policy,
267 Strategy const& strategy,
270 bool const is_empty1 = geometry::is_empty(geometry1);
271 bool const is_empty2 = geometry::is_empty(geometry2);
273 if (is_empty1 && is_empty2)
278 if (is_empty1 || is_empty2)
280 return return_if_one_input_is_empty
282 GeometryOut, OverlayType, ReverseOut
283 >(geometry1, geometry2, out, strategy);
286 typedef typename geometry::point_type<GeometryOut>::type point_type;
287 typedef detail::overlay::traversal_turn_info
290 typename geometry::segment_ratio_type<point_type, RobustPolicy>::type
292 typedef std::deque<turn_info> turn_container_type;
296 typename geometry::ring_type<GeometryOut>::type
297 > ring_container_type;
299 // Define the clusters, mapping cluster_id -> turns
306 turn_container_type turns;
308 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
309 std::cout << "get turns" << std::endl;
311 detail::get_turns::no_interrupt_policy policy;
315 detail::overlay::assign_null_policy
316 >(geometry1, geometry2, strategy, robust_policy, turns, policy);
318 visitor.visit_turns(1, turns);
320 #if ! defined(BOOST_GEOMETRY_NO_SELF_TURNS)
321 if (needs_self_turns<Geometry1>::apply(geometry1))
323 self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
324 strategy, robust_policy, turns, policy, 0);
326 if (needs_self_turns<Geometry2>::apply(geometry2))
328 self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
329 strategy, robust_policy, turns, policy, 1);
334 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
335 std::cout << "enrich" << std::endl;
338 cluster_type clusters;
339 std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
341 geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(
342 turns, clusters, geometry1, geometry2, robust_policy, strategy);
344 visitor.visit_turns(2, turns);
346 visitor.visit_clusters(clusters, turns);
348 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
349 std::cout << "traverse" << std::endl;
351 // Traverse through intersection/turn points and create rings of them.
352 // Note that these rings are always in clockwise order, even in CCW polygons,
353 // and are marked as "to be reversed" below
354 ring_container_type rings;
355 traverse<Reverse1, Reverse2, Geometry1, Geometry2, OverlayType>::apply
357 geometry1, geometry2,
365 visitor.visit_turns(3, turns);
367 get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters);
369 typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type;
371 typedef ring_properties
374 typename area_strategy_type::template result_type<point_type>::type
377 // Select all rings which are NOT touched by any intersection point
378 std::map<ring_identifier, properties> selected_ring_properties;
379 select_rings<OverlayType>(geometry1, geometry2, turn_info_per_ring,
380 selected_ring_properties, strategy);
382 // Add rings created during traversal
383 area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
385 ring_identifier id(2, 0, -1);
386 for (typename boost::range_iterator<ring_container_type>::type
387 it = boost::begin(rings);
388 it != boost::end(rings);
391 selected_ring_properties[id] = properties(*it, area_strategy);
392 selected_ring_properties[id].reversed = ReverseOut;
397 assign_parents<OverlayType>(geometry1, geometry2,
398 rings, selected_ring_properties, strategy);
400 // NOTE: There is no need to check result area for union because
401 // as long as the polygons in the input are valid the resulting
402 // polygons should be valid as well.
403 // By default the area is checked (this is old behavior) however this
404 // can be changed with #define. This may be important in non-cartesian CSes.
405 // The result may be too big, so the area is negative. In this case either
406 // it can be returned or an exception can be thrown.
407 return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out,
409 OverlayType == overlay_union ?
410 #if defined(BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION)
411 add_rings_throw_if_reversed
412 #elif defined(BOOST_GEOMETRY_UNION_RETURN_INVALID)
413 add_rings_add_unordered
415 add_rings_ignore_unordered
417 : add_rings_ignore_unordered);
420 template <typename RobustPolicy, typename OutputIterator, typename Strategy>
421 static inline OutputIterator apply(
422 Geometry1 const& geometry1, Geometry2 const& geometry2,
423 RobustPolicy const& robust_policy,
425 Strategy const& strategy)
427 overlay_null_visitor visitor;
428 return apply(geometry1, geometry2, robust_policy, out, strategy, visitor);
433 }} // namespace detail::overlay
434 #endif // DOXYGEN_NO_DETAIL
437 }} // namespace boost::geometry
440 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP