From cf12f90cbf721fbbf6752d98c6d76190b6a5052c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 26 Sep 2022 16:08:43 +0200 Subject: [PATCH] Fix broken is_hyperbolic(face/edge) framework The previous code tries to handle finite/infinite and hyperbolic/non-hyperbolic with a single flag, which caused errors to get stuff like finite but non-hyperbolic edges (see e.g. https://github.com/CGAL/cgal/issues/6869). In addition, it used tds_data(), which is something that now also exists in the triangulation_ds_face_base_2 class. Hence, completely re-implement the hyperbolic stack / query. # ../../../../Installation/CHANGES.md.orig --- .../Hyperbolic_Delaunay_triangulation_2.h | 246 +++++------------- .../Hyperbolic_triangulation_face_base_2.h | 40 ++- 2 files changed, 108 insertions(+), 178 deletions(-) diff --git a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h index ca47cb1f922..b5fb838c29c 100644 --- a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h +++ b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_Delaunay_triangulation_2.h @@ -193,10 +193,10 @@ public: do { _ri = cw(_iv); - if (_tri.is_finite_non_hyperbolic(pos, ccw(_iv))) + if (!_tri.is_Delaunay_hyperbolic(pos, ccw(_iv))) { _ri = ccw(_iv); - if (_tri.is_finite_non_hyperbolic(pos, cw(_iv))) + if (!_tri.is_Delaunay_hyperbolic(pos, cw(_iv))) { pos = pos->neighbor(cw(_iv)); _iv = pos->index(_v); @@ -222,10 +222,10 @@ public: do { _ri = cw(_iv); - if (_tri.is_finite_non_hyperbolic(pos, ccw(_iv))) + if (!_tri.is_Delaunay_hyperbolic(pos, ccw(_iv))) { _ri = ccw(_iv); - if (_tri.is_finite_non_hyperbolic(pos, cw(_iv))) + if (!_tri.is_Delaunay_hyperbolic(pos, cw(_iv))) { pos = pos->neighbor(cw(_iv)); _iv = pos->index(_v); @@ -253,10 +253,10 @@ public: do { _ri = ccw(_iv); - if (_tri.is_finite_non_hyperbolic(pos, cw(_iv))) + if (!_tri.is_Delaunay_hyperbolic(pos, cw(_iv))) { _ri = cw(_iv); - if (_tri.is_finite_non_hyperbolic(pos, ccw(_iv))) + if (!_tri.is_Delaunay_hyperbolic(pos, ccw(_iv))) { pos = pos->neighbor(ccw(_iv)); _iv = pos->index(_v); @@ -396,12 +396,6 @@ public: void clear() { Base::clear(); } - void mark_star(Vertex_handle v) const - { - if(!is_star_bounded(v)) - mark_star_faces(v); - } - template OutputItFaces find_conflicts(const Point& p, OutputItFaces fit, Face_handle start = Face_handle()) const { @@ -412,7 +406,7 @@ public: Face_handle start = Face_handle()) { Vertex_handle v = Base::insert(p, start); - mark_star(v); + mark_star_faces(v); ensure_hyperbolic_face_handle(v); return v; @@ -427,7 +421,7 @@ public: Face_handle loc, int li) { Vertex_handle v = Base::insert(p, lt, loc, li); - mark_star(v); + mark_star_faces(v); ensure_hyperbolic_face_handle(v); return v; @@ -491,15 +485,35 @@ public: template bool is_infinite(T v) const { return Base::is_infinite(v); } + bool is_infinite(Face_handle f, int i) const { return Base::is_infinite(f, i); } bool is_Delaunay_hyperbolic(Face_handle f) const { - return !Base::is_infinite(f) && !is_finite_non_hyperbolic(f); + if(dimension() <= 1) + return false; + + return f->hyperbolic_data().is_Delaunay_hyperbolic(); } bool is_Delaunay_hyperbolic(Face_handle f, int i) const { - return !Base::is_infinite(f, i) && !is_finite_non_hyperbolic(f, i); + if(dimension() <= 1) + return false; + + if(is_infinite(f, i)) + return false; + + if(f->hyperbolic_data().is_Delaunay_non_hyperbolic(i)) + return false; + + // another incident face and corresponding index + Face_handle f2 = f->neighbor(i); + int i2 = f2->index(f); + + if(f2->hyperbolic_data().is_Delaunay_non_hyperbolic(i2)) + return false; + + return true; } bool is_Delaunay_hyperbolic(const Edge& e) const @@ -518,38 +532,6 @@ public: } private: - class Face_data - { - private: - // a finite face is non_hyperbolic if its circumscribing circle intersects the circle at infinity - bool _is_Delaunay_hyperbolic; - - // defined only if the face is finite and non_hyperbolic - unsigned int _non_hyperbolic_edge; - - public: - Face_data() : _is_Delaunay_hyperbolic(true), _non_hyperbolic_edge(UCHAR_MAX) {} - - unsigned int get_non_hyperbolic_edge() const - { - CGAL_triangulation_precondition(!_is_Delaunay_hyperbolic); - CGAL_triangulation_precondition(_non_hyperbolic_edge <= 2); - - return _non_hyperbolic_edge; - } - - void set_non_hyperbolic_edge(unsigned int uschar) - { - CGAL_triangulation_precondition(!_is_Delaunay_hyperbolic); - CGAL_triangulation_precondition(uschar <= 2); - - _non_hyperbolic_edge = uschar; - } - - bool get_is_Delaunay_hyperbolic() const { return _is_Delaunay_hyperbolic; } - void set_is_Delaunay_hyperbolic(bool flag) { _is_Delaunay_hyperbolic = flag; } - }; - /* During the insertion of a new point in the triangulation, the added vertex points to a face. This function ensures that the face to which the vertex points is hyperbolic (if there exists one). @@ -634,173 +616,87 @@ private: // Cannot be on the boundary here. lt = FACE; + li = 4; + if(cs1 != cp1 || cs2 != cp2 || cs3 != cp3) return ON_NEGATIVE_SIDE; else return ON_POSITIVE_SIDE; } - int get_finite_non_hyperbolic_edge(Face_handle f) const - { - CGAL_triangulation_precondition(is_finite_non_hyperbolic(f)); - Face_data fd = object_cast(f->tds_data()); - return fd.get_non_hyperbolic_edge(); - } - - bool is_finite_non_hyperbolic(Face_handle f) const - { - if(const Face_data* td = object_cast(&f->tds_data())) - { - return !td->get_is_Delaunay_hyperbolic(); - } - else - { - return false; - } - } - - bool is_finite_non_hyperbolic(Face_handle f, int i) const - { - if(dimension() <= 1) - return false; - - if(is_finite_non_hyperbolic(f) && get_finite_non_hyperbolic_edge(f) == i) - return true; - - // another incident face and corresponding index - Face_handle f2 = f->neighbor(i); - int i2 = f2->index(f); - - if(is_finite_non_hyperbolic(f2) && get_finite_non_hyperbolic_edge(f2) == i2) - return true; - - return false; - } - - bool is_finite_non_hyperbolic(const Edge& e) const - { - return is_finite_non_hyperbolic(e.first, e.second); - } - - // Depth-first search (dfs) and marking the finite non_hyperbolic faces. void mark_finite_non_hyperbolic_faces() const { if(dimension() <= 1) return; - std::set visited_faces; + for(auto fit = Base::all_faces_begin(); fit != Base::all_faces_end(); ++fit) + fit->hyperbolic_data().set_Delaunay_hyperbolic(); // finite & hyperbolic - // maintain a stack to be able to backtrack - // to the most recent faces which neighbors are not visited - std::stack backtrack; + Face_handle ifh = Base::infinite_face(); + ifh->hyperbolic_data().set_infinite(); - // start from a face with infinite vertex - Face_handle current = Base::infinite_face(); + std::stack to_visit; + to_visit.push(ifh); - // mark it as visited - visited_faces.insert(current); + std::set visited_faces; // @todo squat tds_data() - // put the element whose neighbors we are going to explore. - backtrack.push(current); - - Face_handle next; - - while(!backtrack.empty()) + while(!to_visit.empty()) { - // take a face - current = backtrack.top(); + Face_handle fh = to_visit.top(); + to_visit.pop(); - // start visiting the neighbors - int i = 0; - for(; i<3; ++i) + if(!visited_faces.insert(fh).second) // already visited previously + continue; + + for(int i = 0; i<3; ++i) { - next = current->neighbor(i); + Face_handle nfh = fh->neighbor(i); + mark_face(nfh); - // if a neighbor is already visited, then stop going deeper - if(visited_faces.find(next) != visited_faces.end()) + if(is_Delaunay_hyperbolic(nfh)) continue; - visited_faces.insert(next); - mark_face(next); - - // go deeper if the neighbor is non_hyperbolic - if(!is_Delaunay_hyperbolic(next)) - { - backtrack.push(next); - break; - } + to_visit.push(nfh); } - - // if all the neighbors are already visited, then remove "current" face. - if(i == 3) - backtrack.pop(); } } - // check if a star is bounded by finite faces - bool is_star_bounded(Vertex_handle v) const - { - if(dimension() <= 1) - return true; - - Face_handle f = v->face(); - Face_handle next; - int i; - Face_handle start(f); - Face_handle opposite_face; - - do - { - i = f->index(v); - next = f->neighbor(ccw(i)); // turn ccw around v - - opposite_face = f->neighbor(i); - if(!is_Delaunay_hyperbolic(opposite_face)) - return false; - - f = next; - } - while(next != start); - - return true; - } - - void mark_star_faces(Vertex_handle v) const { if(dimension() <= 1) return; Face_handle f = v->face(); - Face_handle start(f), next; - int i; + Face_handle start(f); do { - i = f->index(v); - next = f->neighbor(ccw(i)); // turn ccw around v - mark_face(f); - f = next; - } while(next != start); + int i = f->index(v); + f = f->neighbor(ccw(i)); + } + while(f != start); } void mark_face(const Face_handle f) const { - Is_Delaunay_hyperbolic del; - int idx; - bool flag = del(point(f,0), - point(f,1), - point(f,2), - idx); + if(is_infinite(f)) + { + f->hyperbolic_data().set_infinite(); + } + else + { + int idx; + bool flag = geom_traits().is_Delaunay_hyperbolic_2_object()(point(f,0), + point(f,1), + point(f,2), + idx); - Face_data fd; - fd.set_is_Delaunay_hyperbolic(flag); - - if(!flag) - fd.set_non_hyperbolic_edge(idx); - - f->tds_data() = make_object(fd); + if(flag) + f->hyperbolic_data().set_Delaunay_hyperbolic(); // finite & hyperbolic + else + f->hyperbolic_data().set_Delaunay_non_hyperbolic(idx); // finite but not hyperbolic + } } public: diff --git a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_face_base_2.h b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_face_base_2.h index 6506f397267..16781769cf9 100644 --- a/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_face_base_2.h +++ b/Hyperbolic_triangulation_2/include/CGAL/Hyperbolic_triangulation_face_base_2.h @@ -22,6 +22,40 @@ namespace CGAL { +class Hyperbolic_data +{ + typedef boost::int8_t Id; + +private: + // - 2 for infinite face + // - 1 for finite, hyperbolic face + // 0 for finite, non hyperbolic with non-hyperbolic edge at index 0 + // 2 for finite, non hyperbolic with non-hyperbolic edge at index 1 + // 1 for finite, non hyperbolic with non-hyperbolic edge at index 2 + Id _hyperbolic_tag; + +public: + Hyperbolic_data(Id id = -2) : _hyperbolic_tag(id) { } + + void set_infinite() { _hyperbolic_tag = -2; } + + // a finite face is non_hyperbolic if its circumscribing circle intersects the circle at infinity + void set_Delaunay_hyperbolic() { _hyperbolic_tag = -1; } + + bool is_Delaunay_hyperbolic() const + { + return (_hyperbolic_tag == -1); + } + + // set and get the non-hyperbolic property of the edge #i + void set_Delaunay_non_hyperbolic(int i) { _hyperbolic_tag = i; } + + bool is_Delaunay_non_hyperbolic(int i) const + { + return (_hyperbolic_tag == i); + } +}; + template > class Hyperbolic_triangulation_face_base_2 @@ -60,11 +94,11 @@ public: static int ccw(int i) {return Triangulation_cw_ccw_2::ccw(i);} static int cw(int i) {return Triangulation_cw_ccw_2::cw(i);} - CGAL::Object& tds_data() { return this->_tds_data; } - const CGAL::Object& tds_data() const { return this->_tds_data; } + Hyperbolic_data& hyperbolic_data() { return this->_hyperbolic_data; } + const Hyperbolic_data& hyperbolic_data() const { return this->_hyperbolic_data; } private: - CGAL::Object _tds_data; + Hyperbolic_data _hyperbolic_data; }; } // namespace CGAL