// ============================================================================ // // Copyright (c) 1999 The CGAL Consortium // // This software and related documentation is part of an INTERNAL release // of the Computational Geometry Algorithms Library (CGAL). It is not // intended for general use. // // ---------------------------------------------------------------------------- // // release : // release_date : // // file : include/CGAL/Regular_triangulation_3.h // revision : $Revision$ // revision_date : $Date$ // author(s) : Monique Teillaud // Sylvain Pion // // coordinator : INRIA Sophia Antipolis () // // ============================================================================ #ifndef CGAL_REGULAR_TRIANGULATION_3_H #define CGAL_REGULAR_TRIANGULATION_3_H #include #include #include #include CGAL_BEGIN_NAMESPACE template < class Gt, class Tds = Triangulation_data_structure_3 < Triangulation_vertex_base_3, Triangulation_cell_base_3 > > class Regular_triangulation_3 : public Triangulation_3 { friend std::istream& operator >> CGAL_NULL_TMPL_ARGS (std::istream& is, Triangulation_3 &tr); public: typedef Tds Triangulation_data_structure; typedef Gt Geom_traits; typedef Regular_triangulation_3 Self; typedef typename Triangulation_3::Vertex_handle Vertex_handle; typedef typename Triangulation_3::Cell_handle Cell_handle; typedef typename Triangulation_3::Vertex Vertex; typedef typename Triangulation_3::Cell Cell; typedef typename Triangulation_3::Facet Facet; typedef typename Triangulation_3::Edge Edge; typedef typename Triangulation_3::Locate_type Locate_type; typedef typename Triangulation_3::Cell_iterator Cell_iterator; typedef typename Triangulation_3::Facet_iterator Facet_iterator; typedef typename Triangulation_3::Edge_iterator Edge_iterator; typedef typename Gt::Weighted_point Weighted_point; typedef typename Gt::Power_test_3 Power_test; Regular_triangulation_3() : Triangulation_3() { init_function_objects(); } Regular_triangulation_3(const Gt & gt) : Triangulation_3(gt) { init_function_objects(); } // copy constructor duplicates vertices and cells Regular_triangulation_3(const Regular_triangulation_3 & rt) : Triangulation_3(rt) { init_function_objects(); CGAL_triangulation_postcondition( is_valid() ); } template < class InputIterator > int insert(InputIterator first, InputIterator last) { int n = number_of_vertices(); while(first != last){ insert(*first); ++first; } return number_of_vertices() - n; } Vertex_handle insert( const Weighted_point & p, Cell_handle start = Cell_handle(), Vertex_handle v = NULL); Vertex_handle push_back(const Weighted_point &p) { return insert(p); } Bounded_side side_of_power_sphere( Cell_handle c, const Weighted_point &p) const; Bounded_side side_of_power_circle( const Facet & f, const Weighted_point & p) const { return side_of_power_circle(f.first, f.second, p); } Bounded_side side_of_power_circle( Cell_handle c, int i, const Weighted_point &p) const; Bounded_side side_of_power_segment( Cell_handle c, const Weighted_point &p) const; bool is_valid(bool verbose = false, int level = 0) const; private: Power_test power_test; void init_function_objects() { power_test = geom_traits().power_test_3_object(); } bool in_conflict_3(const Weighted_point &p, const Cell_handle c) const { return side_of_power_sphere(c, p) == ON_BOUNDED_SIDE; } bool in_conflict_2(const Weighted_point &p, const Cell_handle c, int i) const { return side_of_power_circle(c, i, p) == ON_BOUNDED_SIDE; } bool in_conflict_1(const Weighted_point &p, const Cell_handle c) const { return side_of_power_segment(c, p) == ON_BOUNDED_SIDE; } class Conflict_tester_3 { const Weighted_point &p; Self *t; mutable std::vector cv; public: Conflict_tester_3(const Weighted_point &pt, Self *tr) : p(pt), t(tr) {} bool operator()(const typename Tds::Cell *c) const { // We mark the vertices so that we can find the deleted ones easily. if (t->in_conflict_3(p, (Cell_handle)(Cell*)c)) { for (int i=0; i<4; i++) { Vertex_handle v = ((Cell_handle)(Cell*)c)->vertex(i); if (v->cell() != NULL) { cv.push_back(v); v->set_cell(NULL); } } return true; } return false; } std::vector & conflict_vector() { return cv; } }; class Conflict_tester_2 { const Weighted_point &p; Self *t; mutable std::vector cv; public: Conflict_tester_2(const Weighted_point &pt, Self *tr) : p(pt), t(tr) {} bool operator()(const typename Tds::Cell *c) const { if (t->in_conflict_2(p, (Cell_handle)(Cell*)c, 3)) { for (int i=0; i<3; i++) { Vertex_handle v = ((Cell_handle)(Cell*)c)->vertex(i); if (v->cell() != NULL) { cv.push_back(v); v->set_cell(NULL); } } return true; } return false; } std::vector & conflict_vector() { return cv; } }; friend class Conflict_tester_3; friend class Conflict_tester_2; }; template < class Gt, class Tds > Bounded_side Regular_triangulation_3:: side_of_power_sphere( Cell_handle c, const Weighted_point &p) const { CGAL_triangulation_precondition( dimension() == 3 ); int i3; if ( ! c->has_vertex( infinite_vertex(), i3 ) ) { return Bounded_side( power_test (c->vertex(0)->point(), c->vertex(1)->point(), c->vertex(2)->point(), c->vertex(3)->point(), p) ); } // else infinite cell : int i0,i1,i2; if ( (i3%2) == 1 ) { i0 = (i3+1)&3; i1 = (i3+2)&3; i2 = (i3+3)&3; } else { i0 = (i3+2)&3; i1 = (i3+1)&3; i2 = (i3+3)&3; } // general case Orientation o = orientation(c->vertex(i0)->point(), c->vertex(i1)->point(), c->vertex(i2)->point(), p); if (o != ZERO) return Bounded_side(o); // else p coplanar with i0,i1,i2 return Bounded_side( power_test( c->vertex(i0)->point(), c->vertex(i1)->point(), c->vertex(i2)->point(), p ) ); } template < class Gt, class Tds > Bounded_side Regular_triangulation_3:: side_of_power_circle( Cell_handle c, int i, const Weighted_point &p) const { CGAL_triangulation_precondition( dimension() >= 2 ); int i3 = 5; if ( dimension() == 2 ) { CGAL_triangulation_precondition( i == 3 ); // the triangulation is supposed to be valid, ie the facet // with vertices 0 1 2 in this order is positively oriented if ( ! c->has_vertex( infinite_vertex(), i3 ) ) return Bounded_side( power_test(c->vertex(0)->point(), c->vertex(1)->point(), c->vertex(2)->point(), p) ); // else infinite facet // v1, v2 finite vertices of the facet such that v1,v2,infinite // is positively oriented Vertex_handle v1 = c->vertex( ccw(i3) ), v2 = c->vertex( cw(i3) ); // does not work in dimension 3 : // we need a fourth point to look at orientation with respect // to v1v2 Cell_handle n = c->neighbor(i3); Orientation o = coplanar_orientation( v1->point(), v2->point(), n->vertex(n->index(c))->point(), p ); if ( o != ZERO ) return Bounded_side( -o ); // case when p collinear with v1v2 return Bounded_side( power_test( v1->point(), v2->point(), p ) ); }// dim 2 // else dimension == 3 CGAL_triangulation_precondition( (i >= 0) && (i < 4) ); if ( ( ! c->has_vertex(infinite_vertex(),i3) ) || ( i3 != i ) ) { // finite facet // initialization of i0 i1 i2, vertices of the facet positively // oriented (if the triangulation is valid) int i0 = (i>0) ? 0 : 1; int i1 = (i>1) ? 1 : 2; int i2 = (i>2) ? 2 : 3; CGAL_triangulation_precondition( orientation(c->vertex(i0)->point(), c->vertex(i1)->point(), c->vertex(i2)->point(), p) == COPLANAR ); return Bounded_side( power_test(c->vertex(i0)->point(), c->vertex(i1)->point(), c->vertex(i2)->point(), p) ); } //else infinite facet // v1, v2 finite vertices of the facet such that v1,v2,infinite // is positively oriented Vertex_handle v1 = c->vertex( next_around_edge(i3,i) ), v2 = c->vertex( next_around_edge(i,i3) ); Orientation o = coplanar_orientation( v1->point(), v2->point(), c->vertex(i)->point(), p ); // then the code is duplicated from 2d case if ( o != ZERO ) return Bounded_side( -o ); // because p is in f iff // it is not on the same side of v1v2 as c->vertex(i) // case when p collinear with v1v2 : return Bounded_side( power_test( v1->point(), v2->point(), p ) ); } template < class Gt, class Tds > Bounded_side Regular_triangulation_3:: side_of_power_segment( Cell_handle c, const Weighted_point &p) const { CGAL_triangulation_precondition( dimension() == 1 ); if ( ! is_infinite(c,0,1) ) return Bounded_side( power_test( c->vertex(0)->point(), c->vertex(1)->point(), p ) ); Locate_type lt; int i; return side_of_edge( p, c, lt, i ); } template < class Gt, class Tds > typename Regular_triangulation_3::Vertex_handle Regular_triangulation_3:: insert(const Weighted_point & p, Cell_handle start, Vertex_handle v) { switch (dimension()) { case 3: { Locate_type lt; int li, lj; Cell_handle c = locate( p, lt, li, lj, start); if ( lt == VERTEX ) return c->vertex(li); // TODO: look at the weight... if (! in_conflict_3(p, c)) return NULL; // Should I mark c's vertices too ? Conflict_tester_3 tester(p, this); v = (Vertex *) _tds.insert_conflict(&(*v), &(*c), tester); v->set_point(p); for( typename std::vector::iterator it = tester.conflict_vector().begin(); it != tester.conflict_vector().end(); ++it) { if ((*it)->cell() == NULL) { // vertex has to be deleted set_number_of_vertices(number_of_vertices()-1); _tds.delete_vertex( &(*(*it))); } } set_number_of_vertices(number_of_vertices()+1); // a voir : comment compter les sommets redondants ? (***) // else : traiter le cas des points redondants a stocker dans // la face associee pour le cas d'une future suppression return v; } case 2: { Locate_type lt; int li, lj; Cell_handle c = locate( p, lt, li, lj, start); switch (lt) { case OUTSIDE_CONVEX_HULL: case CELL: case FACET: case EDGE: { if (! in_conflict_2(p, c, 3)) return NULL; Conflict_tester_2 tester(p, this); v = (Vertex *) _tds.insert_conflict(&(*v), &(*c), tester); v->set_point(p); for( typename std::vector::iterator it = tester.conflict_vector().begin(); it != tester.conflict_vector().end(); ++it) { if ((*it)->cell() == NULL) { // vertex has to be deleted set_number_of_vertices(number_of_vertices()-1); _tds.delete_vertex( &(*(*it))); } } set_number_of_vertices(number_of_vertices()+1); return v; } case VERTEX: return c->vertex(li); case OUTSIDE_AFFINE_HULL: { // if the 2d triangulation is Delaunay, the 3d // triangulation will be Delaunay return Triangulation_3::insert_outside_affine_hull(p,v); } } }//dim 2 case 1: { Locate_type lt; int li, lj; Cell_handle c = locate( p, lt, li, lj, start); switch (lt) { case OUTSIDE_CONVEX_HULL: case EDGE: { if (! in_conflict_1(p, c) ) return NULL; Vertex_handle v = (Vertex *) _tds.create_vertex(); v->set_point(p); set_number_of_vertices(number_of_vertices()+1); Cell_handle bound[2]; Cell_handle n; std::set conflicts; for (int j =0; j<2; j++ ) { n = c; while ( ( ! is_infinite(n->vertex(1-j)) ) && in_conflict_1( p, n->neighbor(j) ) ) { if (n!=c) (void) conflicts.insert( (void *) &(*n) ); // P = new Weighted_point( n->vertex(1-j)->point() ); // (void) deleted_points.insert((void*) P); _tds.delete_vertex( &(*(n->vertex(1-j))) ); set_number_of_vertices(number_of_vertices()-1); n = n->neighbor(j); } bound[j] = n; } if ( bound[0] != bound[1] ) { if ( (c != bound[0]) && (c != bound[1]) ) (void) conflicts.insert( (void *) &(*c) ); bound[0]->set_vertex(0,v); v->set_cell(bound[0]); bound[1]->set_vertex(1,v); bound[1]->set_neighbor(0,bound[0]); bound[0]->set_neighbor(1,bound[1]); } else { bound[1] = (Cell *) _tds.create_cell(&(*bound[0]->vertex(0)), &(*v), NULL, NULL, &(*bound[0]), &(*bound[0]->neighbor(1)), NULL, NULL); bound[0]->neighbor(1)->set_neighbor(0,bound[1]); bound[0]->vertex(0)->set_cell(bound[1]); bound[0]->set_neighbor(1,bound[1]); bound[0]->set_vertex(0,v); v->set_cell(bound[0]); } std::set::const_iterator it; for ( it = conflicts.begin(); it != conflicts.end(); ++it) delete((Cell*)*it); return v; } case VERTEX: return c->vertex(li); case OUTSIDE_AFFINE_HULL: return Triangulation_3::insert_outside_affine_hull(p,v); case FACET: case CELL: // impossible in dimension 1 return NULL; } } default : { // temporary : will only work for non degenerated dimensions // (only for the first 4 points if they form a true tetrahedron) return Triangulation_3::insert(p,start,v); } } } template < class Gt, class Tds > bool Regular_triangulation_3:: is_valid(bool verbose, int level) const { if ( ! tds().is_valid(verbose,level) ) { if (verbose) std::cerr << "invalid data structure" << std::endl; CGAL_triangulation_assertion(false); return false; } if ( &(*infinite_vertex()) == NULL ) { if (verbose) std::cerr << "no infinite vertex" << std::endl; CGAL_triangulation_assertion(false); return false; } int i; switch ( dimension() ) { case 3: { Cell_iterator it; for ( it = finite_cells_begin(); it != cells_end(); ++it ) { is_valid_finite((*it).handle()); for ( i=0; i<4; i++ ) { if ( side_of_power_sphere ( (*it).handle(), it->vertex( (it->neighbor(i))->index((*it).handle() ) ) ->point() ) == ON_BOUNDED_SIDE ) { if (verbose) std::cerr << "non-empty sphere " << std::endl; CGAL_triangulation_assertion(false); return false; } } } break; } case 2: { Facet_iterator it; for ( it = finite_facets_begin(); it != facets_end(); ++it ) { is_valid_finite((*it).first); for ( i=0; i<3; i++ ) { if ( side_of_power_circle ( (*it).first, 3, (*it).first->vertex( (((*it).first)->neighbor(i)) ->index((*it).first) )->point() ) == ON_BOUNDED_SIDE ) { if (verbose) std::cerr << "non-empty circle " << std::endl; CGAL_triangulation_assertion(false); return false; } } } break; } case 1: { Edge_iterator it; for ( it = finite_edges_begin(); it != edges_end(); ++it ) { is_valid_finite((*it).first); for ( i=0; i<2; i++ ) { if ( side_of_power_segment ( (*it).first, (*it).first->vertex( (((*it).first)->neighbor(i)) ->index((*it).first) )->point() ) == ON_BOUNDED_SIDE ) { if (verbose) std::cerr << "non-empty edge " << std::endl; CGAL_triangulation_assertion(false); return false; } } } break; } } if (verbose) std::cerr << "Regular valid triangulation" << std::endl; return true; } CGAL_END_NAMESPACE #endif // CGAL_REGULAR_TRIANGULATION_3_H