Chris@16
|
1 // Boost.Polygon library voronoi_diagram.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_DIAGRAM
|
Chris@16
|
11 #define BOOST_POLYGON_VORONOI_DIAGRAM
|
Chris@16
|
12
|
Chris@16
|
13 #include <vector>
|
Chris@16
|
14 #include <utility>
|
Chris@16
|
15
|
Chris@16
|
16 #include "detail/voronoi_ctypes.hpp"
|
Chris@16
|
17 #include "detail/voronoi_structures.hpp"
|
Chris@16
|
18
|
Chris@16
|
19 #include "voronoi_geometry_type.hpp"
|
Chris@16
|
20
|
Chris@16
|
21 namespace boost {
|
Chris@16
|
22 namespace polygon {
|
Chris@16
|
23
|
Chris@16
|
24 // Forward declarations.
|
Chris@16
|
25 template <typename T>
|
Chris@16
|
26 class voronoi_edge;
|
Chris@16
|
27
|
Chris@16
|
28 // Represents Voronoi cell.
|
Chris@16
|
29 // Data members:
|
Chris@16
|
30 // 1) index of the source within the initial input set
|
Chris@16
|
31 // 2) pointer to the incident edge
|
Chris@16
|
32 // 3) mutable color member
|
Chris@16
|
33 // Cell may contain point or segment site inside.
|
Chris@16
|
34 template <typename T>
|
Chris@16
|
35 class voronoi_cell {
|
Chris@16
|
36 public:
|
Chris@16
|
37 typedef T coordinate_type;
|
Chris@16
|
38 typedef std::size_t color_type;
|
Chris@16
|
39 typedef voronoi_edge<coordinate_type> voronoi_edge_type;
|
Chris@16
|
40 typedef std::size_t source_index_type;
|
Chris@16
|
41 typedef SourceCategory source_category_type;
|
Chris@16
|
42
|
Chris@16
|
43 voronoi_cell(source_index_type source_index,
|
Chris@16
|
44 source_category_type source_category) :
|
Chris@16
|
45 source_index_(source_index),
|
Chris@16
|
46 incident_edge_(NULL),
|
Chris@16
|
47 color_(source_category) {}
|
Chris@16
|
48
|
Chris@16
|
49 // Returns true if the cell contains point site, false else.
|
Chris@16
|
50 bool contains_point() const {
|
Chris@16
|
51 source_category_type source_category = this->source_category();
|
Chris@16
|
52 return belongs(source_category, GEOMETRY_CATEGORY_POINT);
|
Chris@16
|
53 }
|
Chris@16
|
54
|
Chris@16
|
55 // Returns true if the cell contains segment site, false else.
|
Chris@16
|
56 bool contains_segment() const {
|
Chris@16
|
57 source_category_type source_category = this->source_category();
|
Chris@16
|
58 return belongs(source_category, GEOMETRY_CATEGORY_SEGMENT);
|
Chris@16
|
59 }
|
Chris@16
|
60
|
Chris@16
|
61 source_index_type source_index() const {
|
Chris@16
|
62 return source_index_;
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 source_category_type source_category() const {
|
Chris@16
|
66 return static_cast<source_category_type>(color_ & SOURCE_CATEGORY_BITMASK);
|
Chris@16
|
67 }
|
Chris@16
|
68
|
Chris@16
|
69 // Degenerate cells don't have any incident edges.
|
Chris@16
|
70 bool is_degenerate() const { return incident_edge_ == NULL; }
|
Chris@16
|
71
|
Chris@16
|
72 voronoi_edge_type* incident_edge() { return incident_edge_; }
|
Chris@16
|
73 const voronoi_edge_type* incident_edge() const { return incident_edge_; }
|
Chris@16
|
74 void incident_edge(voronoi_edge_type* e) { incident_edge_ = e; }
|
Chris@16
|
75
|
Chris@16
|
76 color_type color() const { return color_ >> BITS_SHIFT; }
|
Chris@16
|
77 void color(color_type color) const {
|
Chris@16
|
78 color_ &= BITS_MASK;
|
Chris@16
|
79 color_ |= color << BITS_SHIFT;
|
Chris@16
|
80 }
|
Chris@16
|
81
|
Chris@16
|
82 private:
|
Chris@16
|
83 // 5 color bits are reserved.
|
Chris@16
|
84 enum Bits {
|
Chris@16
|
85 BITS_SHIFT = 0x5,
|
Chris@16
|
86 BITS_MASK = 0x1F
|
Chris@16
|
87 };
|
Chris@16
|
88
|
Chris@16
|
89 source_index_type source_index_;
|
Chris@16
|
90 voronoi_edge_type* incident_edge_;
|
Chris@16
|
91 mutable color_type color_;
|
Chris@16
|
92 };
|
Chris@16
|
93
|
Chris@16
|
94 // Represents Voronoi vertex.
|
Chris@16
|
95 // Data members:
|
Chris@16
|
96 // 1) vertex coordinates
|
Chris@16
|
97 // 2) pointer to the incident edge
|
Chris@16
|
98 // 3) mutable color member
|
Chris@16
|
99 template <typename T>
|
Chris@16
|
100 class voronoi_vertex {
|
Chris@16
|
101 public:
|
Chris@16
|
102 typedef T coordinate_type;
|
Chris@16
|
103 typedef std::size_t color_type;
|
Chris@16
|
104 typedef voronoi_edge<coordinate_type> voronoi_edge_type;
|
Chris@16
|
105
|
Chris@16
|
106 voronoi_vertex(const coordinate_type& x, const coordinate_type& y) :
|
Chris@16
|
107 x_(x),
|
Chris@16
|
108 y_(y),
|
Chris@16
|
109 incident_edge_(NULL),
|
Chris@16
|
110 color_(0) {}
|
Chris@16
|
111
|
Chris@16
|
112 const coordinate_type& x() const { return x_; }
|
Chris@16
|
113 const coordinate_type& y() const { return y_; }
|
Chris@16
|
114
|
Chris@16
|
115 bool is_degenerate() const { return incident_edge_ == NULL; }
|
Chris@16
|
116
|
Chris@16
|
117 voronoi_edge_type* incident_edge() { return incident_edge_; }
|
Chris@16
|
118 const voronoi_edge_type* incident_edge() const { return incident_edge_; }
|
Chris@16
|
119 void incident_edge(voronoi_edge_type* e) { incident_edge_ = e; }
|
Chris@16
|
120
|
Chris@16
|
121 color_type color() const { return color_ >> BITS_SHIFT; }
|
Chris@16
|
122 void color(color_type color) const {
|
Chris@16
|
123 color_ &= BITS_MASK;
|
Chris@16
|
124 color_ |= color << BITS_SHIFT;
|
Chris@16
|
125 }
|
Chris@16
|
126
|
Chris@16
|
127 private:
|
Chris@16
|
128 // 5 color bits are reserved.
|
Chris@16
|
129 enum Bits {
|
Chris@16
|
130 BITS_SHIFT = 0x5,
|
Chris@16
|
131 BITS_MASK = 0x1F
|
Chris@16
|
132 };
|
Chris@16
|
133
|
Chris@16
|
134 coordinate_type x_;
|
Chris@16
|
135 coordinate_type y_;
|
Chris@16
|
136 voronoi_edge_type* incident_edge_;
|
Chris@16
|
137 mutable color_type color_;
|
Chris@16
|
138 };
|
Chris@16
|
139
|
Chris@16
|
140 // Half-edge data structure. Represents Voronoi edge.
|
Chris@16
|
141 // Data members:
|
Chris@16
|
142 // 1) pointer to the corresponding cell
|
Chris@16
|
143 // 2) pointer to the vertex that is the starting
|
Chris@16
|
144 // point of the half-edge
|
Chris@16
|
145 // 3) pointer to the twin edge
|
Chris@16
|
146 // 4) pointer to the CCW next edge
|
Chris@16
|
147 // 5) pointer to the CCW prev edge
|
Chris@16
|
148 // 6) mutable color member
|
Chris@16
|
149 template <typename T>
|
Chris@16
|
150 class voronoi_edge {
|
Chris@16
|
151 public:
|
Chris@16
|
152 typedef T coordinate_type;
|
Chris@16
|
153 typedef voronoi_cell<coordinate_type> voronoi_cell_type;
|
Chris@16
|
154 typedef voronoi_vertex<coordinate_type> voronoi_vertex_type;
|
Chris@16
|
155 typedef voronoi_edge<coordinate_type> voronoi_edge_type;
|
Chris@16
|
156 typedef std::size_t color_type;
|
Chris@16
|
157
|
Chris@16
|
158 voronoi_edge(bool is_linear, bool is_primary) :
|
Chris@16
|
159 cell_(NULL),
|
Chris@16
|
160 vertex_(NULL),
|
Chris@16
|
161 twin_(NULL),
|
Chris@16
|
162 next_(NULL),
|
Chris@16
|
163 prev_(NULL),
|
Chris@16
|
164 color_(0) {
|
Chris@16
|
165 if (is_linear)
|
Chris@16
|
166 color_ |= BIT_IS_LINEAR;
|
Chris@16
|
167 if (is_primary)
|
Chris@16
|
168 color_ |= BIT_IS_PRIMARY;
|
Chris@16
|
169 }
|
Chris@16
|
170
|
Chris@16
|
171 voronoi_cell_type* cell() { return cell_; }
|
Chris@16
|
172 const voronoi_cell_type* cell() const { return cell_; }
|
Chris@16
|
173 void cell(voronoi_cell_type* c) { cell_ = c; }
|
Chris@16
|
174
|
Chris@16
|
175 voronoi_vertex_type* vertex0() { return vertex_; }
|
Chris@16
|
176 const voronoi_vertex_type* vertex0() const { return vertex_; }
|
Chris@16
|
177 void vertex0(voronoi_vertex_type* v) { vertex_ = v; }
|
Chris@16
|
178
|
Chris@16
|
179 voronoi_vertex_type* vertex1() { return twin_->vertex0(); }
|
Chris@16
|
180 const voronoi_vertex_type* vertex1() const { return twin_->vertex0(); }
|
Chris@16
|
181
|
Chris@16
|
182 voronoi_edge_type* twin() { return twin_; }
|
Chris@16
|
183 const voronoi_edge_type* twin() const { return twin_; }
|
Chris@16
|
184 void twin(voronoi_edge_type* e) { twin_ = e; }
|
Chris@16
|
185
|
Chris@16
|
186 voronoi_edge_type* next() { return next_; }
|
Chris@16
|
187 const voronoi_edge_type* next() const { return next_; }
|
Chris@16
|
188 void next(voronoi_edge_type* e) { next_ = e; }
|
Chris@16
|
189
|
Chris@16
|
190 voronoi_edge_type* prev() { return prev_; }
|
Chris@16
|
191 const voronoi_edge_type* prev() const { return prev_; }
|
Chris@16
|
192 void prev(voronoi_edge_type* e) { prev_ = e; }
|
Chris@16
|
193
|
Chris@16
|
194 // Returns a pointer to the rotation next edge
|
Chris@16
|
195 // over the starting point of the half-edge.
|
Chris@16
|
196 voronoi_edge_type* rot_next() { return prev_->twin(); }
|
Chris@16
|
197 const voronoi_edge_type* rot_next() const { return prev_->twin(); }
|
Chris@16
|
198
|
Chris@16
|
199 // Returns a pointer to the rotation prev edge
|
Chris@16
|
200 // over the starting point of the half-edge.
|
Chris@16
|
201 voronoi_edge_type* rot_prev() { return twin_->next(); }
|
Chris@16
|
202 const voronoi_edge_type* rot_prev() const { return twin_->next(); }
|
Chris@16
|
203
|
Chris@16
|
204 // Returns true if the edge is finite (segment, parabolic arc).
|
Chris@16
|
205 // Returns false if the edge is infinite (ray, line).
|
Chris@16
|
206 bool is_finite() const { return vertex0() && vertex1(); }
|
Chris@16
|
207
|
Chris@16
|
208 // Returns true if the edge is infinite (ray, line).
|
Chris@16
|
209 // Returns false if the edge is finite (segment, parabolic arc).
|
Chris@16
|
210 bool is_infinite() const { return !vertex0() || !vertex1(); }
|
Chris@16
|
211
|
Chris@16
|
212 // Returns true if the edge is linear (segment, ray, line).
|
Chris@16
|
213 // Returns false if the edge is curved (parabolic arc).
|
Chris@16
|
214 bool is_linear() const {
|
Chris@16
|
215 return (color_ & BIT_IS_LINEAR) ? true : false;
|
Chris@16
|
216 }
|
Chris@16
|
217
|
Chris@16
|
218 // Returns true if the edge is curved (parabolic arc).
|
Chris@16
|
219 // Returns false if the edge is linear (segment, ray, line).
|
Chris@16
|
220 bool is_curved() const {
|
Chris@16
|
221 return (color_ & BIT_IS_LINEAR) ? false : true;
|
Chris@16
|
222 }
|
Chris@16
|
223
|
Chris@16
|
224 // Returns false if edge goes through the endpoint of the segment.
|
Chris@16
|
225 // Returns true else.
|
Chris@16
|
226 bool is_primary() const {
|
Chris@16
|
227 return (color_ & BIT_IS_PRIMARY) ? true : false;
|
Chris@16
|
228 }
|
Chris@16
|
229
|
Chris@16
|
230 // Returns true if edge goes through the endpoint of the segment.
|
Chris@16
|
231 // Returns false else.
|
Chris@16
|
232 bool is_secondary() const {
|
Chris@16
|
233 return (color_ & BIT_IS_PRIMARY) ? false : true;
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 color_type color() const { return color_ >> BITS_SHIFT; }
|
Chris@16
|
237 void color(color_type color) const {
|
Chris@16
|
238 color_ &= BITS_MASK;
|
Chris@16
|
239 color_ |= color << BITS_SHIFT;
|
Chris@16
|
240 }
|
Chris@16
|
241
|
Chris@16
|
242 private:
|
Chris@16
|
243 // 5 color bits are reserved.
|
Chris@16
|
244 enum Bits {
|
Chris@16
|
245 BIT_IS_LINEAR = 0x1, // linear is opposite to curved
|
Chris@16
|
246 BIT_IS_PRIMARY = 0x2, // primary is opposite to secondary
|
Chris@16
|
247
|
Chris@16
|
248 BITS_SHIFT = 0x5,
|
Chris@16
|
249 BITS_MASK = 0x1F
|
Chris@16
|
250 };
|
Chris@16
|
251
|
Chris@16
|
252 voronoi_cell_type* cell_;
|
Chris@16
|
253 voronoi_vertex_type* vertex_;
|
Chris@16
|
254 voronoi_edge_type* twin_;
|
Chris@16
|
255 voronoi_edge_type* next_;
|
Chris@16
|
256 voronoi_edge_type* prev_;
|
Chris@16
|
257 mutable color_type color_;
|
Chris@16
|
258 };
|
Chris@16
|
259
|
Chris@16
|
260 template <typename T>
|
Chris@16
|
261 struct voronoi_diagram_traits {
|
Chris@16
|
262 typedef T coordinate_type;
|
Chris@16
|
263 typedef voronoi_cell<coordinate_type> cell_type;
|
Chris@16
|
264 typedef voronoi_vertex<coordinate_type> vertex_type;
|
Chris@16
|
265 typedef voronoi_edge<coordinate_type> edge_type;
|
Chris@16
|
266 typedef class {
|
Chris@16
|
267 public:
|
Chris@16
|
268 enum { ULPS = 128 };
|
Chris@16
|
269 bool operator()(const vertex_type& v1, const vertex_type& v2) const {
|
Chris@16
|
270 return (ulp_cmp(v1.x(), v2.x(), ULPS) ==
|
Chris@16
|
271 detail::ulp_comparison<T>::EQUAL) &&
|
Chris@16
|
272 (ulp_cmp(v1.y(), v2.y(), ULPS) ==
|
Chris@16
|
273 detail::ulp_comparison<T>::EQUAL);
|
Chris@16
|
274 }
|
Chris@16
|
275 private:
|
Chris@16
|
276 typename detail::ulp_comparison<T> ulp_cmp;
|
Chris@16
|
277 } vertex_equality_predicate_type;
|
Chris@16
|
278 };
|
Chris@16
|
279
|
Chris@16
|
280 // Voronoi output data structure.
|
Chris@16
|
281 // CCW ordering is used on the faces perimeter and around the vertices.
|
Chris@16
|
282 template <typename T, typename TRAITS = voronoi_diagram_traits<T> >
|
Chris@16
|
283 class voronoi_diagram {
|
Chris@16
|
284 public:
|
Chris@16
|
285 typedef typename TRAITS::coordinate_type coordinate_type;
|
Chris@16
|
286 typedef typename TRAITS::cell_type cell_type;
|
Chris@16
|
287 typedef typename TRAITS::vertex_type vertex_type;
|
Chris@16
|
288 typedef typename TRAITS::edge_type edge_type;
|
Chris@16
|
289
|
Chris@16
|
290 typedef std::vector<cell_type> cell_container_type;
|
Chris@16
|
291 typedef typename cell_container_type::const_iterator const_cell_iterator;
|
Chris@16
|
292
|
Chris@16
|
293 typedef std::vector<vertex_type> vertex_container_type;
|
Chris@16
|
294 typedef typename vertex_container_type::const_iterator const_vertex_iterator;
|
Chris@16
|
295
|
Chris@16
|
296 typedef std::vector<edge_type> edge_container_type;
|
Chris@16
|
297 typedef typename edge_container_type::const_iterator const_edge_iterator;
|
Chris@16
|
298
|
Chris@16
|
299 voronoi_diagram() {}
|
Chris@16
|
300
|
Chris@16
|
301 void clear() {
|
Chris@16
|
302 cells_.clear();
|
Chris@16
|
303 vertices_.clear();
|
Chris@16
|
304 edges_.clear();
|
Chris@16
|
305 }
|
Chris@16
|
306
|
Chris@16
|
307 const cell_container_type& cells() const {
|
Chris@16
|
308 return cells_;
|
Chris@16
|
309 }
|
Chris@16
|
310
|
Chris@16
|
311 const vertex_container_type& vertices() const {
|
Chris@16
|
312 return vertices_;
|
Chris@16
|
313 }
|
Chris@16
|
314
|
Chris@16
|
315 const edge_container_type& edges() const {
|
Chris@16
|
316 return edges_;
|
Chris@16
|
317 }
|
Chris@16
|
318
|
Chris@16
|
319 std::size_t num_cells() const {
|
Chris@16
|
320 return cells_.size();
|
Chris@16
|
321 }
|
Chris@16
|
322
|
Chris@16
|
323 std::size_t num_edges() const {
|
Chris@16
|
324 return edges_.size();
|
Chris@16
|
325 }
|
Chris@16
|
326
|
Chris@16
|
327 std::size_t num_vertices() const {
|
Chris@16
|
328 return vertices_.size();
|
Chris@16
|
329 }
|
Chris@16
|
330
|
Chris@16
|
331 void _reserve(std::size_t num_sites) {
|
Chris@16
|
332 cells_.reserve(num_sites);
|
Chris@16
|
333 vertices_.reserve(num_sites << 1);
|
Chris@16
|
334 edges_.reserve((num_sites << 2) + (num_sites << 1));
|
Chris@16
|
335 }
|
Chris@16
|
336
|
Chris@16
|
337 template <typename CT>
|
Chris@16
|
338 void _process_single_site(const detail::site_event<CT>& site) {
|
Chris@16
|
339 cells_.push_back(cell_type(site.initial_index(), site.source_category()));
|
Chris@16
|
340 }
|
Chris@16
|
341
|
Chris@16
|
342 // Insert a new half-edge into the output data structure.
|
Chris@16
|
343 // Takes as input left and right sites that form a new bisector.
|
Chris@16
|
344 // Returns a pair of pointers to a new half-edges.
|
Chris@16
|
345 template <typename CT>
|
Chris@16
|
346 std::pair<void*, void*> _insert_new_edge(
|
Chris@16
|
347 const detail::site_event<CT>& site1,
|
Chris@16
|
348 const detail::site_event<CT>& site2) {
|
Chris@16
|
349 // Get sites' indexes.
|
Chris@16
|
350 int site_index1 = site1.sorted_index();
|
Chris@16
|
351 int site_index2 = site2.sorted_index();
|
Chris@16
|
352
|
Chris@16
|
353 bool is_linear = is_linear_edge(site1, site2);
|
Chris@16
|
354 bool is_primary = is_primary_edge(site1, site2);
|
Chris@16
|
355
|
Chris@16
|
356 // Create a new half-edge that belongs to the first site.
|
Chris@16
|
357 edges_.push_back(edge_type(is_linear, is_primary));
|
Chris@16
|
358 edge_type& edge1 = edges_.back();
|
Chris@16
|
359
|
Chris@16
|
360 // Create a new half-edge that belongs to the second site.
|
Chris@16
|
361 edges_.push_back(edge_type(is_linear, is_primary));
|
Chris@16
|
362 edge_type& edge2 = edges_.back();
|
Chris@16
|
363
|
Chris@16
|
364 // Add the initial cell during the first edge insertion.
|
Chris@16
|
365 if (cells_.empty()) {
|
Chris@16
|
366 cells_.push_back(cell_type(
|
Chris@16
|
367 site1.initial_index(), site1.source_category()));
|
Chris@16
|
368 }
|
Chris@16
|
369
|
Chris@16
|
370 // The second site represents a new site during site event
|
Chris@16
|
371 // processing. Add a new cell to the cell records.
|
Chris@16
|
372 cells_.push_back(cell_type(
|
Chris@16
|
373 site2.initial_index(), site2.source_category()));
|
Chris@16
|
374
|
Chris@16
|
375 // Set up pointers to cells.
|
Chris@16
|
376 edge1.cell(&cells_[site_index1]);
|
Chris@16
|
377 edge2.cell(&cells_[site_index2]);
|
Chris@16
|
378
|
Chris@16
|
379 // Set up twin pointers.
|
Chris@16
|
380 edge1.twin(&edge2);
|
Chris@16
|
381 edge2.twin(&edge1);
|
Chris@16
|
382
|
Chris@16
|
383 // Return a pointer to the new half-edge.
|
Chris@16
|
384 return std::make_pair(&edge1, &edge2);
|
Chris@16
|
385 }
|
Chris@16
|
386
|
Chris@16
|
387 // Insert a new half-edge into the output data structure with the
|
Chris@16
|
388 // start at the point where two previously added half-edges intersect.
|
Chris@16
|
389 // Takes as input two sites that create a new bisector, circle event
|
Chris@16
|
390 // that corresponds to the intersection point of the two old half-edges,
|
Chris@16
|
391 // pointers to those half-edges. Half-edges' direction goes out of the
|
Chris@16
|
392 // new Voronoi vertex point. Returns a pair of pointers to a new half-edges.
|
Chris@16
|
393 template <typename CT1, typename CT2>
|
Chris@16
|
394 std::pair<void*, void*> _insert_new_edge(
|
Chris@16
|
395 const detail::site_event<CT1>& site1,
|
Chris@16
|
396 const detail::site_event<CT1>& site3,
|
Chris@16
|
397 const detail::circle_event<CT2>& circle,
|
Chris@16
|
398 void* data12, void* data23) {
|
Chris@16
|
399 edge_type* edge12 = static_cast<edge_type*>(data12);
|
Chris@16
|
400 edge_type* edge23 = static_cast<edge_type*>(data23);
|
Chris@16
|
401
|
Chris@16
|
402 // Add a new Voronoi vertex.
|
Chris@16
|
403 vertices_.push_back(vertex_type(circle.x(), circle.y()));
|
Chris@16
|
404 vertex_type& new_vertex = vertices_.back();
|
Chris@16
|
405
|
Chris@16
|
406 // Update vertex pointers of the old edges.
|
Chris@16
|
407 edge12->vertex0(&new_vertex);
|
Chris@16
|
408 edge23->vertex0(&new_vertex);
|
Chris@16
|
409
|
Chris@16
|
410 bool is_linear = is_linear_edge(site1, site3);
|
Chris@16
|
411 bool is_primary = is_primary_edge(site1, site3);
|
Chris@16
|
412
|
Chris@16
|
413 // Add a new half-edge.
|
Chris@16
|
414 edges_.push_back(edge_type(is_linear, is_primary));
|
Chris@16
|
415 edge_type& new_edge1 = edges_.back();
|
Chris@16
|
416 new_edge1.cell(&cells_[site1.sorted_index()]);
|
Chris@16
|
417
|
Chris@16
|
418 // Add a new half-edge.
|
Chris@16
|
419 edges_.push_back(edge_type(is_linear, is_primary));
|
Chris@16
|
420 edge_type& new_edge2 = edges_.back();
|
Chris@16
|
421 new_edge2.cell(&cells_[site3.sorted_index()]);
|
Chris@16
|
422
|
Chris@16
|
423 // Update twin pointers.
|
Chris@16
|
424 new_edge1.twin(&new_edge2);
|
Chris@16
|
425 new_edge2.twin(&new_edge1);
|
Chris@16
|
426
|
Chris@16
|
427 // Update vertex pointer.
|
Chris@16
|
428 new_edge2.vertex0(&new_vertex);
|
Chris@16
|
429
|
Chris@16
|
430 // Update Voronoi prev/next pointers.
|
Chris@16
|
431 edge12->prev(&new_edge1);
|
Chris@16
|
432 new_edge1.next(edge12);
|
Chris@16
|
433 edge12->twin()->next(edge23);
|
Chris@16
|
434 edge23->prev(edge12->twin());
|
Chris@16
|
435 edge23->twin()->next(&new_edge2);
|
Chris@16
|
436 new_edge2.prev(edge23->twin());
|
Chris@16
|
437
|
Chris@16
|
438 // Return a pointer to the new half-edge.
|
Chris@16
|
439 return std::make_pair(&new_edge1, &new_edge2);
|
Chris@16
|
440 }
|
Chris@16
|
441
|
Chris@16
|
442 void _build() {
|
Chris@16
|
443 // Remove degenerate edges.
|
Chris@16
|
444 edge_iterator last_edge = edges_.begin();
|
Chris@16
|
445 for (edge_iterator it = edges_.begin(); it != edges_.end(); it += 2) {
|
Chris@16
|
446 const vertex_type* v1 = it->vertex0();
|
Chris@16
|
447 const vertex_type* v2 = it->vertex1();
|
Chris@16
|
448 if (v1 && v2 && vertex_equality_predicate_(*v1, *v2)) {
|
Chris@16
|
449 remove_edge(&(*it));
|
Chris@16
|
450 } else {
|
Chris@16
|
451 if (it != last_edge) {
|
Chris@16
|
452 edge_type* e1 = &(*last_edge = *it);
|
Chris@16
|
453 edge_type* e2 = &(*(last_edge + 1) = *(it + 1));
|
Chris@16
|
454 e1->twin(e2);
|
Chris@16
|
455 e2->twin(e1);
|
Chris@16
|
456 if (e1->prev()) {
|
Chris@16
|
457 e1->prev()->next(e1);
|
Chris@16
|
458 e2->next()->prev(e2);
|
Chris@16
|
459 }
|
Chris@16
|
460 if (e2->prev()) {
|
Chris@16
|
461 e1->next()->prev(e1);
|
Chris@16
|
462 e2->prev()->next(e2);
|
Chris@16
|
463 }
|
Chris@16
|
464 }
|
Chris@16
|
465 last_edge += 2;
|
Chris@16
|
466 }
|
Chris@16
|
467 }
|
Chris@16
|
468 edges_.erase(last_edge, edges_.end());
|
Chris@16
|
469
|
Chris@16
|
470 // Set up incident edge pointers for cells and vertices.
|
Chris@16
|
471 for (edge_iterator it = edges_.begin(); it != edges_.end(); ++it) {
|
Chris@16
|
472 it->cell()->incident_edge(&(*it));
|
Chris@16
|
473 if (it->vertex0()) {
|
Chris@16
|
474 it->vertex0()->incident_edge(&(*it));
|
Chris@16
|
475 }
|
Chris@16
|
476 }
|
Chris@16
|
477
|
Chris@16
|
478 // Remove degenerate vertices.
|
Chris@16
|
479 vertex_iterator last_vertex = vertices_.begin();
|
Chris@16
|
480 for (vertex_iterator it = vertices_.begin(); it != vertices_.end(); ++it) {
|
Chris@16
|
481 if (it->incident_edge()) {
|
Chris@16
|
482 if (it != last_vertex) {
|
Chris@16
|
483 *last_vertex = *it;
|
Chris@16
|
484 vertex_type* v = &(*last_vertex);
|
Chris@16
|
485 edge_type* e = v->incident_edge();
|
Chris@16
|
486 do {
|
Chris@16
|
487 e->vertex0(v);
|
Chris@16
|
488 e = e->rot_next();
|
Chris@16
|
489 } while (e != v->incident_edge());
|
Chris@16
|
490 }
|
Chris@16
|
491 ++last_vertex;
|
Chris@16
|
492 }
|
Chris@16
|
493 }
|
Chris@16
|
494 vertices_.erase(last_vertex, vertices_.end());
|
Chris@16
|
495
|
Chris@16
|
496 // Set up next/prev pointers for infinite edges.
|
Chris@16
|
497 if (vertices_.empty()) {
|
Chris@16
|
498 if (!edges_.empty()) {
|
Chris@16
|
499 // Update prev/next pointers for the line edges.
|
Chris@16
|
500 edge_iterator edge_it = edges_.begin();
|
Chris@16
|
501 edge_type* edge1 = &(*edge_it);
|
Chris@16
|
502 edge1->next(edge1);
|
Chris@16
|
503 edge1->prev(edge1);
|
Chris@16
|
504 ++edge_it;
|
Chris@16
|
505 edge1 = &(*edge_it);
|
Chris@16
|
506 ++edge_it;
|
Chris@16
|
507
|
Chris@16
|
508 while (edge_it != edges_.end()) {
|
Chris@16
|
509 edge_type* edge2 = &(*edge_it);
|
Chris@16
|
510 ++edge_it;
|
Chris@16
|
511
|
Chris@16
|
512 edge1->next(edge2);
|
Chris@16
|
513 edge1->prev(edge2);
|
Chris@16
|
514 edge2->next(edge1);
|
Chris@16
|
515 edge2->prev(edge1);
|
Chris@16
|
516
|
Chris@16
|
517 edge1 = &(*edge_it);
|
Chris@16
|
518 ++edge_it;
|
Chris@16
|
519 }
|
Chris@16
|
520
|
Chris@16
|
521 edge1->next(edge1);
|
Chris@16
|
522 edge1->prev(edge1);
|
Chris@16
|
523 }
|
Chris@16
|
524 } else {
|
Chris@16
|
525 // Update prev/next pointers for the ray edges.
|
Chris@16
|
526 for (cell_iterator cell_it = cells_.begin();
|
Chris@16
|
527 cell_it != cells_.end(); ++cell_it) {
|
Chris@16
|
528 if (cell_it->is_degenerate())
|
Chris@16
|
529 continue;
|
Chris@16
|
530 // Move to the previous edge while
|
Chris@16
|
531 // it is possible in the CW direction.
|
Chris@16
|
532 edge_type* left_edge = cell_it->incident_edge();
|
Chris@16
|
533 while (left_edge->prev() != NULL) {
|
Chris@16
|
534 left_edge = left_edge->prev();
|
Chris@16
|
535 // Terminate if this is not a boundary cell.
|
Chris@16
|
536 if (left_edge == cell_it->incident_edge())
|
Chris@16
|
537 break;
|
Chris@16
|
538 }
|
Chris@16
|
539
|
Chris@16
|
540 if (left_edge->prev() != NULL)
|
Chris@16
|
541 continue;
|
Chris@16
|
542
|
Chris@16
|
543 edge_type* right_edge = cell_it->incident_edge();
|
Chris@16
|
544 while (right_edge->next() != NULL)
|
Chris@16
|
545 right_edge = right_edge->next();
|
Chris@16
|
546 left_edge->prev(right_edge);
|
Chris@16
|
547 right_edge->next(left_edge);
|
Chris@16
|
548 }
|
Chris@16
|
549 }
|
Chris@16
|
550 }
|
Chris@16
|
551
|
Chris@16
|
552 private:
|
Chris@16
|
553 typedef typename cell_container_type::iterator cell_iterator;
|
Chris@16
|
554 typedef typename vertex_container_type::iterator vertex_iterator;
|
Chris@16
|
555 typedef typename edge_container_type::iterator edge_iterator;
|
Chris@16
|
556 typedef typename TRAITS::vertex_equality_predicate_type
|
Chris@16
|
557 vertex_equality_predicate_type;
|
Chris@16
|
558
|
Chris@16
|
559 template <typename SEvent>
|
Chris@16
|
560 bool is_primary_edge(const SEvent& site1, const SEvent& site2) const {
|
Chris@16
|
561 bool flag1 = site1.is_segment();
|
Chris@16
|
562 bool flag2 = site2.is_segment();
|
Chris@16
|
563 if (flag1 && !flag2) {
|
Chris@16
|
564 return (site1.point0() != site2.point0()) &&
|
Chris@16
|
565 (site1.point1() != site2.point0());
|
Chris@16
|
566 }
|
Chris@16
|
567 if (!flag1 && flag2) {
|
Chris@16
|
568 return (site2.point0() != site1.point0()) &&
|
Chris@16
|
569 (site2.point1() != site1.point0());
|
Chris@16
|
570 }
|
Chris@16
|
571 return true;
|
Chris@16
|
572 }
|
Chris@16
|
573
|
Chris@16
|
574 template <typename SEvent>
|
Chris@16
|
575 bool is_linear_edge(const SEvent& site1, const SEvent& site2) const {
|
Chris@16
|
576 if (!is_primary_edge(site1, site2)) {
|
Chris@16
|
577 return true;
|
Chris@16
|
578 }
|
Chris@16
|
579 return !(site1.is_segment() ^ site2.is_segment());
|
Chris@16
|
580 }
|
Chris@16
|
581
|
Chris@16
|
582 // Remove degenerate edge.
|
Chris@16
|
583 void remove_edge(edge_type* edge) {
|
Chris@16
|
584 // Update the endpoints of the incident edges to the second vertex.
|
Chris@16
|
585 vertex_type* vertex = edge->vertex0();
|
Chris@16
|
586 edge_type* updated_edge = edge->twin()->rot_next();
|
Chris@16
|
587 while (updated_edge != edge->twin()) {
|
Chris@16
|
588 updated_edge->vertex0(vertex);
|
Chris@16
|
589 updated_edge = updated_edge->rot_next();
|
Chris@16
|
590 }
|
Chris@16
|
591
|
Chris@16
|
592 edge_type* edge1 = edge;
|
Chris@16
|
593 edge_type* edge2 = edge->twin();
|
Chris@16
|
594
|
Chris@16
|
595 edge_type* edge1_rot_prev = edge1->rot_prev();
|
Chris@16
|
596 edge_type* edge1_rot_next = edge1->rot_next();
|
Chris@16
|
597
|
Chris@16
|
598 edge_type* edge2_rot_prev = edge2->rot_prev();
|
Chris@16
|
599 edge_type* edge2_rot_next = edge2->rot_next();
|
Chris@16
|
600
|
Chris@16
|
601 // Update prev/next pointers for the incident edges.
|
Chris@16
|
602 edge1_rot_next->twin()->next(edge2_rot_prev);
|
Chris@16
|
603 edge2_rot_prev->prev(edge1_rot_next->twin());
|
Chris@16
|
604 edge1_rot_prev->prev(edge2_rot_next->twin());
|
Chris@16
|
605 edge2_rot_next->twin()->next(edge1_rot_prev);
|
Chris@16
|
606 }
|
Chris@16
|
607
|
Chris@16
|
608 cell_container_type cells_;
|
Chris@16
|
609 vertex_container_type vertices_;
|
Chris@16
|
610 edge_container_type edges_;
|
Chris@16
|
611 vertex_equality_predicate_type vertex_equality_predicate_;
|
Chris@16
|
612
|
Chris@16
|
613 // Disallow copy constructor and operator=
|
Chris@16
|
614 voronoi_diagram(const voronoi_diagram&);
|
Chris@16
|
615 void operator=(const voronoi_diagram&);
|
Chris@16
|
616 };
|
Chris@16
|
617 } // polygon
|
Chris@16
|
618 } // boost
|
Chris@16
|
619
|
Chris@16
|
620 #endif // BOOST_POLYGON_VORONOI_DIAGRAM
|