1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
6 // This file was modified by Oracle on 2019-2020.
7 // Modifications copyright (c) 2019-2020 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
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)
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
18 #include <boost/range/begin.hpp>
19 #include <boost/range/end.hpp>
20 #include <boost/range/value_type.hpp>
22 #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
23 #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
24 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
25 #include <boost/geometry/algorithms/covered_by.hpp>
26 #include <boost/geometry/algorithms/within.hpp>
28 namespace boost { namespace geometry
31 #ifndef DOXYGEN_NO_DETAIL
32 namespace detail { namespace overlay
38 typename Point, typename Geometry,
39 typename Tag2 = typename geometry::tag<Geometry>::type
41 struct check_within_strategy
43 template <typename Strategy>
44 static inline typename Strategy::template point_in_geometry_strategy<Point, Geometry>::type
45 within(Strategy const& strategy)
47 return strategy.template get_point_in_geometry_strategy<Point, Geometry>();
50 template <typename Strategy>
51 static inline typename Strategy::template point_in_geometry_strategy<Point, Geometry>::type
52 covered_by(Strategy const& strategy)
54 return strategy.template get_point_in_geometry_strategy<Point, Geometry>();
58 template <typename Point, typename Geometry>
59 struct check_within_strategy<Point, Geometry, box_tag>
61 template <typename Strategy>
62 static inline typename Strategy::within_point_box_strategy_type
63 within(Strategy const& )
65 return typename Strategy::within_point_box_strategy_type();
68 template <typename Strategy>
69 static inline typename Strategy::covered_by_point_box_strategy_type
70 covered_by(Strategy const&)
72 return typename Strategy::covered_by_point_box_strategy_type();
77 template <overlay_type OverlayType>
82 typename Turn, typename Geometry0, typename Geometry1,
83 typename UmbrellaStrategy
86 bool apply(Turn const& turn, Geometry0 const& geometry0,
87 Geometry1 const& geometry1, UmbrellaStrategy const& strategy)
89 typedef typename Turn::point_type point_type;
91 // Operations 0 and 1 have the same source index in self-turns
92 return turn.operations[0].seg_id.source_index == 0
93 ? geometry::within(turn.point, geometry1,
94 check_within_strategy<point_type, Geometry1>::within(strategy))
95 : geometry::within(turn.point, geometry0,
96 check_within_strategy<point_type, Geometry0>::within(strategy));
102 struct check_within<overlay_difference>
106 typename Turn, typename Geometry0, typename Geometry1,
107 typename UmbrellaStrategy
110 bool apply(Turn const& turn, Geometry0 const& geometry0,
111 Geometry1 const& geometry1, UmbrellaStrategy const& strategy)
113 typedef typename Turn::point_type point_type;
115 // difference = intersection(a, reverse(b))
116 // therefore we should reverse the meaning of within for geometry1
117 return turn.operations[0].seg_id.source_index == 0
118 ? ! geometry::covered_by(turn.point, geometry1,
119 check_within_strategy<point_type, Geometry1>::covered_by(strategy))
120 : geometry::within(turn.point, geometry0,
121 check_within_strategy<point_type, Geometry0>::within(strategy));
129 typename Turns, typename Clusters,
130 typename Geometry0, typename Geometry1,
134 void apply(Turns& , Clusters const& ,
135 Geometry0 const& , Geometry1 const& ,
140 template <overlay_type OverlayType, operation_type OperationType>
141 struct discard_closed_turns : discard_turns {};
143 // It is only implemented for operation_union, not in buffer
145 struct discard_closed_turns<overlay_union, operation_union>
147 // Point in Geometry Strategy
150 typename Turns, typename Clusters,
151 typename Geometry0, typename Geometry1,
155 void apply(Turns& turns, Clusters const& /*clusters*/,
156 Geometry0 const& geometry0, Geometry1 const& geometry1,
157 Strategy const& strategy)
159 typedef typename boost::range_value<Turns>::type turn_type;
161 for (typename boost::range_iterator<Turns>::type
162 it = boost::begin(turns);
163 it != boost::end(turns);
166 turn_type& turn = *it;
169 && is_self_turn<overlay_union>(turn)
170 && check_within<overlay_union>::apply(turn, geometry0,
171 geometry1, strategy))
173 // Turn is in the interior of other geometry
174 turn.discarded = true;
180 template <overlay_type OverlayType>
181 struct discard_self_intersection_turns
185 template <typename Turns, typename Clusters>
187 bool is_self_cluster(signed_size_type cluster_id,
188 const Turns& turns, Clusters const& clusters)
190 typename Clusters::const_iterator cit = clusters.find(cluster_id);
191 if (cit == clusters.end())
196 cluster_info const& cinfo = cit->second;
197 for (std::set<signed_size_type>::const_iterator it
198 = cinfo.turn_indices.begin();
199 it != cinfo.turn_indices.end(); ++it)
201 if (! is_self_turn<OverlayType>(turns[*it]))
210 template <typename Turns, typename Clusters,
211 typename Geometry0, typename Geometry1, typename Strategy>
213 void discard_clusters(Turns& turns, Clusters const& clusters,
214 Geometry0 const& geometry0, Geometry1 const& geometry1,
215 Strategy const& strategy)
217 for (typename Clusters::const_iterator cit = clusters.begin();
218 cit != clusters.end(); ++cit)
220 signed_size_type const cluster_id = cit->first;
222 // If there are only self-turns in the cluster, the cluster should
223 // be located within the other geometry, for intersection
224 if (! cit->second.turn_indices.empty()
225 && is_self_cluster(cluster_id, turns, clusters))
227 cluster_info const& cinfo = cit->second;
228 signed_size_type const index = *cinfo.turn_indices.begin();
229 if (! check_within<OverlayType>::apply(turns[index],
230 geometry0, geometry1,
233 // Discard all turns in cluster
234 for (std::set<signed_size_type>::const_iterator sit
235 = cinfo.turn_indices.begin();
236 sit != cinfo.turn_indices.end(); ++sit)
238 turns[*sit].discarded = true;
247 template <typename Turns, typename Clusters,
248 typename Geometry0, typename Geometry1, typename Strategy>
250 void apply(Turns& turns, Clusters const& clusters,
251 Geometry0 const& geometry0, Geometry1 const& geometry1,
252 Strategy const& strategy)
254 discard_clusters(turns, clusters, geometry0, geometry1, strategy);
256 typedef typename boost::range_value<Turns>::type turn_type;
258 for (typename boost::range_iterator<Turns>::type
259 it = boost::begin(turns);
260 it != boost::end(turns);
263 turn_type& turn = *it;
265 // It is a ii self-turn
266 // Check if it is within the other geometry
268 && is_self_turn<overlay_intersection>(turn)
269 && ! check_within<OverlayType>::apply(turn, geometry0,
270 geometry1, strategy))
272 // It is not within another geometry, set it as non startable.
273 // It still might be traveled (#case_recursive_boxes_70)
274 turn.operations[0].enriched.startable = false;
275 turn.operations[1].enriched.startable = false;
282 template <overlay_type OverlayType, operation_type OperationType>
283 struct discard_open_turns : discard_turns {};
285 // Handler for intersection
287 struct discard_open_turns<overlay_intersection, operation_intersection>
288 : discard_self_intersection_turns<overlay_intersection> {};
290 // Handler for difference, with different meaning of 'within'
292 struct discard_open_turns<overlay_difference, operation_intersection>
293 : discard_self_intersection_turns<overlay_difference> {};
295 }} // namespace detail::overlay
296 #endif //DOXYGEN_NO_DETAIL
299 }} // namespace boost::geometry
301 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP