// ====================================================================== // // Copyright (c) 1997 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/Triangulation_2.h // package : Triangulation // source : $RCSfile$ // revision : $Revision$ // revision_date : $Date$ // author(s) : Olivier Devillers, Mariette Yvinec // // coordinator : Mariette Yvinec // // ====================================================================== #ifndef CGAL_TRIANGULATION_2_H #define CGAL_TRIANGULATION_2_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CGAL_BEGIN_NAMESPACE template < class Gt, class Tds > class Triangulation_2; template < class Gt, class Tds > std::istream& operator>> (std::istream& is, Triangulation_2 &tr); template < class Gt, class Tds > std::ostream& operator<< (std::ostream& os, const Triangulation_2 &tr); template < class Gt, class Tds > class Triangulation_2 : public Triangulation_cw_ccw_2 { friend std::istream& operator>> CGAL_NULL_TMPL_ARGS (std::istream& is, Triangulation_2 &tr); friend std::ostream& operator<< CGAL_NULL_TMPL_ARGS (std::ostream& os, const Triangulation_2 &tr); friend Triangulation_all_faces_iterator_2; friend Triangulation_all_edges_iterator_2; friend Triangulation_all_vertices_iterator_2; friend Triangulation_finite_faces_iterator_2; friend Triangulation_finite_edges_iterator_2; friend Triangulation_finite_vertices_iterator_2; public: typedef Tds Triangulation_data_structure; typedef Triangulation_2 Triangulation; typedef Gt Geom_traits; typedef typename Geom_traits::Point Point; typedef typename Geom_traits::Segment Segment; typedef typename Geom_traits::Triangle Triangle; typedef Triangulation_face_2 Face; typedef Triangulation_vertex_2 Vertex; typedef Triangulation_face_handle_2 Face_handle; typedef Triangulation_vertex_handle_2 Vertex_handle; typedef std::pair Edge; typedef Triangulation_face_circulator_2 Face_circulator; typedef Triangulation_edge_circulator_2 Edge_circulator; typedef Triangulation_vertex_circulator_2 Vertex_circulator; typedef Triangulation_all_faces_iterator_2 All_faces_iterator; typedef Triangulation_all_edges_iterator_2 All_edges_iterator; typedef Triangulation_all_vertices_iterator_2 All_vertices_iterator; typedef Triangulation_finite_faces_iterator_2 Finite_faces_iterator; typedef Triangulation_finite_edges_iterator_2 Finite_edges_iterator; typedef Triangulation_finite_vertices_iterator_2 Finite_vertices_iterator; //for compatibility with previous version typedef Triangulation_finite_faces_iterator_2 Face_iterator; typedef Triangulation_finite_edges_iterator_2 Edge_iterator; typedef Triangulation_finite_vertices_iterator_2 Vertex_iterator; typedef Triangulation_line_face_circulator_2 Line_face_circulator; typedef Point value_type; // to have a back_inserter enum Locate_type {VERTEX=0, EDGE, FACE, OUTSIDE_CONVEX_HULL, OUTSIDE_AFFINE_HULL}; protected: Gt _gt; Tds _tds; Vertex_handle _infinite_vertex; public: // CONSTRUCTORS Triangulation_2(const Geom_traits& geom_traits=Geom_traits()); Triangulation_2(const Triangulation_2 &tr); //Assignement Triangulation_2 &operator=(const Triangulation_2 &tr); //Helping void copy_triangulation(const Triangulation_2 &tr); void swap(Triangulation_2 &tr); void clear(); //ACCESS FUNCTIONs int dimension() const { return _tds.dimension();} int number_of_vertices() const {return _tds.number_of_vertices() - 1;} const Geom_traits& geom_traits() const { return _gt;} int number_of_faces() const; Vertex_handle infinite_vertex() const; Vertex_handle finite_vertex() const; Face_handle infinite_face() const; //SETTING void set_number_of_vertices(int n) {_tds.set_number_of_vertices(n+1);} void set_infinite_vertex(const Vertex_handle& v) {_infinite_vertex=v;} void set_dimension(int n) {_tds.set_dimension(n);} // CHECKING bool is_valid(bool verbose = false, int level = 0) const; // TEST INFINITE FEATURES AND OTHER FEATURES bool is_infinite(const Face_handle& f) const; bool is_infinite(const Vertex_handle& v) const; bool is_infinite(const Face_handle& f, int i) const; bool is_infinite(const Edge& e) const; bool is_infinite(const Edge_circulator& ec) const; bool is_infinite(const All_edges_iterator& ei) const; bool is_edge(Vertex_handle va, Vertex_handle vb) const; bool is_edge(Vertex_handle va, Vertex_handle vb, Face_handle& fr, int & i) const; bool includes_edge(Vertex_handle va, Vertex_handle vb, Vertex_handle& vbb, Face_handle& fr, int & i) const; //bool is_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3) const; //bool is_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, // Face_handle &fr) const; // GEOMETRIC FEATURES AND CONSTRUCTION Triangle triangle(const Face_handle& f) const; Segment segment(const Face_handle& f, int i) const; Segment segment(const Edge& e) const; Segment segment(const Edge_circulator& ec) const; Segment segment(const All_edges_iterator& ei) const; Segment segment(const Finite_edges_iterator& ei) const; Point circumcenter(Face_handle f) const; //INSERTION - DELETION - Flip public: void flip(Face_handle& f, int i); Vertex_handle insert_first(const Point& p); Vertex_handle insert_second(const Point& p); Vertex_handle insert_in_edge(const Point& p, Face_handle f,int i); Vertex_handle insert_in_face(const Point& p, Face_handle f); Vertex_handle insert_outside_convex_hull(const Point& p, Face_handle f); Vertex_handle insert_outside_affine_hull(const Point& p); Vertex_handle insert(const Point &p, Face_handle start = Face_handle() ); Vertex_handle insert(const Point& p, Locate_type lt, Face_handle loc, int li ); Vertex_handle push_back(const Point &p); void remove_degree_3(Vertex_handle v, Face_handle f = Face_handle()); void remove_first(Vertex_handle v); void remove_second(Vertex_handle v); void remove(Vertex_handle v); // POINT LOCATION Face_handle march_locate_1D(const Point& t, Locate_type& lt, int& li) const ; Face_handle march_locate_2D(const Face_handle& start, const Point& t, Locate_type& lt, int& li) const; Face_handle locate(const Point& p, Locate_type& lt, int& li, Face_handle start = Face_handle()) const; Face_handle locate(const Point &p, Face_handle start = Face_handle()) const; //TRAVERSING : ITERATORS AND CIRCULATORS Finite_faces_iterator finite_faces_begin() const; Finite_faces_iterator finite_faces_end() const; Finite_vertices_iterator finite_vertices_begin() const; Finite_vertices_iterator finite_vertices_end() const; Finite_edges_iterator finite_edges_begin() const; Finite_edges_iterator finite_edges_end() const; All_faces_iterator all_faces_begin() const; All_faces_iterator all_faces_end() const; All_vertices_iterator all_vertices_begin() const; All_vertices_iterator all_vertices_end() const; All_edges_iterator all_edges_begin() const; All_edges_iterator all_edges_end() const; //for compatibility with previous versions Face_iterator faces_begin() const {return finite_faces_begin();} Face_iterator faces_end() const {return finite_faces_end();} Edge_iterator edges_begin() const {return finite_edges_begin();} Edge_iterator edges_end() const {return finite_edges_end();} Vertex_iterator vertices_begin() const {return finite_vertices_begin();} Vertex_iterator vertices_end() const {return finite_vertices_end();} Face_circulator incident_faces( Vertex_handle v, Face_handle f = Face_handle()) const; Vertex_circulator incident_vertices(Vertex_handle v, Face_handle f = Face_handle()) const; Edge_circulator incident_edges(Vertex_handle v, Face_handle f = Face_handle()) const; Line_face_circulator line_walk(const Point& p, const Point& q, Face_handle f = Face_handle()) const; // TO DEBUG void show_all(); void show_face( Face_handle fh); //PREDICATES Oriented_side oriented_side(const Point &p0, const Point &p1, const Point &p2, const Point &p) const; Bounded_side bounded_side(const Point &p0, const Point &p1, const Point &p2, const Point &p) const; Oriented_side oriented_side(const Face_handle& f, const Point &p) const; Oriented_side side_of_oriented_circle(Face_handle f, const Point & p) const; bool collinear_between(const Point& p, const Point& q, const Point& r) const; protected: void remove_1D(Vertex_handle v); void remove_2D(Vertex_handle v); bool test_dim_down(Vertex_handle v); void make_hole(Vertex_handle v, std::list & hole); void fill_hole(Vertex_handle v, std::list & hole); void fill_hole_delaunay(std::list & hole); Face_handle create_face(Face_handle f1, int i1, Face_handle f2, int i2, Face_handle f3, int i3); Face_handle create_face(Face_handle f1, int i1, Face_handle f2, int i2); Face_handle create_face(Face_handle f, int i, Vertex_handle v); Face_handle create_face(Vertex_handle v1, Vertex_handle v2,Vertex_handle v3); Face_handle create_face(Vertex_handle v1, Vertex_handle v2,Vertex_handle v3, Face_handle f1, Face_handle f2, Face_handle f3); Face_handle create_face(); Face_handle create_face(Face_handle); //calls copy constructor of Face void delete_face(Face_handle f); Vertex_handle file_input(std::istream& is); void file_output(std::ostream& os) const; private: Vertex_handle insert_outside_convex_hull_1(const Point& p, Face_handle f); Vertex_handle insert_outside_convex_hull_2(const Point& p, Face_handle f); public: template < class Stream > Stream& draw_triangulation(Stream& os) const { Finite_edges_iterator it = finite_edges_begin(); for( ;it != finite_edges_end() ; ++it) { os << segment(it); } return os; } 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; } }; // CONSTRUCTORS template Triangulation_2:: Triangulation_2(const Geom_traits& geom_traits) : _gt(geom_traits), _tds() { _infinite_vertex = (Vertex *)_tds.insert_first(); } // copy constructor duplicates vertices and faces template Triangulation_2:: Triangulation_2(const Triangulation_2 &tr) : _gt(tr._gt) { _infinite_vertex = (Vertex *) _tds.copy_tds(tr._tds, &(*tr.infinite_vertex())); } //Assignement template Triangulation_2 & Triangulation_2:: operator=(const Triangulation_2 &tr) { copy_triangulation(tr); return *this; } // Helping functions template void Triangulation_2:: copy_triangulation(const Triangulation_2 &tr) { _tds.clear(); _gt = tr._gt; _infinite_vertex = (Vertex *) _tds.copy_tds(tr._tds, &(*tr._infinite_vertex)); } template void Triangulation_2:: swap(Triangulation_2 &tr) { Vertex_handle v= _infinite_vertex; _infinite_vertex = tr._infinite_vertex; tr._infinite_vertex = v; _tds.swap(tr._tds); Geom_traits t = geom_traits(); _gt = tr.geom_traits(); tr._gt = t; } template void Triangulation_2:: clear() { _tds.clear(); //detruit tous les sommets et toutes les faces _infinite_vertex = (Vertex *)_tds.insert_first(); } template int Triangulation_2:: number_of_faces() const { int count = _tds.number_of_faces(); Face_circulator fc= infinite_vertex()->incident_faces(), done(fc); if ( ! fc.is_empty() ) { do { --count; ++fc; } while (fc != done); } return count; } template inline Triangulation_2::Vertex_handle Triangulation_2:: infinite_vertex() const { return _infinite_vertex; } template inline Triangulation_2::Vertex_handle Triangulation_2:: finite_vertex() const { CGAL_triangulation_precondition (number_of_vertices() >= 1); return (finite_vertices_begin()); } template inline Triangulation_2::Face_handle Triangulation_2:: infinite_face() const { return infinite_vertex()->face(); } template bool Triangulation_2:: is_valid(bool verbose, int level) const { bool result = _tds.is_valid(verbose, level); if (dimension() <= 0 || (dimension()==1 && number_of_vertices() == 2 ) ) return result; if (dimension() == 1) { Finite_vertices_iterator it1 = finite_vertices_begin(), it2(it1), it3(it1); ++it2; ++it3; ++it3; while( it3 != finite_vertices_end()) { Orientation s = geom_traits().orientation(it1->point(), it2->point(), it3->point()); result = result && s == COLLINEAR ; CGAL_triangulation_assertion(result); ++it1 ; ++it2; ++it3; } } else { //dimension() == 2 for(Finite_faces_iterator it=finite_faces_begin(); it!=finite_faces_end(); it++) { CGAL_triangulation_assertion( ! is_infinite(it)); Orientation s = geom_traits().orientation(it->vertex(0)->point(), it->vertex(1)->point(), it->vertex(2)->point()); CGAL_triangulation_assertion( s == LEFTTURN ); result = result && ( s == LEFTTURN ); } Vertex_circulator start = infinite_vertex()->incident_vertices(); Vertex_circulator pc(start); Vertex_circulator qc(start); ++qc; Vertex_circulator rc(start); ++rc; ++rc; do{ Orientation s = geom_traits().orientation(pc->point(), qc->point(), rc->point()); CGAL_triangulation_assertion( s != LEFTTURN ); result = result && ( s != LEFTTURN ); ++pc ; ++qc ; ++rc; }while(pc != start); } return result; } template inline bool Triangulation_2:: is_infinite(const Face_handle& f) const { return f->has_vertex(infinite_vertex()); } template inline bool Triangulation_2:: is_infinite(const Vertex_handle& v) const { return v == infinite_vertex(); } template inline bool Triangulation_2:: is_infinite(const Face_handle& f, int i) const { return is_infinite(f->vertex(ccw(i))) || is_infinite(f->vertex(cw(i))); } template inline bool Triangulation_2:: is_infinite(const Edge& e) const { return is_infinite(e.first,e.second); } template inline bool Triangulation_2:: is_infinite(const Edge_circulator& ec) const { return is_infinite(*ec); } template inline bool Triangulation_2:: is_infinite(const All_edges_iterator& ei) const { return is_infinite(*ei); } template inline bool Triangulation_2:: is_edge(Vertex_handle va, Vertex_handle vb) const { return _tds.is_edge( &(*(va)), &(*(vb))); } template inline bool Triangulation_2:: is_edge(Vertex_handle va, Vertex_handle vb, Face_handle& fr, int & i) const { typename Tds::Face* f ; bool b = _tds.is_edge( &(*(va)), &(*(vb)), f, i); fr = Face_handle(static_cast(f)); return b; } template bool Triangulation_2:: includes_edge(Vertex_handle va, Vertex_handle vb, Vertex_handle & vbb, Face_handle& fr, int & i) const // returns true if the line segment ab contains an edge e of t // incident to a, false otherwise // if true, vbb becomes the vertex of e distinct from a // fr is the face incident to e and e=(fr,i) // fr is on the right side of a->b { Vertex_handle v; Orientation orient; int indv; Edge_circulator ec = va->incident_edges(), done(ec); if (ec != 0) { do { //find the index of the other vertex of *ec indv = 3 - ((*ec).first)->index(va) - (*ec).second ; v = ((*ec).first)->vertex(indv); if (!is_infinite(v)) { if (v==vb) { vbb = vb; fr=(*ec).first; i= (*ec).second; return true; } else { orient = geom_traits().orientation(va->point(), vb->point(), v->point()); if((orient==COLLINEAR) && (collinear_between (va->point(), v->point(), vb->point()))) { vbb = v; fr=(*ec).first; i= (*ec).second; return true; } } } } while (++ec != done); } return false; } template Triangulation_2::Triangle Triangulation_2:: triangle(const Face_handle& f) const { CGAL_triangulation_precondition( ! is_infinite(f) ); return Triangle(f->vertex(0)->point(), f->vertex(1)->point(), f->vertex(2)->point()); } template Triangulation_2::Segment Triangulation_2:: segment(const Face_handle& f, int i) const { CGAL_triangulation_precondition( ! is_infinite(f,i)); return Segment(f->vertex(ccw(i))->point(), f->vertex(cw(i))->point()); } template Triangulation_2::Segment Triangulation_2:: segment(const Edge& e) const { CGAL_triangulation_precondition(! is_infinite(e)); return Segment(e.first->vertex(ccw(e.second))->point(), e.first->vertex( cw(e.second))->point()); } template Triangulation_2::Segment Triangulation_2:: segment(const Edge_circulator& ec) const { return segment(*ec); } template Triangulation_2::Segment Triangulation_2:: segment(const Finite_edges_iterator& ei) const { return segment(*ei); } template Triangulation_2::Segment Triangulation_2:: segment(const All_edges_iterator& ei) const { return segment(*ei); } template void Triangulation_2:: flip(Face_handle& f, int i) { CGAL_triangulation_precondition ( ! f.is_null() ); CGAL_triangulation_precondition (i == 0 || i == 1 || i == 2); CGAL_triangulation_precondition( dimension()==2); CGAL_triangulation_precondition( !is_infinite(f) && !is_infinite(f->neighbor(i)) ); CGAL_triangulation_precondition( geom_traits().orientation(f->vertex(i)->point(), f->vertex(cw(i))->point(), f->mirror_vertex(i)->point()) == RIGHTTURN && geom_traits().orientation(f->vertex(i)->point(), f->vertex(ccw(i))->point(), f->mirror_vertex(i)->point()) == LEFTTURN); _tds.flip( &(*f), i); return; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_first(const Point& p) { CGAL_triangulation_precondition(number_of_vertices() == 0); Vertex_handle v = static_cast(_tds.insert_second()); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_second(const Point& p) { CGAL_triangulation_precondition(number_of_vertices() == 1); Vertex_handle v = static_cast (_tds.insert_dim_up(&(*infinite_vertex()),true)); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_in_edge(const Point& p, Face_handle f,int i) { CGAL_triangulation_precondition( geom_traits().orientation(f->vertex(cw(i))->point(), p, f->vertex(ccw(i))->point() ) == COLLINEAR && collinear_between(f->vertex(cw(i))->point(), p, f->vertex(ccw(i))->point()) ); Vertex_handle v = static_cast (_tds.insert_in_edge(&(*f), i)); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_in_face(const Point& p, Face_handle f) { CGAL_triangulation_precondition(oriented_side(f,p) == ON_POSITIVE_SIDE); Vertex_handle v= static_cast (_tds.insert_in_face( &(*f))); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_outside_convex_hull(const Point& p, Face_handle f) { CGAL_triangulation_precondition(is_infinite(f) && dimension() >= 1); Vertex_handle v; if (dimension() == 1) v=insert_outside_convex_hull_1(p, f); else v=insert_outside_convex_hull_2(p, f); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_outside_convex_hull_1(const Point& p, Face_handle f) { CGAL_triangulation_precondition( is_infinite(f) && dimension()==1); CGAL_triangulation_precondition( geom_traits().orientation( f->mirror_vertex(f->index(infinite_vertex()))->point(), f->vertex(1- f->index(infinite_vertex()))->point(), p) == COLLINEAR && collinear_between( f->mirror_vertex(f->index(infinite_vertex()))->point(), f->vertex(1- f->index(infinite_vertex()))->point(), p) ); Vertex_handle v=static_cast(_tds.insert_in_edge( &(*f), 2)); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_outside_convex_hull_2(const Point& p, Face_handle f) { CGAL_triangulation_precondition(is_infinite(f)); int li = f->index(infinite_vertex()); Point q,r; q = f->vertex(ccw(li))->point(); r = f->vertex(cw(li))->point(); CGAL_triangulation_precondition( geom_traits().orientation(p,q,r) == LEFTTURN); std::list ccwlist; std::list cwlist; Face_circulator fc = infinite_vertex()->incident_faces(f); bool done = false; while(! done) { fc--; li = fc->index(infinite_vertex()); q = fc->vertex(ccw(li))->point(); r = fc->vertex(cw(li))->point(); if(geom_traits().orientation(p,q,r) == LEFTTURN ) { ccwlist.push_back(&(*fc)); } else {done=true;} } fc= infinite_vertex()->incident_faces(f); done = false; while(! done){ fc++; li = fc->index(infinite_vertex()); q = fc->vertex(ccw(li))->point(); r = fc->vertex(cw(li))->point(); if(geom_traits().orientation(p,q,r) == LEFTTURN ) { cwlist.push_back(&(*fc)); } else {done=true;} } Vertex_handle v =static_cast(_tds.insert_in_face( &(*f))); v->set_point(p); Face_handle fh; while ( ! ccwlist.empty()) { fh = ccwlist.front(); li = ccw(fh->index(infinite_vertex())); _tds.flip( &(*fh) , li); ccwlist.pop_front(); } while ( ! cwlist.empty()) { fh = cwlist.front(); li = cw(fh->index(infinite_vertex())); _tds.flip( &(*fh) , li); cwlist.pop_front(); } //reset infinite_vertex()->face(); fc = v->incident_faces(); while( ! is_infinite(&(*fc))) { fc++;} infinite_vertex()->set_face(&(*fc)); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert_outside_affine_hull(const Point& p) { CGAL_triangulation_precondition(dimension() == 1); Face_handle f = (*finite_edges_begin()).first; Orientation or = geom_traits().orientation( f->vertex(0)->point(), f->vertex(1)->point(), p); CGAL_triangulation_precondition(or != COLLINEAR); bool conform = ( or == COUNTERCLOCKWISE); Vertex_handle v = static_cast (_tds.insert_dim_up( &(*infinite_vertex()), conform)); v->set_point(p); return v; } template Triangulation_2::Vertex_handle Triangulation_2:: insert(const Point &p, Face_handle start) { Locate_type lt; int li; Face_handle loc = locate (p, lt, li, start); return insert(p, lt, loc, li); } template Triangulation_2::Vertex_handle Triangulation_2:: insert(const Point& p, Locate_type lt, Face_handle loc, int li) // insert a point p, whose localisation is known (lt, f, i) { if(number_of_vertices() == 0) { return(insert_first(p)); } if(number_of_vertices() == 1) { if (lt == VERTEX) return finite_vertex(); else return(insert_second(p)); } switch(lt) { case FACE: return insert_in_face(p,loc); case EDGE: return insert_in_edge(p,loc,li); case OUTSIDE_CONVEX_HULL: return insert_outside_convex_hull(p,loc); case OUTSIDE_AFFINE_HULL: return insert_outside_affine_hull(p); case VERTEX: return loc->vertex(li); } CGAL_triangulation_assertion(false); // locate step failed return Vertex_handle(); } template inline Triangulation_2::Vertex_handle Triangulation_2:: push_back(const Point &p) { return insert(p); } template inline void Triangulation_2:: remove_degree_3(Vertex_handle v, Face_handle f) { if (f == Face_handle()) f=v->face(); _tds.remove_degree_3(&(*v), &(*f)); return; } template inline void Triangulation_2:: remove_first(Vertex_handle v) { _tds.remove_second(&(*v)); return; } template inline void Triangulation_2:: remove_second(Vertex_handle v) { _tds.remove_dim_down(&(*v)); return; } template void Triangulation_2:: remove(Vertex_handle v) { CGAL_triangulation_precondition( ! v.is_null() ); CGAL_triangulation_precondition( !is_infinite(v)); if (number_of_vertices() == 1) remove_first(v); else if (number_of_vertices() == 2) remove_second(v); else if ( dimension() == 1) remove_1D(v); else remove_2D(v); return; } template inline void Triangulation_2:: remove_1D(Vertex_handle v) { _tds.remove_1D(&(*v)); } template bool Triangulation_2:: test_dim_down(Vertex_handle v) { //test the dimensionality of the resulting triangulation //upon removing of vertex v //it goes down to 1 iff // 1) any finite face is incident to v // 2) all vertices are colinear CGAL_triangulation_precondition(dimension() == 2); bool dim1 = true; Finite_faces_iterator fit = finite_faces_begin(); while (dim1==true && fit != finite_faces_end()) { dim1 = dim1 && fit->has_vertex(v); fit++; } Face_circulator fic = v->incident_faces(); while (is_infinite(fic)) {++fic;} Face_circulator done(fic); Face_handle start(fic); int iv = start->index(v); Point p = start->vertex(cw(iv))->point(); Point q = start->vertex(ccw(iv))->point(); while ( dim1 && ++fic != done) { iv = fic->index(v); if (fic->vertex(ccw(iv)) != infinite_vertex()) { dim1 = dim1 && geom_traits().orientation(p, q, fic->vertex(ccw(iv))->point()) == COLLINEAR; } } return dim1; } template void Triangulation_2:: remove_2D(Vertex_handle v) { if (test_dim_down(v)) { _tds.remove_dim_down(&(*v)); } else { std::list hole; make_hole(v, hole); fill_hole(v, hole); delete &(*v); set_number_of_vertices(number_of_vertices()-1); } return; } template void Triangulation_2:: make_hole ( Vertex_handle v, std::list & hole) { std::list to_delete; Face_handle f, fn; int i =0, in =0; Vertex_handle vv; Face_circulator fc = v->incident_faces(); Face_circulator done(fc); do { f = (*fc).handle(); fc++; i = f->index(v); fn = f->neighbor(i); in = fn->index(f); vv = f->vertex(cw(i)); if( vv->face()== f) vv->set_face(fn); vv = f->vertex(ccw(i)); if( vv->face()== f) vv->set_face(fn); fn->set_neighbor(in, NULL); hole.push_back(Edge(fn,in)); to_delete.push_back(f); } while(fc != done); while (! to_delete.empty()){ delete_face(to_delete.front()); to_delete.pop_front(); } return; } template void Triangulation_2:: fill_hole ( Vertex_handle v, std::list< Edge > & hole ) { typedef std::list Hole; Face_handle ff, fn; int ii =0, in =0; Vertex_handle v0, v1, v2; Bounded_side side; //stack algorithm to create faces // create face v0,v1,v2 //if v0,v1,v2 are finite vertices // and form a leftturn // and triangle v0v1v2 does not contain v->point() if( hole.size() != 3) { typename Hole::iterator hit = hole.begin(); typename Hole::iterator next= hit; while( hit != hole.end() && hole.size() != 3) { ff = (*hit).first; ii = (*hit).second; v0 = ff->vertex(cw(ii)); v1 = ff->vertex(ccw(ii)); if( !is_infinite(v0) && !is_infinite(v1)) { next=hit; next++; if(next == hole.end()) next=hole.begin(); fn = (*next).first; in = (*next).second; v2 = fn->vertex(ccw(in)); if ( !is_infinite(v2) && geom_traits().orientation(v0->point(), v1->point(), v2->point()) == LEFTTURN ) { side = bounded_side(v0->point(), v1->point(), v2->point(), v->point()); if( side == ON_UNBOUNDED_SIDE || (side == ON_BOUNDARY && geom_traits().orientation(v0->point(), v->point(), v2->point()) == COLLINEAR && collinear_between(v0->point(),v->point(),v2->point()) )) { //create face Face_handle newf = create_face(ff,ii,fn,in); typename Hole::iterator tempo=hit; hit = hole.insert(hit,Edge(newf,1)); //push newf hole.erase(tempo); //erase ff hole.erase(next); //erase fn if (hit != hole.begin() ) --hit; continue; } } } ++hit; } } // either the hole has only three edges // or all its finite vertices are reflex or flat // except may be one vertex whose corresponding ear // includes the vertex being removed // deal with the last leftturn if any if(hole.size() != 3) { typename Hole::iterator hit=hole.begin(); while(hit != hole.end()) { ff = (*hit).first; ii = (*hit).second; hit++; if(hit != hole.end()) { fn = (*hit).first; in = (*hit).second;} else { fn = ((hole.front()).first); in = (hole.front()).second;} if ( !is_infinite(ff->vertex(cw(ii))) && !is_infinite(fn->vertex(cw(in))) && !is_infinite(fn->vertex(ccw(in))) && geom_traits().orientation(ff->vertex(cw(ii))->point(), fn->vertex(cw(in))->point(), fn->vertex(ccw(in))->point()) == LEFTTURN) { create_face(ff,ii,fn,in); break; } } } // deal with a reflex chain of convex hull edges if(hole.size() != 3) { // look for infinite vertex ff = (hole.front()).first; ii = (hole.front()).second; while ( ! is_infinite(ff->vertex(cw(ii)))){ hole.push_back(hole.front()); hole.pop_front(); ff = (hole.front()).first; ii = (hole.front()).second; } //create faces while(hole.size() != 3){ ff = (hole.front()).first; ii = (hole.front()).second; hole.pop_front(); fn = (hole.front()).first; in = (hole.front()).second; hole.pop_front(); Face_handle newf = create_face(ff,ii,fn,in); hole.push_front(Edge(newf,1)); } } // now hole has three edges typename Hole::iterator hit; hit = hole.begin(); // I don't know why the following yelds a segmentation fault // create_face( (*hit).first, (*hit).second, // (* ++hit).first, (*hit).second, // (* ++hit).first, (*hit).second); ff = (*hit).first; ii = (*hit).second; fn = (* ++hit).first; in = (*hit).second; Face_handle f3 = (* ++hit).first; int i3 = (*hit).second; create_face(ff,ii,fn,in,f3,i3); } template void Triangulation_2:: fill_hole_delaunay(std::list & first_hole) { typedef std::list Hole; typedef std::list Hole_list; Face_handle f, ff, fn; int i =0,ii =0, in =0; Hole_list hole_list; Hole hole; hole_list.push_front(first_hole); while( ! hole_list.empty()) { hole = hole_list.front(); hole_list.pop_front(); typename Hole::iterator hit = hole.begin(); // if the hole has only three edges, create the triangle if (hole.size() == 3) { hit = hole.begin(); f = (*hit).first; i = (*hit).second; ff = (* ++hit).first; ii = (*hit).second; fn = (* ++hit).first; in = (*hit).second; create_face(f,i,ff,ii,fn,in); continue; } // else find an edge with two finite vertices // on the hole boundary // and the new triangle adjacent to that edge // cut the hole and push it back // first, ensure that a neighboring face // whose vertices on the hole boundary are finite // is the first of the hole bool finite= false; while (!finite){ ff = (hole.front()).first; ii = (hole.front()).second; if ( is_infinite(ff->vertex(cw(ii))) || is_infinite(ff->vertex(ccw(ii)))) { hole.push_back(hole.front()); hole.pop_front(); } else finite=true; } // take the first neighboring face and pop it; ff = (hole.front()).first; ii =(hole.front()).second; hole.pop_front(); Vertex_handle v0 = ff->vertex(ff->cw(ii)); Point p0 =v0->point(); Vertex_handle v1 = ff->vertex(ff->ccw(ii)); Point p1 =v1->point(); Vertex_handle v2 = infinite_vertex(); Point p2; Vertex_handle vv; Point p; typename Hole::iterator hdone = hole.end(); hit = hole.begin(); typename Hole::iterator cut_after(hit); // if tested vertex is c with respect to the vertex opposite // to NULL neighbor, // stop at the before last face; hdone--; while( hit != hdone) { fn = (*hit).first; in = (*hit).second; vv = fn->vertex(ccw(in)); if (is_infinite(vv)) { if(is_infinite(v2)) cut_after = hit; } else { // vv is a finite vertex p = vv->point(); if (geom_traits().orientation(p0,p1,p) == COUNTERCLOCKWISE) { if(is_infinite(v2)) { v2=vv; p2=p; cut_after=hit;} else{ if( geom_traits().side_of_oriented_circle (p0,p1,p2,p) == ON_POSITIVE_SIDE){ v2=vv; p2=p; cut_after=hit;} } } } ++hit; } // create new triangle and update adjacency relations Face_handle newf; //update the hole and push back in the Hole_List stack // if v2 belongs to the neighbor following or preceding *f // the hole remain a single hole // otherwise it is split in two holes fn = (hole.front()).first; in = (hole.front()).second; if (fn->has_vertex(v2, i) && i == fn->ccw(in)) { newf = create_face(ff,ii,fn,in); hole.pop_front(); hole.push_front(Edge( &(*newf),1)); hole_list.push_front(hole); } else{ fn = (hole.back()).first; in = (hole.back()).second; if (fn->has_vertex(v2, i) && i== fn->cw(in)) { newf = create_face(fn,in,ff,ii); hole.pop_back(); hole.push_back(Edge(&(*newf),1)); hole_list.push_front(hole); } else{ // split the hole in two holes newf = create_face(ff,ii,v2); Hole new_hole; ++cut_after; while( hole.begin() != cut_after ) { new_hole.push_back(hole.front()); hole.pop_front(); } hole.push_front(Edge( &(*newf),1)); new_hole.push_front(Edge( &(*newf),0)); hole_list.push_front(hole); hole_list.push_front(new_hole); } } } } template inline Triangulation_2::Face_handle Triangulation_2:: create_face(Face_handle f1, int i1, Face_handle f2, int i2, Face_handle f3, int i3) { return static_cast(_tds.create_face(&(*f1),i1, &(*f2),i2, &(*f3),i3)); } template inline Triangulation_2::Face_handle Triangulation_2:: create_face(Face_handle f1, int i1, Face_handle f2, int i2) { return static_cast(_tds.create_face(&(*f1),i1, &(*f2),i2)); } template inline Triangulation_2::Face_handle Triangulation_2:: create_face(Face_handle f, int i, Vertex_handle v) { return static_cast(_tds.create_face(&(*f),i, &(*v))); } template inline Triangulation_2::Face_handle Triangulation_2:: create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3) { return static_cast(_tds.create_face(&(*v1), &(*v2), &(*v3))); } template inline Triangulation_2::Face_handle Triangulation_2:: create_face(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, Face_handle f1, Face_handle f2, Face_handle f3) { return static_cast(_tds.create_face(&(*v1), &(*v2), &(*v3), &(*f1), &(*f2), &(*f3))); } template inline Triangulation_2::Face_handle Triangulation_2:: create_face(Face_handle fh) { return static_cast(_tds.create_face(&(*fh))); } template inline Triangulation_2::Face_handle Triangulation_2:: create_face() { return static_cast(_tds.create_face()); } template inline void Triangulation_2:: delete_face(Face_handle f) { _tds.delete_face(&(*f)); } // POINT LOCATION template Triangulation_2::Face_handle Triangulation_2:: march_locate_1D(const Point& t, Locate_type& lt, int& li) const { Face_handle ff = infinite_face(); int iv = ff->index(infinite_vertex()); Face_handle f = ff->neighbor(iv); Orientation pqt = geom_traits().orientation(f->vertex(0)->point(), f->vertex(1)->point(), t); if(pqt == RIGHTTURN || pqt == LEFTTURN) { lt = OUTSIDE_AFFINE_HULL; li = 4 ;// should not be used return Face_handle(); } int i= f->index(ff); if (collinear_between(t,f->vertex(1-i)->point(),f->vertex(i)->point())) { lt = OUTSIDE_CONVEX_HULL; li = iv; return ff; } if(geom_traits().compare(t,f->vertex(1-i)->point())){ lt = VERTEX; li=1-i; return f; } ff = ff->neighbor(1-iv); //the other infinite face iv = ff->index(infinite_vertex()); f = ff->neighbor(iv); i = f->index(ff); if (collinear_between(t,f->vertex(1-i)->point(),f->vertex(i)->point())) { lt = OUTSIDE_CONVEX_HULL; li = iv; return ff; } if(geom_traits().compare(t,f->vertex(1-i)->point())){ lt = VERTEX; li=1-i; return f; } Finite_edges_iterator eit= finite_edges_begin(); Vertex_handle u,v; for( ; eit != finite_edges_end() ; eit++) { u = (*eit).first->vertex(0); v = (*eit).first->vertex(1); if(geom_traits().compare(t,v->point())){ lt = VERTEX; li = 1; return (*eit).first; } if(collinear_between(u->point(), t, v->point())){ lt = EDGE; li = 2; return (*eit).first; } } CGAL_triangulation_assertion(false); return Face_handle(); } template Triangulation_2::Face_handle Triangulation_2:: march_locate_2D(const Face_handle& start, const Point& t, Locate_type& lt, int& li) const { // CGAL_triangulation_precondition( ! is_infinite(start) ); Triangulation_2 *ncthis = (Triangulation_2 *)this; Point p(start->vertex(0)->point()); if(geom_traits().compare_x(t,p) == EQUAL && geom_traits().compare_y(t,p) == EQUAL) { lt = VERTEX; li = 0; return start; } Line_face_circulator lfc(start->vertex(0), ncthis, t); if(lfc.collinear_outside()) { // point t lies outside or on the convex hull // we walk clockwise on the hull to decide int i = lfc->index(infinite_vertex()); p = lfc->vertex(ccw(i))->point(); if(geom_traits().compare_x(t,p) == EQUAL && geom_traits().compare_y(t,p) == EQUAL){ lt = VERTEX; li = ccw(i); return lfc; } Point q(lfc->vertex(cw(i))->point()); Orientation pqt; Face_handle f(lfc); while(1) { if(geom_traits().compare_x(t,q) == EQUAL && geom_traits().compare_y(t,q) == EQUAL){ lt = VERTEX; li = cw(i); return f; } pqt = geom_traits().orientation(p,q,t); if (pqt == COLLINEAR && collinear_between(p, t, q)){ lt = EDGE; li = i; return f; } if (pqt == LEFTTURN){ lt = OUTSIDE_CONVEX_HULL; li = i; return f ; } // go to the next face f = f->neighbor(ccw(i)); i = f->index(infinite_vertex()); p = q; q = f->vertex(cw(i))->point(); } } while(! lfc.locate(t, lt, li) ){ ++lfc; } return lfc; } template Triangulation_2::Face_handle Triangulation_2:: locate(const Point& p, Locate_type& lt, int& li, Face_handle start) const { if( dimension() <= 0) { if(number_of_vertices() == 0) { lt = OUTSIDE_AFFINE_HULL; li = 4; // li should not be used in this case } else { // number_of_vertices() == 1 lt = geom_traits().compare(p,finite_vertex()->point()) ? VERTEX : OUTSIDE_AFFINE_HULL; li = 4; // li should not be used in this case } return NULL; } if(dimension() == 1){ return march_locate_1D(p, lt, li); } if(start.is_null()){ start = infinite_face()-> neighbor(infinite_face()->index(infinite_vertex())); }else if(is_infinite(start)){ start = start->neighbor(start->index(infinite_vertex())); } return march_locate_2D(start, p, lt, li); } template Triangulation_2:: Face_handle Triangulation_2:: locate(const Point &p, Face_handle start) const { Locate_type lt; int li; return locate(p, lt, li, start); } template Triangulation_2::Finite_faces_iterator Triangulation_2:: finite_faces_begin() const { Triangulation_2* ncthis = (Triangulation_2 *)this; return Finite_faces_iterator(ncthis); } template Triangulation_2::Finite_faces_iterator Triangulation_2:: finite_faces_end() const { Triangulation_2* ncthis = (Triangulation_2*)this; return Finite_faces_iterator(ncthis,1); } template Triangulation_2::Finite_vertices_iterator Triangulation_2:: finite_vertices_begin() const { Triangulation_2* ncthis = (Triangulation_2*)this; return Finite_vertices_iterator(ncthis); } template Triangulation_2::Finite_vertices_iterator Triangulation_2:: finite_vertices_end() const { Triangulation_2* ncthis = (Triangulation_2*)this; return Finite_vertices_iterator(ncthis,1); } template Triangulation_2::Finite_edges_iterator Triangulation_2:: finite_edges_begin() const { Triangulation_2* ncthis = (Triangulation_2*)this; return Finite_edges_iterator(ncthis); } template Triangulation_2::Finite_edges_iterator Triangulation_2:: finite_edges_end() const { Triangulation_2* ncthis = (Triangulation_2*)this; return Finite_edges_iterator(ncthis,1); } template Triangulation_2::All_faces_iterator Triangulation_2:: all_faces_begin() const { Triangulation_2* ncthis = (Triangulation_2 *)this; return All_faces_iterator(ncthis); } template Triangulation_2::All_faces_iterator Triangulation_2:: all_faces_end() const { Triangulation_2* ncthis = (Triangulation_2*)this; return All_faces_iterator(ncthis,1); } template Triangulation_2::All_vertices_iterator Triangulation_2:: all_vertices_begin() const { Triangulation_2* ncthis = (Triangulation_2*)this; return All_vertices_iterator(ncthis); } template Triangulation_2::All_vertices_iterator Triangulation_2:: all_vertices_end() const { Triangulation_2* ncthis = (Triangulation_2*)this; return All_vertices_iterator(ncthis,1); } template Triangulation_2::All_edges_iterator Triangulation_2:: all_edges_begin() const { Triangulation_2* ncthis = (Triangulation_2*)this; return All_edges_iterator(ncthis); } template Triangulation_2::All_edges_iterator Triangulation_2:: all_edges_end() const { Triangulation_2* ncthis = (Triangulation_2*)this; return All_edges_iterator(ncthis,1); } template inline Triangulation_2::Face_circulator Triangulation_2:: incident_faces(Vertex_handle v, Face_handle f) const { return Face_circulator(v,f); } template inline Triangulation_2::Vertex_circulator Triangulation_2:: incident_vertices(Vertex_handle v, Face_handle f) const { return Vertex_circulator(v,f); } template inline Triangulation_2::Edge_circulator Triangulation_2:: incident_edges(Vertex_handle v, Face_handle f) const { return Edge_circulator(v,f); } template Triangulation_2::Line_face_circulator Triangulation_2:: line_walk(const Point& p, const Point& q, Face_handle f) const { CGAL_triangulation_precondition( (dimension() == 2) && (! geom_traits().compare(p,q)) ); Line_face_circulator lfc = (f.is_null()) ? Line_face_circulator(p, q, this) : Line_face_circulator(p, q, f, this); if( (!lfc.is_empty()) && is_infinite( lfc )){ return Line_face_circulator(); } return lfc; } template Oriented_side Triangulation_2:: oriented_side(const Point &p0, const Point &p1, const Point &p2, const Point &p) const { // depends on the orientation of the vertices Orientation o1 = geom_traits().orientation(p0, p1, p), o2 = geom_traits().orientation(p1, p2, p), o3 = geom_traits().orientation(p2, p0, p), ot = geom_traits().orientation(p0, p1, p2); if (o1 == COLLINEAR || o2 == COLLINEAR || o3 == COLLINEAR) { if ((o1 == COLLINEAR && collinear_between(p0, p, p1)) || (o2 == COLLINEAR && collinear_between(p1, p, p2)) || (o3 == COLLINEAR && collinear_between(p2, p, p0))) { return ON_ORIENTED_BOUNDARY; } // for ot == ON_ORIENTED_BOUNDARY the following also // does the right thing: return (ot == LEFTTURN) ? ON_POSITIVE_SIDE : ON_NEGATIVE_SIDE; } if (ot == RIGHTTURN) { if (o1 == RIGHTTURN && o2 == RIGHTTURN && o3 == RIGHTTURN) { return ON_NEGATIVE_SIDE; } return ON_POSITIVE_SIDE; } if (o1 == LEFTTURN && o2 == LEFTTURN && o3 == LEFTTURN) { return ON_POSITIVE_SIDE; } return ON_NEGATIVE_SIDE; } template Bounded_side Triangulation_2:: bounded_side(const Point &p0, const Point &p1, const Point &p2, const Point &p) const { Orientation o1 = geom_traits().orientation(p0, p1, p), o2 = geom_traits().orientation(p1, p2, p), o3 = geom_traits().orientation(p2, p0, p), ot = geom_traits().orientation(p0, p1, p2); if(o1 == COLLINEAR || o2 == COLLINEAR || o3 == COLLINEAR) { if ((o1 == COLLINEAR && collinear_between(p0, p, p1)) || (o2 == COLLINEAR && collinear_between(p1, p, p2)) || (o3 == COLLINEAR && collinear_between(p2, p, p0))) { return ON_BOUNDARY; } return ON_UNBOUNDED_SIDE; } if (ot == RIGHTTURN) { if(o1==RIGHTTURN && o2==RIGHTTURN && o3==RIGHTTURN) { return ON_BOUNDED_SIDE; } return ON_UNBOUNDED_SIDE; } if (o1 == LEFTTURN && o2 == LEFTTURN && o3 == LEFTTURN) { return ON_BOUNDED_SIDE; } return ON_UNBOUNDED_SIDE; } template Oriented_side Triangulation_2:: oriented_side(const Face_handle& f, const Point &p) const { CGAL_triangulation_precondition ( dimension()==2); return oriented_side(f->vertex(0)->point(), f->vertex(1)->point(), f->vertex(2)->point(), p); } template < class Gt, class Tds > Oriented_side Triangulation_2:: side_of_oriented_circle(Face_handle f, const Point & p) const { if ( ! is_infinite(f) ) { return geom_traits().side_of_oriented_circle(f->vertex(0)->point(), f->vertex(1)->point(), f->vertex(2)->point(),p); } int i = f->index(infinite_vertex()); Orientation o = geom_traits().orientation(f->vertex(ccw(i))->point(), f->vertex(cw(i))->point(), p); return (o == NEGATIVE) ? ON_NEGATIVE_SIDE : (o == POSITIVE) ? ON_POSITIVE_SIDE : ON_ORIENTED_BOUNDARY; } template bool Triangulation_2:: collinear_between(const Point& p, const Point& q, const Point& r) const { // return true if point q is between p and r // p,q and r are supposed to be colinear points Comparison_result c_pr = geom_traits().compare_x(p, r); Comparison_result c_pq; Comparison_result c_qr; if(c_pr == EQUAL) { c_pr = geom_traits().compare_y(p, r); c_pq = geom_traits().compare_y(p, q); c_qr = geom_traits().compare_y(q, r); } else { c_pq = geom_traits().compare_x(p, q); c_qr = geom_traits().compare_x(q, r); } return ( (c_pq == SMALLER) && (c_qr == SMALLER) ) || ( (c_pq == LARGER) && (c_qr == LARGER) ); } template Triangulation_2::Point Triangulation_2:: circumcenter(Face_handle f) const { return geom_traits().circumcenter((f->vertex(0))->point(), (f->vertex(1))->point(), (f->vertex(2))->point()); } template void Triangulation_2:: show_all() { std::cerr<< "AFFICHE TOUTE LA TRIANGULATION :"< void Triangulation_2:: show_face(Face_handle fh) { std::cerr << "face : "<<(void*)&(*fh)<<" => "<dimension(); switch(i){ case 0: std::cerr <<"point :"<<(fh->vertex(0)->point()) <<" / voisin "<<&(*(fh->neighbor(0))) <<"["<<(fh->neighbor(0))->vertex(0)->point()<<"]" <vertex(0)->point()) <<" / voisin "<<&(*(fh->neighbor(0))) <<"["<<(fh->neighbor(0))->vertex(0)->point() <<"/"<<(fh->neighbor(0))->vertex(1)->point()<<"]" <vertex(1)->point()) <<" / voisin "<<&(*(fh->neighbor(1))) <<"["<<(fh->neighbor(1))->vertex(0)->point() <<"/"<<(fh->neighbor(1))->vertex(1)->point()<<"]" <vertex(0)->point()) <<" / voisin "<<&(*(fh->neighbor(0))) <<"["<<(fh->neighbor(0))->vertex(0)->point() <<"/"<<(fh->neighbor(0))->vertex(1)->point() <<"/"<<(fh->neighbor(0))->vertex(2)->point()<<"]" <vertex(1)->point()) <<" / voisin "<<&(*(fh->neighbor(1))) <<"["<<(fh->neighbor(1))->vertex(0)->point() <<"/"<<(fh->neighbor(1))->vertex(1)->point() <<"/"<<(fh->neighbor(1))->vertex(2)->point()<<"]" <vertex(2)->point()) <<" / voisin "<<&(*(fh->neighbor(2))) <<"["<<(fh->neighbor(2))->vertex(0)->point() <<"/"<<(fh->neighbor(2))->vertex(1)->point() <<"/"<<(fh->neighbor(2))->vertex(2)->point()<<"]" < void Triangulation_2:: file_output(std::ostream& os) const { _tds.file_output(os, &(*infinite_vertex()), true); } template Triangulation_2::Vertex_handle Triangulation_2:: file_input(std::istream& is) { clear(); Vertex_handle v= static_cast(_tds.file_input(is, true)); set_infinite_vertex(v); return v; } template std::ostream& operator<<(std::ostream& os, const Triangulation_2 &tr) { tr.file_output(os); return os ; } template < class Gt, class Tds > std::istream& operator>>(std::istream& is, Triangulation_2 &tr) { tr.file_input(is); CGAL_triangulation_assertion(tr.is_valid()); return is; } CGAL_END_NAMESPACE #endif //CGAL_TRIANGULATION_2_H