Chris@16
|
1 // Boost.Polygon library detail/voronoi_structures.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_DETAIL_VORONOI_STRUCTURES
|
Chris@16
|
11 #define BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES
|
Chris@16
|
12
|
Chris@16
|
13 #include <list>
|
Chris@16
|
14 #include <queue>
|
Chris@16
|
15 #include <vector>
|
Chris@16
|
16
|
Chris@16
|
17 #include "boost/polygon/voronoi_geometry_type.hpp"
|
Chris@16
|
18
|
Chris@16
|
19 namespace boost {
|
Chris@16
|
20 namespace polygon {
|
Chris@16
|
21 namespace detail {
|
Chris@16
|
22 // Cartesian 2D point data structure.
|
Chris@16
|
23 template <typename T>
|
Chris@16
|
24 class point_2d {
|
Chris@16
|
25 public:
|
Chris@16
|
26 typedef T coordinate_type;
|
Chris@16
|
27
|
Chris@16
|
28 point_2d() {}
|
Chris@16
|
29
|
Chris@16
|
30 point_2d(coordinate_type x, coordinate_type y) :
|
Chris@16
|
31 x_(x),
|
Chris@16
|
32 y_(y) {}
|
Chris@16
|
33
|
Chris@16
|
34 bool operator==(const point_2d& that) const {
|
Chris@16
|
35 return (this->x_ == that.x()) && (this->y_ == that.y());
|
Chris@16
|
36 }
|
Chris@16
|
37
|
Chris@16
|
38 bool operator!=(const point_2d& that) const {
|
Chris@16
|
39 return (this->x_ != that.x()) || (this->y_ != that.y());
|
Chris@16
|
40 }
|
Chris@16
|
41
|
Chris@16
|
42 coordinate_type x() const {
|
Chris@16
|
43 return x_;
|
Chris@16
|
44 }
|
Chris@16
|
45
|
Chris@16
|
46 coordinate_type y() const {
|
Chris@16
|
47 return y_;
|
Chris@16
|
48 }
|
Chris@16
|
49
|
Chris@16
|
50 point_2d& x(coordinate_type x) {
|
Chris@16
|
51 x_ = x;
|
Chris@16
|
52 return *this;
|
Chris@16
|
53 }
|
Chris@16
|
54
|
Chris@16
|
55 point_2d& y(coordinate_type y) {
|
Chris@16
|
56 y_ = y;
|
Chris@16
|
57 return *this;
|
Chris@16
|
58 }
|
Chris@16
|
59
|
Chris@16
|
60 private:
|
Chris@16
|
61 coordinate_type x_;
|
Chris@16
|
62 coordinate_type y_;
|
Chris@16
|
63 };
|
Chris@16
|
64
|
Chris@16
|
65 // Site event type.
|
Chris@16
|
66 // Occurs when the sweepline sweeps over one of the initial sites:
|
Chris@16
|
67 // 1) point site
|
Chris@16
|
68 // 2) start-point of the segment site
|
Chris@16
|
69 // 3) endpoint of the segment site
|
Chris@16
|
70 // Implicit segment direction is defined: the start-point of
|
Chris@16
|
71 // the segment compares less than its endpoint.
|
Chris@16
|
72 // Each input segment is divided onto two site events:
|
Chris@16
|
73 // 1) One going from the start-point to the endpoint
|
Chris@16
|
74 // (is_inverse() = false)
|
Chris@16
|
75 // 2) Another going from the endpoint to the start-point
|
Chris@16
|
76 // (is_inverse() = true)
|
Chris@16
|
77 // In beach line data structure segment sites of the first
|
Chris@16
|
78 // type precede sites of the second type for the same segment.
|
Chris@16
|
79 // Members:
|
Chris@16
|
80 // point0_ - point site or segment's start-point
|
Chris@16
|
81 // point1_ - segment's endpoint if site is a segment
|
Chris@16
|
82 // sorted_index_ - the last bit encodes information if the site is inverse;
|
Chris@16
|
83 // the other bits encode site event index among the sorted site events
|
Chris@16
|
84 // initial_index_ - site index among the initial input set
|
Chris@16
|
85 // Note: for all sites is_inverse_ flag is equal to false by default.
|
Chris@16
|
86 template <typename T>
|
Chris@16
|
87 class site_event {
|
Chris@16
|
88 public:
|
Chris@16
|
89 typedef T coordinate_type;
|
Chris@16
|
90 typedef point_2d<T> point_type;
|
Chris@16
|
91
|
Chris@16
|
92 site_event() :
|
Chris@16
|
93 point0_(0, 0),
|
Chris@16
|
94 point1_(0, 0),
|
Chris@16
|
95 sorted_index_(0),
|
Chris@16
|
96 flags_(0) {}
|
Chris@16
|
97
|
Chris@16
|
98 site_event(coordinate_type x, coordinate_type y) :
|
Chris@16
|
99 point0_(x, y),
|
Chris@16
|
100 point1_(x, y),
|
Chris@16
|
101 sorted_index_(0),
|
Chris@16
|
102 flags_(0) {}
|
Chris@16
|
103
|
Chris@16
|
104 explicit site_event(const point_type& point) :
|
Chris@16
|
105 point0_(point),
|
Chris@16
|
106 point1_(point),
|
Chris@16
|
107 sorted_index_(0),
|
Chris@16
|
108 flags_(0) {}
|
Chris@16
|
109
|
Chris@16
|
110 site_event(coordinate_type x1, coordinate_type y1,
|
Chris@16
|
111 coordinate_type x2, coordinate_type y2):
|
Chris@16
|
112 point0_(x1, y1),
|
Chris@16
|
113 point1_(x2, y2),
|
Chris@16
|
114 sorted_index_(0),
|
Chris@16
|
115 flags_(0) {}
|
Chris@16
|
116
|
Chris@16
|
117 site_event(const point_type& point1, const point_type& point2) :
|
Chris@16
|
118 point0_(point1),
|
Chris@16
|
119 point1_(point2),
|
Chris@16
|
120 sorted_index_(0),
|
Chris@16
|
121 flags_(0) {}
|
Chris@16
|
122
|
Chris@16
|
123 bool operator==(const site_event& that) const {
|
Chris@16
|
124 return (this->point0_ == that.point0_) &&
|
Chris@16
|
125 (this->point1_ == that.point1_);
|
Chris@16
|
126 }
|
Chris@16
|
127
|
Chris@16
|
128 bool operator!=(const site_event& that) const {
|
Chris@16
|
129 return (this->point0_ != that.point0_) ||
|
Chris@16
|
130 (this->point1_ != that.point1_);
|
Chris@16
|
131 }
|
Chris@16
|
132
|
Chris@16
|
133 coordinate_type x() const {
|
Chris@16
|
134 return point0_.x();
|
Chris@16
|
135 }
|
Chris@16
|
136
|
Chris@16
|
137 coordinate_type y() const {
|
Chris@16
|
138 return point0_.y();
|
Chris@16
|
139 }
|
Chris@16
|
140
|
Chris@16
|
141 coordinate_type x0() const {
|
Chris@16
|
142 return point0_.x();
|
Chris@16
|
143 }
|
Chris@16
|
144
|
Chris@16
|
145 coordinate_type y0() const {
|
Chris@16
|
146 return point0_.y();
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 coordinate_type x1() const {
|
Chris@16
|
150 return point1_.x();
|
Chris@16
|
151 }
|
Chris@16
|
152
|
Chris@16
|
153 coordinate_type y1() const {
|
Chris@16
|
154 return point1_.y();
|
Chris@16
|
155 }
|
Chris@16
|
156
|
Chris@16
|
157 const point_type& point0() const {
|
Chris@16
|
158 return point0_;
|
Chris@16
|
159 }
|
Chris@16
|
160
|
Chris@16
|
161 const point_type& point1() const {
|
Chris@16
|
162 return point1_;
|
Chris@16
|
163 }
|
Chris@16
|
164
|
Chris@16
|
165 std::size_t sorted_index() const {
|
Chris@16
|
166 return sorted_index_;
|
Chris@16
|
167 }
|
Chris@16
|
168
|
Chris@16
|
169 site_event& sorted_index(std::size_t index) {
|
Chris@16
|
170 sorted_index_ = index;
|
Chris@16
|
171 return *this;
|
Chris@16
|
172 }
|
Chris@16
|
173
|
Chris@16
|
174 std::size_t initial_index() const {
|
Chris@16
|
175 return initial_index_;
|
Chris@16
|
176 }
|
Chris@16
|
177
|
Chris@16
|
178 site_event& initial_index(std::size_t index) {
|
Chris@16
|
179 initial_index_ = index;
|
Chris@16
|
180 return *this;
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 bool is_inverse() const {
|
Chris@16
|
184 return (flags_ & IS_INVERSE) ? true : false;
|
Chris@16
|
185 }
|
Chris@16
|
186
|
Chris@16
|
187 site_event& inverse() {
|
Chris@16
|
188 std::swap(point0_, point1_);
|
Chris@16
|
189 flags_ ^= IS_INVERSE;
|
Chris@16
|
190 return *this;
|
Chris@16
|
191 }
|
Chris@16
|
192
|
Chris@16
|
193 SourceCategory source_category() const {
|
Chris@16
|
194 return static_cast<SourceCategory>(flags_ & SOURCE_CATEGORY_BITMASK);
|
Chris@16
|
195 }
|
Chris@16
|
196
|
Chris@16
|
197 site_event& source_category(SourceCategory source_category) {
|
Chris@16
|
198 flags_ |= source_category;
|
Chris@16
|
199 return *this;
|
Chris@16
|
200 }
|
Chris@16
|
201
|
Chris@16
|
202 bool is_point() const {
|
Chris@16
|
203 return (point0_.x() == point1_.x()) && (point0_.y() == point1_.y());
|
Chris@16
|
204 }
|
Chris@16
|
205
|
Chris@16
|
206 bool is_segment() const {
|
Chris@16
|
207 return (point0_.x() != point1_.x()) || (point0_.y() != point1_.y());
|
Chris@16
|
208 }
|
Chris@16
|
209
|
Chris@16
|
210 private:
|
Chris@16
|
211 enum Bits {
|
Chris@16
|
212 IS_INVERSE = 0x20 // 32
|
Chris@16
|
213 };
|
Chris@16
|
214
|
Chris@16
|
215 point_type point0_;
|
Chris@16
|
216 point_type point1_;
|
Chris@16
|
217 std::size_t sorted_index_;
|
Chris@16
|
218 std::size_t initial_index_;
|
Chris@16
|
219 std::size_t flags_;
|
Chris@16
|
220 };
|
Chris@16
|
221
|
Chris@16
|
222 // Circle event type.
|
Chris@16
|
223 // Occurs when the sweepline sweeps over the rightmost point of the Voronoi
|
Chris@16
|
224 // circle (with the center at the intersection point of the bisectors).
|
Chris@16
|
225 // Circle event is made of the two consecutive nodes in the beach line data
|
Chris@16
|
226 // structure. In case another node was inserted during algorithm execution
|
Chris@16
|
227 // between the given two nodes circle event becomes inactive.
|
Chris@16
|
228 // Variables:
|
Chris@16
|
229 // center_x_ - center x-coordinate;
|
Chris@16
|
230 // center_y_ - center y-coordinate;
|
Chris@16
|
231 // lower_x_ - leftmost x-coordinate;
|
Chris@16
|
232 // is_active_ - states whether circle event is still active.
|
Chris@16
|
233 // NOTE: lower_y coordinate is always equal to center_y.
|
Chris@16
|
234 template <typename T>
|
Chris@16
|
235 class circle_event {
|
Chris@16
|
236 public:
|
Chris@16
|
237 typedef T coordinate_type;
|
Chris@16
|
238
|
Chris@16
|
239 circle_event() : is_active_(true) {}
|
Chris@16
|
240
|
Chris@16
|
241 circle_event(coordinate_type c_x,
|
Chris@16
|
242 coordinate_type c_y,
|
Chris@16
|
243 coordinate_type lower_x) :
|
Chris@16
|
244 center_x_(c_x),
|
Chris@16
|
245 center_y_(c_y),
|
Chris@16
|
246 lower_x_(lower_x),
|
Chris@16
|
247 is_active_(true) {}
|
Chris@16
|
248
|
Chris@16
|
249 coordinate_type x() const {
|
Chris@16
|
250 return center_x_;
|
Chris@16
|
251 }
|
Chris@16
|
252
|
Chris@16
|
253 circle_event& x(coordinate_type center_x) {
|
Chris@16
|
254 center_x_ = center_x;
|
Chris@16
|
255 return *this;
|
Chris@16
|
256 }
|
Chris@16
|
257
|
Chris@16
|
258 coordinate_type y() const {
|
Chris@16
|
259 return center_y_;
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 circle_event& y(coordinate_type center_y) {
|
Chris@16
|
263 center_y_ = center_y;
|
Chris@16
|
264 return *this;
|
Chris@16
|
265 }
|
Chris@16
|
266
|
Chris@16
|
267 coordinate_type lower_x() const {
|
Chris@16
|
268 return lower_x_;
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 circle_event& lower_x(coordinate_type lower_x) {
|
Chris@16
|
272 lower_x_ = lower_x;
|
Chris@16
|
273 return *this;
|
Chris@16
|
274 }
|
Chris@16
|
275
|
Chris@16
|
276 coordinate_type lower_y() const {
|
Chris@16
|
277 return center_y_;
|
Chris@16
|
278 }
|
Chris@16
|
279
|
Chris@16
|
280 bool is_active() const {
|
Chris@16
|
281 return is_active_;
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 circle_event& deactivate() {
|
Chris@16
|
285 is_active_ = false;
|
Chris@16
|
286 return *this;
|
Chris@16
|
287 }
|
Chris@16
|
288
|
Chris@16
|
289 private:
|
Chris@16
|
290 coordinate_type center_x_;
|
Chris@16
|
291 coordinate_type center_y_;
|
Chris@16
|
292 coordinate_type lower_x_;
|
Chris@16
|
293 bool is_active_;
|
Chris@16
|
294 };
|
Chris@16
|
295
|
Chris@16
|
296 // Event queue data structure, holds circle events.
|
Chris@16
|
297 // During algorithm run, some of the circle events disappear (become
|
Chris@16
|
298 // inactive). Priority queue data structure doesn't support
|
Chris@16
|
299 // iterators (there is no direct ability to modify its elements).
|
Chris@16
|
300 // Instead list is used to store all the circle events and priority queue
|
Chris@16
|
301 // of the iterators to the list elements is used to keep the correct circle
|
Chris@16
|
302 // events ordering.
|
Chris@16
|
303 template <typename T, typename Predicate>
|
Chris@16
|
304 class ordered_queue {
|
Chris@16
|
305 public:
|
Chris@16
|
306 ordered_queue() {}
|
Chris@16
|
307
|
Chris@16
|
308 bool empty() const {
|
Chris@16
|
309 return c_.empty();
|
Chris@16
|
310 }
|
Chris@16
|
311
|
Chris@16
|
312 const T &top() const {
|
Chris@16
|
313 return *c_.top();
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 void pop() {
|
Chris@16
|
317 list_iterator_type it = c_.top();
|
Chris@16
|
318 c_.pop();
|
Chris@16
|
319 c_list_.erase(it);
|
Chris@16
|
320 }
|
Chris@16
|
321
|
Chris@16
|
322 T &push(const T &e) {
|
Chris@16
|
323 c_list_.push_front(e);
|
Chris@16
|
324 c_.push(c_list_.begin());
|
Chris@16
|
325 return c_list_.front();
|
Chris@16
|
326 }
|
Chris@16
|
327
|
Chris@16
|
328 void clear() {
|
Chris@16
|
329 while (!c_.empty())
|
Chris@16
|
330 c_.pop();
|
Chris@16
|
331 c_list_.clear();
|
Chris@16
|
332 }
|
Chris@16
|
333
|
Chris@16
|
334 private:
|
Chris@16
|
335 typedef typename std::list<T>::iterator list_iterator_type;
|
Chris@16
|
336
|
Chris@16
|
337 struct comparison {
|
Chris@16
|
338 bool operator() (const list_iterator_type &it1,
|
Chris@16
|
339 const list_iterator_type &it2) const {
|
Chris@16
|
340 return cmp_(*it1, *it2);
|
Chris@16
|
341 }
|
Chris@16
|
342 Predicate cmp_;
|
Chris@16
|
343 };
|
Chris@16
|
344
|
Chris@16
|
345 std::priority_queue< list_iterator_type,
|
Chris@16
|
346 std::vector<list_iterator_type>,
|
Chris@16
|
347 comparison > c_;
|
Chris@16
|
348 std::list<T> c_list_;
|
Chris@16
|
349
|
Chris@16
|
350 // Disallow copy constructor and operator=
|
Chris@16
|
351 ordered_queue(const ordered_queue&);
|
Chris@16
|
352 void operator=(const ordered_queue&);
|
Chris@16
|
353 };
|
Chris@16
|
354
|
Chris@16
|
355 // Represents a bisector node made by two arcs that correspond to the left
|
Chris@16
|
356 // and right sites. Arc is defined as a curve with points equidistant from
|
Chris@16
|
357 // the site and from the sweepline. If the site is a point then arc is
|
Chris@16
|
358 // a parabola, otherwise it's a line segment. A segment site event will
|
Chris@16
|
359 // produce different bisectors based on its direction.
|
Chris@16
|
360 // In general case two sites will create two opposite bisectors. That's
|
Chris@16
|
361 // why the order of the sites is important to define the unique bisector.
|
Chris@16
|
362 // The one site is considered to be newer than the other one if it was
|
Chris@16
|
363 // processed by the algorithm later (has greater index).
|
Chris@16
|
364 template <typename Site>
|
Chris@16
|
365 class beach_line_node_key {
|
Chris@16
|
366 public:
|
Chris@16
|
367 typedef Site site_type;
|
Chris@16
|
368
|
Chris@16
|
369 // Constructs degenerate bisector, used to search an arc that is above
|
Chris@16
|
370 // the given site. The input to the constructor is the new site point.
|
Chris@16
|
371 explicit beach_line_node_key(const site_type &new_site) :
|
Chris@16
|
372 left_site_(new_site),
|
Chris@16
|
373 right_site_(new_site) {}
|
Chris@16
|
374
|
Chris@16
|
375 // Constructs a new bisector. The input to the constructor is the two
|
Chris@16
|
376 // sites that create the bisector. The order of sites is important.
|
Chris@16
|
377 beach_line_node_key(const site_type &left_site,
|
Chris@16
|
378 const site_type &right_site) :
|
Chris@16
|
379 left_site_(left_site),
|
Chris@16
|
380 right_site_(right_site) {}
|
Chris@16
|
381
|
Chris@16
|
382 const site_type &left_site() const {
|
Chris@16
|
383 return left_site_;
|
Chris@16
|
384 }
|
Chris@16
|
385
|
Chris@16
|
386 site_type &left_site() {
|
Chris@16
|
387 return left_site_;
|
Chris@16
|
388 }
|
Chris@16
|
389
|
Chris@16
|
390 beach_line_node_key& left_site(const site_type &site) {
|
Chris@16
|
391 left_site_ = site;
|
Chris@16
|
392 return *this;
|
Chris@16
|
393 }
|
Chris@16
|
394
|
Chris@16
|
395 const site_type &right_site() const {
|
Chris@16
|
396 return right_site_;
|
Chris@16
|
397 }
|
Chris@16
|
398
|
Chris@16
|
399 site_type &right_site() {
|
Chris@16
|
400 return right_site_;
|
Chris@16
|
401 }
|
Chris@16
|
402
|
Chris@16
|
403 beach_line_node_key& right_site(const site_type &site) {
|
Chris@16
|
404 right_site_ = site;
|
Chris@16
|
405 return *this;
|
Chris@16
|
406 }
|
Chris@16
|
407
|
Chris@16
|
408 private:
|
Chris@16
|
409 site_type left_site_;
|
Chris@16
|
410 site_type right_site_;
|
Chris@16
|
411 };
|
Chris@16
|
412
|
Chris@16
|
413 // Represents edge data structure from the Voronoi output, that is
|
Chris@16
|
414 // associated as a value with beach line bisector in the beach
|
Chris@16
|
415 // line. Contains pointer to the circle event in the circle event
|
Chris@16
|
416 // queue if the edge corresponds to the right bisector of the circle event.
|
Chris@16
|
417 template <typename Edge, typename Circle>
|
Chris@16
|
418 class beach_line_node_data {
|
Chris@16
|
419 public:
|
Chris@16
|
420 explicit beach_line_node_data(Edge* new_edge) :
|
Chris@16
|
421 circle_event_(NULL),
|
Chris@16
|
422 edge_(new_edge) {}
|
Chris@16
|
423
|
Chris@16
|
424 Circle* circle_event() const {
|
Chris@16
|
425 return circle_event_;
|
Chris@16
|
426 }
|
Chris@16
|
427
|
Chris@16
|
428 beach_line_node_data& circle_event(Circle* circle_event) {
|
Chris@16
|
429 circle_event_ = circle_event;
|
Chris@16
|
430 return *this;
|
Chris@16
|
431 }
|
Chris@16
|
432
|
Chris@16
|
433 Edge* edge() const {
|
Chris@16
|
434 return edge_;
|
Chris@16
|
435 }
|
Chris@16
|
436
|
Chris@16
|
437 beach_line_node_data& edge(Edge* new_edge) {
|
Chris@16
|
438 edge_ = new_edge;
|
Chris@16
|
439 return *this;
|
Chris@16
|
440 }
|
Chris@16
|
441
|
Chris@16
|
442 private:
|
Chris@16
|
443 Circle* circle_event_;
|
Chris@16
|
444 Edge* edge_;
|
Chris@16
|
445 };
|
Chris@16
|
446 } // detail
|
Chris@16
|
447 } // polygon
|
Chris@16
|
448 } // boost
|
Chris@16
|
449
|
Chris@16
|
450 #endif // BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES
|