Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4
|
Chris@16
|
5 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
|
Chris@16
|
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
|
Chris@16
|
11
|
Chris@16
|
12
|
Chris@16
|
13 #include <deque>
|
Chris@16
|
14 #include <map>
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/range.hpp>
|
Chris@16
|
17 #include <boost/mpl/assert.hpp>
|
Chris@16
|
18
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
|
Chris@16
|
21 #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
|
Chris@16
|
22 #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
|
Chris@16
|
23 #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
|
Chris@16
|
24 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
|
Chris@16
|
25 #include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
|
Chris@16
|
26 #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
|
Chris@16
|
27 #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
Chris@16
|
28
|
Chris@16
|
29
|
Chris@16
|
30 #include <boost/geometry/algorithms/num_points.hpp>
|
Chris@16
|
31 #include <boost/geometry/algorithms/reverse.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
|
Chris@16
|
34 #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
|
Chris@16
|
35 #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
|
Chris@16
|
36 #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
|
Chris@16
|
37
|
Chris@16
|
38
|
Chris@16
|
39 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
|
Chris@16
|
40 # include <boost/geometry/io/dsv/write.hpp>
|
Chris@16
|
41 #endif
|
Chris@16
|
42
|
Chris@16
|
43 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
44 # include <boost/timer.hpp>
|
Chris@16
|
45 #endif
|
Chris@16
|
46
|
Chris@16
|
47
|
Chris@16
|
48 namespace boost { namespace geometry
|
Chris@16
|
49 {
|
Chris@16
|
50
|
Chris@16
|
51
|
Chris@16
|
52 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
53 namespace detail { namespace overlay
|
Chris@16
|
54 {
|
Chris@16
|
55
|
Chris@16
|
56 // Skip for assemble process
|
Chris@16
|
57 template <typename TurnInfo>
|
Chris@16
|
58 inline bool skip(TurnInfo const& turn_info)
|
Chris@16
|
59 {
|
Chris@16
|
60 return (turn_info.discarded || turn_info.both(operation_union))
|
Chris@16
|
61 && ! turn_info.any_blocked()
|
Chris@16
|
62 && ! turn_info.both(operation_intersection)
|
Chris@16
|
63 ;
|
Chris@16
|
64 }
|
Chris@16
|
65
|
Chris@16
|
66
|
Chris@16
|
67 template <typename TurnPoints, typename Map>
|
Chris@16
|
68 inline void map_turns(Map& map, TurnPoints const& turn_points)
|
Chris@16
|
69 {
|
Chris@16
|
70 typedef typename boost::range_value<TurnPoints>::type turn_point_type;
|
Chris@16
|
71 typedef typename turn_point_type::container_type container_type;
|
Chris@16
|
72
|
Chris@16
|
73 int index = 0;
|
Chris@16
|
74 for (typename boost::range_iterator<TurnPoints const>::type
|
Chris@16
|
75 it = boost::begin(turn_points);
|
Chris@16
|
76 it != boost::end(turn_points);
|
Chris@16
|
77 ++it, ++index)
|
Chris@16
|
78 {
|
Chris@16
|
79 if (! skip(*it))
|
Chris@16
|
80 {
|
Chris@16
|
81 int op_index = 0;
|
Chris@16
|
82 for (typename boost::range_iterator<container_type const>::type
|
Chris@16
|
83 op_it = boost::begin(it->operations);
|
Chris@16
|
84 op_it != boost::end(it->operations);
|
Chris@16
|
85 ++op_it, ++op_index)
|
Chris@16
|
86 {
|
Chris@16
|
87 ring_identifier ring_id
|
Chris@16
|
88 (
|
Chris@16
|
89 op_it->seg_id.source_index,
|
Chris@16
|
90 op_it->seg_id.multi_index,
|
Chris@16
|
91 op_it->seg_id.ring_index
|
Chris@16
|
92 );
|
Chris@16
|
93 map[ring_id]++;
|
Chris@16
|
94 }
|
Chris@16
|
95 }
|
Chris@16
|
96 }
|
Chris@16
|
97 }
|
Chris@16
|
98
|
Chris@16
|
99
|
Chris@16
|
100 template
|
Chris@16
|
101 <
|
Chris@16
|
102 typename GeometryOut, overlay_type Direction, bool ReverseOut,
|
Chris@16
|
103 typename Geometry1, typename Geometry2,
|
Chris@16
|
104 typename OutputIterator
|
Chris@16
|
105 >
|
Chris@16
|
106 inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
|
Chris@16
|
107 Geometry2 const& geometry2,
|
Chris@16
|
108 OutputIterator out)
|
Chris@16
|
109 {
|
Chris@16
|
110 typedef std::deque
|
Chris@16
|
111 <
|
Chris@16
|
112 typename geometry::ring_type<GeometryOut>::type
|
Chris@16
|
113 > ring_container_type;
|
Chris@16
|
114
|
Chris@16
|
115 typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
|
Chris@16
|
116
|
Chris@16
|
117 // Silence warning C4127: conditional expression is constant
|
Chris@16
|
118 #if defined(_MSC_VER)
|
Chris@16
|
119 #pragma warning(push)
|
Chris@16
|
120 #pragma warning(disable : 4127)
|
Chris@16
|
121 #endif
|
Chris@16
|
122
|
Chris@16
|
123 // Union: return either of them
|
Chris@16
|
124 // Intersection: return nothing
|
Chris@16
|
125 // Difference: return first of them
|
Chris@16
|
126 if (Direction == overlay_intersection
|
Chris@16
|
127 || (Direction == overlay_difference
|
Chris@16
|
128 && geometry::num_points(geometry1) == 0))
|
Chris@16
|
129 {
|
Chris@16
|
130 return out;
|
Chris@16
|
131 }
|
Chris@16
|
132
|
Chris@16
|
133 #if defined(_MSC_VER)
|
Chris@16
|
134 #pragma warning(pop)
|
Chris@16
|
135 #endif
|
Chris@16
|
136
|
Chris@16
|
137
|
Chris@16
|
138 std::map<ring_identifier, int> empty;
|
Chris@16
|
139 std::map<ring_identifier, properties> all_of_one_of_them;
|
Chris@16
|
140
|
Chris@16
|
141 select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them, false);
|
Chris@16
|
142 ring_container_type rings;
|
Chris@16
|
143 assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
|
Chris@16
|
144 return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
|
Chris@16
|
145 }
|
Chris@16
|
146
|
Chris@16
|
147
|
Chris@16
|
148 template
|
Chris@16
|
149 <
|
Chris@16
|
150 typename Geometry1, typename Geometry2,
|
Chris@16
|
151 bool Reverse1, bool Reverse2, bool ReverseOut,
|
Chris@16
|
152 typename GeometryOut,
|
Chris@16
|
153 overlay_type Direction
|
Chris@16
|
154 >
|
Chris@16
|
155 struct overlay
|
Chris@16
|
156 {
|
Chris@16
|
157 template <typename OutputIterator, typename Strategy>
|
Chris@16
|
158 static inline OutputIterator apply(
|
Chris@16
|
159 Geometry1 const& geometry1, Geometry2 const& geometry2,
|
Chris@16
|
160 OutputIterator out,
|
Chris@16
|
161 Strategy const& )
|
Chris@16
|
162 {
|
Chris@16
|
163 if (geometry::num_points(geometry1) == 0
|
Chris@16
|
164 && geometry::num_points(geometry2) == 0)
|
Chris@16
|
165 {
|
Chris@16
|
166 return out;
|
Chris@16
|
167 }
|
Chris@16
|
168
|
Chris@16
|
169 if (geometry::num_points(geometry1) == 0
|
Chris@16
|
170 || geometry::num_points(geometry2) == 0)
|
Chris@16
|
171 {
|
Chris@16
|
172 return return_if_one_input_is_empty
|
Chris@16
|
173 <
|
Chris@16
|
174 GeometryOut, Direction, ReverseOut
|
Chris@16
|
175 >(geometry1, geometry2, out);
|
Chris@16
|
176 }
|
Chris@16
|
177
|
Chris@16
|
178 typedef typename geometry::point_type<GeometryOut>::type point_type;
|
Chris@16
|
179 typedef detail::overlay::traversal_turn_info<point_type> turn_info;
|
Chris@16
|
180 typedef std::deque<turn_info> container_type;
|
Chris@16
|
181
|
Chris@16
|
182 typedef std::deque
|
Chris@16
|
183 <
|
Chris@16
|
184 typename geometry::ring_type<GeometryOut>::type
|
Chris@16
|
185 > ring_container_type;
|
Chris@16
|
186
|
Chris@16
|
187 container_type turn_points;
|
Chris@16
|
188
|
Chris@16
|
189 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
190 boost::timer timer;
|
Chris@16
|
191 #endif
|
Chris@16
|
192
|
Chris@16
|
193 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
|
Chris@16
|
194 std::cout << "get turns" << std::endl;
|
Chris@16
|
195 #endif
|
Chris@16
|
196 detail::get_turns::no_interrupt_policy policy;
|
Chris@16
|
197 geometry::get_turns
|
Chris@16
|
198 <
|
Chris@16
|
199 Reverse1, Reverse2,
|
Chris@16
|
200 detail::overlay::calculate_distance_policy
|
Chris@16
|
201 >(geometry1, geometry2, turn_points, policy);
|
Chris@16
|
202
|
Chris@16
|
203 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
204 std::cout << "get_turns: " << timer.elapsed() << std::endl;
|
Chris@16
|
205 #endif
|
Chris@16
|
206
|
Chris@16
|
207 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
|
Chris@16
|
208 std::cout << "enrich" << std::endl;
|
Chris@16
|
209 #endif
|
Chris@16
|
210 typename Strategy::side_strategy_type side_strategy;
|
Chris@16
|
211 geometry::enrich_intersection_points<Reverse1, Reverse2>(turn_points,
|
Chris@16
|
212 Direction == overlay_union
|
Chris@16
|
213 ? geometry::detail::overlay::operation_union
|
Chris@16
|
214 : geometry::detail::overlay::operation_intersection,
|
Chris@16
|
215 geometry1, geometry2,
|
Chris@16
|
216 side_strategy);
|
Chris@16
|
217
|
Chris@16
|
218 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
219 std::cout << "enrich_intersection_points: " << timer.elapsed() << std::endl;
|
Chris@16
|
220 #endif
|
Chris@16
|
221
|
Chris@16
|
222
|
Chris@16
|
223 #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
|
Chris@16
|
224 std::cout << "traverse" << std::endl;
|
Chris@16
|
225 #endif
|
Chris@16
|
226 // Traverse through intersection/turn points and create rings of them.
|
Chris@16
|
227 // Note that these rings are always in clockwise order, even in CCW polygons,
|
Chris@16
|
228 // and are marked as "to be reversed" below
|
Chris@16
|
229 ring_container_type rings;
|
Chris@16
|
230 traverse<Reverse1, Reverse2, Geometry1, Geometry2>::apply
|
Chris@16
|
231 (
|
Chris@16
|
232 geometry1, geometry2,
|
Chris@16
|
233 Direction == overlay_union
|
Chris@16
|
234 ? geometry::detail::overlay::operation_union
|
Chris@16
|
235 : geometry::detail::overlay::operation_intersection,
|
Chris@16
|
236 turn_points, rings
|
Chris@16
|
237 );
|
Chris@16
|
238
|
Chris@16
|
239 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
240 std::cout << "traverse: " << timer.elapsed() << std::endl;
|
Chris@16
|
241 #endif
|
Chris@16
|
242
|
Chris@16
|
243
|
Chris@16
|
244 std::map<ring_identifier, int> map;
|
Chris@16
|
245 map_turns(map, turn_points);
|
Chris@16
|
246
|
Chris@16
|
247 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
248 std::cout << "map_turns: " << timer.elapsed() << std::endl;
|
Chris@16
|
249 #endif
|
Chris@16
|
250
|
Chris@16
|
251 typedef ring_properties<typename geometry::point_type<GeometryOut>::type> properties;
|
Chris@16
|
252
|
Chris@16
|
253 std::map<ring_identifier, properties> selected;
|
Chris@16
|
254 select_rings<Direction>(geometry1, geometry2, map, selected, ! turn_points.empty());
|
Chris@16
|
255
|
Chris@16
|
256 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
257 std::cout << "select_rings: " << timer.elapsed() << std::endl;
|
Chris@16
|
258 #endif
|
Chris@16
|
259
|
Chris@16
|
260
|
Chris@16
|
261 // Add rings created during traversal
|
Chris@16
|
262 {
|
Chris@16
|
263 ring_identifier id(2, 0, -1);
|
Chris@16
|
264 for (typename boost::range_iterator<ring_container_type>::type
|
Chris@16
|
265 it = boost::begin(rings);
|
Chris@16
|
266 it != boost::end(rings);
|
Chris@16
|
267 ++it)
|
Chris@16
|
268 {
|
Chris@16
|
269 selected[id] = properties(*it, true);
|
Chris@16
|
270 selected[id].reversed = ReverseOut;
|
Chris@16
|
271 id.multi_index++;
|
Chris@16
|
272 }
|
Chris@16
|
273 }
|
Chris@16
|
274
|
Chris@16
|
275 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
276 std::cout << "add traversal rings: " << timer.elapsed() << std::endl;
|
Chris@16
|
277 #endif
|
Chris@16
|
278
|
Chris@16
|
279
|
Chris@16
|
280 assign_parents(geometry1, geometry2, rings, selected);
|
Chris@16
|
281
|
Chris@16
|
282 #ifdef BOOST_GEOMETRY_TIME_OVERLAY
|
Chris@16
|
283 std::cout << "assign_parents: " << timer.elapsed() << std::endl;
|
Chris@16
|
284 #endif
|
Chris@16
|
285
|
Chris@16
|
286 return add_rings<GeometryOut>(selected, geometry1, geometry2, rings, out);
|
Chris@16
|
287 }
|
Chris@16
|
288 };
|
Chris@16
|
289
|
Chris@16
|
290
|
Chris@16
|
291 // Metafunction helper for intersection and union
|
Chris@16
|
292 template <order_selector Selector, bool Reverse = false>
|
Chris@16
|
293 struct do_reverse {};
|
Chris@16
|
294
|
Chris@16
|
295 template <>
|
Chris@16
|
296 struct do_reverse<clockwise, false> : boost::false_type {};
|
Chris@16
|
297
|
Chris@16
|
298 template <>
|
Chris@16
|
299 struct do_reverse<clockwise, true> : boost::true_type {};
|
Chris@16
|
300
|
Chris@16
|
301 template <>
|
Chris@16
|
302 struct do_reverse<counterclockwise, false> : boost::true_type {};
|
Chris@16
|
303
|
Chris@16
|
304 template <>
|
Chris@16
|
305 struct do_reverse<counterclockwise, true> : boost::false_type {};
|
Chris@16
|
306
|
Chris@16
|
307
|
Chris@16
|
308
|
Chris@16
|
309 }} // namespace detail::overlay
|
Chris@16
|
310 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
311
|
Chris@16
|
312
|
Chris@16
|
313 }} // namespace boost::geometry
|
Chris@16
|
314
|
Chris@16
|
315
|
Chris@16
|
316 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
|