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