1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2011 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
11
12 #include <vector>
13 #include <boost/geometry/algorithms/assign.hpp>
14 #include <boost/range/algorithm/copy.hpp>
15 #include <boost/geometry/core/coordinate_type.hpp>
16
17 namespace boost { namespace geometry
18 {
19
20
21 namespace detail { namespace partition
22 {
23
24 typedef std::vector<std::size_t> index_vector_type;
25
26 template <int Dimension, typename Box>
divide_box(Box const & box,Box & lower_box,Box & upper_box)27 inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
28 {
29 typedef typename coordinate_type<Box>::type ctype;
30
31 // Divide input box into two parts, e.g. left/right
32 ctype two = 2;
33 ctype mid = (geometry::get<min_corner, Dimension>(box)
34 + geometry::get<max_corner, Dimension>(box)) / two;
35
36 lower_box = box;
37 upper_box = box;
38 geometry::set<max_corner, Dimension>(lower_box, mid);
39 geometry::set<min_corner, Dimension>(upper_box, mid);
40 }
41
42 // Divide collection into three subsets: lower, upper and oversized (not-fitting)
43 // (lower == left or bottom, upper == right or top)
44 template <typename OverlapsPolicy, typename InputCollection, typename Box>
divide_into_subsets(Box const & lower_box,Box const & upper_box,InputCollection const & collection,index_vector_type const & input,index_vector_type & lower,index_vector_type & upper,index_vector_type & exceeding)45 static inline void divide_into_subsets(Box const& lower_box, Box const& upper_box,
46 InputCollection const& collection,
47 index_vector_type const& input,
48 index_vector_type& lower,
49 index_vector_type& upper,
50 index_vector_type& exceeding)
51 {
52 typedef boost::range_iterator<index_vector_type const>::type index_iterator_type;
53
54 for(index_iterator_type it = boost::begin(input);
55 it != boost::end(input);
56 ++it)
57 {
58 bool const lower_overlapping = OverlapsPolicy::apply(lower_box, collection[*it]);
59 bool const upper_overlapping = OverlapsPolicy::apply(upper_box, collection[*it]);
60
61 if (lower_overlapping && upper_overlapping)
62 {
63 exceeding.push_back(*it);
64 }
65 else if (lower_overlapping)
66 {
67 lower.push_back(*it);
68 }
69 else if (upper_overlapping)
70 {
71 upper.push_back(*it);
72 }
73 else
74 {
75 // Is nowhere! Should not occur!
76 BOOST_ASSERT(true);
77 }
78 }
79 }
80
81
82 // Match collection with itself
83 template <typename InputCollection, typename Policy>
handle_one(InputCollection const & collection,index_vector_type const & input,Policy & policy)84 static inline void handle_one(InputCollection const& collection,
85 index_vector_type const& input,
86 Policy& policy)
87 {
88 typedef boost::range_iterator<index_vector_type const>::type index_iterator_type;
89 // Quadratic behaviour at lowest level (lowest quad, or all exceeding)
90 for(index_iterator_type it1 = boost::begin(input); it1 != boost::end(input); ++it1)
91 {
92 index_iterator_type it2 = it1;
93 for(++it2; it2 != boost::end(input); ++it2)
94 {
95 policy.apply(collection[*it1], collection[*it2]);
96 }
97 }
98 }
99
100 // Match collection 1 with collection 2
101 template <typename InputCollection, typename Policy>
handle_two(InputCollection const & collection1,index_vector_type const & input1,InputCollection const & collection2,index_vector_type const & input2,Policy & policy)102 static inline void handle_two(
103 InputCollection const& collection1, index_vector_type const& input1,
104 InputCollection const& collection2, index_vector_type const& input2,
105 Policy& policy)
106 {
107 typedef boost::range_iterator<index_vector_type const>::type index_iterator_type;
108 for(index_iterator_type it1 = boost::begin(input1); it1 != boost::end(input1); ++it1)
109 {
110 for(index_iterator_type it2 = boost::begin(input2); it2 != boost::end(input2); ++it2)
111 {
112 policy.apply(collection1[*it1], collection2[*it2]);
113 }
114 }
115 }
116
117
118 template
119 <
120 int Dimension,
121 typename Box,
122 typename OverlapsPolicy,
123 typename VisitBoxPolicy
124 >
125 class partition_one_collection
126 {
127 typedef std::vector<std::size_t> index_vector_type;
128 typedef typename coordinate_type<Box>::type ctype;
129 typedef partition_one_collection
130 <
131 1 - Dimension,
132 Box,
133 OverlapsPolicy,
134 VisitBoxPolicy
135 > sub_divide;
136
137 template <typename InputCollection, typename Policy>
next_level(Box const & box,InputCollection const & collection,index_vector_type const & input,int level,int min_elements,Policy & policy,VisitBoxPolicy & box_policy)138 static inline void next_level(Box const& box,
139 InputCollection const& collection,
140 index_vector_type const& input,
141 int level, int min_elements,
142 Policy& policy, VisitBoxPolicy& box_policy)
143 {
144 if (boost::size(input) > 0)
145 {
146 if (boost::size(input) > min_elements && level < 100)
147 {
148 sub_divide::apply(box, collection, input, level + 1, min_elements, policy, box_policy);
149 }
150 else
151 {
152 handle_one(collection, input, policy);
153 }
154 }
155 }
156
157 public :
158 template <typename InputCollection, typename Policy>
apply(Box const & box,InputCollection const & collection,index_vector_type const & input,int level,int min_elements,Policy & policy,VisitBoxPolicy & box_policy)159 static inline void apply(Box const& box,
160 InputCollection const& collection,
161 index_vector_type const& input,
162 int level,
163 int min_elements,
164 Policy& policy, VisitBoxPolicy& box_policy)
165 {
166 box_policy.apply(box, level);
167
168 Box lower_box, upper_box;
169 divide_box<Dimension>(box, lower_box, upper_box);
170
171 index_vector_type lower, upper, exceeding;
172 divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection, input, lower, upper, exceeding);
173
174 if (boost::size(exceeding) > 0)
175 {
176 // All what is not fitting a partition should be combined
177 // with each other, and with all which is fitting.
178 handle_one(collection, exceeding, policy);
179 handle_two(collection, exceeding, collection, lower, policy);
180 handle_two(collection, exceeding, collection, upper, policy);
181 }
182
183 // Recursively call operation both parts
184 next_level(lower_box, collection, lower, level, min_elements, policy, box_policy);
185 next_level(upper_box, collection, upper, level, min_elements, policy, box_policy);
186 }
187 };
188
189
190 template
191 <
192 int Dimension,
193 typename Box,
194 typename OverlapsPolicy,
195 typename VisitBoxPolicy
196 >
197 class partition_two_collections
198 {
199 typedef std::vector<std::size_t> index_vector_type;
200 typedef typename coordinate_type<Box>::type ctype;
201 typedef partition_two_collections
202 <
203 1 - Dimension,
204 Box,
205 OverlapsPolicy,
206 VisitBoxPolicy
207 > sub_divide;
208
209 template <typename InputCollection, typename Policy>
next_level(Box const & box,InputCollection const & collection1,index_vector_type const & input1,InputCollection const & collection2,index_vector_type const & input2,int level,int min_elements,Policy & policy,VisitBoxPolicy & box_policy)210 static inline void next_level(Box const& box,
211 InputCollection const& collection1, index_vector_type const& input1,
212 InputCollection const& collection2, index_vector_type const& input2,
213 int level, int min_elements,
214 Policy& policy, VisitBoxPolicy& box_policy)
215 {
216 if (boost::size(input1) > 0 && boost::size(input2) > 0)
217 {
218 if (boost::size(input1) > min_elements
219 && boost::size(input2) > min_elements
220 && level < 100)
221 {
222 sub_divide::apply(box, collection1, input1, collection2, input2, level + 1, min_elements, policy, box_policy);
223 }
224 else
225 {
226 box_policy.apply(box, level + 1);
227 handle_two(collection1, input1, collection2, input2, policy);
228 }
229 }
230 }
231
232 public :
233 template <typename InputCollection, typename Policy>
apply(Box const & box,InputCollection const & collection1,index_vector_type const & input1,InputCollection const & collection2,index_vector_type const & input2,int level,int min_elements,Policy & policy,VisitBoxPolicy & box_policy)234 static inline void apply(Box const& box,
235 InputCollection const& collection1, index_vector_type const& input1,
236 InputCollection const& collection2, index_vector_type const& input2,
237 int level,
238 int min_elements,
239 Policy& policy, VisitBoxPolicy& box_policy)
240 {
241 box_policy.apply(box, level);
242
243 Box lower_box, upper_box;
244 divide_box<Dimension>(box, lower_box, upper_box);
245
246 index_vector_type lower1, upper1, exceeding1;
247 index_vector_type lower2, upper2, exceeding2;
248 divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection1, input1, lower1, upper1, exceeding1);
249 divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection2, input2, lower2, upper2, exceeding2);
250
251 if (boost::size(exceeding1) > 0)
252 {
253 // All exceeding from 1 with 2:
254 handle_two(collection1, exceeding1, collection2, exceeding2, policy);
255
256 // All exceeding from 1 with lower and upper of 2:
257 handle_two(collection1, exceeding1, collection2, lower2, policy);
258 handle_two(collection1, exceeding1, collection2, upper2, policy);
259 }
260 if (boost::size(exceeding2) > 0)
261 {
262 // All exceeding from 2 with lower and upper of 1:
263 handle_two(collection1, lower1, collection2, exceeding2, policy);
264 handle_two(collection1, upper1, collection2, exceeding2, policy);
265 }
266
267 next_level(lower_box, collection1, lower1, collection2, lower2, level, min_elements, policy, box_policy);
268 next_level(upper_box, collection1, upper1, collection2, upper2, level, min_elements, policy, box_policy);
269 }
270 };
271
272
273
274 }} // namespace detail::partition
275
276 struct visit_no_policy
277 {
278 template <typename Box>
applyboost::geometry::visit_no_policy279 static inline void apply(Box const&, int )
280 {}
281 };
282
283
284 template
285 <
286 typename Box,
287 typename ExpandPolicy,
288 typename OverlapsPolicy,
289 typename VisitBoxPolicy = visit_no_policy
290 >
291 class partition
292 {
293 typedef std::vector<std::size_t> index_vector_type;
294
295 template <typename InputCollection>
expand_to_collection(InputCollection const & collection,Box & total,index_vector_type & index_vector)296 static inline void expand_to_collection(InputCollection const& collection, Box& total, index_vector_type& index_vector)
297 {
298 std::size_t index = 0;
299 for(typename boost::range_iterator<InputCollection const>::type it
300 = boost::begin(collection);
301 it != boost::end(collection);
302 ++it, ++index)
303 {
304 ExpandPolicy::apply(total, *it);
305 index_vector.push_back(index);
306 }
307 }
308
309
310 public :
311 template <typename InputCollection, typename VisitPolicy>
apply(InputCollection const & collection,VisitPolicy & visitor,int min_elements=16,VisitBoxPolicy box_visitor=visit_no_policy ())312 static inline void apply(InputCollection const& collection,
313 VisitPolicy& visitor,
314 int min_elements = 16,
315 VisitBoxPolicy box_visitor = visit_no_policy()
316 )
317 {
318 if (boost::size(collection) > min_elements)
319 {
320 index_vector_type index_vector;
321 Box total;
322 assign_inverse(total);
323 expand_to_collection(collection, total, index_vector);
324
325 detail::partition::partition_one_collection
326 <
327 0, Box,
328 OverlapsPolicy,
329 VisitBoxPolicy
330 >::apply(total, collection, index_vector, 0, min_elements, visitor, box_visitor);
331 }
332 else
333 {
334 typedef typename boost::range_iterator<InputCollection const>::type iterator_type;
335 for(iterator_type it1 = boost::begin(collection); it1 != boost::end(collection); ++it1)
336 {
337 iterator_type it2 = it1;
338 for(++it2; it2 != boost::end(collection); ++it2)
339 {
340 visitor.apply(*it1, *it2);
341 }
342 }
343 }
344 }
345
346 template <typename InputCollection, typename VisitPolicy>
apply(InputCollection const & collection1,InputCollection const & collection2,VisitPolicy & visitor,int min_elements=16,VisitBoxPolicy box_visitor=visit_no_policy ())347 static inline void apply(InputCollection const& collection1,
348 InputCollection const& collection2,
349 VisitPolicy& visitor,
350 int min_elements = 16,
351 VisitBoxPolicy box_visitor = visit_no_policy()
352 )
353 {
354 if (boost::size(collection1) > min_elements && boost::size(collection2) > min_elements)
355 {
356 index_vector_type index_vector1, index_vector2;
357 Box total;
358 assign_inverse(total);
359 expand_to_collection(collection1, total, index_vector1);
360 expand_to_collection(collection2, total, index_vector2);
361
362 detail::partition::partition_two_collections
363 <
364 0, Box, OverlapsPolicy, VisitBoxPolicy
365 >::apply(total,
366 collection1, index_vector1,
367 collection2, index_vector2,
368 0, min_elements, visitor, box_visitor);
369 }
370 else
371 {
372 typedef typename boost::range_iterator<InputCollection const>::type iterator_type;
373 for(iterator_type it1 = boost::begin(collection1); it1 != boost::end(collection1); ++it1)
374 {
375 for(iterator_type it2 = boost::begin(collection2); it2 != boost::end(collection2); ++it2)
376 {
377 visitor.apply(*it1, *it2);
378 }
379 }
380 }
381 }
382
383 };
384
385
386 }} // namespace boost::geometry
387
388
389 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
390