Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r77257 - in sandbox/gtl: boost/polygon libs/polygon/test
From: sydorchuk.andriy_at_[hidden]
Date: 2012-03-07 16:40:42


Author: asydorchuk
Date: 2012-03-07 16:40:40 EST (Wed, 07 Mar 2012)
New Revision: 77257
URL: http://svn.boost.org/trac/boost/changeset/77257

Log:
Changing voronoi diagram internal structure:
1) better memory packing;
2) removing num_incident_edges field;
3) adding additional data field.
Text files modified:
   sandbox/gtl/boost/polygon/voronoi_diagram.hpp | 1497 +++++++++++++++++++--------------------
   sandbox/gtl/boost/polygon/voronoi_utils.hpp | 2
   sandbox/gtl/libs/polygon/test/voronoi_builder_test.cpp | 6
   sandbox/gtl/libs/polygon/test/voronoi_test_helper.hpp | 2
   4 files changed, 732 insertions(+), 775 deletions(-)

Modified: sandbox/gtl/boost/polygon/voronoi_diagram.hpp
==============================================================================
--- sandbox/gtl/boost/polygon/voronoi_diagram.hpp (original)
+++ sandbox/gtl/boost/polygon/voronoi_diagram.hpp 2012-03-07 16:40:40 EST (Wed, 07 Mar 2012)
@@ -1,9 +1,9 @@
 // Boost.Polygon library voronoi_diagram.hpp header file
 
-// Copyright Andrii Sydorchuk 2010-2012.
+// Copyright Andrii Sydorchuk 2010-2012.
 // Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
 
 // See http://www.boost.org for updates, documentation, and revision history.
 
