// Copyright (c) 2005 Rijksuniversiteit Groningen (Netherlands) // All rights reserved. // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0+ // // // Author(s) : Nico Kruithof #ifndef CGAL_COMPUTE_ANCHOR_3_H #define CGAL_COMPUTE_ANCHOR_3_H #include #include #include namespace CGAL { template < class RegularTriangulation_3> class Compute_anchor_3 { public: typedef RegularTriangulation_3 Regular_triangulation; typedef typename Regular_triangulation::Geom_traits Geom_traits; typedef typename Geom_traits::Weighted_point_3 Weighted_point; typedef typename RegularTriangulation_3::Vertex_handle Vertex_handle; typedef typename RegularTriangulation_3::Cell_handle Cell_handle; typedef typename RegularTriangulation_3::Facet Facet; typedef typename RegularTriangulation_3::Edge Edge; typedef typename RegularTriangulation_3::Finite_vertices_iterator Finite_vertices_iterator; typedef typename RegularTriangulation_3::Finite_edges_iterator Finite_edges_iterator; typedef typename RegularTriangulation_3::Finite_facets_iterator Finite_facets_iterator; typedef typename RegularTriangulation_3::Finite_cells_iterator Finite_cells_iterator; typedef typename RegularTriangulation_3::Facet_circulator Facet_circulator; typedef Triangulation_simplex_3 Simplex; typedef typename std::list::iterator Simplex_iterator; Compute_anchor_3(const RegularTriangulation_3 ®) : reg(reg) { } Simplex anchor_del( const Vertex_handle v ) { equiv_anchors.clear(); return v; } Simplex anchor_del( const Edge &e ) { return compute_anchor_del(e); } Simplex anchor_del( const Facet &f ) { return compute_anchor_del(f); } Simplex anchor_del( const Cell_handle ch ) { return compute_anchor_del(ch); } Simplex anchor_del( const Simplex &s ) { int dim = s.dimension(); if (dim == 0) { Vertex_handle vh = s; return anchor_del(vh); } else if (dim == 1) { Edge e = s; return anchor_del(e); } else if (dim == 2) { Facet f = s; return anchor_del(f); } else if (dim == 3) { Cell_handle ch = s; return anchor_del(ch); } CGAL_error(); return Simplex(); } Simplex anchor_vor( const Vertex_handle v ) { return compute_anchor_vor(v); } Simplex anchor_vor( const Edge &e ) { return compute_anchor_vor(e); } Simplex anchor_vor( const Facet &f ) { return compute_anchor_vor(f); } Simplex anchor_vor( const Cell_handle ch ) { equiv_anchors.clear(); for (int i=0; i<4; i++) { Cell_handle ch2 = ch->neighbor(i); if (!reg.is_infinite(ch2)) { Sign side = test_anchor(ch,ch2); CGAL_assertion(test_anchor(ch2,ch)==side); if (side==ZERO) { equiv_anchors.push_back(ch2); } else { CGAL_assertion(side==POSITIVE); } } } return ch; } Simplex anchor_vor( const Simplex &s ) { int dim = s.dimension(); if (dim == 0) { return anchor_vor(Vertex_handle(s)); } else if (dim == 1) { return anchor_vor(Edge(s)); } else if (dim == 2) { return anchor_vor(Facet(s)); } else if (dim == 3) { return anchor_vor(Cell_handle(s)); } return Simplex(); } bool is_degenerate() { return !equiv_anchors.empty(); } Simplex_iterator equivalent_anchors_begin() { return equiv_anchors.begin(); } Simplex_iterator equivalent_anchors_end() { return equiv_anchors.end(); } private: /////////////////////////////// // Anchor functions /////////////////////////////// Simplex compute_anchor_del( Edge const &e ); Simplex compute_anchor_del( Facet const &f ); Simplex compute_anchor_del( Cell_handle const ch ); Simplex compute_anchor_vor( Vertex_handle const v ); Simplex compute_anchor_vor( Edge const &e ); Simplex compute_anchor_vor( Facet const &f ); // Test whether the anchor of edge (wp1,wp2) and wp2 are equal Sign test_anchor(Weighted_point &wp1, Weighted_point &wp2) { return enum_cast( -reg.geom_traits().power_side_of_bounded_power_sphere_3_object()(wp1, wp2)); } Sign test_anchor(Weighted_point const& wp1, Weighted_point const& wp2, Weighted_point const& wp3) { return enum_cast( - reg.geom_traits().power_side_of_bounded_power_sphere_3_object()(wp1, wp2, wp3)); } Sign test_anchor(Weighted_point const& wp1, Weighted_point const& wp2, Weighted_point const& wp3, Weighted_point const& wp4) { return enum_cast( -reg.geom_traits().power_side_of_bounded_power_sphere_3_object()(wp1, wp2, wp3, wp4)); } // Test whether the anchor of e and anchor of e.first->vertex(i) are equal Sign test_anchor(Edge e, int i) { CGAL_assertion(!reg.is_infinite(e)); CGAL_assertion(e.second == i || e.third == i); Weighted_point wp1, wp2; Cell_handle ch = e.first; return test_anchor( ch->vertex(e.second+e.third-i)->point(), ch->vertex(i)->point()); } // Test whether the anchor of f and anchor of the edge f - f.first->vertex(i) // are equal Sign test_anchor(Facet f, int i) { CGAL_assertion(!reg.is_infinite(f)); CGAL_assertion(f.second != i); CGAL_assertion(0<=f.second && f.second<4); CGAL_assertion(0<=i && i<4); Weighted_point wp1, wp2, wp3; Cell_handle ch = f.first; wp3 = ch->vertex(i)->point(); switch ((4+i-f.second)&3) { case 1: CGAL_assertion (((f.second+1)&3) == i); wp1 = ch->vertex((f.second+2)&3)->point(); wp2 = ch->vertex((f.second+3)&3)->point(); break; case 2: CGAL_assertion (((f.second+2)&3) == i); wp1 = ch->vertex((f.second+1)&3)->point(); wp2 = ch->vertex((f.second+3)&3)->point(); break; case 3: CGAL_assertion (((f.second+3)&3) == i); wp1 = ch->vertex((f.second+1)&3)->point(); wp2 = ch->vertex((f.second+2)&3)->point(); break; default: CGAL_error(); } return enum_cast( -reg.geom_traits().power_side_of_bounded_power_sphere_3_object()(wp1, wp2, wp3)); } // Test whether the anchor of ch and anchor of the facet (ch,i) are equal Sign test_anchor(Cell_handle ch, int i) { CGAL_assertion(!reg.is_infinite(ch)); return enum_cast( - reg.geom_traits().power_side_of_bounded_power_sphere_3_object()( ch->vertex((i+1)&3)->point(), ch->vertex((i+2)&3)->point(), ch->vertex((i+3)&3)->point(), ch->vertex(i)->point())); } Sign test_anchor(Cell_handle ch, Cell_handle ch2) { CGAL_assertion(!reg.is_infinite(ch)); CGAL_assertion(!reg.is_infinite(ch2)); int index = ch2->index(ch); return enum_cast( -reg.geom_traits().power_side_of_bounded_power_sphere_3_object()( ch->vertex(0)->point(), ch->vertex(1)->point(), ch->vertex(2)->point(), ch->vertex(3)->point(), ch2->vertex(index)->point())); } Sign test_anchor(Weighted_point const& wp1, Weighted_point const& wp2, Weighted_point const& wp3, Weighted_point const& wp4, Weighted_point const& wp5) { return enum_cast( -reg.geom_traits().power_side_of_bounded_power_sphere_3_object()(wp1, wp2, wp3, wp4, wp5)); } const Regular_triangulation ® std::list equiv_anchors; }; // compute_anchor_del template < class RegularTriangulation3 > typename Compute_anchor_3::Simplex Compute_anchor_3:: compute_anchor_del(Edge const &e) { CGAL_assertion(!reg.is_infinite(e)); equiv_anchors.clear(); Sign result = test_anchor(e, e.second); if (result==NEGATIVE) { return Simplex(e.first->vertex(e.third)); } else if (result==ZERO) { equiv_anchors.push_back(Simplex(e.first->vertex(e.third))); } result = test_anchor(e, e.third); if (result==NEGATIVE) { equiv_anchors.clear(); return Simplex(e.first->vertex(e.second)); } else if (result==ZERO) { equiv_anchors.push_back(Simplex(e.first->vertex(e.third))); } return Simplex(e); } template < class RegularTriangulation3 > typename Compute_anchor_3::Simplex Compute_anchor_3:: compute_anchor_del(Facet const &f) { CGAL_assertion(!reg.is_infinite(f)); equiv_anchors.clear(); int i; Sign result; bool contains_center = true; for (i=1; (i<4) && contains_center; i++) { result = test_anchor(f, (f.second+i)&3); contains_center = (result != NEGATIVE); if (result == ZERO) { //equiv_anchors.push_back(Edge(f.first, f.second,(f.second+i)&3)); equiv_anchors.push_back( Edge(f.first, (f.second+(i==1?2:1))&3, (f.second+(i==3?2:3))&3)); } } if (contains_center) { return Simplex(f); } else { i--; Edge e; e.first = f.first; if (i==1) e.second = ((f.second+2)&3); else e.second = ((f.second+1)&3); if (i==3) e.third = ((f.second+2)&3); else e.third = ((f.second+3)&3); Simplex s = anchor_del(e); if (s.dimension() == 1) { equiv_anchors.clear(); return s; } else { // The anchor is the anchor of the other edge adjacent to tmp CGAL_assertion(s.dimension() == 0); Vertex_handle vh=s; e.second = e.first->index(vh); e.third = (f.second+i)&3; s = anchor_del(e); equiv_anchors.clear(); return s; } } } template < class RegularTriangulation3 > typename Compute_anchor_3::Simplex Compute_anchor_3:: compute_anchor_del(Cell_handle const ch) { CGAL_assertion(!reg.is_infinite(ch)); equiv_anchors.clear(); Simplex s; bool contains_center = true; Sign result; for (int i=0; (i<4) && contains_center; i++) { result = test_anchor(ch, i); if (result == NEGATIVE) { contains_center = false; s = anchor_del(Facet(ch,i)); } else if (result == ZERO) { equiv_anchors.push_back(Facet(ch,i)); } } if (contains_center) { return Simplex(ch); } else { Simplex tmp; bool found=true; while (true) { if (s.dimension() == 1) { // Test two adjacent facets Edge e=s; int ind1 = ch->index(e.first->vertex(e.second)); int ind2 = ch->index(e.first->vertex(e.third)); for (int i=0; (i<4) && found; i++) { if ((i != ind1) && (i != ind2)) { tmp = anchor_del(Facet(ch, i)); found = (s == tmp); } } } else if (s.dimension() == 0) { // Test adjacent edges Vertex_handle vh=s; int index = ch->index(vh); for (int i=0; (i<4) && found; i++) { if (i != index) { tmp = anchor_del(Edge(ch, index, i)); found = (s == tmp); } } } else { CGAL_assertion(s.dimension() == 2); } if (found) { equiv_anchors.clear(); return s; } found = true; s = tmp; } } } template < class RegularTriangulation3 > typename Compute_anchor_3::Simplex Compute_anchor_3:: compute_anchor_vor (Vertex_handle const v) { CGAL_assertion(!reg.is_infinite(v)); CGAL_assertion(reg.is_vertex(v)); equiv_anchors.clear(); Sign side; bool contains_center=true; Simplex s; std::list adj_vertices; typename std::list::iterator adj_vertex; reg.incident_vertices(v, std::back_inserter(adj_vertices)); for (adj_vertex = adj_vertices.begin(); (adj_vertex != adj_vertices.end()) && contains_center; adj_vertex++) { if (!reg.is_infinite(*adj_vertex)) { side = test_anchor(v->point(),(*adj_vertex)->point()); if (side == NEGATIVE) { contains_center = false; } else if (side == ZERO) { Edge e; if (!reg.is_edge (v, *adj_vertex, e.first, e.second, e.third)) { CGAL_error(); } equiv_anchors.push_back(Simplex(e)); } } } if (contains_center) { return Simplex(v); } else { adj_vertex--; Edge e; if (!reg.is_edge(v, *adj_vertex, e.first, e.second, e.third)) { CGAL_error(); } s = anchor_vor(e); Simplex tmp; while (true) { bool found = true; if (s.dimension() == 2) { // s lies on a Voronoi edge Facet f=s; int index = f.first->index(v); for (int i=1; (i<4) && found; i++) { if (((f.second+i)&3) != index) { tmp = anchor_vor(Edge(f.first, index, (f.second+i)&3)); found = (tmp == s); } } } else if (s.dimension() == 3) { // s lies on a Voronoi vertex Cell_handle ch=s; CGAL_assertion(ch != Cell_handle()); int index = ch->index(v); for (int i=1; (i<4) && (found); i++) { tmp = anchor_vor(Facet(ch, (index+i)&3)); found = (tmp == s); } } else { CGAL_assertion(s.dimension() == 1); } if (found) { equiv_anchors.clear(); if (s.dimension() == 1) { Edge e = s; Vertex_handle v_other = e.first->vertex(e.second+e.third-e.first->index(v)); for (adj_vertex = adj_vertices.begin(); adj_vertex != adj_vertices.end(); adj_vertex++) { if ((v_other != (*adj_vertex)) && (!reg.is_infinite(*adj_vertex))) { CGAL_assertion(!reg.is_infinite(v)); CGAL_assertion(!reg.is_infinite(v_other)); CGAL_assertion(!reg.is_infinite(*adj_vertex)); side = test_anchor(v->point(), v_other->point(), (*adj_vertex)->point()); if (side==ZERO) { Edge e2; if (!reg.is_edge(v, *adj_vertex, e2.first, e2.second, e2.third)) { CGAL_error(); } equiv_anchors.push_back(e2); } } } } return s; } s = tmp; } } } template < class RegularTriangulation3 > typename Compute_anchor_3::Simplex Compute_anchor_3::compute_anchor_vor (Edge const &e) { CGAL_assertion(!reg.is_infinite(e)); equiv_anchors.clear(); Vertex_handle v0 = e.first->vertex(e.second); Vertex_handle v1 = e.first->vertex(e.third); bool contains_center = true; Sign side; Simplex s; Facet_circulator fcir, fstart; fstart = fcir = reg.incident_facets(e); do { if (!reg.is_infinite(*fcir)) { int i = 6 - (*fcir).second - (*fcir).first->index(v0) - (*fcir).first->index(v1); side = test_anchor(*fcir, i); if (side == NEGATIVE) { contains_center = false; s = anchor_vor(Facet(*fcir)); } else if (side == ZERO) { equiv_anchors.push_back(Facet(*fcir)); } } } while (++fcir != fstart); if (contains_center) { s = Simplex(e); return s; } else { Simplex tmp; while (true) { bool found = true; if (s.dimension() == 3) { CGAL_assertion(s.dimension() == 3); Cell_handle ch=s; int index0 = ch->index(v0); int index1 = ch->index(v1); for (int i=0; (i<4) && found; i++) { if ((i != index0) && (i != index1)) { if (!reg.is_infinite(Facet(ch,i))) { side = test_anchor(ch,6-index0-index1-i); if (side != POSITIVE) { tmp = anchor_vor(Facet(ch,i)); found = (s==tmp); } } } } } else { CGAL_assertion(s.dimension() == 2); } if (found) { equiv_anchors.clear(); if (s.dimension() == 2) { // Check whether facet is degenerate (a line segment): Facet f = s; int index = 6 - f.second - f.first->index(v0) - f.first->index(v1); fstart = fcir = reg.incident_facets(e); do { if (!reg.is_infinite(*fcir)) { int index2 = 6 - (*fcir).second - (*fcir).first->index(v0) - (*fcir).first->index(v1); if (!(f.first->vertex(index) == (*fcir).first->vertex(index2))) { side = test_anchor(v0->point(), v1->point(), f.first->vertex(index)->point(), (*fcir).first->vertex(index2)->point()); if (side == ZERO) { equiv_anchors.push_back(Facet(*fcir)); } } } } while (++fcir != fstart); } return s; } s = tmp; } } } template < class RegularTriangulation3 > typename Compute_anchor_3::Simplex Compute_anchor_3::compute_anchor_vor (Facet const &f) { CGAL_assertion(!reg.is_infinite(f)); equiv_anchors.clear(); Sign side; CGAL_assertion(f.first != Cell_handle()); if (!reg.is_infinite(f.first)) { side = test_anchor(f.first, f.second); if (side==NEGATIVE) { return Simplex(f.first); } else if (side == ZERO) { equiv_anchors.push_back(f.first); } } Cell_handle neighbor = f.first->neighbor(f.second); CGAL_assertion(neighbor != Cell_handle()); if (!reg.is_infinite(neighbor)) { int n_index = neighbor->index(f.first); side = test_anchor(neighbor, n_index); if (side==NEGATIVE) { CGAL_assertion(equiv_anchors.empty()); return Simplex(neighbor); } else if (side == ZERO) { equiv_anchors.push_back(neighbor); } } return Simplex(f); } } //namespace CGAL #endif // CGAL_COMPUTE_ANCHOR_3_H