Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/polygon/voronoi_builder.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 // Boost.Polygon library voronoi_builder.hpp header file | |
2 | |
3 // Copyright Andrii Sydorchuk 2010-2012. | |
4 // Distributed under the Boost Software License, Version 1.0. | |
5 // (See accompanying file LICENSE_1_0.txt or copy at | |
6 // http://www.boost.org/LICENSE_1_0.txt) | |
7 | |
8 // See http://www.boost.org for updates, documentation, and revision history. | |
9 | |
10 #ifndef BOOST_POLYGON_VORONOI_BUILDER | |
11 #define BOOST_POLYGON_VORONOI_BUILDER | |
12 | |
13 #include <algorithm> | |
14 #include <map> | |
15 #include <queue> | |
16 #include <utility> | |
17 #include <vector> | |
18 | |
19 #include "detail/voronoi_ctypes.hpp" | |
20 #include "detail/voronoi_predicates.hpp" | |
21 #include "detail/voronoi_structures.hpp" | |
22 | |
23 #include "voronoi_geometry_type.hpp" | |
24 | |
25 namespace boost { | |
26 namespace polygon { | |
27 // GENERAL INFO: | |
28 // The sweepline algorithm implementation to compute Voronoi diagram of | |
29 // points and non-intersecting segments (except endpoints). | |
30 // Complexity - O(N*logN), memory usage - O(N), where N is the total number | |
31 // of input geometries. Input geometries should have integer coordinate type. | |
32 // | |
33 // IMPLEMENTATION DETAILS: | |
34 // Each input point creates one site event. Each input segment creates three | |
35 // site events: two for its endpoints and one for the segment itself (this is | |
36 // made to simplify output construction). All the site events are constructed | |
37 // and sorted at the algorithm initialization step. Priority queue is used to | |
38 // dynamically hold circle events. At each step of the algorithm execution the | |
39 // leftmost event is retrieved by comparing the current site event and the | |
40 // topmost element from the circle event queue. STL map (red-black tree) | |
41 // container was chosen to hold state of the beach line. The keys of the map | |
42 // correspond to the neighboring sites that form a bisector and values map to | |
43 // the corresponding Voronoi edges in the output data structure. | |
44 template <typename T, | |
45 typename CTT = detail::voronoi_ctype_traits<T>, | |
46 typename VP = detail::voronoi_predicates<CTT> > | |
47 class voronoi_builder { | |
48 public: | |
49 typedef typename CTT::int_type int_type; | |
50 typedef typename CTT::fpt_type fpt_type; | |
51 | |
52 voronoi_builder() : index_(0) {} | |
53 | |
54 // Each point creates a single site event. | |
55 std::size_t insert_point(const int_type& x, const int_type& y) { | |
56 site_events_.push_back(site_event_type(x, y)); | |
57 site_events_.back().initial_index(index_); | |
58 site_events_.back().source_category(SOURCE_CATEGORY_SINGLE_POINT); | |
59 return index_++; | |
60 } | |
61 | |
62 // Each segment creates three site events that correspond to: | |
63 // 1) the start point of the segment; | |
64 // 2) the end point of the segment; | |
65 // 3) the segment itself defined by its start point. | |
66 std::size_t insert_segment( | |
67 const int_type& x1, const int_type& y1, | |
68 const int_type& x2, const int_type& y2) { | |
69 // Set up start point site. | |
70 point_type p1(x1, y1); | |
71 site_events_.push_back(site_event_type(p1)); | |
72 site_events_.back().initial_index(index_); | |
73 site_events_.back().source_category(SOURCE_CATEGORY_SEGMENT_START_POINT); | |
74 | |
75 // Set up end point site. | |
76 point_type p2(x2, y2); | |
77 site_events_.push_back(site_event_type(p2)); | |
78 site_events_.back().initial_index(index_); | |
79 site_events_.back().source_category(SOURCE_CATEGORY_SEGMENT_END_POINT); | |
80 | |
81 // Set up segment site. | |
82 if (point_comparison_(p1, p2)) { | |
83 site_events_.push_back(site_event_type(p1, p2)); | |
84 site_events_.back().source_category(SOURCE_CATEGORY_INITIAL_SEGMENT); | |
85 } else { | |
86 site_events_.push_back(site_event_type(p2, p1)); | |
87 site_events_.back().source_category(SOURCE_CATEGORY_REVERSE_SEGMENT); | |
88 } | |
89 site_events_.back().initial_index(index_); | |
90 return index_++; | |
91 } | |
92 | |
93 // Run sweepline algorithm and fill output data structure. | |
94 template <typename OUTPUT> | |
95 void construct(OUTPUT* output) { | |
96 // Init structures. | |
97 output->_reserve(site_events_.size()); | |
98 init_sites_queue(); | |
99 init_beach_line(output); | |
100 | |
101 // The algorithm stops when there are no events to process. | |
102 event_comparison_predicate event_comparison; | |
103 while (!circle_events_.empty() || | |
104 !(site_event_iterator_ == site_events_.end())) { | |
105 if (circle_events_.empty()) { | |
106 process_site_event(output); | |
107 } else if (site_event_iterator_ == site_events_.end()) { | |
108 process_circle_event(output); | |
109 } else { | |
110 if (event_comparison(*site_event_iterator_, | |
111 circle_events_.top().first)) { | |
112 process_site_event(output); | |
113 } else { | |
114 process_circle_event(output); | |
115 } | |
116 } | |
117 while (!circle_events_.empty() && | |
118 !circle_events_.top().first.is_active()) { | |
119 circle_events_.pop(); | |
120 } | |
121 } | |
122 beach_line_.clear(); | |
123 | |
124 // Finish construction. | |
125 output->_build(); | |
126 } | |
127 | |
128 void clear() { | |
129 index_ = 0; | |
130 site_events_.clear(); | |
131 } | |
132 | |
133 private: | |
134 typedef detail::point_2d<int_type> point_type; | |
135 typedef detail::site_event<int_type> site_event_type; | |
136 typedef typename std::vector<site_event_type>::const_iterator | |
137 site_event_iterator_type; | |
138 typedef detail::circle_event<fpt_type> circle_event_type; | |
139 typedef typename VP::template point_comparison_predicate<point_type> | |
140 point_comparison_predicate; | |
141 typedef typename VP:: | |
142 template event_comparison_predicate<site_event_type, circle_event_type> | |
143 event_comparison_predicate; | |
144 typedef typename VP:: | |
145 template circle_formation_predicate<site_event_type, circle_event_type> | |
146 circle_formation_predicate_type; | |
147 typedef void edge_type; | |
148 typedef detail::beach_line_node_key<site_event_type> key_type; | |
149 typedef detail::beach_line_node_data<edge_type, circle_event_type> | |
150 value_type; | |
151 typedef typename VP::template node_comparison_predicate<key_type> | |
152 node_comparer_type; | |
153 typedef std::map< key_type, value_type, node_comparer_type > beach_line_type; | |
154 typedef typename beach_line_type::iterator beach_line_iterator; | |
155 typedef std::pair<circle_event_type, beach_line_iterator> event_type; | |
156 typedef struct { | |
157 bool operator()(const event_type& lhs, const event_type& rhs) const { | |
158 return predicate(rhs.first, lhs.first); | |
159 } | |
160 event_comparison_predicate predicate; | |
161 } event_comparison_type; | |
162 typedef detail::ordered_queue<event_type, event_comparison_type> | |
163 circle_event_queue_type; | |
164 typedef std::pair<point_type, beach_line_iterator> end_point_type; | |
165 | |
166 void init_sites_queue() { | |
167 // Sort site events. | |
168 std::sort(site_events_.begin(), site_events_.end(), | |
169 event_comparison_predicate()); | |
170 | |
171 // Remove duplicates. | |
172 site_events_.erase(std::unique( | |
173 site_events_.begin(), site_events_.end()), site_events_.end()); | |
174 | |
175 // Index sites. | |
176 for (std::size_t cur = 0; cur < site_events_.size(); ++cur) { | |
177 site_events_[cur].sorted_index(cur); | |
178 } | |
179 | |
180 // Init site iterator. | |
181 site_event_iterator_ = site_events_.begin(); | |
182 } | |
183 | |
184 template <typename OUTPUT> | |
185 void init_beach_line(OUTPUT* output) { | |
186 if (site_events_.empty()) | |
187 return; | |
188 if (site_events_.size() == 1) { | |
189 // Handle single site event case. | |
190 output->_process_single_site(site_events_[0]); | |
191 ++site_event_iterator_; | |
192 } else { | |
193 int skip = 0; | |
194 | |
195 while (site_event_iterator_ != site_events_.end() && | |
196 VP::is_vertical(site_event_iterator_->point0(), | |
197 site_events_.begin()->point0()) && | |
198 VP::is_vertical(*site_event_iterator_)) { | |
199 ++site_event_iterator_; | |
200 ++skip; | |
201 } | |
202 | |
203 if (skip == 1) { | |
204 // Init beach line with the first two sites. | |
205 init_beach_line_default(output); | |
206 } else { | |
207 // Init beach line with collinear vertical sites. | |
208 init_beach_line_collinear_sites(output); | |
209 } | |
210 } | |
211 } | |
212 | |
213 // Init beach line with the two first sites. | |
214 // The first site is always a point. | |
215 template <typename OUTPUT> | |
216 void init_beach_line_default(OUTPUT* output) { | |
217 // Get the first and the second site event. | |
218 site_event_iterator_type it_first = site_events_.begin(); | |
219 site_event_iterator_type it_second = site_events_.begin(); | |
220 ++it_second; | |
221 insert_new_arc( | |
222 *it_first, *it_first, *it_second, beach_line_.end(), output); | |
223 // The second site was already processed. Move the iterator. | |
224 ++site_event_iterator_; | |
225 } | |
226 | |
227 // Init beach line with collinear sites. | |
228 template <typename OUTPUT> | |
229 void init_beach_line_collinear_sites(OUTPUT* output) { | |
230 site_event_iterator_type it_first = site_events_.begin(); | |
231 site_event_iterator_type it_second = site_events_.begin(); | |
232 ++it_second; | |
233 while (it_second != site_event_iterator_) { | |
234 // Create a new beach line node. | |
235 key_type new_node(*it_first, *it_second); | |
236 | |
237 // Update the output. | |
238 edge_type* edge = output->_insert_new_edge(*it_first, *it_second).first; | |
239 | |
240 // Insert a new bisector into the beach line. | |
241 beach_line_.insert(beach_line_.end(), | |
242 std::pair<key_type, value_type>(new_node, value_type(edge))); | |
243 | |
244 // Update iterators. | |
245 ++it_first; | |
246 ++it_second; | |
247 } | |
248 } | |
249 | |
250 void deactivate_circle_event(value_type* value) { | |
251 if (value->circle_event()) { | |
252 value->circle_event()->deactivate(); | |
253 value->circle_event(NULL); | |
254 } | |
255 } | |
256 | |
257 template <typename OUTPUT> | |
258 void process_site_event(OUTPUT* output) { | |
259 // Get next site event to process. | |
260 site_event_type site_event = *site_event_iterator_; | |
261 | |
262 // Move site iterator. | |
263 site_event_iterator_type last = site_event_iterator_ + 1; | |
264 | |
265 // If a new site is an end point of some segment, | |
266 // remove temporary nodes from the beach line data structure. | |
267 if (!site_event.is_segment()) { | |
268 while (!end_points_.empty() && | |
269 end_points_.top().first == site_event.point0()) { | |
270 beach_line_iterator b_it = end_points_.top().second; | |
271 end_points_.pop(); | |
272 beach_line_.erase(b_it); | |
273 } | |
274 } else { | |
275 while (last != site_events_.end() && | |
276 last->is_segment() && last->point0() == site_event.point0()) | |
277 ++last; | |
278 } | |
279 | |
280 // Find the node in the binary search tree with left arc | |
281 // lying above the new site point. | |
282 key_type new_key(*site_event_iterator_); | |
283 beach_line_iterator right_it = beach_line_.lower_bound(new_key); | |
284 | |
285 for (; site_event_iterator_ != last; ++site_event_iterator_) { | |
286 site_event = *site_event_iterator_; | |
287 beach_line_iterator left_it = right_it; | |
288 | |
289 // Do further processing depending on the above node position. | |
290 // For any two neighboring nodes the second site of the first node | |
291 // is the same as the first site of the second node. | |
292 if (right_it == beach_line_.end()) { | |
293 // The above arc corresponds to the second arc of the last node. | |
294 // Move the iterator to the last node. | |
295 --left_it; | |
296 | |
297 // Get the second site of the last node | |
298 const site_event_type& site_arc = left_it->first.right_site(); | |
299 | |
300 // Insert new nodes into the beach line. Update the output. | |
301 right_it = insert_new_arc( | |
302 site_arc, site_arc, site_event, right_it, output); | |
303 | |
304 // Add a candidate circle to the circle event queue. | |
305 // There could be only one new circle event formed by | |
306 // a new bisector and the one on the left. | |
307 activate_circle_event(left_it->first.left_site(), | |
308 left_it->first.right_site(), | |
309 site_event, right_it); | |
310 } else if (right_it == beach_line_.begin()) { | |
311 // The above arc corresponds to the first site of the first node. | |
312 const site_event_type& site_arc = right_it->first.left_site(); | |
313 | |
314 // Insert new nodes into the beach line. Update the output. | |
315 left_it = insert_new_arc( | |
316 site_arc, site_arc, site_event, right_it, output); | |
317 | |
318 // If the site event is a segment, update its direction. | |
319 if (site_event.is_segment()) { | |
320 site_event.inverse(); | |
321 } | |
322 | |
323 // Add a candidate circle to the circle event queue. | |
324 // There could be only one new circle event formed by | |
325 // a new bisector and the one on the right. | |
326 activate_circle_event(site_event, right_it->first.left_site(), | |
327 right_it->first.right_site(), right_it); | |
328 right_it = left_it; | |
329 } else { | |
330 // The above arc corresponds neither to the first, | |
331 // nor to the last site in the beach line. | |
332 const site_event_type& site_arc2 = right_it->first.left_site(); | |
333 const site_event_type& site3 = right_it->first.right_site(); | |
334 | |
335 // Remove the candidate circle from the event queue. | |
336 deactivate_circle_event(&right_it->second); | |
337 --left_it; | |
338 const site_event_type& site_arc1 = left_it->first.right_site(); | |
339 const site_event_type& site1 = left_it->first.left_site(); | |
340 | |
341 // Insert new nodes into the beach line. Update the output. | |
342 beach_line_iterator new_node_it = | |
343 insert_new_arc(site_arc1, site_arc2, site_event, right_it, output); | |
344 | |
345 // Add candidate circles to the circle event queue. | |
346 // There could be up to two circle events formed by | |
347 // a new bisector and the one on the left or right. | |
348 activate_circle_event(site1, site_arc1, site_event, new_node_it); | |
349 | |
350 // If the site event is a segment, update its direction. | |
351 if (site_event.is_segment()) { | |
352 site_event.inverse(); | |
353 } | |
354 activate_circle_event(site_event, site_arc2, site3, right_it); | |
355 right_it = new_node_it; | |
356 } | |
357 } | |
358 } | |
359 | |
360 // In general case circle event is made of the three consecutive sites | |
361 // that form two bisectors in the beach line data structure. | |
362 // Let circle event sites be A, B, C, two bisectors that define | |
363 // circle event are (A, B), (B, C). During circle event processing | |
364 // we remove (A, B), (B, C) and insert (A, C). As beach line comparison | |
365 // works correctly only if one of the nodes is a new one we remove | |
366 // (B, C) bisector and change (A, B) bisector to the (A, C). That's | |
367 // why we use const_cast there and take all the responsibility that | |
368 // map data structure keeps correct ordering. | |
369 template <typename OUTPUT> | |
370 void process_circle_event(OUTPUT* output) { | |
371 // Get the topmost circle event. | |
372 const event_type& e = circle_events_.top(); | |
373 const circle_event_type& circle_event = e.first; | |
374 beach_line_iterator it_first = e.second; | |
375 beach_line_iterator it_last = it_first; | |
376 | |
377 // Get the C site. | |
378 site_event_type site3 = it_first->first.right_site(); | |
379 | |
380 // Get the half-edge corresponding to the second bisector - (B, C). | |
381 edge_type* bisector2 = it_first->second.edge(); | |
382 | |
383 // Get the half-edge corresponding to the first bisector - (A, B). | |
384 --it_first; | |
385 edge_type* bisector1 = it_first->second.edge(); | |
386 | |
387 // Get the A site. | |
388 site_event_type site1 = it_first->first.left_site(); | |
389 | |
390 if (!site1.is_segment() && site3.is_segment() && | |
391 site3.point1() == site1.point0()) { | |
392 site3.inverse(); | |
393 } | |
394 | |
395 // Change the (A, B) bisector node to the (A, C) bisector node. | |
396 const_cast<key_type&>(it_first->first).right_site(site3); | |
397 | |
398 // Insert the new bisector into the beach line. | |
399 it_first->second.edge(output->_insert_new_edge( | |
400 site1, site3, circle_event, bisector1, bisector2).first); | |
401 | |
402 // Remove the (B, C) bisector node from the beach line. | |
403 beach_line_.erase(it_last); | |
404 it_last = it_first; | |
405 | |
406 // Pop the topmost circle event from the event queue. | |
407 circle_events_.pop(); | |
408 | |
409 // Check new triplets formed by the neighboring arcs | |
410 // to the left for potential circle events. | |
411 if (it_first != beach_line_.begin()) { | |
412 deactivate_circle_event(&it_first->second); | |
413 --it_first; | |
414 const site_event_type& site_l1 = it_first->first.left_site(); | |
415 activate_circle_event(site_l1, site1, site3, it_last); | |
416 } | |
417 | |
418 // Check the new triplet formed by the neighboring arcs | |
419 // to the right for potential circle events. | |
420 ++it_last; | |
421 if (it_last != beach_line_.end()) { | |
422 deactivate_circle_event(&it_last->second); | |
423 const site_event_type& site_r1 = it_last->first.right_site(); | |
424 activate_circle_event(site1, site3, site_r1, it_last); | |
425 } | |
426 } | |
427 | |
428 // Insert new nodes into the beach line. Update the output. | |
429 template <typename OUTPUT> | |
430 beach_line_iterator insert_new_arc( | |
431 const site_event_type& site_arc1, const site_event_type &site_arc2, | |
432 const site_event_type& site_event, beach_line_iterator position, | |
433 OUTPUT* output) { | |
434 // Create two new bisectors with opposite directions. | |
435 key_type new_left_node(site_arc1, site_event); | |
436 key_type new_right_node(site_event, site_arc2); | |
437 | |
438 // Set correct orientation for the first site of the second node. | |
439 if (site_event.is_segment()) { | |
440 new_right_node.left_site().inverse(); | |
441 } | |
442 | |
443 // Update the output. | |
444 std::pair<edge_type*, edge_type*> edges = | |
445 output->_insert_new_edge(site_arc2, site_event); | |
446 position = beach_line_.insert(position, | |
447 typename beach_line_type::value_type( | |
448 new_right_node, value_type(edges.second))); | |
449 | |
450 if (site_event.is_segment()) { | |
451 // Update the beach line with temporary bisector, that will | |
452 // disappear after processing site event corresponding to the | |
453 // second endpoint of the segment site. | |
454 key_type new_node(site_event, site_event); | |
455 new_node.right_site().inverse(); | |
456 position = beach_line_.insert(position, | |
457 typename beach_line_type::value_type(new_node, value_type(NULL))); | |
458 | |
459 // Update the data structure that holds temporary bisectors. | |
460 end_points_.push(std::make_pair(site_event.point1(), position)); | |
461 } | |
462 | |
463 position = beach_line_.insert(position, | |
464 typename beach_line_type::value_type( | |
465 new_left_node, value_type(edges.first))); | |
466 | |
467 return position; | |
468 } | |
469 | |
470 // Add a new circle event to the event queue. | |
471 // bisector_node corresponds to the (site2, site3) bisector. | |
472 void activate_circle_event(const site_event_type& site1, | |
473 const site_event_type& site2, | |
474 const site_event_type& site3, | |
475 beach_line_iterator bisector_node) { | |
476 circle_event_type c_event; | |
477 // Check if the three input sites create a circle event. | |
478 if (circle_formation_predicate_(site1, site2, site3, c_event)) { | |
479 // Add the new circle event to the circle events queue. | |
480 // Update bisector's circle event iterator to point to the | |
481 // new circle event in the circle event queue. | |
482 event_type& e = circle_events_.push( | |
483 std::pair<circle_event_type, beach_line_iterator>( | |
484 c_event, bisector_node)); | |
485 bisector_node->second.circle_event(&e.first); | |
486 } | |
487 } | |
488 | |
489 private: | |
490 point_comparison_predicate point_comparison_; | |
491 struct end_point_comparison { | |
492 bool operator() (const end_point_type& end1, | |
493 const end_point_type& end2) const { | |
494 return point_comparison(end2.first, end1.first); | |
495 } | |
496 point_comparison_predicate point_comparison; | |
497 }; | |
498 | |
499 std::vector<site_event_type> site_events_; | |
500 site_event_iterator_type site_event_iterator_; | |
501 std::priority_queue< end_point_type, std::vector<end_point_type>, | |
502 end_point_comparison > end_points_; | |
503 circle_event_queue_type circle_events_; | |
504 beach_line_type beach_line_; | |
505 circle_formation_predicate_type circle_formation_predicate_; | |
506 std::size_t index_; | |
507 | |
508 // Disallow copy constructor and operator= | |
509 voronoi_builder(const voronoi_builder&); | |
510 void operator=(const voronoi_builder&); | |
511 }; | |
512 | |
513 typedef voronoi_builder<detail::int32> default_voronoi_builder; | |
514 } // polygon | |
515 } // boost | |
516 | |
517 #endif // BOOST_POLYGON_VORONOI_BUILDER |