// Copyright (c) 2014 GeometryFactory (France). All rights reserved. // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0+ // // 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 { namespace Euler { template< typename Graph> void fill_hole(typename boost::graph_traits::halfedge_descriptor h, Graph& g); template typename boost::graph_traits::face_descriptor add_face(const VertexRange& vr, Graph& g); }//Euler /*! \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 boost::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 boost::optional::halfedge_descriptor>(); } /*! \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; BOOST_FOREACH(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) { 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; BOOST_FOREACH(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) { 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; BOOST_FOREACH(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; 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) { 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; BOOST_FOREACH(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; 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) { 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; BOOST_FOREACH(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; 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; } template bool is_valid_halfedge_descriptor( typename boost::graph_traits::halfedge_descriptor h, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; face_descriptor f = face(h,g); halfedge_descriptor done(h); do{ if(face(h,g) != f){ std::cerr << "halfedge " << h << " is invalid\n"; return false; } halfedge_descriptor hn = h; hn = next(h,g); if(prev(hn,g) != h){ std::cerr << "halfedge " << h << " is invalid\n"; return false; } h = hn; } while(h != done); return true; } template bool is_valid_vertex_descriptor( typename boost::graph_traits::vertex_descriptor v, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; halfedge_descriptor h = halfedge(v,g), done(h); if(h == boost::graph_traits::null_halfedge()){ return true; } do{ if(target(h,g) != v){ std::cerr << "vertex " << v << " is invalid\n"; return false; } h = opposite(next(h,g),g); }while(h != done); return true; } template bool is_valid_face_descriptor( typename boost::graph_traits::face_descriptor f, const FaceGraph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; halfedge_descriptor h = halfedge(f,g); if(face(h,g) != f){ std::cerr << "face " << f << " is invalid\n"; return false; } return true; } /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of `g`. * * `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::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::vertices_size_type vertex_size_type; typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; Verbose_ostream verr(verb); std::size_t num_v(std::distance(boost::begin(vertices(g)), boost::end(vertices(g)))), num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g)))); bool valid = ( 1 != (num_h& 1)); if ( ! valid) verr << "number of halfedges is odd." << std::endl; // All halfedges. halfedges_size_type n = 0; BOOST_FOREACH(halfedge_descriptor begin, halfedges(g)) { if(!valid) break; verr << "halfedge " << n << std::endl; // Pointer integrity. valid = valid && ( next(begin, g) != boost::graph_traits::null_halfedge()); valid = valid && ( opposite(begin, g) != boost::graph_traits::null_halfedge()); if ( ! valid) { verr << " pointer integrity corrupted (ptr==0)." << std::endl; break; } //edge integrity valid = valid && ( halfedge(edge(begin, g), g) == begin); // opposite integrity. valid = valid && ( opposite(begin, g) != begin); valid = valid && ( opposite(opposite(begin, g), g) == begin); if ( ! valid) { verr << " opposite pointer integrity corrupted." << std::endl; break; } // previous integrity. valid = valid && ( prev(next(begin, g), g) == begin); valid = valid && ( next(prev(begin, g), g) == begin); if ( ! valid) { verr << " previous pointer integrity corrupted." << std::endl; break; } // vertex integrity. valid = valid && ( target(begin, g) != boost::graph_traits::null_vertex()); if ( ! valid) { verr << " vertex pointer integrity corrupted." << std::endl; break; } valid = valid && ( target(begin, g) == target(opposite(next(begin, g), g), g)); if ( ! valid) { verr << " vertex pointer integrity2 corrupted." << std::endl; break; } ++n; } if ( valid && n != num_h) verr << "counting halfedges failed." << std::endl; // All vertices. vertex_size_type v = 0; n = 0; BOOST_FOREACH(vertex_descriptor vbegin, vertices(g)){ if(!valid) break; verr << "vertex " << v << std::endl; // Pointer integrity. if ( halfedge(vbegin, g) != boost::graph_traits::null_halfedge()) valid = valid && ( target( halfedge(vbegin, g), g) == vbegin); else valid = false; if ( ! valid) { verr << " halfedge pointer in vertex corrupted." << std::endl; break; } // cycle-around-vertex test. halfedge_descriptor h = halfedge(vbegin, g); if ( h != boost::graph_traits::null_halfedge()) { halfedge_descriptor ge = h; do { verr << " halfedge " << n << std::endl; ++n; h = opposite(next(h, g), g); valid = valid && ( n <= num_h && n!=0); if ( ! valid) verr << " too many halfedges around vertices." << std::endl; } while ( valid && (h != ge)); } ++v; } if ( valid && v != num_v) verr << "counting vertices failed." << std::endl; if ( valid && ( n != num_h)) verr << "counting halfedges via vertices failed." << std::endl; valid = valid && ( v == num_v); // All halfedges. n = 0; BOOST_FOREACH(halfedge_descriptor i, halfedges(g)){ verr << "halfedge " << n << std::endl; // At least triangular facets and distinct geometry. valid = valid && ( next(i, g) != i); valid = valid && ( target(i, g) != target(opposite(i, g), g)); if ( ! valid) { verr << " pointer validity corrupted." << std::endl; break; } ++n; } valid = valid && (n == num_h); if ( n != num_h) verr << "counting halfedges failed." << std::endl; verr << "structure is " << ( valid ? "valid." : "NOT VALID.") << std::endl; return valid; } /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of `g`. * * `g` is valid if it is a valid `HalfedgeListGraph`, 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`. * calls `is_valid_halfedge_graph()` * \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 `FaceListGraph` * \return `true` if `g` is valid, `false` otherwise. * * \see `is_valid_halfedge_graph()` */ template bool is_valid_face_graph(const Graph& g, bool verb = false) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::faces_size_type faces_size_type; typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; std::size_t num_f(std::distance(boost::begin(faces(g)), boost::end(faces(g)))), num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g)))); //is valid halfedge_graph ? bool valid=is_valid_halfedge_graph(g, verb); if ( ! valid) { return false; } Verbose_ostream verr(verb); // All faces. faces_size_type f = 0; std::size_t n = 0; halfedges_size_type nb = 0; BOOST_FOREACH(face_descriptor fbegin, faces(g)){ if(!valid) break; verr << "face " << f << std::endl; // Pointer integrity. if ( halfedge(fbegin, g) != boost::graph_traits::null_halfedge()) valid = valid && ( face(halfedge(fbegin, g), g) == fbegin); else valid = false; if ( ! valid) { verr << " halfedge pointer in face corrupted." << std::endl; break; } // cycle-around-face test. halfedge_descriptor h = halfedge( fbegin, g); if (h != boost::graph_traits::null_halfedge()) { halfedge_descriptor ge = h; do { verr << " halfedge " << n << std::endl; ++n; h = next(h, g); valid = valid && ( n <= num_h && n!=0); if ( ! valid) verr << " too many halfedges around faces." << std::endl; } while ( valid && (h != ge)); } ++f; } if ( valid && f != num_f) verr << "counting faces failed." << std::endl; BOOST_FOREACH(halfedge_descriptor i, halfedges(g)){ //counting borders if ( is_border(i, g)) ++nb; // face integrity. valid = valid && ( face(i, g) == face(next(i, g), g)); if ( ! valid) { verr << " face pointer integrity2 corrupted." << std::endl; break; } } verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl; if ( valid && n + nb != num_h) verr << "counting halfedges via faces failed." << std::endl; valid = valid && ( f == num_f); valid = valid && ( n + nb == num_h); verr << "is_valid(): structure is " << ( valid ? "valid." : "NOT VALID.") << std::endl; return valid; } /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of `g`. * * `g` is valid if it is a valid `FaceListGraph` and it has distinct faces on each side of an edge. * calls `is_valid_face_graph()`. * * \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`, and follows * the definition of a \ref PMPDef "PolygonMesh" * \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); //test for 2-manifoldness // Distinct facets on each side of an halfedge. BOOST_FOREACH(halfedge_descriptor i, halfedges(g)){ valid = valid && (face(i, g) != face(opposite(i, g), g)); if ( ! valid) { verr << " both incident facets are equal." << std::endl; break; } valid = 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; break; } if ( ! valid) { verr << " incident facet is not at least a triangle." << std::endl; break; } } return valid; } /*! \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; 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; } /** * \ingroup PkgBGLHelperFct * \brief Creates an isolated triangle * with its vertices initialized to `p0`, `p1` and `p2`, and adds it to the graph `g`. * \returns the non-border halfedge that has the target vertex associated with `p0`. **/ template typename boost::graph_traits::halfedge_descriptor make_triangle(const P& p0, const P& p1, const P& p2, Graph& g) { typedef typename boost::graph_traits Traits; typedef typename Traits::halfedge_descriptor halfedge_descriptor; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::face_descriptor face_descriptor; typedef typename boost::property_map::type Point_property_map; Point_property_map ppmap = get(CGAL::vertex_point, g); vertex_descriptor v0, v1, v2; v0 = add_vertex(g); v1 = add_vertex(g); v2 = add_vertex(g); ppmap[v0] = p0; ppmap[v1] = p1; ppmap[v2] = p2; halfedge_descriptor h0 = halfedge(add_edge(g),g); halfedge_descriptor h1 = halfedge(add_edge(g),g); halfedge_descriptor h2 = halfedge(add_edge(g),g); set_next(h0, h1, g); set_next(h1, h2, g); set_next(h2, h0, g); set_target(h0, v1, g); set_target(h1, v2, g); set_target(h2, v0, g); set_halfedge(v1, h0, g); set_halfedge(v2, h1, g); set_halfedge(v0, h2, g); face_descriptor f = add_face(g); set_face(h0,f,g); set_face(h1,f,g); set_face(h2,f,g); set_halfedge(f,h0,g); h0 = opposite(h0,g); h1 = opposite(h1,g); h2 = opposite(h2,g); set_next(h0, h2, g); set_next(h2, h1, g); set_next(h1, h0, g); set_target(h0, v0, g); set_target(h1, v1, g); set_target(h2, v2, g); set_face(h0, boost::graph_traits::null_face(),g); set_face(h1, boost::graph_traits::null_face(),g); set_face(h2, boost::graph_traits::null_face(),g); return opposite(h2,g); } namespace internal { template typename boost::graph_traits::halfedge_descriptor make_quad(typename boost::graph_traits::vertex_descriptor v0, typename boost::graph_traits::vertex_descriptor v1, typename boost::graph_traits::vertex_descriptor v2, typename boost::graph_traits::vertex_descriptor v3, Graph& g) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; halfedge_descriptor h0 = halfedge(add_edge(g),g); halfedge_descriptor h1 = halfedge(add_edge(g),g); halfedge_descriptor h2 = halfedge(add_edge(g),g); halfedge_descriptor h3 = halfedge(add_edge(g),g); set_next(h0, h1, g); set_next(h1, h2, g); set_next(h2, h3, g); set_next(h3, h0, g); set_target(h0, v1, g); set_target(h1, v2, g); set_target(h2, v3, g); set_target(h3, v0, g); set_halfedge(v1, h0, g); set_halfedge(v2, h1, g); set_halfedge(v3, h2, g); set_halfedge(v0, h3, g); face_descriptor f = add_face(g); set_face(h0,f,g); set_face(h1,f,g); set_face(h2,f,g); set_face(h3,f,g); set_halfedge(f,h0,g); h0 = opposite(h0,g); h1 = opposite(h1,g); h2 = opposite(h2,g); h3 = opposite(h3,g); set_next(h0, h3, g); set_next(h3, h2, g); set_next(h2, h1, g); set_next(h1, h0, g); set_target(h0, v0, g); set_target(h1, v1, g); set_target(h2, v2, g); set_target(h3, v3, g); set_face(h0, boost::graph_traits::null_face(),g); set_face(h1, boost::graph_traits::null_face(),g); set_face(h2, boost::graph_traits::null_face(),g); set_face(h3, boost::graph_traits::null_face(),g); return opposite(h3,g); } } // namespace internal /** * \ingroup PkgBGLHelperFct * \brief Creates an isolated quad with * its vertices initialized to `p0`, `p1`, `p2`, and `p3`, and adds it to the graph `g`. * \returns the non-border halfedge that has the target vertex associated with `p0`. **/ template typename boost::graph_traits::halfedge_descriptor make_quad(const P& p0, const P& p1, const P& p2, const P& p3, Graph& g) { typedef typename boost::graph_traits Traits; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename boost::property_map::type Point_property_map; Point_property_map ppmap = get(CGAL::vertex_point, g); vertex_descriptor v0, v1, v2, v3; v0 = add_vertex(g); v1 = add_vertex(g); v2 = add_vertex(g); v3 = add_vertex(g); ppmap[v0] = p0; ppmap[v1] = p1; ppmap[v2] = p2; ppmap[v3] = p3; return internal::make_quad(v0, v1, v2, v3, g); } /** * \ingroup PkgBGLHelperFct * \brief Creates an isolated hexahedron * with its vertices initialized to `p0`, `p1`, ...\ , and `p7`, and adds it to the graph `g`. * \returns the halfedge that has the target vertex associated with `p0`, in the face with the vertices with the points `p0`, `p1`, `p2`, and `p3`. **/ template typename boost::graph_traits::halfedge_descriptor make_hexahedron(const P& p0, const P& p1, const P& p2, const P& p3, const P& p4, const P& p5, const P& p6, const P& p7, Graph& g) { typedef typename boost::graph_traits Traits; typedef typename Traits::halfedge_descriptor halfedge_descriptor; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename boost::property_map::type Point_property_map; Point_property_map ppmap = get(CGAL::vertex_point, g); vertex_descriptor v0, v1, v2, v3, v4, v5, v6, v7; v0 = add_vertex(g); v1 = add_vertex(g); v2 = add_vertex(g); v3 = add_vertex(g); v4 = add_vertex(g); v5 = add_vertex(g); v6 = add_vertex(g); v7 = add_vertex(g); ppmap[v0] = p0; ppmap[v1] = p1; ppmap[v2] = p2; ppmap[v3] = p3; ppmap[v4] = p4; ppmap[v5] = p5; ppmap[v6] = p6; ppmap[v7] = p7; halfedge_descriptor ht = internal::make_quad(v7, v4, v5, v6, g); halfedge_descriptor hb = prev(internal::make_quad(v1, v0, v3, v2, g),g); for(int i=0; i <4; i++){ halfedge_descriptor h = halfedge(add_edge(g),g); set_target(h,target(hb,g),g); set_next(h,opposite(hb,g),g); set_next(opposite(next(ht,g),g),h,g); h = opposite(h,g); set_target(h,target(ht,g),g); set_next(h,opposite(ht,g),g); set_next(opposite(next(hb,g),g),h,g); hb = next(hb,g); ht = prev(ht,g); } for(int i=0; i <4; i++){ Euler::fill_hole(opposite(hb,g),g); hb = next(hb,g); } return next(next(hb,g),g); } /** * \ingroup PkgBGLHelperFct * \brief Creates an isolated tetrahedron * with its vertices initialized to `p0`, `p1`, `p2`, and `p3`, and adds it to the graph `g`. * \returns the halfedge that has the target vertex associated with `p0`, in the face with the vertices with the points `p0`, `p1`, and `p2`. **/ template typename boost::graph_traits::halfedge_descriptor make_tetrahedron(const P& p0, const P& p1, const P& p2, const P& p3, Graph& g) { typedef typename boost::graph_traits Traits; typedef typename Traits::halfedge_descriptor halfedge_descriptor; typedef typename Traits::vertex_descriptor vertex_descriptor; typedef typename Traits::face_descriptor face_descriptor; typedef typename boost::property_map::type Point_property_map; Point_property_map ppmap = get(CGAL::vertex_point, g); vertex_descriptor v0, v1, v2, v3; v0 = add_vertex(g); v2 = add_vertex(g); // this and the next line are switched to keep points in order v1 = add_vertex(g); v3 = add_vertex(g); ppmap[v0] = p0; ppmap[v1] = p2;// this and the next line are switched to reorient the surface ppmap[v2] = p1; ppmap[v3] = p3; halfedge_descriptor h0 = halfedge(add_edge(g),g); halfedge_descriptor h1 = halfedge(add_edge(g),g); halfedge_descriptor h2 = halfedge(add_edge(g),g); set_next(h0, h1, g); set_next(h1, h2, g); set_next(h2, h0, g); set_target(h0, v1, g); set_target(h1, v2, g); set_target(h2, v0, g); set_halfedge(v1, h0, g); set_halfedge(v2, h1, g); set_halfedge(v0, h2, g); face_descriptor f = add_face(g); set_face(h0,f,g); set_face(h1,f,g); set_face(h2,f,g); set_halfedge(f,h0,g); h0 = opposite(h0,g); h1 = opposite(h1,g); h2 = opposite(h2,g); set_next(h0, h2, g); set_next(h2, h1, g); set_next(h1, h0, g); set_target(h0, v0, g); set_target(h1, v1, g); set_target(h2, v2, g); halfedge_descriptor h3 = halfedge(add_edge(g),g); halfedge_descriptor h4 = halfedge(add_edge(g),g); halfedge_descriptor h5 = halfedge(add_edge(g),g); set_target(h3, v3, g); set_target(h4, v3, g); set_target(h5, v3, g); set_halfedge(v3, h3, g); set_next(h0, h3, g); set_next(h1, h4, g); set_next(h2, h5, g); set_next(h3, opposite(h4,g), g); set_next(h4, opposite(h5,g), g); set_next(h5, opposite(h3,g), g); set_next(opposite(h4,g), h0, g); set_next(opposite(h5,g), h1, g); set_next(opposite(h3,g), h2, g); set_target(opposite(h3,g), v0, g); set_target(opposite(h4,g), v1, g); set_target(opposite(h5,g), v2, g); f = add_face(g); set_halfedge(f,h0,g); set_face(h0, f, g); set_face(h3, f, g); set_face(opposite(h4,g), f, g); f = add_face(g); set_halfedge(f,h1,g); set_face(h1, f, g); set_face(h4, f, g); set_face(opposite(h5,g), f, g); f = add_face(g); set_halfedge(f,h2,g); set_face(h2, f, g); set_face(h5, f, g); set_face(opposite(h3,g), f, g); return opposite(h2,g); } /// \cond SKIP_IN_DOC template bool is_degenerate_triangle_face( typename boost::graph_traits::halfedge_descriptor hd, TriangleMesh& tmesh, const VertexPointMap& vpmap, const Traits& traits) { CGAL_assertion(!is_border(hd, tmesh)); const typename Traits::Point_3& p1 = get(vpmap, target( hd, tmesh) ); const typename Traits::Point_3& p2 = get(vpmap, target(next(hd, tmesh), tmesh) ); const typename Traits::Point_3& p3 = get(vpmap, source( hd, tmesh) ); return traits.collinear_3_object()(p1, p2, p3); } template bool is_degenerate_triangle_face( typename boost::graph_traits::face_descriptor fd, TriangleMesh& tmesh, const VertexPointMap& vpmap, const Traits& traits) { return is_degenerate_triangle_face(halfedge(fd,tmesh), tmesh, vpmap, traits); } /// \endcond /** * \ingroup PkgBGLHelperFct * \brief Creates a triangulated regular prism, outward oriented, * having `nb_vertices` vertices in each of its bases and adds it to the graph `g`. * If `center` is (0, 0, 0), then the first point of the prism is (`radius`, `height`, 0) * \param nb_vertices the number of vertices per base. It must be greater than or equal to 3. * \param g the graph in which the regular prism will be created. * \param base_center the center of the circle in which the lower base is inscribed. * \param height the distance between the two bases. * \param radius the radius of the circles in which the bases are inscribed. * \param is_closed determines if the bases must be created or not. If `is_closed` is `true`, `center` is a vertex. * \returns the halfedge that has the target vertex associated with the first point in the first face. */ template typename boost::graph_traits::halfedge_descriptor make_regular_prism( typename boost::graph_traits::vertices_size_type nb_vertices, Graph& g, const P& base_center = P(0,0,0), typename CGAL::Kernel_traits