@@ -19,769 +19,734 @@
 namespace boost {
 namespace polygon {
 
- // Forward declarations.
- template <typename T>
- class voronoi_edge;
-
- // Bounding rectangle data structure. Contains coordinates
- // of the bottom left and the upper right points of the rectangle.
- template <typename T>
- class bounding_rectangle {
- public:
- typedef T coordinate_type;
-
- bounding_rectangle() {}
-
- bounding_rectangle(T x, T y) {
- x_min_ = x_max_ = x;
- y_min_ = y_max_ = y;
- }
-
- template <typename P>
- bounding_rectangle(const P &p) {
- x_min_ = x_max_ = p.x();
- y_min_ = y_max_ = p.y();
- }
-
- bounding_rectangle(T x1, T y1, T x2, T y2) {
- x_min_ = (std::min)(x1, x2);
- y_min_ = (std::min)(y1, y2);
- x_max_ = (std::max)(x1, x2);
- y_max_ = (std::max)(y1, y2);
- }
-
- template <typename P>
- bounding_rectangle(const P &p1, const P &p2) {
- x_min_ = (std::min)(p1.x(), p2.x());
- y_min_ = (std::min)(p1.y(), p2.y());
- x_max_ = (std::max)(p1.x(), p2.x());
- y_max_ = (std::max)(p1.y(), p2.y());
- }
-
- void update(T x, T y) {
- x_min_ = (std::min)(x_min_, x);
- y_min_ = (std::min)(y_min_, y);
- x_max_ = (std::max)(x_max_, x);
- y_max_ = (std::max)(y_max_, y);
- }
-
- // Extend the rectangle with a new point.
- template <typename P>
- void update(const P &p) {
- x_min_ = (std::min)(x_min_, p.x());
- y_min_ = (std::min)(y_min_, p.y());
- x_max_ = (std::max)(x_max_, p.x());
- y_max_ = (std::max)(y_max_, p.y());
- }
-
- bool contains(T x, T y) const {
- return x >= x_min_ && x <= x_max_ &&
- y >= y_min_ && y <= y_max_;
- }
-
- // Check whether a point is situated inside the bounding rectangle.
- template <typename P>
- bool contains(const P &p) const {
- return p.x() >= x_min_ && p.x() <= x_max_ &&
- p.y() >= y_min_ && p.y() <= y_max_;
- }
-
- // Return the x-coordinate of the bottom left point of the rectangle.
- coordinate_type x_min() const {
- return x_min_;
- }
-
- // Return the y-coordinate of the bottom left point of the rectangle.
- coordinate_type y_min() const {
- return y_min_;
- }
-
- // Return the x-coordinate of the upper right point of the rectangle.
- coordinate_type x_max() const {
- return x_max_;
- }
-
- // Return the y-coordinate of the upper right point of the rectangle.
- coordinate_type y_max() const {
- return y_max_;
- }
-
- coordinate_type min_len() const {
- return (std::min)(x_max_ - x_min_, y_max_ - y_min_);
- }
-
- coordinate_type max_len() const {
- return (std::max)(x_max_ - x_min_, y_max_ - y_min_);
- }
-
- private:
- coordinate_type x_min_;
- coordinate_type y_min_;
- coordinate_type x_max_;
- coordinate_type y_max_;
- };
-
- // Represents voronoi cell.
- // Data members: 1) pointer to the incident edge;
- // 2) site inside the cell;
- // 3) number of incident edges.
- // The cell may contain point or segment site.
- template <typename T>
- class voronoi_cell {
- public:
- typedef T coordinate_type;
- typedef detail::point_2d<coordinate_type> point_type;
- typedef voronoi_edge<coordinate_type> voronoi_edge_type;
-
- voronoi_cell(const point_type &p1, voronoi_edge_type *edge) :
- point0_(p1),
- point1_(p1),
- incident_edge_(edge),
- num_incident_edges_(0) {}
-
- voronoi_cell(const point_type &p1,
- const point_type &p2,
- voronoi_edge_type *edge) :
- point0_(p1),
- point1_(p2),
- incident_edge_(edge),
- num_incident_edges_(0) {}
-
- // Returns true if the cell contains segment site, false else.
- bool contains_segment() const { return point0_ != point1_; }
-
- // Returns site point in case cell contains point site,
- // the first point of the segment site else.
- const point_type &point0() const { return point0_; }
-
- // Returns site point in case cell contains point site,
- // the second point of the segment site else.
- const point_type &point1() const { return point1_; }
-
- voronoi_edge_type *incident_edge() { return incident_edge_; }
- const voronoi_edge_type *incident_edge() const {
- return incident_edge_;
- }
- void incident_edge(voronoi_edge_type *e) { incident_edge_ = e; }
-
- int num_incident_edges() const { return num_incident_edges_; }
- void inc_num_incident_edges() { ++num_incident_edges_; }
- void dec_num_incident_edges() { --num_incident_edges_; }
-
- private:
- point_type point0_;
- point_type point1_;
- voronoi_edge_type *incident_edge_;
- int num_incident_edges_;
- };
-
- // Represents voronoi vertex.
- // Data members: 1) vertex point itself;
- // 2) pointer to the incident edge;
- // 3) number of incident edges.
- template <typename T>
- class voronoi_vertex {
- public:
- typedef T coordinate_type;
- typedef detail::point_2d<T> point_type;
- typedef voronoi_edge<coordinate_type> voronoi_edge_type;
-
- voronoi_vertex(const point_type &vertex,
- voronoi_edge_type *edge) :
- vertex_(vertex),
- incident_edge_(edge),
- num_incident_edges_(3) {}
-
- const point_type &vertex() const { return vertex_; }
-
- voronoi_edge_type *incident_edge() { return incident_edge_; }
- const voronoi_edge_type *incident_edge() const {
- return incident_edge_;
- }
- void incident_edge(voronoi_edge_type *e) { incident_edge_ = e; }
-
- int num_incident_edges() const { return num_incident_edges_; }
- void num_incident_edges(int n) { num_incident_edges_ = n; }
-
- private:
- point_type vertex_;
- voronoi_edge_type *incident_edge_;
- int num_incident_edges_;
- };
-
- // Half-edge data structure. Represents voronoi edge.
- // Variables: 1) pointer to the corresponding cell;
- // 2) pointer to the vertex that is the starting
- // point of the half-edge;
- // 3) pointer to the twin edge;
- // 4) pointer to the CCW/CW next edge.
- // 5) pointer to the CCW/CW prev edge.
- template <typename T>
- class voronoi_edge {
- public:
- typedef T coordinate_type;
- typedef voronoi_cell<coordinate_type> voronoi_cell_type;
- typedef voronoi_vertex<coordinate_type> voronoi_vertex_type;
- typedef voronoi_edge<coordinate_type> voronoi_edge_type;
-
- voronoi_edge() :
- cell_(NULL),
- vertex_(NULL),
- twin_(NULL),
- next_(NULL),
- prev_(NULL) {}
-
- voronoi_cell_type *cell() { return cell_; }
- const voronoi_cell_type *cell() const { return cell_; }
- void cell(voronoi_cell_type *c) { cell_ = c; }
-
- voronoi_vertex_type *vertex0() { return vertex_; }
- const voronoi_vertex_type *vertex0() const { return vertex_; }
- void vertex0(voronoi_vertex_type *v) { vertex_ = v; }
-
- voronoi_vertex_type *vertex1() { return twin_->vertex0(); }
- const voronoi_vertex_type *vertex1() const { return twin_->vertex0(); }
- void vertex1(voronoi_vertex_type *v) { twin_->vertex0(v); }
-
- voronoi_edge_type *twin() { return twin_; }
- const voronoi_edge_type *twin() const { return twin_; }
- void twin(voronoi_edge_type *e) { twin_ = e; }
-
- voronoi_edge_type *next() { return next_; }
- const voronoi_edge_type *next() const { return next_; }
- void next(voronoi_edge_type *e) { next_ = e; }
-
- voronoi_edge_type *prev() { return prev_; }
- const voronoi_edge_type *prev() const { return prev_; }
- void prev(voronoi_edge_type *e) { prev_ = e; }
-
- // Return a pointer to the rotation next edge
- // over the starting point of the half-edge.
- voronoi_edge_type *rot_next() {
- return (vertex_) ? prev_->twin() : NULL;
- }
- const voronoi_edge_type *rot_next() const {
- return (vertex_) ? prev_->twin() : NULL;
- }
-
- // Return a pointer to the rotation prev edge
- // over the starting point of the half-edge.
- voronoi_edge_type *rot_prev() {
- return (vertex_) ? twin_->next() : NULL;
- }
- const voronoi_edge_type *rot_prev() const {
- return (vertex_) ? twin_->next() : NULL;
- }
-
- // Return true if the edge is finite (segment, parabolic arc).
- // Return false if the edge is infinite (ray, line).
- bool is_bounded() const { return vertex0() && vertex1(); }
-
- // Return true if the edge is linear.
- // Return false if the edge is curved (parabolic arc).
- bool is_linear() const {
- return !(cell()->contains_segment() ^
- twin()->cell()->contains_segment());
- }
-
- // Returns true if the edge is curved (parabolic arc).
- // Returns false if the edge is linear.
- bool is_curved() const {
- return (cell()->contains_segment() ^
- twin()->cell()->contains_segment());
- }
-
- // Return false if edge goes through the endpoint of the segment.
- // Return true else.
- bool is_primary() const {
- voronoi_cell_type *cell1 = cell_;
- voronoi_cell_type *cell2 = twin_->cell();
- if (cell1->contains_segment() && !cell2->contains_segment()) {
- if (cell1->point0() == cell2->point0() ||
- cell1->point1() == cell2->point0())
- return false;
- }
- if (cell2->contains_segment() && !cell1->contains_segment()) {
- if (cell2->point0() == cell1->point0() ||
- cell2->point1() == cell1->point0())
- return false;
- }
- return true;
- }
-
- private:
- voronoi_cell_type *cell_;
- voronoi_vertex_type *vertex_;
- voronoi_edge_type *twin_;
- voronoi_edge_type *next_;
- voronoi_edge_type *prev_;
- };
-
- template <typename T>
- struct voronoi_diagram_traits {
- typedef T coordinate_type;
- typedef struct {
- template <typename CT>
- coordinate_type operator()(const CT& value) {
- return static_cast<coordinate_type>(value);
- }
- } ctype_converter_type;
- typedef detail::point_2d<coordinate_type> point_type;
- typedef bounding_rectangle<coordinate_type> brect_type;
- typedef voronoi_cell<coordinate_type> cell_type;
- typedef voronoi_vertex<coordinate_type> vertex_type;
- typedef voronoi_edge<coordinate_type> edge_type;
- typedef class {
- public:
- enum { ULPS = 128 };
- bool operator()(const point_type &v1,
- const point_type &v2) const {
- return (ulp_cmp(v1.x(), v2.x(), ULPS) ==
- detail::ulp_comparison<T>::EQUAL) &&
- (ulp_cmp(v1.y(), v2.y(), ULPS) ==
- detail::ulp_comparison<T>::EQUAL);
- }
- private:
- typename detail::ulp_comparison<T> ulp_cmp;
- } vertex_equality_predicate_type;
- };
-
- // Voronoi output data structure.
- // Data members:
- // 1) cell_records_ - vector of the voronoi cells;
- // 2) vertex_records_ - list of the voronoi vertices;
- // 3) edge_records_ - list of the voronoi edges;
- // 4) voronoi_rect_ - bounding rectangle;
- // 5) num_cell_records_ - number of the voronoi cells;
- // 6) num_vertex_records_ - number of the voronoi vertices;
- // 7) num_edge_records_ - number of the voronoi edges.
- // CCW ordering is used on the faces perimeter and around the vertices.
- // Robust vertices are used to make the simplification stage epsilon
- // robust. Vector data structure is used to store voronoi cells as the
- // number of the cells may be precomputed at the initialization step.
- // As size() method takes O(n) time on the list data structure three
- // additional counters are used to count the number of the voronoi cells,
- // vertices and edges. As we use list data structure to represent voronoi
- // vertices and edges there is no copy method available, because it will
- // invalidate all the pointers. Another approach could be used to make
- // copying available:
- // 1) use vectors to store voronoi vertices and cells;
- // 2) store vector indices instead of the pointers;
- // 3) store additional pointer to the voronoi output data structure
- // in the voronoi cell, vertex, edge data structure.
- // 4) implement simplification via copying not degenerate elements
- // to the new vector as removing elements from a vector takes O(n)
- // time.
- template <typename T, typename TRAITS = voronoi_diagram_traits<T> >
- class voronoi_diagram {
- public:
- typedef typename TRAITS::coordinate_type coordinate_type;
- typedef typename TRAITS::ctype_converter_type ctype_converter_type;
- typedef typename TRAITS::point_type point_type;
- typedef typename TRAITS::brect_type brect_type;
- typedef typename TRAITS::cell_type cell_type;
- typedef typename TRAITS::vertex_type vertex_type;
- typedef typename TRAITS::edge_type edge_type;
- typedef typename TRAITS::vertex_equality_predicate_type
- vertex_equality_predicate_type;
-
- typedef std::vector<cell_type> cell_container_type;
- typedef typename cell_container_type::iterator cell_iterator;
- typedef typename cell_container_type::const_iterator const_cell_iterator;
-
- typedef std::list<vertex_type> vertex_container_type;
- typedef typename vertex_container_type::iterator vertex_iterator;
- typedef typename vertex_container_type::const_iterator const_vertex_iterator;
-
- typedef std::list<edge_type> edge_container_type;
- typedef typename edge_container_type::iterator edge_iterator;
- typedef typename edge_container_type::const_iterator const_edge_iterator;
-
- voronoi_diagram() :
- num_cells_(0),
- num_edges_(0),
- num_vertices_(0) {}
-
- void reserve(int num_sites) {
- cells_.reserve(num_sites);
- }
-
- void clear() {
- cells_.clear();
- vertices_.clear();
- edges_.clear();
-
- num_cells_ = 0;
- num_edges_ = 0;
- num_vertices_ = 0;
- }
-
- const brect_type &bounding_rectangle() const {
- return voronoi_rect_;
- }
-
- const cell_container_type &cells() const {
- return cells_;
- }
-
- const vertex_container_type &vertices() const {
- return vertices_;
- }
-
- const edge_container_type &edges() const {
- return edges_;
- }
-
- unsigned int num_cells() const {
- return num_cells_;
- }
-
- unsigned int num_edges() const {
- return num_edges_;
- }
-
- unsigned int num_vertices() const {
- return num_vertices_;
- }
-
- // Update the voronoi output in case of a single point input.
- template <typename SEvent>
- void process_single_site(const SEvent &site) {
- // Update bounding rectangle.
- point_type p = prepare_point(site.point0());
- voronoi_rect_ = brect_type(p);
-
- // Update cell records.
- cells_.push_back(cell_type(p, NULL));
- }
-
- // Insert a new half-edge into the output data structure.
- // Takes as input left and right sites that form a new bisector.
- // Returns a pointer to a new half-edge.
- template <typename SEvent>
- std::pair<void*, void*> insert_new_edge(const SEvent &site1,
- const SEvent &site2) {
- // Get sites' indexes.
- int site_index1 = site1.index();
- int site_index2 = site2.index();
-
- // Create a new half-edge that belongs to the first site.
- edges_.push_back(edge_type());
- edge_type &edge1 = edges_.back();
-
- // Create a new half-edge that belongs to the second site.
- edges_.push_back(edge_type());
- edge_type &edge2 = edges_.back();
-
- // Add the initial cell during the first edge insertion.
- if (cells_.empty()) {
- process_single_site(site1);
- cells_.back().incident_edge(&edge1);
- }
- cells_[site_index1].inc_num_incident_edges();
-
- // Update the bounding rectangle.
- voronoi_rect_.update(prepare_point(site2.point0()));
-
- // The second site represents a new site during site event
- // processing. Add a new cell to the cell records.
- cells_.push_back(cell_type(
- prepare_point(site2.point0()),
- prepare_point(site2.point1()),
- &edge2));
- cells_.back().inc_num_incident_edges();
-
- // Set up pointers to cells.
- edge1.cell(&cells_[site_index1]);
- edge2.cell(&cells_[site_index2]);
-
- // Set up twin pointers.
- edge1.twin(&edge2);
- edge2.twin(&edge1);
-
- // Return a pointer to the new half-edge.
- return std::make_pair(&edge1, &edge2);
- }
-
- // Insert a new half-edge into the output data structure with the
- // start at the point where two previously added half-edges intersect.
- // Takes as input two sites that create a new bisector, circle event
- // that corresponds to the intersection point of the two old half-edges,
- // pointers to those half-edges. Half-edges' direction goes out of the
- // new voronoi vertex point. Returns a pointer to the new half-edge.
- template <typename SEvent, typename CEvent>
- void *insert_new_edge(const SEvent &site1,
- const SEvent &site3,
- const CEvent &circle,
- void *data12,
- void *data23) {
- edge_type *edge12 = static_cast<edge_type*>(data12);
- edge_type *edge23 = static_cast<edge_type*>(data23);
-
- // Add a new voronoi vertex.
- coordinate_type x = convert_(circle.x());
- coordinate_type y = convert_(circle.y());
- vertices_.push_back(vertex_type(point_type(x, y), edge12));
- vertex_type &new_vertex = vertices_.back();
-
- // Update vertex pointers of the old edges.
- edge12->vertex0(&new_vertex);
- edge23->vertex0(&new_vertex);
-
- // Add a new half-edge.
- edges_.push_back(edge_type());
- edge_type &new_edge1 = edges_.back();
- new_edge1.cell(&cells_[site1.index()]);
- new_edge1.cell()->inc_num_incident_edges();
-
- // Add a new half-edge.
- edges_.push_back(edge_type());
- edge_type &new_edge2 = edges_.back();
- new_edge2.cell(&cells_[site3.index()]);
- new_edge2.cell()->inc_num_incident_edges();
-
- // Update twin pointers.
- new_edge1.twin(&new_edge2);
- new_edge2.twin(&new_edge1);
-
- // Update vertex pointer.
- new_edge2.vertex0(&new_vertex);
-
- // Update voronoi prev/next pointers.
- edge12->prev(&new_edge1);
- new_edge1.next(edge12);
- edge12->twin()->next(edge23);
- edge23->prev(edge12->twin());
- edge23->twin()->next(&new_edge2);
- new_edge2.prev(edge23->twin());
-
- // Return a pointer to the new half-edge.
- return &new_edge1;
- }
-
- // Remove zero-length edges from the voronoi output.
- void clean() {
- edge_iterator edge_it1;
- edge_iterator edge_it = edges_.begin();
- num_cells_ = cells_.size();
-
- // All the initial sites are collinear.
- if (vertices_.empty()) {
- // Update edges counter.
- num_edges_ = num_cells_ - 1;
-
- // Return if there are no edges.
- if (edge_it == edges_.end())
- return;
-
- // Update prev/next pointers of the edges. Those edges won't
- // have any common endpoints, cause they are infinite.
- // But still they follow each other using CCW ordering.
- edge_type *edge1 = &(*edge_it);
- edge1->next(edge1);
- edge1->prev(edge1);
- ++edge_it;
- edge1 = &(*edge_it);
- ++edge_it;
-
- while (edge_it != edges_.end()) {
- edge_type *edge2 = &(*edge_it);
- ++edge_it;
-
- edge1->next(edge2);
- edge1->prev(edge2);
- edge2->next(edge1);
- edge2->prev(edge1);
-
- edge1 = &(*edge_it);
- ++edge_it;
- }
-
- edge1->next(edge1);
- edge1->prev(edge1);
- return;
- }
-
- // Iterate over all the edges and remove degeneracies
- // (zero-length edges). Edge is considered to be zero-length
- // if both its endpoints lie within some epsilon-rectangle.
- while (edge_it != edges_.end()) {
- edge_it1 = edge_it;
- std::advance(edge_it, 2);
-
- // Degenerate edges exist only among finite edges.
- if (!edge_it1->vertex0() || !edge_it1->vertex1()) {
- ++num_edges_;
- continue;
- }
-
- const vertex_type *v1 = edge_it1->vertex0();
- const vertex_type *v2 = edge_it1->vertex1();
-
- // Make epsilon robust check.
- if (vertex_equality_predicate_(v1->vertex(), v2->vertex())) {
- // Decrease number of cell's incident edges.
- edge_it1->cell()->dec_num_incident_edges();
- edge_it1->twin()->cell()->dec_num_incident_edges();
-
- // Corresponding cell incident edge pointer
- // points to the degenerate edge.
- if (edge_it1->cell()->incident_edge() == &(*edge_it1)) {
- // Update incident edge pointer.
- if (edge_it1->cell()->incident_edge() ==
- edge_it1->next()) {
- edge_it1->cell()->incident_edge(NULL);
- } else {
- edge_it1->cell()->incident_edge(edge_it1->next());
- }
- }
-
- // Cell corresponding to the twin edge
- // points to the degenerate edge.
- if (edge_it1->twin()->cell()->incident_edge() ==
- edge_it1->twin()) {
- // Update incident edge pointer.
- if (edge_it1->twin()->cell()->incident_edge() ==
- edge_it1->twin()->next()) {
- edge_it1->twin()->cell()->incident_edge(NULL);
- } else {
- edge_it1->twin()->cell()->incident_edge(
- edge_it1->twin()->next());
- }
- }
-
- // To guarantee O(N) time for all removal operations we
- // merge vertex with less incident edges to the one with
- // more.
- if (v1->num_incident_edges() >= v2->num_incident_edges()) {
- remove_edge(&(*edge_it1));
- } else {
- remove_edge(edge_it1->twin());
- }
-
- // Remove zero-length edge.
- edges_.erase(edge_it1, edge_it);
- } else {
- // Count not degenerate edge.
- ++num_edges_;
- }
- }
-
- // Remove degenerate voronoi vertices with zero incident edges.
- for (vertex_iterator vertex_it =
- vertices_.begin();
- vertex_it != vertices_.end();) {
- if (vertex_it->incident_edge() == NULL) {
- vertex_it = vertices_.erase(vertex_it);
- } else {
- ++vertex_it;
- ++num_vertices_;
- }
- }
-
- // Update prev/next pointers for the ray-edges.
- for (cell_iterator cell_it = cells_.begin();
- cell_it != cells_.end(); ++cell_it) {
- // Move to the previous edge while
- // it is possible in the CW direction.
- edge_type *cur_edge = cell_it->incident_edge();
- if (cur_edge) {
- while (cur_edge->prev() != NULL) {
- cur_edge = cur_edge->prev();
-
- // Terminate if this is not a boundary cell.
- if (cur_edge == cell_it->incident_edge())
- break;
- }
-
- // Rewind incident edge pointer to the
- // CW leftmost edge for the boundary cells.
- cell_it->incident_edge(cur_edge);
-
- // Set up prev/next half-edge pointers for the ray-edges.
- if (cur_edge->prev() == NULL) {
- edge_type *last_edge = cell_it->incident_edge();
- while (last_edge->next() != NULL)
- last_edge = last_edge->next();
- last_edge->next(cur_edge);
- cur_edge->prev(last_edge);
- }
- }
- }
- }
-
- private:
- template <typename CT>
- point_type prepare_point(const CT& x, const CT& y) {
- coordinate_type xc = convert_(x);
- coordinate_type yc = convert_(y);
- return point_type(xc, yc);
- }
-
- template <typename P>
- point_type prepare_point(const P& p) {
- return prepare_point(p.x(), p.y());
- }
-
- // Remove degenerate edge.
- void remove_edge(edge_type *edge) {
- vertex_type *vertex1 = edge->vertex0();
- vertex_type *vertex2 = edge->vertex1();
-
- // Update number of incident edges.
- vertex1->num_incident_edges(vertex1->num_incident_edges() +
- vertex2->num_incident_edges() - 2);
-
- // Update the endpoints of the incident edges to the second vertex.
- edge_type *updated_edge = edge->twin()->rot_next();
- while (updated_edge != edge->twin()) {
- updated_edge->vertex0(vertex1);
- updated_edge = updated_edge->rot_next();
- }
-
- edge_type *edge1 = edge;
- edge_type *edge2 = edge->twin();
-
- edge_type *edge1_rot_prev = edge1->rot_prev();
- edge_type *edge1_rot_next = edge1->rot_next();
-
- edge_type *edge2_rot_prev = edge2->rot_prev();
- edge_type *edge2_rot_next = edge2->rot_next();
-
- // Update prev/next pointers for the incident edges.
- edge1_rot_next->twin()->next(edge2_rot_prev);
- edge2_rot_prev->prev(edge1_rot_next->twin());
- edge1_rot_prev->prev(edge2_rot_next->twin());
- edge2_rot_next->twin()->next(edge1_rot_prev);
-
- // Change the pointer to the incident edge if it points to the
- // degenerate edge.
- if (vertex1->incident_edge() == edge) {
- vertex1->incident_edge(edge->rot_prev());
- }
-
- // Set the incident edge pointer of the second vertex to NULL value.
- if (vertex1 != vertex2) {
- vertex2->incident_edge(NULL);
- }
- }
-
- cell_container_type cells_;
- vertex_container_type vertices_;
- edge_container_type edges_;
-
- unsigned int num_cells_;
- unsigned int num_edges_;
- unsigned int num_vertices_;
-
- brect_type voronoi_rect_;
- ctype_converter_type convert_;
- vertex_equality_predicate_type vertex_equality_predicate_;
-
- // Disallow copy constructor and operator=
- voronoi_diagram(const voronoi_diagram&);
- void operator=(const voronoi_diagram&);
- };
+// Forward declarations.
+template <typename T>
+class voronoi_edge;
+
+// Bounding rectangle data structure. Contains coordinates
+// of the bottom left and the upper right points of the rectangle.
+template <typename T>
+class bounding_rectangle {
+public:
+ typedef T coordinate_type;
+
+ bounding_rectangle() {}
+
+ bounding_rectangle(T x, T y) :
+ x_min_(x),
+ x_max_(x),
+ y_min_(y),
+ y_max_(y) {}
+
+ template <typename P>
+ bounding_rectangle(const P &p) :
+ x_min_(p.x()),
+ x_max_(p.x()),
+ y_min_(p.y()),
+ y_max_(p.y()) {}
+
+ bounding_rectangle(T x1, T y1, T x2, T y2) {
+ x_min_ = (std::min)(x1, x2);
+ y_min_ = (std::min)(y1, y2);
+ x_max_ = (std::max)(x1, x2);
+ y_max_ = (std::max)(y1, y2);
+ }
+
+ template <typename P>
+ bounding_rectangle(const P &p1, const P &p2) {
+ x_min_ = (std::min)(p1.x(), p2.x());
+ y_min_ = (std::min)(p1.y(), p2.y());
+ x_max_ = (std::max)(p1.x(), p2.x());
+ y_max_ = (std::max)(p1.y(), p2.y());
+ }
+
+ void update(T x, T y) {
+ x_min_ = (std::min)(x_min_, x);
+ y_min_ = (std::min)(y_min_, y);
+ x_max_ = (std::max)(x_max_, x);
+ y_max_ = (std::max)(y_max_, y);
+ }
+
+ // Extend the rectangle with a new point.
+ template <typename P>
+ void update(const P &p) {
+ x_min_ = (std::min)(x_min_, p.x());
+ y_min_ = (std::min)(y_min_, p.y());
+ x_max_ = (std::max)(x_max_, p.x());
+ y_max_ = (std::max)(y_max_, p.y());
+ }
+
+ bool contains(T x, T y) const {
+ return x >= x_min_ && x <= x_max_ &&
+ y >= y_min_ && y <= y_max_;
+ }
+
+ // Check whether a point is situated inside the bounding rectangle.
+ template <typename P>
+ bool contains(const P &p) const {
+ return p.x() >= x_min_ && p.x() <= x_max_ &&
+ p.y() >= y_min_ && p.y() <= y_max_;
+ }
+
+ // Return the x-coordinate of the bottom left point of the rectangle.
+ coordinate_type x_min() const {
+ return x_min_;
+ }
+
+ // Return the y-coordinate of the bottom left point of the rectangle.
+ coordinate_type y_min() const {
+ return y_min_;
+ }
+
+ // Return the x-coordinate of the upper right point of the rectangle.
+ coordinate_type x_max() const {
+ return x_max_;
+ }
+
+ // Return the y-coordinate of the upper right point of the rectangle.
+ coordinate_type y_max() const {
+ return y_max_;
+ }
+
+ coordinate_type min_len() const {
+ return (std::min)(x_max_ - x_min_, y_max_ - y_min_);
+ }
+
+ coordinate_type max_len() const {
+ return (std::max)(x_max_ - x_min_, y_max_ - y_min_);
+ }
+
+private:
+ coordinate_type x_min_;
+ coordinate_type y_min_;
+ coordinate_type x_max_;
+ coordinate_type y_max_;
+};
+
+// Represents voronoi cell.
+// Data members: 1) pointer to the incident edge;
+// 2) site inside cell;
+// 3) data associated with a cell.
+// The cell may contain point or segment site.
+template <typename T>
+class voronoi_cell {
+public:
+ typedef T coordinate_type;
+ typedef detail::point_2d<coordinate_type> point_type;
+ typedef voronoi_edge<coordinate_type> voronoi_edge_type;
+
+ voronoi_cell(const point_type &p1, voronoi_edge_type *edge) :
+ point0_(p1),
+ point1_(p1),
+ incident_edge_(edge),
+ data_(NULL) {}
+
+ voronoi_cell(const point_type &p1,
+ const point_type &p2,
+ voronoi_edge_type *edge) :
+ point0_(p1),
+ point1_(p2),
+ incident_edge_(edge),
+ data_(NULL) {}
+
+ // Returns true if the cell contains segment site, false else.
+ bool contains_segment() const { return point0_ != point1_; }
+
+ // Returns site point in case cell contains point site,
+ // the first point of the segment site else.
+ const point_type &point0() const { return point0_; }
+
+ // Returns site point in case cell contains point site,
+ // the second point of the segment site else.
+ const point_type &point1() const { return point1_; }
+
+ voronoi_edge_type *incident_edge() { return incident_edge_; }
+ const voronoi_edge_type *incident_edge() const { return incident_edge_; }
+ void incident_edge(voronoi_edge_type *e) { incident_edge_ = e; }
+
+ void *data() { return data_; }
+ const void *data() const { return data_; }
+ void data(void *d) const { data_ = d; }
+
+private:
+ point_type point0_;
+ point_type point1_;
+ voronoi_edge_type *incident_edge_;
+ mutable void *data_;
+};
+
+// Represents voronoi vertex.
+// Data members: 1) vertex point itself;
+// 2) pointer to the incident edge;
+// 3) data associated with vertex.
+template <typename T>
+class voronoi_vertex {
+public:
+ typedef T coordinate_type;
+ typedef detail::point_2d<T> point_type;
+ typedef voronoi_edge<coordinate_type> voronoi_edge_type;
+
+ voronoi_vertex(const point_type &vertex,
+ voronoi_edge_type *edge) :
+ vertex_(vertex),
+ incident_edge_(edge),
+ data_(NULL) {}
+
+ const point_type &vertex() const { return vertex_; }
+
+ voronoi_edge_type *incident_edge() { return incident_edge_; }
+ const voronoi_edge_type *incident_edge() const { return incident_edge_; }
+ void incident_edge(voronoi_edge_type *e) { incident_edge_ = e; }
+
+ void *data() { return data_; }
+ const void *data() const { return data_; }
+ void data(void *d) const { data_ = d; }
+
+private:
+ point_type vertex_;
+ voronoi_edge_type *incident_edge_;
+ mutable void *data_;
+};
+
+// Half-edge data structure. Represents voronoi edge.
+// Variables: 1) pointer to the corresponding cell;
+// 2) pointer to the vertex that is the starting
+// point of the half-edge;
+// 3) pointer to the twin edge;
+// 4) pointer to the CCW next edge;
+// 5) pointer to the CCW prev edge;
+// 6) pointer to data associated with edge.
+template <typename T>
+class voronoi_edge {
+public:
+ typedef T coordinate_type;
+ typedef voronoi_cell<coordinate_type> voronoi_cell_type;
+ typedef voronoi_vertex<coordinate_type> voronoi_vertex_type;
+ typedef voronoi_edge<coordinate_type> voronoi_edge_type;
+
+ voronoi_edge() :
+ cell_(NULL),
+ vertex_(NULL),
+ twin_(NULL),
+ next_(NULL),
+ prev_(NULL),
+ data_(NULL) {}
+
+ voronoi_cell_type *cell() { return cell_; }
+ const voronoi_cell_type *cell() const { return cell_; }
+ void cell(voronoi_cell_type *c) { cell_ = c; }
+
+ voronoi_vertex_type *vertex0() { return vertex_; }
+ const voronoi_vertex_type *vertex0() const { return vertex_; }
+ void vertex0(voronoi_vertex_type *v) { vertex_ = v; }
+
+ voronoi_vertex_type *vertex1() { return twin_->vertex0(); }
+ const voronoi_vertex_type *vertex1() const { return twin_->vertex0(); }
+ void vertex1(voronoi_vertex_type *v) { twin_->vertex0(v); }
+
+ voronoi_edge_type *twin() { return twin_; }
+ const voronoi_edge_type *twin() const { return twin_; }
+ void twin(voronoi_edge_type *e) { twin_ = e; }
+
+ voronoi_edge_type *next() { return next_; }
+ const voronoi_edge_type *next() const { return next_; }
+ void next(voronoi_edge_type *e) { next_ = e; }
+
+ voronoi_edge_type *prev() { return prev_; }
+ const voronoi_edge_type *prev() const { return prev_; }
+ void prev(voronoi_edge_type *e) { prev_ = e; }
+
+ void *data() { return data_; }
+ const void *data() const { return data_; }
+ void data(void *d) const { data_ = d; }
+
+ // Return a pointer to the rotation next edge
+ // over the starting point of the half-edge.
+ voronoi_edge_type *rot_next() {
+ return (vertex_) ? prev_->twin() : NULL;
+ }
+ const voronoi_edge_type *rot_next() const {
+ return (vertex_) ? prev_->twin() : NULL;
+ }
+
+ // Return a pointer to the rotation prev edge
+ // over the starting point of the half-edge.
+ voronoi_edge_type *rot_prev() {
+ return (vertex_) ? twin_->next() : NULL;
+ }
+ const voronoi_edge_type *rot_prev() const {
+ return (vertex_) ? twin_->next() : NULL;
+ }
+
+ // Return true if the edge is finite (segment, parabolic arc).
+ // Return false if the edge is infinite (ray, line).
+ bool is_bounded() const { return vertex0() && vertex1(); }
+
+ // Return true if the edge is linear.
+ // Return false if the edge is curved (parabolic arc).
+ bool is_linear() const {
+ return !(cell()->contains_segment() ^ twin()->cell()->contains_segment());
+ }
+
+ // Returns true if the edge is curved (parabolic arc).
+ // Returns false if the edge is linear.
+ bool is_curved() const {
+ return (cell()->contains_segment() ^ twin()->cell()->contains_segment());
+ }
+
+ // Return false if edge goes through the endpoint of the segment.
+ // Return true else.
+ bool is_primary() const {
+ voronoi_cell_type *cell1 = cell_;
+ voronoi_cell_type *cell2 = twin_->cell();
+ if (cell1->contains_segment() && !cell2->contains_segment()) {
+ if (cell1->point0() == cell2->point0() ||
+ cell1->point1() == cell2->point0())
+ return false;
+ }
+ if (cell2->contains_segment() && !cell1->contains_segment()) {
+ if (cell2->point0() == cell1->point0() ||
+ cell2->point1() == cell1->point0())
+ return false;
+ }
+ return true;
+ }
+
+private:
+ voronoi_cell_type *cell_;
+ voronoi_vertex_type *vertex_;
+ voronoi_edge_type *twin_;
+ voronoi_edge_type *next_;
+ voronoi_edge_type *prev_;
+ mutable void *data_;
+};
+
+template <typename T>
+struct voronoi_diagram_traits {
+ typedef T coordinate_type;
+ typedef struct {
+ template <typename CT>
+ coordinate_type operator()(const CT& value) {
+ return static_cast<coordinate_type>(value);
+ }
+ } ctype_converter_type;
+ typedef detail::point_2d<coordinate_type> point_type;
+ typedef bounding_rectangle<coordinate_type> brect_type;
+ typedef voronoi_cell<coordinate_type> cell_type;
+ typedef voronoi_vertex<coordinate_type> vertex_type;
+ typedef voronoi_edge<coordinate_type> edge_type;
+ typedef class {
+ public:
+ enum { ULPS = 128 };
+ bool operator()(const point_type &v1, const point_type &v2) const {
+ return (ulp_cmp(v1.x(), v2.x(), ULPS) ==
+ detail::ulp_comparison<T>::EQUAL) &&
+ (ulp_cmp(v1.y(), v2.y(), ULPS) ==
+ detail::ulp_comparison<T>::EQUAL);
+ }
+ private:
+ typename detail::ulp_comparison<T> ulp_cmp;
+ } vertex_equality_predicate_type;
+};
+
+// Voronoi output data structure.
+// Data members:
+// 1) cells_ - vector of the voronoi cells;
+// 2) vertices_ - list of the voronoi vertices;
+// 3) edges_ - list of the voronoi edges;
+// 4) vrect_ - bounding rectangle;
+// 5) num_cells_ - number of the voronoi cells;
+// 6) num_vertices_ - number of the voronoi vertices;
+// 7) num_edges_ - number of the voronoi edges.
+// CCW ordering is used on the faces perimeter and around the vertices.
+template <typename T, typename TRAITS = voronoi_diagram_traits<T> >
+class voronoi_diagram {
+public:
+ typedef typename TRAITS::coordinate_type coordinate_type;
+ typedef typename TRAITS::ctype_converter_type ctype_converter_type;
+ typedef typename TRAITS::point_type point_type;
+ typedef typename TRAITS::brect_type brect_type;
+ typedef typename TRAITS::cell_type cell_type;
+ typedef typename TRAITS::vertex_type vertex_type;
+ typedef typename TRAITS::edge_type edge_type;
+ typedef typename TRAITS::vertex_equality_predicate_type
+ vertex_equality_predicate_type;
+
+ typedef std::vector<cell_type> cell_container_type;
+ typedef typename cell_container_type::iterator cell_iterator;
+ typedef typename cell_container_type::const_iterator const_cell_iterator;
+
+ typedef std::list<vertex_type> vertex_container_type;
+ typedef typename vertex_container_type::iterator vertex_iterator;
+ typedef typename vertex_container_type::const_iterator const_vertex_iterator;
+
+ typedef std::list<edge_type> edge_container_type;
+ typedef typename edge_container_type::iterator edge_iterator;
+ typedef typename edge_container_type::const_iterator const_edge_iterator;
+
+ voronoi_diagram() :
+ num_cells_(0),
+ num_edges_(0),
+ num_vertices_(0) {}
+
+ void reserve(int num_sites) {
+ cells_.reserve(num_sites);
+ }
+
+ void clear() {
+ cells_.clear();
+ vertices_.clear();
+ edges_.clear();
+
+ num_cells_ = 0;
+ num_edges_ = 0;
+ num_vertices_ = 0;
+ }
+
+ const brect_type &bounding_rectangle() const {
+ return vrect_;
+ }
+
+ const cell_container_type &cells() const {
+ return cells_;
+ }
+
+ const vertex_container_type &vertices() const {
+ return vertices_;
+ }
+
+ const edge_container_type &edges() const {
+ return edges_;
+ }
+
+ unsigned int num_cells() const {
+ return num_cells_;
+ }
+
+ unsigned int num_edges() const {
+ return num_edges_;
+ }
+
+ unsigned int num_vertices() const {
+ return num_vertices_;
+ }
+
+ // Update the voronoi output in case of a single point input.
+ template <typename SEvent>
+ void process_single_site(const SEvent &site) {
+ // Update bounding rectangle.
+ point_type p = prepare_point(site.point0());
+ vrect_ = brect_type(p);
+
+ // Update cell records.
+ cells_.push_back(cell_type(p, NULL));
+ }
+
+ // Insert a new half-edge into the output data structure.
+ // Takes as input left and right sites that form a new bisector.
+ // Returns a pair of pointers to a new half-edges.
+ template <typename SEvent>
+ std::pair<void*, void*> insert_new_edge(
+ const SEvent &site1, const SEvent &site2) {
+ // Get sites' indices.
+ int site_index1 = site1.index();
+ int site_index2 = site2.index();
+
+ // Create a new half-edge that belongs to the first site.
+ edges_.push_back(edge_type());
+ edge_type &edge1 = edges_.back();
+
+ // Create a new half-edge that belongs to the second site.
+ edges_.push_back(edge_type());
+ edge_type &edge2 = edges_.back();
+
+ // Add the initial cell during the first edge insertion.
+ if (cells_.empty()) {
+ process_single_site(site1);
+ cells_.back().incident_edge(&edge1);
+ }
+
+ // Update the bounding rectangle.
+ vrect_.update(prepare_point(site2.point0()));
+
+ // The second site represents a new site during site event
+ // processing. Add a new cell to the cell records.
+ cells_.push_back(cell_type(prepare_point(site2.point0()),
+ prepare_point(site2.point1()),
+ &edge2));
+
+ // Set up pointers to cells.
+ edge1.cell(&cells_[site_index1]);
+ edge2.cell(&cells_[site_index2]);
+
+ // Set up twin pointers.
+ edge1.twin(&edge2);
+ edge2.twin(&edge1);
+
+ // Return a pointer to the new half-edge.
+ return std::make_pair(&edge1, &edge2);
+ }
+
+ // Insert a new half-edge into the output data structure with the
+ // start at the point where two previously added half-edges intersect.
+ // Takes as input two sites that create a new bisector, circle event
+ // that corresponds to the intersection point of the two old half-edges,
+ // pointers to those half-edges. Half-edges' direction goes out of the
+ // new voronoi vertex point. Returns a pointer to the new half-edge.
+ template <typename SEvent, typename CEvent>
+ void *insert_new_edge(
+ const SEvent &site1, const SEvent &site3, const CEvent &circle,
+ void *data12, void *data23) {
+ edge_type *edge12 = static_cast<edge_type*>(data12);
+ edge_type *edge23 = static_cast<edge_type*>(data23);
+
+ // Add a new voronoi vertex.
+ coordinate_type x = convert_(circle.x());
+ coordinate_type y = convert_(circle.y());
+ vertices_.push_back(vertex_type(point_type(x, y), edge12));
+ vertex_type &new_vertex = vertices_.back();
+
+ // Update vertex pointers of the old edges.
+ edge12->vertex0(&new_vertex);
+ edge23->vertex0(&new_vertex);
+
+ // Add a new half-edge.
+ edges_.push_back(edge_type());
+ edge_type &new_edge1 = edges_.back();
+ new_edge1.cell(&cells_[site1.index()]);
+
+ // Add a new half-edge.
+ edges_.push_back(edge_type());
+ edge_type &new_edge2 = edges_.back();
+ new_edge2.cell(&cells_[site3.index()]);
+
+ // Update twin pointers.
+ new_edge1.twin(&new_edge2);
+ new_edge2.twin(&new_edge1);
+
+ // Update vertex pointer.
+ new_edge2.vertex0(&new_vertex);
+
+ // Update voronoi prev/next pointers.
+ edge12->prev(&new_edge1);
+ new_edge1.next(edge12);
+ edge12->twin()->next(edge23);
+ edge23->prev(edge12->twin());
+ edge23->twin()->next(&new_edge2);
+ new_edge2.prev(edge23->twin());
+
+ // Return a pointer to the new half-edge.
+ return &new_edge1;
+ }
+
+ // Remove zero-length edges from the voronoi output.
+ void clean() {
+ edge_iterator edge_it1;
+ edge_iterator edge_it = edges_.begin();
+ num_cells_ = cells_.size();
+
+ // All the initial sites are collinear.
+ if (vertices_.empty()) {
+ // Update edges counter.
+ num_edges_ = num_cells_ - 1;
+
+ // Return if there are no edges.
+ if (edge_it == edges_.end())
+ return;
+
+ // Update prev/next pointers of the edges. Those edges won't
+ // have any common endpoints, cause they are infinite.
+ // But still they follow each other using CCW ordering.
+ edge_type *edge1 = &(*edge_it);
+ edge1->next(edge1);
+ edge1->prev(edge1);
+ ++edge_it;
+ edge1 = &(*edge_it);
+ ++edge_it;
+
+ while (edge_it != edges_.end()) {
+ edge_type *edge2 = &(*edge_it);
+ ++edge_it;
+
+ edge1->next(edge2);
+ edge1->prev(edge2);
+ edge2->next(edge1);
+ edge2->prev(edge1);
+
+ edge1 = &(*edge_it);
+ ++edge_it;
+ }
+
+ edge1->next(edge1);
+ edge1->prev(edge1);
+ return;
+ }
+
+ // Iterate over all the edges and remove degeneracies
+ // (zero-length edges). Edge is considered to be zero-length
+ // if both its endpoints lie within some epsilon-rectangle.
+ while (edge_it != edges_.end()) {
+ edge_it1 = edge_it;
+ std::advance(edge_it, 2);
+
+ // Degenerate edges exist only among finite edges.
+ if (!edge_it1->vertex0() || !edge_it1->vertex1()) {
+ ++num_edges_;
+ continue;
+ }
+
+ const vertex_type *v1 = edge_it1->vertex0();
+ const vertex_type *v2 = edge_it1->vertex1();
+
+ // Make epsilon robust check.
+ if (vertex_equality_predicate_(v1->vertex(), v2->vertex())) {
+ // Corresponding cell incident edge pointer
+ // points to the degenerate edge.
+ if (edge_it1->cell()->incident_edge() == &(*edge_it1)) {
+ // Update incident edge pointer.
+ if (edge_it1->cell()->incident_edge() ==
+ edge_it1->next()) {
+ edge_it1->cell()->incident_edge(NULL);
+ } else {
+ edge_it1->cell()->incident_edge(edge_it1->next());
+ }
+ }
+
+ // Cell corresponding to the twin edge
+ // points to the degenerate edge.
+ if (edge_it1->twin()->cell()->incident_edge() ==
+ edge_it1->twin()) {
+ // Update incident edge pointer.
+ if (edge_it1->twin()->cell()->incident_edge() ==
+ edge_it1->twin()->next()) {
+ edge_it1->twin()->cell()->incident_edge(NULL);
+ } else {
+ edge_it1->twin()->cell()->incident_edge(
+ edge_it1->twin()->next());
+ }
+ }
+
+ remove_edge(&(*edge_it1));
+
+ // Remove zero-length edge.
+ edges_.erase(edge_it1, edge_it);
+ } else {
+ // Count not degenerate edge.
+ ++num_edges_;
+ }
+ }
+
+ // Remove degenerate voronoi vertices with zero incident edges.
+ for (vertex_iterator vertex_it =
+ vertices_.begin();
+ vertex_it != vertices_.end();) {
+ if (vertex_it->incident_edge() == NULL) {
+ vertex_it = vertices_.erase(vertex_it);
+ } else {
+ ++vertex_it;
+ ++num_vertices_;
+ }
+ }
+
+ // Update prev/next pointers for the ray-edges.
+ for (cell_iterator cell_it = cells_.begin();
+ cell_it != cells_.end(); ++cell_it) {
+ // Move to the previous edge while
+ // it is possible in the CW direction.
+ edge_type *cur_edge = cell_it->incident_edge();
+ if (cur_edge) {
+ while (cur_edge->prev() != NULL) {
+ cur_edge = cur_edge->prev();
+
+ // Terminate if this is not a boundary cell.
+ if (cur_edge == cell_it->incident_edge())
+ break;
+ }
+
+ // Rewind incident edge pointer to the
+ // CW leftmost edge for the boundary cells.
+ cell_it->incident_edge(cur_edge);
+
+ // Set up prev/next half-edge pointers for the ray-edges.
+ if (cur_edge->prev() == NULL) {
+ edge_type *last_edge = cell_it->incident_edge();
+ while (last_edge->next() != NULL)
+ last_edge = last_edge->next();
+ last_edge->next(cur_edge);
+ cur_edge->prev(last_edge);
+ }
+ }
+ }
+ }
+
+private:
+ template <typename CT>
+ point_type prepare_point(const CT& x, const CT& y) {
+ coordinate_type nx = convert_(x);
+ coordinate_type ny = convert_(y);
+ return point_type(nx, ny);
+ }
+
+ template <typename P>
+ point_type prepare_point(const P& p) {
+ return prepare_point(p.x(), p.y());
+ }
+
+ // Remove degenerate edge.
+ void remove_edge(edge_type *edge) {
+ vertex_type *vertex1 = edge->vertex0();
+ vertex_type *vertex2 = edge->vertex1();
+
+ // Update the endpoints of the incident edges to the second vertex.
+ edge_type *updated_edge = edge->twin()->rot_next();
+ while (updated_edge != edge->twin()) {
+ updated_edge->vertex0(vertex1);
+ updated_edge = updated_edge->rot_next();
+ }
+
+ edge_type *edge1 = edge;
+ edge_type *edge2 = edge->twin();
+
+ edge_type *edge1_rot_prev = edge1->rot_prev();
+ edge_type *edge1_rot_next = edge1->rot_next();
+
+ edge_type *edge2_rot_prev = edge2->rot_prev();
+ edge_type *edge2_rot_next = edge2->rot_next();
+
+ // Update prev/next pointers for the incident edges.
+ edge1_rot_next->twin()->next(edge2_rot_prev);
+ edge2_rot_prev->prev(edge1_rot_next->twin());
+ edge1_rot_prev->prev(edge2_rot_next->twin());
+ edge2_rot_next->twin()->next(edge1_rot_prev);
+
+ // Change the pointer to the incident edge if it points to the
+ // degenerate edge.
+ if (vertex1->incident_edge() == edge) {
+ vertex1->incident_edge(edge->rot_prev());
+ }
+
+ // Set the incident edge pointer of the second vertex to NULL value.
+ if (vertex1 != vertex2) {
+ vertex2->incident_edge(NULL);
+ }
+ }
+
+ cell_container_type cells_;
+ vertex_container_type vertices_;
+ edge_container_type edges_;
+
+ unsigned int num_cells_;
+ unsigned int num_edges_;
+ unsigned int num_vertices_;
+
+ brect_type vrect_;
+ ctype_converter_type convert_;
+ vertex_equality_predicate_type vertex_equality_predicate_;
+
+ // Disallow copy constructor and operator=
+ voronoi_diagram(const voronoi_diagram&);
+ void operator=(const voronoi_diagram&);
+};
 } // polygon
 } // boost
 

