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