::Kernel::FT height = 1.0, typename CGAL::Kernel_traits

::Kernel::FT radius = 1.0, bool is_closed = true) { CGAL_assertion(nb_vertices >= 3); typedef typename boost::property_map::type Point_property_map; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename CGAL::Kernel_traits

::Kernel::FT FT; const FT to_rad = CGAL_PI / 180.0; const FT precision = 360.0/nb_vertices; const FT diameter = 2*radius; Point_property_map vpmap = get(CGAL::vertex_point, g); std::vector vertices; vertices.resize(nb_vertices*2); for(typename boost::graph_traits::vertices_size_type i=0; i::vertices_size_type i=0; i < nb_vertices; ++i) { put(vpmap, vertices[i], P(0.5*diameter*cos(i*precision*to_rad)+base_center.x(), height+base_center.y(), -0.5*diameter*sin(i*precision*to_rad) + base_center.z())); put(vpmap, vertices[i+nb_vertices], P(0.5*diameter*cos(i*precision*to_rad)+base_center.x(), base_center.y(), -0.5*diameter*sin(i*precision*to_rad)+base_center.z())); } std::vector face; face.resize(3); //fill faces for(typename boost::graph_traits::vertices_size_type i=0; i::vertices_size_type i=0; i typename boost::graph_traits::halfedge_descriptor make_pyramid( typename boost::graph_traits::vertices_size_type nb_vertices, Graph& g, const P& base_center = P(0,0,0), typename CGAL::Kernel_traits

::Kernel::FT height = 1.0, typename CGAL::Kernel_traits

::Kernel::FT radius = 1.0, bool is_closed = true) { CGAL_assertion(nb_vertices >= 3); typedef typename boost::property_map::type Point_property_map; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename CGAL::Kernel_traits

::Kernel::FT FT; const FT to_rad = CGAL_PI / 180.0; const FT precision = 360.0/nb_vertices; const FT diameter = 2*radius; Point_property_map vpmap = get(CGAL::vertex_point, g); std::vector vertices; vertices.resize(nb_vertices); for(typename boost::graph_traits::vertices_size_type i=0; i::vertices_size_type i=0; i < nb_vertices; ++i) { put(vpmap, vertices[i], P(0.5*diameter*cos(i*precision*to_rad)+base_center.x(), base_center.y(), -0.5*diameter*sin(i*precision*to_rad)+base_center.z())); } std::vector face; face.resize(3); //fill faces for(typename boost::graph_traits::vertices_size_type i=0; i::vertices_size_type i=0; i typename boost::graph_traits::halfedge_descriptor make_icosahedron( Graph& g, const P& center = P(0,0,0), typename CGAL::Kernel_traits

::Kernel::FT radius = 1.0) { typedef typename boost::property_map::type Point_property_map; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; Point_property_map vpmap = get(CGAL::vertex_point, g); // create the initial icosahedron std::vector v_vertices; v_vertices.resize(12); for(int i=0; i<12; ++i) v_vertices[i] = add_vertex(g); typename CGAL::Kernel_traits

::Kernel::FT t = (radius + radius*CGAL::approximate_sqrt(5.0)) / 2.0; put(vpmap, v_vertices[0],P(-radius + center.x(), t + center.y(), 0.0 + center.z())); put(vpmap, v_vertices[1],P( radius + center.x(), t + center.y(), 0.0 + center.z())); put(vpmap, v_vertices[2],P(-radius + center.x(), -t + center.y(), 0.0 + center.z())); put(vpmap, v_vertices[3],P( radius + center.x(), -t + center.y(), 0.0 + center.z())); put(vpmap, v_vertices[4],P( 0.0 + center.x(), -radius + center.y(), t + center.z())); put(vpmap, v_vertices[5],P( 0.0 + center.x(), radius + center.y(), t + center.z())); put(vpmap, v_vertices[6],P( 0.0 + center.x(), -radius + center.y(), -t + center.z())); put(vpmap, v_vertices[7],P( 0.0 + center.x(), radius + center.y(), -t + center.z())); put(vpmap, v_vertices[8],P( t + center.x(), 0.0 + center.y(), -radius + center.z())); put(vpmap, v_vertices[9],P( t + center.x(), 0.0 + center.y(), radius + center.z())); put(vpmap, v_vertices[10],P(-t + center.x(), 0.0 + center.y(), -radius + center.z())); put(vpmap, v_vertices[11],P(-t + center.x(), 0.0 + center.y(), radius + center.z())); std::vector face; face.resize(3); face[1] = v_vertices[0]; face[0] = v_vertices[5]; face[2] = v_vertices[11]; Euler::add_face(face, g); face[1] = v_vertices[0]; face[0] = v_vertices[1]; face[2] = v_vertices[5]; Euler::add_face(face, g); face[1] = v_vertices[0]; face[0] = v_vertices[7]; face[2] = v_vertices[1]; Euler::add_face(face, g); face[1] = v_vertices[0]; face[0] = v_vertices[10]; face[2] = v_vertices[7]; Euler::add_face(face, g); face[1] = v_vertices[0]; face[0] = v_vertices[11]; face[2] = v_vertices[10]; Euler::add_face(face, g); face[1] = v_vertices[1] ; face[0] = v_vertices[9] ; face[2] = v_vertices[5]; Euler::add_face(face, g); face[1] = v_vertices[5] ; face[0] = v_vertices[4]; face[2] = v_vertices[11]; Euler::add_face(face, g); face[1] = v_vertices[11]; face[0] = v_vertices[2]; face[2] = v_vertices[10]; Euler::add_face(face, g); face[1] = v_vertices[10]; face[0] = v_vertices[6] ; face[2] = v_vertices[7]; Euler::add_face(face, g); face[1] = v_vertices[7] ; face[0] = v_vertices[8] ; face[2] = v_vertices[1]; Euler::add_face(face, g); face[1] = v_vertices[3] ; face[0] = v_vertices[4] ; face[2] = v_vertices[9]; Euler::add_face(face, g); face[1] = v_vertices[3] ; face[0] = v_vertices[2] ; face[2] = v_vertices[4]; Euler::add_face(face, g); face[1] = v_vertices[3] ; face[0] = v_vertices[6] ; face[2] = v_vertices[2]; Euler::add_face(face, g); face[1] = v_vertices[3] ; face[0] = v_vertices[8] ; face[2] = v_vertices[6]; Euler::add_face(face, g); face[1] = v_vertices[3] ; face[0] = v_vertices[9] ; face[2] = v_vertices[8]; Euler::add_face(face, g); face[1] = v_vertices[4] ; face[0] = v_vertices[5] ; face[2] = v_vertices[9] ; Euler::add_face(face, g); face[1] = v_vertices[2] ; face[0] = v_vertices[11] ; face[2] = v_vertices[4]; Euler::add_face(face, g); face[1] = v_vertices[6] ; face[0] = v_vertices[10] ; face[2] = v_vertices[2]; Euler::add_face(face, g); face[1] = v_vertices[8] ; face[0] = v_vertices[7] ; face[2] = v_vertices[6] ; Euler::add_face(face, g); face[1] = v_vertices[9] ; face[0] = v_vertices[1] ; face[2] = v_vertices[8] ; Euler::add_face(face, g); return halfedge(v_vertices[1], v_vertices[0], g).first; } /*! * \ingroup PkgBGLHelperFct * * \brief Creates a row major ordered grid with `i` cells along the width and `j` cells * along the height and adds it to the graph `g`. * * \param i the number of cells along the width. * \param j the number of cells along the height. * \param g the graph in which the grid will be created. * \param calculator the functor that will assign coordinates to the grid vertices. * \param triangulated decides if a cell is composed of one quad or two triangles. * If `triangulated` is `true`, the diagonal of each cell is oriented from (0,0) to (1,1) * in the cell coordinates. * * \tparam CoordinateFunctor that takes two `boost::graph_traits::%vertices_size_type` * and outputs a `boost::property_traits::%type>::%value_type`. *

%Default: a point with positive integer coordinates (`w`, `h`, 0), with `w` in [0..`i`] and `h` in [0..`j`] * \returns the non-border non-diagonal halfedge that has the target vertex associated with the first point of the grid (default is (0,0,0) ). */ #ifndef DOXYGEN_RUNNING template #else template::vertices_size_type, typename boost::property_traits::type>::value_type> > #endif typename boost::graph_traits::halfedge_descriptor make_grid(typename boost::graph_traits::vertices_size_type i, typename boost::graph_traits::vertices_size_type j, Graph& g, const CoordinateFunctor& calculator, bool triangulated = false) { typedef typename boost::property_map::type Point_property_map; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typename boost::graph_traits::vertices_size_type w(i+1), h(j+1); Point_property_map vpmap = get(CGAL::vertex_point, g); // create the initial icosahedron //create the vertices std::vector v_vertices; v_vertices.resize(static_cast(w*h)); for(std::size_t k = 0; k < v_vertices.size(); ++k) v_vertices[k] = add_vertex(g); //assign the coordinates for(typename boost::graph_traits::vertices_size_type a = 0; a::vertices_size_type b=0; b face; if(triangulated) face.resize(3); else face.resize(4); for(typename boost::graph_traits::vertices_size_type a = 0; a::vertices_size_type b = 0; b typename boost::graph_traits::halfedge_descriptor make_grid(typename boost::graph_traits::vertices_size_type w, typename boost::graph_traits::vertices_size_type h, Graph& g, bool triangulated = false) { typedef typename boost::graph_traits::vertices_size_type Size_type; typedef typename boost::property_traits::type>::value_type Point; return make_grid(w, h, g, CGAL::Creator_uniform_3(), triangulated); } namespace internal { template inline typename boost::enable_if, void>::type clear_impl(FaceGraph& g) { g.clear(); } template inline typename boost::disable_if, void>::type clear_impl(FaceGraph& g) { while(boost::begin(edges(g))!=boost::end(edges(g))) remove_edge(*boost::begin(edges(g)), g); while(boost::begin(faces(g))!=boost::end(faces(g))) remove_face(*boost::begin(faces(g)), g); while(boost::begin(vertices(g))!=boost::end(vertices(g))) remove_vertex(*boost::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; halfedge_descriptor hq=halfedge(q, g); halfedge_descriptor hp=halfedge(p, g); BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(hq, g)) set_target(h, p, g); BOOST_FOREACH(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; 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); } } //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(boost::begin(edges(g)),boost::end(edges(g))) == 0); CGAL_postcondition(std::distance(boost::begin(vertices(g)),boost::end(vertices(g))) == 0); CGAL_postcondition(std::distance(boost::begin(faces(g)),boost::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)); } } // namespace CGAL // Include "Euler_operations.h" at the end, because its implementation // requires this header. #include #endif // CGAL_BOOST_GRAPH_HELPERS_H