// Copyright (c) 1997 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Triangulation_2/include/CGAL/Constrained_triangulation_2.h $ // $Id: Constrained_triangulation_2.h 871c972 2020-06-03T16:23:22+02:00 Laurent Rineau // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Mariette Yvinec, Jean-Daniel Boissonnat #ifndef CGAL_CONSTRAINED_TRIANGULATION_2_H #define CGAL_CONSTRAINED_TRIANGULATION_2_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace CGAL { struct No_constraint_intersection_tag{}; struct No_constraint_intersection_requiring_constructions_tag{}; struct Exact_intersections_tag{}; // to be used with an exact number type struct Exact_predicates_tag{}; // to be used with filtered exact number // This was deprecated and replaced by ` No_constraint_intersection_tag` and `No_constraint_intersection_requiring_constructions_tag` // due to an inconsistency between the code and the documenation. struct CGAL_DEPRECATED No_intersection_tag : public No_constraint_intersection_requiring_constructions_tag { }; namespace internal { #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS struct Indentation_level { int n; Indentation_level() : n(0) {} friend std::ostream& operator<<(std::ostream& os, Indentation_level level) { return os << std::string(2*level.n, ' '); } Indentation_level& operator++() { ++n; return *this; } Indentation_level& operator--() { --n; return *this; } struct Exit_guard { Exit_guard(Indentation_level& level): level(level) { ++level; } Exit_guard(const Exit_guard& other) : level(other.level) { ++level; } Indentation_level& level; ~Exit_guard() { --level; } }; Exit_guard open_new_scope() { return Exit_guard(*this); } } cdt_2_indent_level; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS template struct Itag { typedef typename boost::mpl::if_::Is_exact, Exact_intersections_tag, Exact_predicates_tag>::type type; }; } // namespace internal template < class Gt, class Tds_ = Default , class Itag_ = Default > class Constrained_triangulation_2 : public Triangulation_2, Constrained_triangulation_face_base_2 > >::type > { public: typedef typename Default::Get, Constrained_triangulation_face_base_2 > >::type Tds; typedef typename Default::Get::type Itag; typedef Triangulation_2 Triangulation; typedef Constrained_triangulation_2 Constrained_triangulation; typedef typename Triangulation::Edge Edge; typedef typename Triangulation::Vertex Vertex; typedef typename Triangulation::Vertex_handle Vertex_handle; typedef typename Triangulation::Face_handle Face_handle; typedef typename Triangulation::size_type size_type; typedef typename Triangulation::Locate_type Locate_type; typedef typename Triangulation::All_faces_iterator All_faces_iterator; typedef typename Triangulation::Finite_edges_iterator Finite_edges_iterator; typedef typename Triangulation::Face_circulator Face_circulator; typedef typename Triangulation::Edge_circulator Edge_circulator; typedef typename Triangulation::Vertex_circulator Vertex_circulator; typedef typename Triangulation::Line_face_circulator Line_face_circulator; struct Is_constrained { const Constrained_triangulation& ct; Is_constrained(const Constrained_triangulation& ct) : ct(ct) {} template bool operator()(const E& e) const { return ct.is_constrained(e); } }; class Intersection_of_constraints_exception : public std::exception { const char* what() const throw () { return "Unauthorized intersections of constraints"; } }; typedef boost::filter_iterator Constrained_edges_iterator; typedef Iterator_range Constrained_edges; #ifndef CGAL_CFG_USING_BASE_MEMBER_BUG_2 using Triangulation::number_of_vertices; using Triangulation::cw; using Triangulation::ccw; using Triangulation::dimension; using Triangulation::geom_traits; using Triangulation::all_faces_begin; using Triangulation::all_faces_end; using Triangulation::finite_edges_begin; using Triangulation::finite_edges_end; using Triangulation::side_of_oriented_circle; using Triangulation::is_infinite; using Triangulation::collinear_between; using Triangulation::incident_edges; using Triangulation::test_dim_down; using Triangulation::make_hole; using Triangulation::fill_hole; using Triangulation::delete_vertex; using Triangulation::delete_face; using Triangulation::create_face; using Triangulation::incident_faces; using Triangulation::locate; using Triangulation::includes_edge; using Triangulation::remove_first; using Triangulation::remove_second; using Triangulation::is_valid; using Triangulation::all_edges_begin; using Triangulation::all_edges_end; using Triangulation::mirror_index; using Triangulation::mirror_edge; using Triangulation::orientation; #endif typedef Gt Geom_traits; typedef Itag Intersection_tag; typedef typename Geom_traits::Point_2 Point; typedef typename Geom_traits::Segment_2 Segment; typedef std::pair Constraint; typedef std::list List_edges; typedef std::list List_faces; typedef std::list List_vertices; typedef std::list List_constraints; // Tag to mark the presence of a hierarchy of constraints typedef Tag_false Constraint_hierarchy_tag; //Tag to distinguish Delaunay from regular triangulations typedef Tag_false Weighted_tag; // Tag to distinguish periodic triangulations from others typedef Tag_false Periodic_tag; Constrained_triangulation_2(const Gt& gt = Gt()) : Triangulation(gt) { } Constrained_triangulation_2(std::list& lc, const Gt& gt=Gt()) : Triangulation_2(gt) { typename List_constraints::iterator lcit=lc.begin(); for( ;lcit != lc.end(); lcit++) { insert( (*lcit).first, (*lcit).second); } CGAL_triangulation_postcondition( is_valid() ); } template Constrained_triangulation_2(InputIterator it, InputIterator last, const Gt& gt=Gt() ) : Triangulation_2(gt) { for ( ; it != last; it++) { insert_constraint((*it).first, (*it).second); } CGAL_triangulation_postcondition( is_valid() ); } //TODO Is that destructor correct ? virtual ~Constrained_triangulation_2() {} // Ensure rule-of-five: define the copy- and move- constructors // as well as the copy- and move- assignment operators. Constrained_triangulation_2(const Constrained_triangulation_2 &) = default; Constrained_triangulation_2(Constrained_triangulation_2 &&) = default; Constrained_triangulation_2 & operator=(const Constrained_triangulation_2 &) = default; Constrained_triangulation_2 & operator=(Constrained_triangulation_2 &&) = default; Constrained_edges_iterator constrained_edges_begin() const { Is_constrained pred(*this); return Constrained_edges_iterator(pred, all_edges_begin(), all_edges_end()); } Constrained_edges_iterator constrained_edges_end() const { Is_constrained pred(*this); return Constrained_edges_iterator(pred, all_edges_end(), all_edges_end()); } Constrained_edges constrained_edges() const { return Constrained_edges(constrained_edges_begin(),constrained_edges_end()); } // INSERTION 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& a); // template < class InputIterator > // std::ptrdiff_t insert(InputIterator first, InputIterator last); // The iterator range [edge_it, edge_pteit) is a set of edges // that delimit areas in the triangulation. // This function writes the face handles that cover this // area to the output iterator faces_it template void get_bounded_faces(InputIterator edge_it, InputIterator edge_pteit, OutputIterator faces_it) const { Edge e; Unique_hash_map visited; std::stack st; for(; edge_it != edge_pteit; edge_it++){ e = *edge_it; visited[e.first] = true; st.push(e.first->neighbor(e.second)); } while(! st.empty()){ Face_handle fh = st.top(); st.pop(); typename CGAL::Unique_hash_map::Data& data = visited[fh]; if(! data) { data = true; *faces_it++ = fh; for(int i = 0 ; i < 3 ; ++i){ Face_handle n = fh->neighbor(i); if(! visited[n]) { st.push(n); } } } } } #if 1 template static const Point& get_source(const Segment_2& segment){ return segment.source(); } template static const Point& get_target(const Segment_2& segment){ return segment.target(); } static const Point& get_source(const Constraint& cst){ return cst.first; } static const Point& get_target(const Constraint& cst){ return cst.second; } #endif // A version of insert_constraint, that additionally writes // the new faces in an output iterator // We duplicate code, as to run this one with an Emptyset_iterator // is still too much overhead template void insert_constraint(Vertex_handle vaa, Vertex_handle vbb, OutputIterator out) // forces the constrained [va,vb] // [va,vb] will eventually be split into several edges // if a vertex vc of t lies on segment ab // of if ab intersect some constrained edges { CGAL_triangulation_precondition( vaa != vbb); Vertex_handle vi; Face_handle fr; int i; if(includes_edge(vaa,vbb,vi,fr,i)) { // if the segment (or a subpart of the segment) that we are trying to constraint is already // present in the triangulation and is already marked as constrained, // then this is an intersection if(boost::is_same::value) { if(dimension() == 1) { if(fr->is_constrained(2)) throw Intersection_of_constraints_exception(); } else { if(fr->is_constrained(i)) throw Intersection_of_constraints_exception(); } } mark_constraint(fr,i); if (vi != vbb) { insert_constraint(vi,vbb,out); } return; } List_faces intersected_faces; List_edges conflict_boundary_ab, conflict_boundary_ba; bool intersection = find_intersected_faces( vaa, vbb, intersected_faces, conflict_boundary_ab, conflict_boundary_ba, vi); if ( intersection) { if (vi != vaa && vi != vbb) { insert_constraint(vaa,vi,out); insert_constraint(vi,vbb,out); } else { insert_constraint(vaa,vbb,out); } return; } List_edges edges(conflict_boundary_ab); std::copy(conflict_boundary_ba.begin(), conflict_boundary_ba.end(), std::back_inserter(edges)); typename List_edges::iterator last = edges.end(); --last; for(typename List_edges::iterator it = edges.begin(); it != last; ){ typename List_edges::iterator n = it; ++n; if(it->first == n->first->neighbor(n->second) ){ // remove dangling edge edges.erase(it); it = n; ++n; edges.erase(it); } it = n; } triangulate_hole(intersected_faces, conflict_boundary_ab, conflict_boundary_ba); get_bounded_faces(edges.begin(), edges.end(), out); if (vi != vbb) { insert_constraint(vi,vbb,out); } return; } void insert_constraint(const Point& a, const Point& b); void insert_constraint(Vertex_handle va, Vertex_handle vb); void push_back(const Constraint& c); template void insert_constraint(PointIterator first, PointIterator last, bool close=false) { if(first == last){ return; } const Point& p0 = *first; Point p = p0; Vertex_handle v0 = insert(p0), v(v0), w(v0); ++first; for(; first!=last; ++first){ const Point& q = *first; if(p != q){ w = insert(q); insert_constraint(v,w); v = w; p = q; } } if(close && (p != p0)){ insert(w,v0); } } void remove(Vertex_handle v); void remove_constrained_edge(Face_handle f, int i); void remove_incident_constraints(Vertex_handle v); // to be used by Constrained_triangulation_plus_2 template OutputItFaces remove_constrained_edge(Face_handle f, int i, OutputItFaces out) { remove_constrained_edge(f, i); return out; } //for backward compatibility void remove_constraint(Face_handle f, int i) {remove_constrained_edge(f,i);} void insert(Point a, Point b) { insert_constraint(a, b);} void insert(Vertex_handle va, Vertex_handle vb) {insert_constraint(va,vb);} // QUERY bool is_constrained(Edge e) const; bool are_there_incident_constraints(Vertex_handle v) const; bool is_valid(bool verbose = false, int level = 0) const; // template // OutputItEdges incident_constraints(Vertex_handle v, // OutputItEdges out) const; void file_output(std::ostream& os) const; protected: virtual Vertex_handle virtual_insert(const Point& a, Face_handle start = Face_handle()); virtual Vertex_handle virtual_insert(const Point& a, Locate_type lt, Face_handle loc, int li ); //Vertex_handle special_insert_in_edge(const Point & a, Face_handle f, int i); void update_constraints_incident(Vertex_handle va, Vertex_handle c1, Vertex_handle c2); void clear_constraints_incident(Vertex_handle va); void update_constraints_opposite(Vertex_handle va); void update_constraints(const List_edges &hole); void mark_constraint(Face_handle fr, int i); virtual Vertex_handle intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb); Vertex_handle intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb, No_constraint_intersection_tag); Vertex_handle intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb, No_constraint_intersection_requiring_constructions_tag); Vertex_handle intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb, Exact_intersections_tag); Vertex_handle intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb, Exact_predicates_tag); private: //made private to avoid using the Triangulation_2 version Vertex_handle move(Vertex_handle v, const Point &) { CGAL_error_msg("Do not use that function!"); return v; } public: // made public for Laurent to find out deleted faces // when inserting a constraint with most probably // no intersection bool find_intersected_faces(Vertex_handle va, Vertex_handle vb, List_faces & intersected_faces, List_edges & list_ab, List_edges & list_ba, Vertex_handle& vi); protected: virtual void triangulate_hole(List_faces& intersected_faces, List_edges& conflict_boundary_ab, List_edges& conflict_boundary_ba); void triangulate_hole(List_faces& intersected_faces, List_edges& conflict_boundary_ab, List_edges& conflict_boundary_ba, List_edges& new_edges); void triangulate_half_hole(List_edges & list_edges, List_edges & new_edges); void remove_1D(Vertex_handle v); void remove_2D(Vertex_handle v); //templated member function public: // the int parameter is a work around for VC7 to compile template < class InputIterator > #if defined(_MSC_VER) std::ptrdiff_t insert(InputIterator first, InputIterator last, int i = 0) #else std::ptrdiff_t insert(InputIterator first, InputIterator last) #endif { #if defined(_MSC_VER) CGAL_USE(i); #endif size_type n = number_of_vertices(); std::vector points (first, last); CGAL::spatial_sort (points.begin(), points.end(), geom_traits()); Face_handle hint; for (typename std::vector::const_iterator p = points.begin(), end = points.end(); p != end; ++p) hint = insert (*p, hint)->face(); return number_of_vertices() - n; } //deprecated template bool are_there_incident_constraints(Vertex_handle v, OutputIterator out) const { Edge_circulator ec=incident_edges(v), done(ec); bool are_there = false; if (ec == nullptr) return are_there; do { if(is_constrained(*ec)) { *out++ = *ec; are_there = true; } ec++; } while (ec != done); return are_there; } template OutputItEdges incident_constraints(Vertex_handle v, OutputItEdges out) const { Edge_circulator ec=incident_edges(v), done(ec); if (ec == nullptr) return out; do { if(is_constrained(*ec)) *out++ = *ec; ec++; } while (ec != done); return out; } // the following fonctions are overloaded // to take care of constraint marks template Vertex_handle star_hole( const Point& p, EdgeIt edge_begin, EdgeIt edge_end) { std::list empty_list; return star_hole(p, edge_begin, edge_end, empty_list.begin(), empty_list.end()); } template Vertex_handle star_hole( const Point& p, EdgeIt edge_begin, EdgeIt edge_end, FaceIt face_begin, FaceIt face_end) { Vertex_handle v = Triangulation::star_hole(p, edge_begin, edge_end, face_begin, face_end); // restore constraint status for new faces. int vindex; Face_handle fh; int ih; Face_circulator fc = incident_faces(v), done(fc); do { vindex = fc->index(v); fc->set_constraint(cw(vindex), false); fc->set_constraint(ccw(vindex), false); fh = fc->neighbor(vindex); ih = mirror_index(fc,vindex); fc->set_constraint(vindex, fh->is_constrained(ih)); } while (++fc != done); return v; } }; template < class Gt, class Tds, class Itag > inline typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: virtual_insert(const Point& a, Face_handle start) // virtual version of insert { return insert(a,start); } template < class Gt, class Tds, class Itag > inline typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: virtual_insert(const Point& a, Locate_type lt, Face_handle loc, int li ) // virtual version of insert { return insert(a,lt,loc,li); } template < class Gt, class Tds, class Itag > inline typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: insert(const Point& a, Face_handle start) // inserts point a // in addition to what is done for non constrained triangulations // constrained edges are updated { Face_handle loc; int li; Locate_type lt; loc = locate(a, lt, li, start); return Constrained_triangulation::insert(a,lt,loc,li); } template < class Gt, class Tds, class Itag > typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: insert(const Point& a, Locate_type lt, Face_handle loc, int li) // insert a point p, whose localisation is known (lt, f, i) // in addition to what is done for non constrained triangulations // constrained edges are updated { Vertex_handle va; Vertex_handle v1, v2; bool insert_in_constrained_edge = false; std::list > constrained_edges; bool one_dimensional = false; if(dimension() == 1){ one_dimensional = true; for(Finite_edges_iterator it = finite_edges_begin(); it != finite_edges_end(); ++it){ if(is_constrained(*it)){ constrained_edges.emplace_back(it->first->vertex(cw(it->second)), it->first->vertex(ccw(it->second))); } } } if ( lt == Triangulation::EDGE && loc->is_constrained(li) ) { if(boost::is_same::value) throw Intersection_of_constraints_exception(); insert_in_constrained_edge = true; v1=loc->vertex(ccw(li)); //endpoint of the constraint v2=loc->vertex(cw(li)); // endpoint of the constraint } va = Triangulation::insert(a,lt,loc,li); if(one_dimensional && (dimension() == 2)){ for(const std::pair& vp : constrained_edges){ Face_handle fh; int i; if(this->is_edge(vp.first, vp.second, fh,i)){ fh->set_constraint(i,true); boost::tie(fh,i) = mirror_edge(Edge(fh,i)); fh->set_constraint(i,true); } } } if (insert_in_constrained_edge) update_constraints_incident(va, v1,v2); else if(lt != Triangulation::VERTEX) clear_constraints_incident(va); if (dimension() == 2) update_constraints_opposite(va); return va; } // template < class Gt, class Tds, class Itag > // typename Constrained_triangulation_2::Vertex_handle // Constrained_triangulation_2:: // special_insert_in_edge(const Point & a, Face_handle f, int i) // // insert point p in edge(f,i) // // bypass the precondition for point a to be in edge(f,i) // // update constrained status // { // Vertex_handle va; // Vertex_handle c1,c2; // c1 = f->vertex(cw(i)); //endpoint of edge // c2 = f->vertex(ccw(i)); //endpoint of edge // bool insert_in_constrained_edge = f->is_constrained(i); // va = this->_tds.insert_in_edge(f, i); // va->set_point(a); // if (insert_in_constrained_edge) update_constraints_incident(va, c1,c2); // else clear_constraints_incident(va); // if (dimension() == 2) update_constraints_opposite(va); // return va; // } template < class Gt, class Tds, class Itag > inline void Constrained_triangulation_2:: insert_constraint(const Point& a, const Point& b) // the algorithm first inserts a and b, // and then forces the constraint [va,vb] { Vertex_handle va= virtual_insert(a); Vertex_handle vb= virtual_insert(b); if ( va != vb) insert_constraint(va,vb); } template inline void Constrained_triangulation_2:: insert_constraint(Vertex_handle vaa, Vertex_handle vbb) // forces the constraint [va,vb] // [va,vb] will eventually be split into several edges // if a vertex vc of t lies on segment ab // or if ab intersect some constrained edges { std::stack > stack; stack.push(std::make_pair(vaa,vbb)); #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::insert_constraint( #" << vaa->time_stamp() << "= " << vaa->point() << " , #" << vbb->time_stamp() << "= " << vbb->point() << " )\n"; internal::Indentation_level::Exit_guard exit_guard = CGAL::internal::cdt_2_indent_level.open_new_scope(); #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS while(! stack.empty()){ boost::tie(vaa,vbb) = stack.top(); stack.pop(); CGAL_triangulation_precondition( vaa != vbb); #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::insert_constraint, stack pop=( #" << vaa->time_stamp() << "= " << vaa->point() << " , #" << vbb->time_stamp() << "= " << vbb->point() << " ) remaining stack size: " << stack.size() << '\n'; CGAL_assertion(this->is_valid()); #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS Vertex_handle vi; Face_handle fr; int i; if(includes_edge(vaa,vbb,vi,fr,i)) { // if the segment (or a subpart of the segment) that we are trying to constraint is already // present in the triangulation and is already marked as constrained, // then this is an intersection if(boost::is_same::value) { if(dimension() == 1) { if(fr->is_constrained(2)) throw Intersection_of_constraints_exception(); } else { if(fr->is_constrained(i)) throw Intersection_of_constraints_exception(); } } mark_constraint(fr,i); if (vi != vbb) { stack.push(std::make_pair(vi,vbb)); } continue; } List_faces intersected_faces; List_edges conflict_boundary_ab, conflict_boundary_ba; bool intersection = find_intersected_faces( vaa, vbb, intersected_faces, conflict_boundary_ab, conflict_boundary_ba, vi); if ( intersection) { if (vi != vaa && vi != vbb) { #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::insert_constraint stask push [vaa, vi] ( #" << vaa->time_stamp() << "= " << vaa->point() << " , #" << vi->time_stamp() << "= " << vi->point() << " )\n"; std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::insert_constraint stask push [vi, vbb] ( #" << vi->time_stamp() << "= " << vi->point() << " , #" << vbb->time_stamp() << "= " << vbb->point() << " )\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS stack.push(std::make_pair(vaa,vi)); stack.push(std::make_pair(vi,vbb)); } else{ #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::insert_constraint stask push [vaa, vbb]( #" << vaa->time_stamp() << "= " << vaa->point() << " , #" << vbb->time_stamp() << "= " << vbb->point() << " )\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS stack.push(std::make_pair(vaa,vbb)); } continue; } //no intersection triangulate_hole(intersected_faces, conflict_boundary_ab, conflict_boundary_ba); if (vi != vbb) { stack.push(std::make_pair(vi,vbb)); } } } template bool Constrained_triangulation_2:: find_intersected_faces(Vertex_handle vaa, Vertex_handle vbb, List_faces & intersected_faces, List_edges & list_ab, List_edges & list_ba, Vertex_handle & vi) // vi is set to the first vertex of the triangulation on [vaa,vbb]. // Return true if an intersection with a constrained edge is // encountered, false otherwise // When false : // intersected_faces contains the list if faces intersected by [va,vi] // list_ab and list_ba represents the boundary of the union // of the intersected faces oriented cw // list_ab consists of the edges from vaa to vi (i.e. on the left of a->b) // list_ba " " from vi to vaa (i.e. on the right of a->b) { const Point& aa = vaa->point(); const Point& bb = vbb->point(); Line_face_circulator current_face=Line_face_circulator(vaa, this, bb); int ind=current_face->index(vaa); // to deal with the case where the first crossed edge // is constrained #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::find_intersected_faces ( #" << vaa->time_stamp() << "= " << vaa->point() << " , #" << vbb->time_stamp() << "= " << vbb->point() << " )\n" << CGAL::internal::cdt_2_indent_level << "> current constrained edges are:\n"; for(Constrained_edges_iterator edge_it = this->constrained_edges_begin(), end = this->constrained_edges_end(); edge_it != end; ++edge_it) { std::cerr < (#" << edge_it->first->vertex(cw(edge_it->second))->time_stamp() << ", #" << edge_it->first->vertex(ccw(edge_it->second))->time_stamp() << ")\n"; } std::cerr << CGAL::internal::cdt_2_indent_level << "> current face is ( #" << current_face->vertex(0)->time_stamp() << " #" << current_face->vertex(1)->time_stamp() << " #" << current_face->vertex(2)->time_stamp() << " )\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS if(current_face->is_constrained(ind)) { vi=intersect(current_face, ind, vaa, vbb); return true; } Face_handle lf= current_face->neighbor(ccw(ind)); Face_handle rf= current_face->neighbor(cw(ind)); Orientation orient; Face_handle previous_face; Vertex_handle current_vertex; list_ab.push_back(Edge(lf, lf->index(current_face))); list_ba.push_front(Edge(rf, rf->index(current_face))); intersected_faces.push_front(current_face); // initcd previous_face=current_face; ++current_face; ind=current_face->index(previous_face); current_vertex=current_face->vertex(ind); // loop over triangles intersected by ab bool done = false; while (current_vertex != vbb && !done) { orient = orientation(aa,bb,current_vertex->point()); int i1, i2; switch (orient) { case COLLINEAR : done = true; // current_vertex is the new endpoint break; case LEFT_TURN : case RIGHT_TURN : if (orient == LEFT_TURN) { i1 = ccw(ind) ; //index of second intersected edge of current_face i2 = cw(ind); //index of non intersected edge of current_face } else { i1 = cw(ind) ; //index of second intersected edge of current_face i2 = ccw(ind); //index of non intersected edge of current_face } if(current_face->is_constrained(i1)) { vi = intersect(current_face, i1, vaa,vbb); return true; } else { lf= current_face->neighbor(i2); intersected_faces.push_front(current_face); if (orient == LEFT_TURN) list_ab.push_back(Edge(lf, lf->index(current_face))); else // orient == RIGHT_TURN list_ba.push_front(Edge(lf, lf->index(current_face))); previous_face=current_face; ++current_face; ind=current_face->index(previous_face); current_vertex=current_face->vertex(ind); } break; } } // last triangle vi = current_vertex; intersected_faces.push_front(current_face); lf= current_face->neighbor(cw(ind)); list_ab.push_back(Edge(lf, lf->index(current_face))); rf= current_face->neighbor(ccw(ind)); list_ba.push_front(Edge(rf, rf->index(current_face))); return false; } template typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb) { return intersect(f, i, vaa, vbb, Itag()); } template typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: intersect(Face_handle , int , Vertex_handle , Vertex_handle , No_constraint_intersection_tag) { throw Intersection_of_constraints_exception(); return Vertex_handle() ; } template typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: intersect(Face_handle , int , Vertex_handle , Vertex_handle , No_constraint_intersection_requiring_constructions_tag) { throw Intersection_of_constraints_exception(); return Vertex_handle() ; } template typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb, Exact_intersections_tag) // compute the intersection of the constraint edge (f,i) // with the subconstraint (vaa,vbb) being inserted // insert the intersection point // split constraint edge (f,i) // and return the Vertex_handle of the new Vertex { #ifndef CGAL_NO_CDT_2_WARNING CGAL_warning_msg(false, "You are using an exact number type,\n" "using a Constrained_triangulation_plus_2 class\n" "would avoid cascading intersection computation\n" " and be much more efficient\n" "This message is shown only if CGAL_NO_CDT_2_WARNING" " is not defined.\n"); #endif const Point& pa = vaa->point(); const Point& pb = vbb->point(); const Point& pc = f->vertex(cw(i))->point(); const Point& pd = f->vertex(ccw(i))->point(); Point pi; Itag itag = Itag(); CGAL_triangulation_assertion_code( bool ok = ) intersection(geom_traits(), pa, pb, pc, pd, pi, itag ); CGAL_triangulation_assertion(ok); Vertex_handle vi = virtual_insert(pi, Triangulation::EDGE, f, i); return vi; } template typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: intersect(Face_handle f, int i, Vertex_handle vaa, Vertex_handle vbb, Exact_predicates_tag) { Vertex_handle vcc, vdd; vcc = f->vertex(cw(i)); vdd = f->vertex(ccw(i)); const Point& pa = vaa->point(); const Point& pb = vbb->point(); const Point& pc = vcc->point(); const Point& pd = vdd->point(); #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::intersect segment ( #" << vaa->time_stamp() << "= " << vaa->point() << " , #" << vbb->time_stamp() << "= " << vbb->point() << " ) with edge ( #"<< vcc->time_stamp() << "= " << vcc->point() << " , #" << vdd->time_stamp() << "= " << vdd->point() << " )\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS Point pi; //creator for point is required here Itag itag = Itag(); bool ok = intersection(geom_traits(), pa, pb, pc, pd, pi, itag ); Vertex_handle vi; if ( !ok) { //intersection detected but not computed int int_index = limit_intersection(geom_traits(), pa, pb, pc, pd, itag); switch(int_index){ case 0 : vi = vaa; break; case 1 : vi = vbb; break; case 2 : vi = vcc; break; case 3 : vi = vdd; break; } if(vi == vaa || vi == vbb) { remove_constrained_edge(f, i); } } else{ //intersection computed remove_constrained_edge(f, i); vi = virtual_insert(pi, f); } #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::intersect, `vi` is ( #" << vi->time_stamp() << "= " << vi->point() << " )\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS // vi == vc or vi == vd may happen even if intersection==true // due to approximate construction of the intersection if (vi != vcc && vi != vdd) { insert_constraint(vcc,vi); insert_constraint(vi, vdd); } else { insert_constraint(vcc,vdd); } return vi; } template inline typename Constrained_triangulation_2::Vertex_handle Constrained_triangulation_2:: push_back(const Point &p) { return insert(p); } template inline void Constrained_triangulation_2:: push_back(const Constraint &c) { insert(c.first, c.second); } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: update_constraints_incident(Vertex_handle va, Vertex_handle c1, Vertex_handle c2) // update status of edges incident to a // after insertion in the constrained edge c1c2 { if (dimension() == 0) return; if (dimension()== 1) { Edge_circulator ec=incident_edges(va), done(ec); do { ((*ec).first)->set_constraint(2,true); }while (++ec != done); } else{ //dimension() ==2 int cwi, ccwi, indf; Face_circulator fc=incident_faces(va), done(fc); CGAL_triangulation_assertion(fc != nullptr); do { indf = fc->index(va); cwi=cw(indf); ccwi=ccw(indf); if ((fc->vertex(cwi) == c1)||(fc->vertex(cwi) == c2)) { fc->set_constraint(ccwi,true); fc->set_constraint(cwi,false); } else { fc->set_constraint(ccwi,false); fc->set_constraint(cwi,true); } ++fc; } while (fc != done); } } template < class Gt, class Tds ,class Itag > void Constrained_triangulation_2:: clear_constraints_incident(Vertex_handle va) // make the edges incident to a newly created vertex unconstrained { Edge_circulator ec=incident_edges(va), done(ec); Face_handle f; int indf; if ( ec != nullptr){ do { f = (*ec).first ; indf = (*ec).second; f->set_constraint(indf,false); if (dimension() == 2) { f->neighbor(indf)->set_constraint(mirror_index(f,indf),false); } } while (++ec != done); } return; } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: update_constraints_opposite(Vertex_handle va) // update status of edges opposite to a // after insertion of a { CGAL_triangulation_assertion(dimension()==2); Face_handle f=va->face(), start=f; int indf; do { indf = f->index(va); if (f->neighbor(indf)->is_constrained(mirror_index(f,indf)) ) { f->set_constraint(indf,true); } else { f->set_constraint(indf,false); } f= f->neighbor(ccw(indf)); // turns ccw around va } while (f != start); return; } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: update_constraints( const List_edges &hole) { typename List_edges::const_iterator it = hole.begin(); Face_handle f; int i; for ( ; it != hole.end(); it ++) { f =(*it).first; i = (*it).second; if ( f->is_constrained(i) ) (f->neighbor(i))->set_constraint(mirror_index(f,i),true); else (f->neighbor(i))->set_constraint(mirror_index(f,i),false); } } template < class Gt, class Tds, class Itag > inline void Constrained_triangulation_2:: mark_constraint(Face_handle fr, int i) { if (dimension()==1) fr->set_constraint(2, true); else{ fr->set_constraint(i,true); fr->neighbor(i)->set_constraint(mirror_index(fr,i),true); } return; } template < class Gt, class Tds, class Itag > inline void Constrained_triangulation_2:: triangulate_hole(List_faces& intersected_faces, List_edges& conflict_boundary_ab, List_edges& conflict_boundary_ba) { List_edges new_edges; triangulate_hole(intersected_faces, conflict_boundary_ab, conflict_boundary_ba, new_edges); } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: triangulate_hole(List_faces& intersected_faces, List_edges& conflict_boundary_ab, List_edges& conflict_boundary_ba, List_edges& new_edges) // triangulate the hole limited by conflict_boundary_ab // and conflict_boundary_ba // insert the new edges in new-edges // delete the faces of intersected_faces { if ( !conflict_boundary_ab.empty() ) { triangulate_half_hole(conflict_boundary_ab, new_edges); triangulate_half_hole(conflict_boundary_ba, new_edges); // the two faces that share edge ab are neighbors // their common edge ab is a constraint Face_handle fr,fl; fl=(*conflict_boundary_ab.begin()).first; fr=(*conflict_boundary_ba.begin()).first; fl->set_neighbor(2, fr); fr->set_neighbor(2, fl); fl->set_constraint(2, true); fr->set_constraint(2, true); // delete intersected faces while( ! intersected_faces.empty()) { fl = intersected_faces.front(); intersected_faces.pop_front(); delete_face(fl); } } } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: remove(Vertex_handle v) // remove a vertex and updates the constrained edges of the new faces // precondition : there is no incident constraints { CGAL_triangulation_precondition( v != Vertex_handle() ); CGAL_triangulation_precondition( ! is_infinite(v)); CGAL_triangulation_precondition( ! are_there_incident_constraints(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 < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: remove_1D(Vertex_handle v) { Edge_circulator ec = incident_edges(v), done(ec); do { (*ec).first->set_constraint(2,false); } while (++ec != done); Triangulation::remove_1D(v); } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: remove_2D(Vertex_handle v) { if (test_dim_down(v)) { this->_tds.remove_dim_down(v);} else { List_edges hole; make_hole(v, hole); List_edges shell=hole; //save hole because it will be emptied by fill_hole fill_hole(v, hole); update_constraints(shell); delete_vertex(v); } return; } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: remove_constrained_edge(Face_handle f, int i) { #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << "CT_2::remove_constrained_edge ( #" << f->vertex(cw(i))->time_stamp() << ", #" << f->vertex(ccw(i))->time_stamp() << ")\n"; #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS f->set_constraint(i, false); if (dimension() == 2) (f->neighbor(i))->set_constraint(mirror_index(f,i), false); return; } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: remove_incident_constraints(Vertex_handle v) { Edge_circulator ec=incident_edges(v), done(ec); if (ec == nullptr) return; do { if(is_constrained(*ec)) { remove_constrained_edge((*ec).first, (*ec).second);} ec++; } while (ec != done); return; } template < class Gt, class Tds, class Itag > inline bool Constrained_triangulation_2:: are_there_incident_constraints(Vertex_handle v) const { return are_there_incident_constraints(v, Emptyset_iterator()); } template < class Gt, class Tds, class Itag > inline bool Constrained_triangulation_2:: is_valid(bool verbose, int level) const { bool result = Triangulation::is_valid(verbose,level); for( All_faces_iterator it = all_faces_begin(); it != all_faces_end() ; it++) { for(int i=0; i<3; i++) { Face_handle n = it->neighbor(i); result = result && it->is_constrained(i) == n->is_constrained(n->index(it)); } } return result; } template < class Gt, class Tds, class Itag > inline bool Constrained_triangulation_2:: is_constrained(Edge e) const { return (e.first)->is_constrained(e.second); } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: triangulate_half_hole(List_edges & list_edges, List_edges & new_edges) // triangulates the polygon whose boundary consists of list_edges // plus the edge ab joining the two endpoints of list_edges // the orientation of the polygon (as provided by list_edges) must // be cw // the edges of list_edges are assumed to be edges of a // triangulation that will be updated by the procedure // the edges that are created are put in list new_edges // takes linear time { Vertex_handle va; // first vertex of list_edges Face_handle newlf; Face_handle n1,n2,n; int ind1, ind2,ind; Orientation orient; typename List_edges::iterator current, next, tempo; current=list_edges.begin(); va=((*current).first)->vertex(ccw((*current).second)); next=current; ++next; do { n1=(*current).first; ind1=(*current).second; // in case n1 is no longer a triangle of the new triangulation if ( n1->neighbor(ind1) != Face_handle() ) { n=n1->neighbor(ind1); //ind=mirror_index(n1,ind1); // mirror_index does not work in this case ind = cw(n->index(n1->vertex(cw(ind1)))); n1=n->neighbor(ind); ind1= mirror_index(n,ind); } n2=(*next).first; ind2=(*next).second; // in case n2 is no longer a triangle of the new triangulation if (n2->neighbor(ind2) != Face_handle() ) { n=n2->neighbor(ind2); // ind=mirror_index(n2,ind2); // mirror_index does not work in this case ind = cw(n->index(n2->vertex(cw(ind2)))); n2=n->neighbor(ind); ind2= mirror_index(n,ind); } Vertex_handle v0=n1->vertex(ccw(ind1)); Vertex_handle v1=n1->vertex(cw(ind1)); Vertex_handle v2=n2->vertex(cw(ind2)); orient = orientation(v0->point(),v1->point(),v2->point()); switch (orient) { case RIGHT_TURN : // creates the new triangle v0v1v2 // updates the neighbors, the constraints //and the list of new edges newlf = create_face(v0,v2,v1); new_edges.push_back(Edge(newlf,2)); newlf->set_neighbor(1, n1); newlf->set_neighbor(0, n2); n1->set_neighbor(ind1, newlf); n2->set_neighbor(ind2, newlf); if (n1->is_constrained(ind1)) { newlf->set_constraint(1,true); } if (n2->is_constrained(ind2)) { newlf->set_constraint(0,true); } // v0, v1 or v2.face() may have been removed v0->set_face(newlf); v1->set_face(newlf); v2->set_face(newlf); // update list_edges tempo=current; current=list_edges.insert(current, Edge(newlf,2)); list_edges.erase(tempo); list_edges.erase(next); next=current; if (v0 != va) {--current;} else {++next;} break; case LEFT_TURN : ++current; ++next; break; case COLLINEAR : ++current; ++next; break; } } while (next != list_edges.end()); } template < class Gt, class Tds, class Itag > void Constrained_triangulation_2:: file_output(std::ostream& os) const { Triangulation_2::file_output(os); // write constrained status typename Tds::Face_iterator ib = this->_tds.face_iterator_base_begin(); for( ; ib != this->_tds.face_iterator_base_end(); ++ib) { for(int j = 0; j < 3; ++j){ if (ib->is_constrained(j)) { os << "C";} else { os << "N";} if(is_ascii(os)){ if(j==2) { os << "\n"; } else { os << ' '; } } } } } template < class Gt, class Tds, class Itag > std::ostream & operator<<(std::ostream& os, const Constrained_triangulation_2 &ct) { ct.file_output(os); return os ; } template < class Gt, class Tds, class Itag > std::istream & operator>>(std::istream& is, Constrained_triangulation_2 &ct) { typedef Constrained_triangulation_2 CDT; ct.clear(); is >> static_cast(ct); for (typename CDT::All_faces_iterator fit=ct.all_faces_begin(), fit_end=ct.all_faces_end();fit_end!=fit;++fit){ char c[3]; is >> c[0] >> c[1] >> c[2]; for (int k=0;k<3;++k){ fit->set_constraint(k,c[k]=='C'); } } return is; } //Helping functions to compute intersections of constrained edges template bool intersection(const Gt& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , typename Gt::Point_2& , No_constraint_intersection_tag) { return false; } template bool intersection(const Gt& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , typename Gt::Point_2& , No_constraint_intersection_requiring_constructions_tag) { return false; } template bool intersection(const Gt& gt, const typename Gt::Point_2& pa, const typename Gt::Point_2& pb, const typename Gt::Point_2& pc, const typename Gt::Point_2& pd, typename Gt::Point_2& pi, Exact_intersections_tag) { return compute_intersection(gt,pa,pb,pc,pd,pi); } template inline bool intersection(const Gt& gt, const typename Gt::Point_2& pa, const typename Gt::Point_2& pb, const typename Gt::Point_2& pc, const typename Gt::Point_2& pd, typename Gt::Point_2& pi, Exact_predicates_tag, CGAL::Tag_false /* not a FT is not floating-point */) { return compute_intersection(gt,pa,pb,pc,pd,pi); } template inline bool intersection(const Gt& gt, const typename Gt::Point_2& pa, const typename Gt::Point_2& pb, const typename Gt::Point_2& pc, const typename Gt::Point_2& pd, typename Gt::Point_2& pi, Exact_predicates_tag, CGAL::Tag_true /* FT is a floating-point type */) { const bool result = compute_intersection(gt,pa,pb,pc,pd,pi); if(!result) return result; if(pi == pa || pi == pb || pi == pc || pi == pd) { #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS std::cerr << CGAL::internal::cdt_2_indent_level << " CT_2::intersection: intersection is an existing point " << pi << std::endl; #endif return result; } #ifdef CGAL_CDT_2_INTERSECTION_SNAPPING_ULP_DISTANCE const int dist = CGAL_CDT_2_INTERSECTION_SNAPPING_ULP_DISTANCE; #else const int dist = 4; #endif typedef typename Gt::Construct_bbox_2 Construct_bbox_2; Construct_bbox_2 bbox = gt.construct_bbox_2_object(); typename boost::result_of::type bb(bbox(pi)); bb.dilate(dist); if(do_overlap(bb, bbox(pa))) pi = pa; if(do_overlap(bb, bbox(pb))) pi = pb; if(do_overlap(bb, bbox(pc))) pi = pc; if(do_overlap(bb, bbox(pd))) pi = pd; #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS if(pi == pa || pi == pb || pi == pc || pi == pd) { std::cerr << CGAL::internal::cdt_2_indent_level << " CT_2::intersection: intersection SNAPPED to an existing point " << pi << std::endl; } #endif return result; } template inline bool intersection(const Gt& gt, const typename Gt::Point_2& pa, const typename Gt::Point_2& pb, const typename Gt::Point_2& pc, const typename Gt::Point_2& pd, typename Gt::Point_2& pi, Exact_predicates_tag exact_predicates_tag) { typedef typename Gt::FT FT; return intersection(gt,pa,pb,pc,pd,pi, exact_predicates_tag, Boolean_tag::value>()); } template bool compute_intersection(const Gt& gt, const typename Gt::Point_2& pa, const typename Gt::Point_2& pb, const typename Gt::Point_2& pc, const typename Gt::Point_2& pd, typename Gt::Point_2& pi) { typename Gt::Intersect_2 compute_intersec=gt.intersect_2_object(); typename Gt::Construct_segment_2 construct_segment=gt.construct_segment_2_object(); Object result = compute_intersec(construct_segment(pa,pb), construct_segment(pc,pd)); #ifdef CGAL_CDT_2_DEBUG_INTERSECTIONS typename Gt::Segment_2 s; if(assign(s, result)) { std::cerr << CGAL::internal::cdt_2_indent_level << "compute_intersection: " << s << '\n'; } if(assign(pi, result)) { std::cerr << CGAL::internal::cdt_2_indent_level << "compute_intersection: " << pi << '\n'; } #endif // CGAL_CDT_2_DEBUG_INTERSECTIONS return assign(pi, result); } template int limit_intersection(const Gt& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , No_constraint_intersection_tag) { return 0; } template int limit_intersection(const Gt& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , No_constraint_intersection_requiring_constructions_tag) { return 0; } template int limit_intersection(const Gt& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , const typename Gt::Point_2& , Exact_intersections_tag) { return 0; } template int limit_intersection(const Gt& gt, const typename Gt::Point_2& pa, const typename Gt::Point_2& pb, const typename Gt::Point_2& pc, const typename Gt::Point_2& pd, Exact_predicates_tag) { typename Gt::Construct_line_2 line = gt.construct_line_2_object(); typename Gt::Compute_squared_distance_2 distance = gt.compute_squared_distance_2_object(); typename Gt::Line_2 l1 = line(pa,pb); typename Gt::Line_2 l2 = line(pc,pd); int i = 0; typename Gt::FT dx = distance(l2,pa); typename Gt::FT db = distance(l2,pb); typename Gt::FT dc = distance(l1,pc); typename Gt::FT dd = distance(l1,pd); if ( db < dx ) { dx = db; i = 1;} if ( dc < dx ) { dx = dc; i = 2;} if ( dd < dx ) { i = 3;} return i; } } //namespace CGAL #include #endif //CGAL_CONSTRAINED_TRIANGULATION_2_H