diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 85a468bf33a..065c37448a3 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -358,152 +358,174 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des /*! \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`, + * 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::halfedge_descriptor halfedge_descriptor; 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) + num_e(std::distance(boost::begin(edges(g)), boost::end(edges(g)))), + num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g)))); + + bool valid = (1 != (num_h&1) && (2*num_e == num_h)); + if(!valid) verr << "number of halfedges is odd." << std::endl; // All halfedges. - - halfedges_size_type n = 0; - for(halfedge_descriptor begin : halfedges(g)) { + halfedges_size_type n = 0; + for(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; + valid = valid && (next(begin, g) != boost::graph_traits::null_halfedge()); + valid = valid && (opposite(begin, g) != boost::graph_traits::null_halfedge()); + if(!valid) + { + verr << "halfedge " << n << " next / opposite halfedges are null." << std::endl; break; } - //edge integrity - valid = valid && ( halfedge(edge(begin, g), g) == begin); + + // 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; + valid = valid && (opposite(begin, g) != begin); + valid = valid && (opposite(opposite(begin, g), g) == begin); + if(!valid) + { + verr << "halfedge " << n << " invalid halfedge opposite()." << 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; + valid = valid && (prev(next(begin, g), g) == begin); + valid = valid && (next(prev(begin, g), g) == begin); + if(!valid) + { + verr << "halfedge " << n << " prev(next(hd)) != hd OR next(prev(hd)) != hd" << std::endl; break; } + // vertex integrity. - valid = valid && ( target(begin, g) != boost::graph_traits::null_vertex()); - if ( ! valid) { - verr << " vertex pointer integrity corrupted." - << std::endl; + valid = valid && (target(begin, g) != boost::graph_traits::null_vertex()); + if(!valid) + { + verr << "halfedge " << n << " target of halfedge is the null vertex." << std::endl; break; } - valid = valid && ( target(begin, g) == - target(opposite(next(begin, g), g), g)); - if ( ! valid) { - verr << " vertex pointer integrity2 corrupted." - << std::endl; + + valid = valid && (target(begin, g) == target(opposite(next(begin, g), g), g)); + if(!valid) + { + verr << "halfedge " << n << " target(hd) != source(next(hd))." << std::endl; break; } ++n; } - if ( valid && n != num_h) + + if(valid && n != num_h) verr << "counting halfedges failed." << std::endl; + // All vertices. vertex_size_type v = 0; n = 0; - for(vertex_descriptor vbegin : vertices(g)){ + for(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); + 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; + + if(!valid) + { + verr << "vertex " << v << " halfedge incident to vertex is the null halfedge." << std::endl; break; } + // cycle-around-vertex test. halfedge_descriptor h = halfedge(vbegin, g); - if ( h != boost::graph_traits::null_halfedge()) { + if(h != boost::graph_traits::null_halfedge()) + { halfedge_descriptor ge = h; - do { - verr << " halfedge " << n << std::endl; + do + { ++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)); + valid = valid && (n <= num_h && n!=0); + if(!valid) + { + verr << "vertex " << v << " too many halfedges around vertex." << std::endl; + break; + } + } + while (valid && (h != ge)); } + + if(!valid) + break; + ++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); + 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; - for(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; + for(halfedge_descriptor i : halfedges(g)) + { + // 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 << "halfedge " << n << " 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; + ++n; + } + + valid = valid && (n == num_h); + if(n != num_h) + verr << "counting halfedges failed." << std::endl; + verr << "Halfedge Graph 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`. @@ -513,134 +535,159 @@ return valid; * * \tparam `Graph` a model of `FaceListGraph` * \return `true` if `g` is valid, `false` otherwise. - * - * \see `is_valid_halfedge_graph()` + * + * \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::halfedges_size_type halfedges_size_type; 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)))); - + 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) { + 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; - for(face_descriptor fbegin : faces(g)){ + + for(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); + 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; + + if(! valid) + { + verr << "face " << f << " halfedge incident to face is the null halfedge." << std::endl; break; } + // cycle-around-face test. halfedge_descriptor h = halfedge( fbegin, g); - if (h != boost::graph_traits::null_halfedge()) { + if(h != boost::graph_traits::null_halfedge()) + { halfedge_descriptor ge = h; - do { - verr << " halfedge " << n << std::endl; + do + { ++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)); + valid = valid && (n <= num_h && n != 0); + if(!valid) + { + verr << "face " << f << " too many halfedges around face." << std::endl; + break; + } + } + while(valid && (h != ge)); } + + if(! valid) + break; + ++f; } - if ( valid && f != num_f) + + if(valid && f != num_f) verr << "counting faces failed." << std::endl; - - for(halfedge_descriptor i : halfedges(g)){ + + std::size_t hn = 0; + for(halfedge_descriptor i : halfedges(g)) + { + ++hn; + //counting borders - if ( is_border(i, g)) + 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; + valid = valid && (face(i, g) == face(next(i, g), g)); + if(!valid) + { + verr << "halfedge " << hn << " face(hd) != face(next(hd))." << std::endl; break; } } + verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl; - if ( valid && n + nb != num_h) + 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; + + valid = valid && (f == num_f); + valid = valid && (n + nb == num_h); + verr << "Face Graph 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 + * \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. - for(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; -} + 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 = 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; + } + } + + verr << "Polygon Mesh Structure is " << (valid ? "valid." : "NOT VALID.") << std::endl; + + return valid; +} /*! \ingroup PkgBGLHelperFct