// Copyright (c) 2014 GeometryFactory (France). All rights reserved. // All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Andreas Fabri #ifndef CGAL_BOOST_GRAPH_HELPERS_H #define CGAL_BOOST_GRAPH_HELPERS_H #include #include #include #include #include #include #include #include namespace CGAL { /*! \ingroup PkgBGLHelperFct returns `true` if the halfedge `hd` is on a border. */ template bool is_border(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { return face(hd,g) == boost::graph_traits::null_face(); } /*! \ingroup PkgBGLHelperFct returns `true` if the halfedge `hd` or the opposite halfedge is on a border. */ template bool is_border_edge(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { return is_border(hd, g) || is_border(opposite(hd,g), g); } /*! \ingroup PkgBGLHelperFct returns `true` if the edge `e` is on a border. */ template bool is_border(typename boost::graph_traits::edge_descriptor ed, const FaceGraph& g) { return is_border_edge(halfedge(ed,g), g); } /*! \ingroup PkgBGLHelperFct returns a halfedge which is on a border and whose target vertex is `vd`, if such a halfedge exists. */ template std::optional::halfedge_descriptor> is_border(typename boost::graph_traits::vertex_descriptor vd, const FaceGraph& g) { CGAL::Halfedge_around_target_iterator havib, havie; for(boost::tie(havib, havie) = halfedges_around_target(halfedge(vd, g), g); havib != havie; ++havib) { if(is_border(*havib,g)) { typename boost::graph_traits::halfedge_descriptor h = *havib; return h; } } // empty return std::optional::halfedge_descriptor>(); } namespace BGL { template bool is_valid_vertex_descriptor(typename boost::graph_traits::vertex_descriptor v, const Graph& g, const bool verb = false) { Verbose_ostream verr(verb); bool valid = true; // null vertex valid = (v != boost::graph_traits::null_vertex()); if(!valid) { verr << "vertex is null." << std::endl; return false; } if(!CGAL::internal::is_isolated(v, g)) { // Incident halfedge integrity valid = (target(halfedge(v, g), g) == v); if(!valid) { verr << "vertex has invalid halfedge()." << std::endl; return false; } } return true; } template bool is_valid_halfedge_descriptor(typename boost::graph_traits::halfedge_descriptor h, const Graph& g, const bool verb = false) { Verbose_ostream verr(verb); bool valid = true; // null halfedge valid = (h != boost::graph_traits::null_halfedge()); if(!valid) { verr << "halfedge is null." << std::endl; return false; } // Pointer integrity. valid = (prev(h, g) != boost::graph_traits::null_halfedge()); valid = valid && (next(h, g) != boost::graph_traits::null_halfedge()); valid = valid && (opposite(h, g) != boost::graph_traits::null_halfedge()); if(!valid) { verr << "halfedge's prev / next / opposite halfedges are null." << std::endl; return false; } // degeneracies valid = (next(h, g) != h); valid = valid && (prev(h, g) != h); valid = valid && (opposite(h, g) != h); valid = valid && (target(h, g) != target(opposite(h, g), g)); if(!valid) { verr << "combinatorial degeneracies." << std::endl; return false; } // edge integrity valid = (halfedge(edge(h, g), g) == h); if(!valid) { verr << "halfedge has an invalid edge." << std::endl; return false; } // opposite integrity. valid = (opposite(h, g) != h); valid = valid && (opposite(opposite(h, g), g) == h); if(!valid) { verr << "halfedge has invalid opposite()." << std::endl; return false; } // previous integrity. valid = (prev(next(h, g), g) == h); valid = valid && (next(prev(h, g), g) == h); if(!valid) { verr << "prev(next(hd)) != hd OR next(prev(hd)) != hd" << std::endl; return false; } // vertex integrity. valid = (target(h, g) != boost::graph_traits::null_vertex()); if(!valid) { verr << "target of halfedge is the null vertex." << std::endl; return false; } valid = (target(h, g) == target(opposite(next(h, g), g), g)); valid = valid && (target(opposite(h, g), g) == target(prev(h, g), g)); if(!valid) { verr << "vertex inconsistencies with prev/next." << std::endl; return false; } return true; } template bool is_valid_edge_descriptor(typename boost::graph_traits::edge_descriptor e, const FaceGraph& g, const bool verb = false) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; Verbose_ostream verr(verb); bool valid = true; // there is no null_edge() in the Graph concepts // Pointer integrity. const halfedge_descriptor h = halfedge(e, g); valid = (h != boost::graph_traits::null_halfedge()); if(!valid) { verr << "halfedge incident to edge is the null halfedge." << std::endl; return false; } // halfedge integrity valid = (edge(h, g) == e); if(!valid) { verr << "edge has an invalid halfedge()." << std::endl; return false; } return true; } template bool is_valid_face_descriptor(typename boost::graph_traits::face_descriptor f, const FaceGraph& g, const bool verb = false) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; Verbose_ostream verr(verb); bool valid = true; // null face valid = (f != boost::graph_traits::null_face()); if(!valid) { verr << "face is null." << std::endl; return false; } // Pointer integrity. const halfedge_descriptor h = halfedge(f, g); valid = (h != boost::graph_traits::null_halfedge()); if(!valid) { verr << "halfedge incident to face is the null halfedge." << std::endl; return false; } valid = (face(h, g) == f); if(!valid) { verr << "face has an invalid halfedge()." << std::endl; return false; } // face integrity. valid = (face(h, g) == face(next(h, g), g)); valid = valid && (face(h, g) == face(prev(h, g), g)); if(!valid) { verr << "different face incident to face halfedges." << std::endl; return false; } return true; } } // namespace BGL // These empty functions simply calling the BGL versions (just above) are done such that // a specific graph type (e.g. Surface_mesh) can overload those and still call the BGL versions // without duplicating code template bool is_valid_vertex_descriptor(typename boost::graph_traits::vertex_descriptor v, const Graph& g, const bool verb = false) { return BGL::is_valid_vertex_descriptor(v, g, verb); } template bool is_valid_halfedge_descriptor(typename boost::graph_traits::halfedge_descriptor h, const Graph& g, const bool verb = false) { return BGL::is_valid_halfedge_descriptor(h, g, verb); } template bool is_valid_edge_descriptor(typename boost::graph_traits::edge_descriptor e, const Graph& g, const bool verb = false) { return BGL::is_valid_edge_descriptor(e, g, verb); } template bool is_valid_face_descriptor(typename boost::graph_traits::face_descriptor f, const Graph& g, const bool verb = false) { return BGL::is_valid_face_descriptor(f, g, verb); } /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of the graph `g`. * * The graph `g` is valid if it follows the rules of the `HalfedgeListGraph` concept * and all of its associations are reciprocal (for example, `prev(next(h, g), g)` must be `h`, * and `next(prev(h, g), g)` must be `h`). * * \param g the graph to test * \param verb if `true`, the details of the check will be written in the standard output. * * \tparam Graph a model of `HalfedgeListGraph` * * \return `true` if `g` is valid, `false` otherwise. * */ template bool is_valid_halfedge_graph(const Graph& g, bool verb = false) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; Verbose_ostream verr(verb); std::size_t num_v = CGAL::internal::exact_num_vertices(g), num_e = CGAL::internal::exact_num_edges(g), num_h = CGAL::internal::exact_num_halfedges(g); bool valid = (1 != (num_h&1) && (2*num_e == num_h)); if(!valid) { verr << "number of halfedges is odd." << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } // All halfedges. std::size_t hc = 0; for(halfedge_descriptor h : halfedges(g)) { if(!is_valid_halfedge_descriptor(h, g, verb)) { verr << "halfedge " << hc << " is invalid." << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } ++hc; } valid = (hc == num_h); if(!valid) { verr << "counting halfedges failed: " << hc << " vs " << num_h << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } // All vertices. std::size_t vc = 0; hc = 0; for(vertex_descriptor v : vertices(g)) { if(!is_valid_vertex_descriptor(v, g, verb)) { verr << "vertex " << vc << " is invalid." << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } // cycle-around-vertex test. if(!CGAL::internal::is_isolated(v, g)) { halfedge_descriptor h = halfedge(v, g), done = h; do { ++hc; h = opposite(next(h, g), g); valid = (hc <= num_h); if(!valid) { verr << "vertex " << vc << " too many halfedges around vertex." << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } } while(h != done); } ++vc; } valid = (vc == num_v); if(!valid) { verr << "counting vertices failed: " << vc << " vs " << num_v << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } valid = (hc == num_h); if(!valid) { verr << "counting halfedges via vertices failed: " << hc << " vs " << num_h << std::endl; verr << "Halfedge Graph Structure is NOT VALID." << std::endl; return false; } verr << "Halfedge Graph Structure is valid" << std::endl; return valid; } /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of the graph `g`. * * The graph `g` is a valid face graph if it is a valid halfedge graph, and if it follows the rules * of the `FaceListGraph` concept and all of its associations are reciprocal (for example, * `face(halfedge(f,g),g)` must be `f`). * * \param g the graph to test * \param verb if `true`, the details of the check will be written in the standard output * * \tparam FaceGraph a model of `FaceListGraph` and `HalfedgeListGraph` * * \return `true` if `g` is valid, `false` otherwise. * * \see `is_valid_halfedge_graph()` */ template bool is_valid_face_graph(const FaceGraph& g, bool verb = false) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; Verbose_ostream verr(verb); std::size_t num_f = CGAL::internal::exact_num_faces(g), num_h = CGAL::internal::exact_num_halfedges(g); std::size_t fc = 0, hc = 0, nb = 0; bool valid = is_valid_halfedge_graph(g, verb); if(!valid) return false; // All faces. for(face_descriptor f : faces(g)) { if(!is_valid_face_descriptor(f, g, verb)) { verr << "face " << fc << " is invalid." << std::endl; verr << "Face Graph Structure is NOT VALID." << std::endl; return false; } // cycle-around-face test. halfedge_descriptor h = halfedge(f, g), done(h); do { ++hc; valid = (hc <= num_h); if(!valid) { verr << "face " << fc << " too many halfedges around face." << std::endl; verr << "Face Graph Structure is NOT VALID." << std::endl; return false; } h = next(h, g); } while(h != done); ++fc; } valid = (fc == num_f); if(!valid) { verr << "counting faces failed: " << fc << " vs " << num_f << std::endl; verr << "Face Graph Structure is NOT VALID." << std::endl; return false; } for(halfedge_descriptor h : halfedges(g)) { //counting borders if(is_border(h, g)) ++nb; } valid = (hc + nb == num_h); if(!valid) { verr << "counting halfedges via faces failed." << std::endl; verr << "sum border halfedges (2*nb) = " << 2 * nb << " vs " << num_h << std::endl; verr << "Face Graph Structure is NOT VALID." << std::endl; return false; } verr << "Face Graph Structure is valid" << std::endl; return valid; } /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of the mesh `g`. * * The mesh `g` is a valid polygon mesh if it is a valid face graph and if it follows the rules * defined in \ref PMPDef "PolygonMesh". * * \param g the `Mesh` to test * \param verb if `true`, the details of the check will be written in the standard output * * \tparam Mesh a model of `FaceListGraph` and `HalfedgeListGraph` * \return `true` if `g` is valid, `false` otherwise. * * \see `is_valid_face_graph()` * \see `is_valid_halfedge_graph()` * */ template bool is_valid_polygon_mesh(const Mesh& g, bool verb = false) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; Verbose_ostream verr(verb); bool valid = is_valid_face_graph(g, verb); if(!valid) return false; // test for 2-manifoldness // Distinct facets on each side of an halfedge. for(halfedge_descriptor i : halfedges(g)) { valid = (face(i, g) != face(opposite(i, g), g)); if(!valid) { verr << "both incident facets are equal." << std::endl; verr << "Polygon Mesh Structure is NOT VALID." << std::endl; return false; } valid = (next(next(i, g), g) != i); valid = valid && (target(i, g) != target(next(i, g), g)); valid = valid && (target(i, g) != target(next(next(i, g), g), g)); if(!valid) { verr << "incident facet is not at least a triangle." << std::endl; verr << "Polygon Mesh Structure is NOT VALID." << std::endl; return false; } } verr << "Polygon Mesh Structure is valid." << std::endl; return true; } /*! \ingroup PkgBGLHelperFct returns `true` if there are no border edges. */ template bool is_closed(const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; for(halfedge_descriptor hd : halfedges(g)){ if(is_border(hd,g)){ return false; } } return true; } /*! \ingroup PkgBGLHelperFct returns `true` if the target of `hd` has exactly two incident edges. */ template bool is_bivalent(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); return hd == opposite(next(opposite(next(hd,g),g),g),g); } /*! \ingroup PkgBGLHelperFct returns `true` if all vertices have exactly two incident edges. */ template bool is_bivalent_mesh(const FaceGraph& g) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; for(vertex_descriptor vd : vertices(g)){ halfedge_descriptor hd = halfedge(vd,g); if((hd == boost::graph_traits::null_halfedge()) || (! is_bivalent(hd,g))){ return false; } } return true; } /*! \ingroup PkgBGLHelperFct returns `true` if the target of `hd` has exactly three incident edges. */ template bool is_trivalent(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); return hd == opposite(next(opposite(next(opposite(next(hd,g),g),g),g),g),g); } /*! \ingroup PkgBGLHelperFct returns `true` if all vertices have exactly three incident edges. */ template bool is_trivalent_mesh(const FaceGraph& g) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; for(vertex_descriptor vd : vertices(g)){ halfedge_descriptor hd = halfedge(vd,g); if((hd == boost::graph_traits::null_halfedge()) || (! is_trivalent(halfedge(hd,g),g))){ return false; } } return true; } /*! \ingroup PkgBGLHelperFct returns `true` iff the connected component denoted by `hd` is a triangle. \pre `g` must be valid. */ template bool is_isolated_triangle(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); halfedge_descriptor beg = hd; if(is_border(hd,g)) return false; for(int i=0; i<3;i++){ if(! is_border(opposite(hd,g),g)) return false; hd = next(hd,g); } return hd == beg; } /*! \ingroup PkgBGLHelperFct returns `true` iff the face denoted by `hd` is a triangle, that is it has three incident halfedges. */ template bool is_triangle(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); return hd == next(next(next(hd,g),g),g); } /*! \ingroup PkgBGLHelperFct returns `true` if all faces are triangles. */ template bool is_triangle_mesh(const FaceGraph& g) { typedef typename boost::graph_traits::face_descriptor face_descriptor; for(face_descriptor fd : faces(g)){ if(! is_triangle(halfedge(fd,g),g)){ return false; } } return true; } /*! \ingroup PkgBGLHelperFct returns `true` iff the connected component denoted by `hd` is a quadrilateral. */ template bool is_isolated_quad(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); halfedge_descriptor beg = hd; if(is_border(hd,g)) return false; for(int i=0; i<4;i++){ if(! is_border(opposite(hd,g),g)) return false; hd = next(hd,g); } return hd == beg; } /*! \ingroup PkgBGLHelperFct returns `true` iff the face denoted by `hd` is a quad, that is it has four incident halfedges. */ template bool is_quad(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); return hd == next(next(next(next(hd,g),g),g),g); } /*! \ingroup PkgBGLHelperFct returns `true` if all faces are quadrilaterals. */ template bool is_quad_mesh(const FaceGraph& g) { typedef typename boost::graph_traits::face_descriptor face_descriptor; for(face_descriptor fd : faces(g)){ if(! is_quad(halfedge(fd,g),g)){ return false; } } return true; } /*! \ingroup PkgBGLHelperFct returns `true` iff the connected component denoted by `hd` is a tetrahedron. */ template bool is_tetrahedron(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); halfedge_descriptor h1 = hd; if(is_border(h1,g)) return false; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; halfedge_descriptor h2 = next(h1,g); halfedge_descriptor h3 = next(h2,g); halfedge_descriptor h4 = next(opposite(h1,g),g ); halfedge_descriptor h5 = next(opposite(h2,g),g ); halfedge_descriptor h6 = next(opposite(h3,g),g ); // check halfedge combinatorics. // at least three edges at vertices 1, 2, 3. if ( h4 == opposite(h3,g) ) return false; if ( h5 == opposite(h1,g) ) return false; if ( h6 == opposite(h2,g) ) return false; // exact three edges at vertices 1, 2, 3. if ( next(opposite(h4,g),g) != opposite(h3,g) ) return false; if ( next(opposite(h5,g),g) != opposite(h1,g) ) return false; if ( next(opposite(h6,g),g) != opposite(h2,g) ) return false; // three edges at v4. if ( opposite(next(h4,g),g) != h5 ) return false; if ( opposite(next(h5,g),g) != h6 ) return false; if ( opposite(next(h6,g),g) != h4 ) return false; // All facets are triangles. if ( next(next(next(h1,g),g),g) != h1 ) return false; if ( next(next(next(h4,g),g),g) != h4 ) return false; if ( next(next(next(h5,g),g),g) != h5 ) return false; if ( next(next(next(h6,g),g),g) != h6 ) return false; // all edges are non-border edges. if ( is_border(h1,g) ) return false; // implies h2 and h3 if ( is_border(h4,g) ) return false; if ( is_border(h5,g) ) return false; if ( is_border(h6,g) ) return false; return true; } /*! \ingroup PkgBGLHelperFct returns `true` iff the connected component denoted by `hd` is a hexahedron. */ template bool is_hexahedron(typename boost::graph_traits::halfedge_descriptor hd, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; CGAL_precondition(is_valid_halfedge_descriptor(hd, g)); halfedge_descriptor h1 = hd; if(is_border(h1,g)) return false; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; halfedge_descriptor h2 = next(h1,g); halfedge_descriptor h3 = next(h2,g); halfedge_descriptor h4 = next(h3,g); halfedge_descriptor h1o = opposite(h1,g); halfedge_descriptor h2o = opposite(h2,g); halfedge_descriptor h3o = opposite(h3,g); halfedge_descriptor h4o = opposite(h4,g); if(opposite(next(h2o,g),g) != prev(h1o,g)) return false; if(opposite(next(h3o,g),g) != prev(h2o,g)) return false; if(opposite(next(h4o,g),g) != prev(h3o,g)) return false; if(opposite(next(h1o,g),g) != prev(h4o,g)) return false; if(! is_quad(h1,g)) return false; if(! is_quad(h1o,g)) return false; if(! is_quad(h2o,g)) return false; if(! is_quad(h3o,g)) return false; if(! is_quad(h4o,g)) return false; h1o =next(next(h1o,g),g); h2o =next(next(h2o,g),g); h3o =next(next(h3o,g),g); h4o =next(next(h4o,g),g); if(next(opposite(h2o,g),g) != opposite(h1o,g)) return false; if(next(opposite(h3o,g),g) != opposite(h2o,g)) return false; if(next(opposite(h4o,g),g) != opposite(h3o,g)) return false; if(next(opposite(h1o,g),g) != opposite(h4o,g)) return false; if(! is_quad(opposite(h4o,g),g)) return false; return true; } namespace internal { template inline std::enable_if_t::value, void> clear_impl(FaceGraph& g) { g.clear(); } template inline std::enable_if_t::value, void> clear_impl(FaceGraph& g) { while(std::begin(edges(g))!=std::end(edges(g))) remove_edge(*std::begin(edges(g)), g); while(std::begin(faces(g))!=std::end(faces(g))) remove_face(*std::begin(faces(g)), g); while(std::begin(vertices(g))!=std::end(vertices(g))) remove_vertex(*std::begin(vertices(g)), g); } template void swap_vertices(typename boost::graph_traits::vertex_descriptor& p, typename boost::graph_traits::vertex_descriptor& q, FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; CGAL_precondition(is_valid_vertex_descriptor(p, g) && is_valid_vertex_descriptor(q, g)); halfedge_descriptor hq=halfedge(q, g); halfedge_descriptor hp=halfedge(p, g); for(halfedge_descriptor h : halfedges_around_target(hq, g)) set_target(h, p, g); for(halfedge_descriptor h : halfedges_around_target(hp, g)) set_target(h, q, g); set_halfedge(p, hq, g); set_halfedge(q, hp, g); } template void swap_edges(const typename boost::graph_traits::halfedge_descriptor& h1, const typename boost::graph_traits::halfedge_descriptor& h2, FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; CGAL_precondition(is_valid_halfedge_descriptor(h1, g) && is_valid_halfedge_descriptor(h2, g)); const halfedge_descriptor oh1 = opposite(h1, g), oh2 = opposite(h2, g); // backup vertex pointers vertex_descriptor s1 = target(oh1, g), s2 = target(oh2, g); vertex_descriptor t1 = target(h1, g), t2 = target(h2, g); // backup face pointers face_descriptor f1 = face(h1, g), f2 = face(h2, g); face_descriptor fo1 = face(oh1, g), fo2 = face(oh2, g); // backup next prev pointers halfedge_descriptor nh1 = next(h1, g), nh2 = next(h2, g); halfedge_descriptor ph1 = prev(h1, g), ph2 = prev(h2, g); halfedge_descriptor noh1 = next(oh1, g), noh2 = next(oh2, g); halfedge_descriptor poh1 = prev(oh1, g), poh2 = prev(oh2, g); // handle particular cases where next/prev are halfedges to be swapt if (nh1 == oh2) nh1 = oh1; if (nh1 == h2) nh1 = h1; if (nh2 == oh1) nh2 = oh2; if (nh2 == h1) nh2 = h2; if (ph1 == oh2) ph1 = oh1; if (ph1 == h2) ph1 = h1; if (ph2 == oh1) ph2 = oh2; if (ph2 == h1) ph2 = h2; if (noh1 == oh2) noh1 = oh1; if (noh1 == h2) noh1 = h1; if (noh2 == oh1) noh2 = oh2; if (noh2 == h1) noh2 = h2; if (poh1 == oh2) poh1 = oh1; if (poh1 == h2) poh1 = h1; if (poh2 == oh1) poh2 = oh2; if (poh2 == h1) poh2 = h2; // (1) exchange next pointers set_next(h1, nh2, g); set_next(h2, nh1, g); set_next(ph1, h2, g); set_next(ph2, h1, g); set_next(oh1, noh2, g); set_next(oh2, noh1, g); set_next(poh1, oh2, g); set_next(poh2, oh1, g); // (2) exchange vertex-halfedge pointers set_target(h1, t2, g); set_target(h2, t1, g); set_target(oh1, s2, g); set_target(oh2, s1, g); if (halfedge(t1, g)==h1) set_halfedge(t1, h2, g); if (halfedge(t2, g)==h2) set_halfedge(t2, h1, g); if (halfedge(s1, g)==oh1) set_halfedge(s1, oh2, g); if (halfedge(s2, g)==oh2) set_halfedge(s2, oh1, g); // (3) exchange face-halfedge pointers set_face(h1, f2, g); set_face(h2, f1, g); set_face(oh1, fo2, g); set_face(oh2, fo1, g); face_descriptor nf = boost::graph_traits::null_face(); if (f1 != nf && halfedge(f1, g)==h1) set_halfedge(f1, h2, g); if (f2 != nf && halfedge(f2, g)==h2) set_halfedge(f2, h1, g); if (fo1 != nf && halfedge(fo1, g)==oh1) set_halfedge(fo1, oh2, g); if (fo2 != nf && halfedge(fo2, g)==oh2) set_halfedge(fo2, oh1, g); } template void collect_garbage(Graph&) { // nothing by default } } //end of internal namespace /** * \ingroup PkgBGLHelperFct * * removes all vertices, faces and halfedges from a graph. Calls * `remove_edge()`, `remove_vertex()`, and `remove_face()` for each * edge, vertex or face. * * If the graph has a member function `clear()`, it will be called * instead. * * @tparam FaceGraph model of `MutableHalfedgeGraph` and `MutableFaceGraph` * * @param g the graph to clear * **/ template void clear(FaceGraph& g) { internal::clear_impl(g); CGAL_postcondition(std::distance(std::begin(edges(g)),std::end(edges(g))) == 0); CGAL_postcondition(std::distance(std::begin(vertices(g)),std::end(vertices(g))) == 0); CGAL_postcondition(std::distance(std::begin(faces(g)),std::end(faces(g))) == 0); } /** * \ingroup PkgBGLHelperFct * * checks whether the graph is empty, by checking that it does not contain any vertex. * * @tparam FaceGraph model of `FaceGraph` * * @param g the graph to test * **/ template bool is_empty(const FaceGraph& g) { return boost::empty(vertices(g)); } /// \ingroup PkgBGLHelperFct /// /// \brief returns the number of calls to `next()` one has to apply to the halfedge `hd` /// for `source(hd, mesh) == vd` to be true, starting from `hd = halfedge(fd, tm)`. /// /// \tparam Graph a model of `FaceGraph` /// /// \param vd a vertex of `g` whose index is sought /// \param fd a face of `g` in which the index of `vd` is sought /// \param g a mesh of type `Graph` /// /// \pre `vd` is a vertex of `fd`. template int vertex_index_in_face(const typename boost::graph_traits::vertex_descriptor vd, const typename boost::graph_traits::face_descriptor fd, const Graph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; CGAL_precondition(is_valid_vertex_descriptor(vd, g) && is_valid_face_descriptor(fd, g)); halfedge_descriptor start = halfedge(fd, g); halfedge_descriptor current = start; int counter = 0; do { if(source(current, g) == vd) break; ++counter; current = next(current, g); } while(current != start); if(counter != 0 && current == start) { CGAL_assertion_msg(false, "Could not find vertex in face"); return -1; } return counter; } /// \ingroup PkgBGLHelperFct /// /// \brief returns the number of calls to `next(hd, tm)` one has to apply to `hd` for `hd == he` /// to be true, starting from `hd = halfedge(face(he, tm), tm)`. /// /// \tparam Graph a model of `FaceGraph`. /// /// \param he a halfedge of `g` whose index in `face(he, tm)` is sought /// \param g an object of type `Graph` /// template int halfedge_index_in_face(typename boost::graph_traits::halfedge_descriptor he, const Graph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; CGAL_precondition(is_valid_halfedge_descriptor(he, g)); CGAL_precondition(!is_border(he, g)); face_descriptor f = face(he, g); halfedge_descriptor start = halfedge(f, g); halfedge_descriptor current = start; int count = 0; while(current != he) { current = next(current, g); ++count; } return count; } } // namespace CGAL #endif // CGAL_BOOST_GRAPH_HELPERS_H