Modified: sandbox/gtl/boost/polygon/voronoi_utils.hpp
==============================================================================
--- sandbox/gtl/boost/polygon/voronoi_utils.hpp (original)
+++ sandbox/gtl/boost/polygon/voronoi_utils.hpp 2012-03-07 16:40:40 EST (Wed, 07 Mar 2012)
@@ -30,7 +30,7 @@
   typedef bounding_rectangle<coordinate_type> brect_type;
   typedef struct {
     template <typename CT>
- coordinate_type operator()(const CT& value) {
+ coordinate_type operator()(const CT& value) const {
         return static_cast<coordinate_type>(value);
     }
   } ctype_converter_type;

Modified: sandbox/gtl/libs/polygon/test/voronoi_builder_test.cpp
==============================================================================
--- sandbox/gtl/libs/polygon/test/voronoi_builder_test.cpp (original)
+++ sandbox/gtl/libs/polygon/test/voronoi_builder_test.cpp 2012-03-07 16:40:40 EST (Wed, 07 Mar 2012)
@@ -69,7 +69,6 @@
     CHECK_OUTPUT_SIZE(test_output, 1, 0, 0);
 
     const_cell_iterator it = test_output.cells().begin();
- BOOST_CHECK(it->num_incident_edges() == 0);
     BOOST_CHECK(it->incident_edge() == NULL);
 }
 
@@ -86,9 +85,7 @@
     CHECK_OUTPUT_SIZE(test_output, 2, 0, 1);
 
     const_cell_iterator cell_it = test_output.cells().begin();
- BOOST_CHECK_EQUAL(cell_it->num_incident_edges(), 1);
     cell_it++;
- BOOST_CHECK_EQUAL(cell_it->num_incident_edges(), 1);
 
     const voronoi_edge_type *edge1_1 = cell_it->incident_edge();
     const voronoi_edge_type *edge1_2 = edge1_1->twin();
@@ -121,13 +118,10 @@
     CHECK_OUTPUT_SIZE(test_output, 3, 0, 2);
 
     const_cell_iterator cell_it = test_output.cells().begin();
- BOOST_CHECK_EQUAL(cell_it->num_incident_edges(), 1);
     const voronoi_edge_type *edge1_1 = cell_it->incident_edge();
     const voronoi_edge_type *edge1_2 = edge1_1->twin();
     cell_it++;
- BOOST_CHECK_EQUAL(cell_it->num_incident_edges(), 2);
     cell_it++;
- BOOST_CHECK_EQUAL(cell_it->num_incident_edges(), 1);
     const voronoi_edge_type *edge2_2 = cell_it->incident_edge();
     const voronoi_edge_type *edge2_1 = edge2_2->twin();
 

Modified: sandbox/gtl/libs/polygon/test/voronoi_test_helper.hpp
==============================================================================
--- sandbox/gtl/libs/polygon/test/voronoi_test_helper.hpp (original)
+++ sandbox/gtl/libs/polygon/test/voronoi_test_helper.hpp 2012-03-07 16:40:40 EST (Wed, 07 Mar 2012)
@@ -88,8 +88,6 @@
     typename Output::const_vertex_iterator vertex_it;
     for (vertex_it = output.vertices().begin();
          vertex_it != output.vertices().end(); vertex_it++) {
- if (vertex_it->num_incident_edges() < 3)
- continue;
         const voronoi_edge_type *edge = vertex_it->incident_edge();
         do {
             const voronoi_edge_type *edge_next1 = edge->rot_next();


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk