From 6dfa8d0ba3a882b5c4574b9982e2f2bdddf540ab Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 15 Jan 2018 18:01:59 +0100 Subject: [PATCH 01/15] replace CGAL_is_valid(Mesh) by CGAL::is_valid_polygon_mesh(Mesh) --- BGL/include/CGAL/boost/graph/helpers.h | 205 ++++++++++++++++-- BGL/test/BGL/test_Euler_operations.cpp | 28 ++- BGL/test/BGL/test_Face_filtered_graph.cpp | 4 +- BGL/test/BGL/test_Prefix.h | 16 +- BGL/test/BGL/test_clear.cpp | 4 +- BGL/test/BGL/test_graph_traits.cpp | 2 +- BGL/test/BGL/test_helpers.cpp | 16 +- .../Polygon_mesh_processing/orientation.h | 2 +- .../remove_degeneracies_test.cpp | 2 +- .../internal/subdivision_hosts_impl_3.h | 6 +- .../test_Subdivision_method_3.cpp | 46 ++-- 11 files changed, 251 insertions(+), 80 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index a4972113d60..02b3b6a3ce7 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace CGAL { @@ -357,27 +358,199 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des template -bool is_valid_polygon_mesh(const FaceGraph& g) +bool is_valid_polygon_mesh(const FaceGraph& 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::face_descriptor face_descriptor; - BOOST_FOREACH(vertex_descriptor v, vertices(g)){ - if(! is_valid_vertex_descriptor(v,g)){ - return false; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::vertex_iterator vertex_const_iterator; + typedef typename boost::graph_traits::halfedge_iterator halfedge_const_iterator; + typedef typename boost::graph_traits::face_iterator face_const_iterator; + typedef typename boost::graph_traits::vertices_size_type vertex_size_type; + typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; + typedef typename boost::graph_traits::faces_size_type faces_size_type; + Verbose_ostream verr(verb); + int num_v(std::distance(boost::begin(vertices(g)), boost::end(vertices(g)))), + num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g)))), + num_f(std::distance(boost::begin(faces(g)), boost::end(faces(g)))); + bool valid = ( 1 != (num_h& 1)); + if ( ! valid) + verr << "number of halfedges is odd." << std::endl; + + // All halfedges. + + halfedges_size_type n = 0; + halfedges_size_type nb = 0; + BOOST_FOREACH(halfedge_descriptor begin, halfedges(g)) { + if(!valid) + break; + verr << "halfedge " << n << std::endl; + if ( is_border(begin, g)) + verr << " is border halfedge" << 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; } - } - BOOST_FOREACH(halfedge_descriptor h, halfedges(g)){ - if(! is_valid_halfedge_descriptor(h,g)){ - return false; + // 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; } - } - BOOST_FOREACH(face_descriptor f, faces(g)){ - if(! is_valid_face_descriptor(f,g)){ - return false; + // previous integrity. + valid = valid && ( prev(next(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; + } + // face integrity. + + valid = valid && ( face(begin, g) == face(next(begin, g), g)); + if ( ! valid) { + verr << " face pointer integrity2 corrupted." + << std::endl; + break; + } + + ++n; + if ( is_border(begin, g)) + ++nb; } - return true; + verr << "summe border halfedges (2*nb) = " << 2 * nb << std::endl; + 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 faces. + faces_size_type f = 0; + n = 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; + 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; + // 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 && ( next(next(i, g), g) != i); + valid = valid && ( target(i, g) != target(opposite(i, g), g)); + 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; + } + // Distinct facets on each side of an halfegde. + valid = valid && (face(i, g) != face(opposite(i, g), g)); + if ( ! valid) { + verr << " both incident facets are equal." << std::endl; + break; + } + ++n; +} +valid = valid && (n == num_h); +if ( n != num_h) + verr << "counting halfedges failed." << std::endl; + +verr << "end of CGAL::Polyhedron_3<...>::is_valid(): structure is " + << ( valid ? "valid." : "NOT VALID.") << std::endl; +return valid; } /*! diff --git a/BGL/test/BGL/test_Euler_operations.cpp b/BGL/test/BGL/test_Euler_operations.cpp index 616ea782b3f..cdf53ec5f4c 100644 --- a/BGL/test/BGL/test_Euler_operations.cpp +++ b/BGL/test/BGL/test_Euler_operations.cpp @@ -41,7 +41,7 @@ join_face_test() assert(degree(f.w, f.m) == 2); assert(degree(f.v, f.m) == 3); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); } @@ -63,7 +63,7 @@ remove_face_test_1() CGAL::Euler::remove_face(e,f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); assert_EQUAL(degree(f.v, f.m) == 3); assert_EQUAL(degree(f.x, f.m) == 2); @@ -99,7 +99,7 @@ remove_face_test_2() assert(found); assert(face(e, f.m) == f.f1); CGAL::Euler::remove_face(e,f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); assert(CGAL::internal::exact_num_faces(f.m) == 3); assert(CGAL::internal::exact_num_edges(f.m) == 7); @@ -128,7 +128,7 @@ add_face_to_border_test() CGAL::Euler::add_face_to_border(f.h1, f.h2, f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); } @@ -158,7 +158,7 @@ add_vertex_and_face_to_border_test() } halfedge_descriptor res = CGAL::Euler::add_vertex_and_face_to_border(f.h1, f.h2, f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); assert(! CGAL::is_border(res,m)); assert(CGAL::is_border(opposite(res,m),m)); @@ -169,8 +169,6 @@ add_vertex_and_face_to_border_test() } assert(blength == 0); - - } @@ -193,7 +191,7 @@ join_vertex_interior_test() assert(boost::distance(CGAL::halfedges_around_face(halfedge(f.f1, f.m), f.m)) == 3); assert(boost::distance(CGAL::halfedges_around_face(halfedge(f.f2, f.m), f.m)) == 3); assert(degree(f.x, f.m) == 4); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); } template @@ -218,7 +216,7 @@ join_vertex_exterior_test() assert(boost::distance(CGAL::halfedges_around_face(halfedge(f.f1, f.m), f.m)) == 4); assert(boost::distance(CGAL::halfedges_around_face(halfedge(f.f2, f.m), f.m)) == 3); assert(degree(f.y, f.m) == 3); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); } { @@ -237,7 +235,7 @@ join_vertex_exterior_test() assert(boost::distance(CGAL::halfedges_around_face(halfedge(f.f1, f.m), f.m)) == 4); assert(boost::distance(CGAL::halfedges_around_face(halfedge(f.f2, f.m), f.m)) == 3); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); assert(degree(f.w, f.m) == 3); } @@ -261,7 +259,7 @@ split_vertex() // split border vertex y CGAL::Euler::split_vertex(h1, h2,f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); assert(CGAL::internal::exact_num_vertices(f.m) == 7); assert(CGAL::internal::exact_num_edges(f.m) == 8); assert(boost::distance(CGAL::halfedges_around_face(h1, f.m)) == 5); @@ -279,13 +277,13 @@ split_join_vertex_inverse() boost::tie(h, found) = halfedge(f.w, f.x, f.m); assert(found); CGAL::Euler::join_vertex(h,f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); boost::tie(h1, found) = halfedge(f.z, f.x, f.m); assert(found); boost::tie(h2, found) = halfedge(f.v, f.x, f.m); assert(found); CGAL::Euler::join_vertex(CGAL::Euler::split_vertex(h1, h2,f.m),f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); assert(CGAL::internal::exact_num_vertices(f.m)== 5); assert(CGAL::internal::exact_num_faces(f.m) == 2); @@ -305,7 +303,7 @@ join_loop_test() CGAL::Euler::join_loop(f.h1, f.h2, f.m); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); } template @@ -319,7 +317,7 @@ split_loop_test() assert(CGAL::internal::exact_num_vertices(f.m) == 8); assert(CGAL::internal::exact_num_faces(f.m) == 8); assert(CGAL::internal::exact_num_halfedges(f.m) == 24); - assert(CGAL::is_valid(f.m)); + assert(CGAL::is_valid_polygon_mesh(f.m)); } template diff --git a/BGL/test/BGL/test_Face_filtered_graph.cpp b/BGL/test/BGL/test_Face_filtered_graph.cpp index 75427a24292..5446a660266 100644 --- a/BGL/test/BGL/test_Face_filtered_graph.cpp +++ b/BGL/test/BGL/test_Face_filtered_graph.cpp @@ -272,7 +272,7 @@ void test_read(const Graph& g) std::map map; CGAL::Polygon_mesh_processing::connected_components(g, boost::make_assoc_property_map(map), CGAL::Polygon_mesh_processing::parameters::all_default()); Adapter fg(g, 0, boost::make_assoc_property_map(map)); - assert(CGAL::is_valid(fg)); + assert(CGAL::is_valid_polygon_mesh(fg)); } template @@ -357,7 +357,7 @@ void test_mesh(Adapter fga) CGAL_GRAPH_TRAITS_MEMBERS(Adapter); //check that there is the right number of simplices in fga - CGAL_assertion(CGAL::is_valid(fga)); + CGAL_assertion(CGAL::is_valid_polygon_mesh(fga)); CGAL_assertion(num_faces(fga) == 2); CGAL_assertion(num_edges(fga) == 5); CGAL_assertion(num_halfedges(fga) == 10); diff --git a/BGL/test/BGL/test_Prefix.h b/BGL/test/BGL/test_Prefix.h index a06a1381bec..8aacfd12f99 100644 --- a/BGL/test/BGL/test_Prefix.h +++ b/BGL/test/BGL/test_Prefix.h @@ -157,7 +157,7 @@ template struct Surface_fixture_1 { Surface_fixture_1() { assert(read_a_mesh(m, "data/fixture1.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); @@ -206,7 +206,7 @@ template struct Surface_fixture_2 { Surface_fixture_2() { assert(read_a_mesh(m, "data/fixture2.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); @@ -267,7 +267,7 @@ template struct Surface_fixture_3 { Surface_fixture_3() { assert(read_a_mesh(m, "data/fixture3.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); @@ -313,7 +313,7 @@ template struct Surface_fixture_4 { Surface_fixture_4() { assert(read_a_mesh(m, "data/fixture4.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); @@ -348,7 +348,7 @@ template struct Surface_fixture_5 { Surface_fixture_5() { assert(read_a_mesh(m, "data/add_face_to_border.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); @@ -378,7 +378,7 @@ template struct Surface_fixture_6 { Surface_fixture_6() { assert(read_a_mesh(m, "data/quad.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::graph_traits::halfedge_descriptor h; @@ -397,7 +397,7 @@ template struct Surface_fixture_7 { Surface_fixture_7() { assert(read_a_mesh(m, "data/cube.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); h = *(halfedges(m).first); } @@ -410,7 +410,7 @@ template struct Surface_fixture_8 { Surface_fixture_8() { assert(read_a_mesh(m, "data/fixture5.off")); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); typename boost::property_map::const_type pm = get(CGAL::vertex_point, const_cast(m)); diff --git a/BGL/test/BGL/test_clear.cpp b/BGL/test/BGL/test_clear.cpp index eb733d748d4..05c8670a972 100644 --- a/BGL/test/BGL/test_clear.cpp +++ b/BGL/test/BGL/test_clear.cpp @@ -10,13 +10,13 @@ void test() { std::cout << "Error reading file: " << fname << std::endl; } - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); CGAL::clear(m); assert(num_vertices(m) == 0); assert(num_faces(m) == 0); assert(num_edges(m) == 0); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); } int main() diff --git a/BGL/test/BGL/test_graph_traits.cpp b/BGL/test/BGL/test_graph_traits.cpp index 6024ec4782a..73693da6736 100644 --- a/BGL/test/BGL/test_graph_traits.cpp +++ b/BGL/test/BGL/test_graph_traits.cpp @@ -254,7 +254,7 @@ void test_faces(const G& g) template void test_read(const G& g) { - assert(CGAL::is_valid(g)); + assert(CGAL::is_valid_polygon_mesh(g)); } template diff --git a/BGL/test/BGL/test_helpers.cpp b/BGL/test/BGL/test_helpers.cpp index e59447e3837..e2096d4df5e 100644 --- a/BGL/test/BGL/test_helpers.cpp +++ b/BGL/test/BGL/test_helpers.cpp @@ -43,42 +43,42 @@ int main() halfedge_descriptor hd; hd = CGAL::make_triangle(a,b,c,m); assert(CGAL::is_isolated_triangle(hd,m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); m.clear(); hd = CGAL::make_quad(a,b,c,d,m); assert(CGAL::is_isolated_quad(hd,m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); assert(CGAL::is_quad_mesh(m)); m.clear(); hd = CGAL::make_tetrahedron(a,b,c,d,m); assert(CGAL::is_tetrahedron(hd,m)); assert(CGAL::is_triangle_mesh(m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); m.clear(); hd = CGAL::make_hexahedron(a,b,c,d,aa,bb,cc,dd,m); assert(CGAL::is_hexahedron(hd,m)); assert(CGAL::is_quad_mesh(m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); m.clear(); CGAL::make_icosahedron(m); assert(num_faces(m) == 20); assert(CGAL::is_triangle_mesh(m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); m.clear(); hd = CGAL::make_pyramid(3, m); assert(num_faces(m) == 6); assert(CGAL::is_triangle_mesh(m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); m.clear(); hd = CGAL::make_regular_prism(4, m); assert(num_faces(m) == 16); assert(CGAL::is_triangle_mesh(m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); m.clear(); CGAL::make_grid(3,3,m); assert(num_faces(m) == 9); assert(CGAL::is_quad_mesh(m)); - assert(CGAL::is_valid(m)); + assert(CGAL::is_valid_polygon_mesh(m)); std::cerr << "done" << std::endl; return 0; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h index 15d3299f895..45e20154ca7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h @@ -176,7 +176,7 @@ bool is_outward_oriented(const PolygonMesh& pmesh, const NamedParameters& np) { CGAL_warning(CGAL::is_closed(pmesh)); - CGAL_precondition(CGAL::is_valid(pmesh)); + CGAL_precondition(CGAL::is_valid_polygon_mesh(pmesh)); //check for empty pmesh CGAL_warning(faces(pmesh).first != faces(pmesh).second); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp index 70c7162e773..386e27723a1 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remove_degeneracies_test.cpp @@ -26,7 +26,7 @@ void fix(const char* fname) } CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh); - assert( CGAL::is_valid(mesh) ); + assert( CGAL::is_valid_polygon_mesh(mesh) ); } int main() diff --git a/Subdivision_method_3/include/CGAL/Subdivision_method_3/internal/subdivision_hosts_impl_3.h b/Subdivision_method_3/include/CGAL/Subdivision_method_3/internal/subdivision_hosts_impl_3.h index cf467a3112d..2c93c17e0c3 100644 --- a/Subdivision_method_3/include/CGAL/Subdivision_method_3/internal/subdivision_hosts_impl_3.h +++ b/Subdivision_method_3/include/CGAL/Subdivision_method_3/internal/subdivision_hosts_impl_3.h @@ -173,7 +173,7 @@ void PQQ_1step(Poly& p, VertexPointMap vpm, Mask mask) { for (std::size_t i = 0; i < num_v; i++, ++vitr) put(vpm, *vitr, vertex_point_buffer[i]); -// CGAL_postcondition(p.is_valid()); + CGAL_postcondition(CGAL::is_valid_polygon_mesh(p)); delete []vertex_point_buffer; } @@ -277,7 +277,7 @@ void PTQ_1step(Poly& p, VertexPointMap vpm, Mask mask) { for (std::size_t i = 0; i < num_v; i++, ++vitr) put(vpm, *vitr, vertex_point_buffer[i]); -// CGAL_postcondition(p.is_valid()); + CGAL_postcondition(CGAL::is_valid_polygon_mesh(p)); delete []vertex_point_buffer; } @@ -527,7 +527,7 @@ void Sqrt3_1step(Poly& p, VertexPointMap vpm, Mask mask, } } -// CGAL_postcondition(p.is_valid()); + CGAL_postcondition(CGAL::is_valid_polygon_mesh(p)); delete []cpt; } diff --git a/Subdivision_method_3/test/Subdivision_method_3/test_Subdivision_method_3.cpp b/Subdivision_method_3/test/Subdivision_method_3/test_Subdivision_method_3.cpp index 9250848883a..7b0e8f399e5 100644 --- a/Subdivision_method_3/test/Subdivision_method_3/test_Subdivision_method_3.cpp +++ b/Subdivision_method_3/test/Subdivision_method_3/test_Subdivision_method_3.cpp @@ -58,7 +58,7 @@ void test_Subdivision_surface_3() { mesh >> P; Subdivision_method_3::CatmullClark_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Catmull-Clark subdivision on 'opened' quad mesh @@ -69,7 +69,7 @@ void test_Subdivision_surface_3() { mesh >> P; Subdivision_method_3::CatmullClark_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } @@ -81,7 +81,7 @@ void test_Subdivision_surface_3() { mesh >> P; Subdivision_method_3::Loop_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Loop subdivision on 'opened' tri mesh @@ -92,7 +92,7 @@ void test_Subdivision_surface_3() { mesh >> P; Subdivision_method_3::Loop_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Doo-Sabin subdivision on general mesh @@ -103,7 +103,7 @@ void test_Subdivision_surface_3() { mesh >> P; Subdivision_method_3::DooSabin_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Sqrt-3 subdivision on tri mesh @@ -114,7 +114,7 @@ void test_Subdivision_surface_3() { mesh >> P; Subdivision_method_3::Sqrt3_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } } @@ -130,7 +130,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::CatmullClark_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Catmull-Clark subdivision on 'opened' quad mesh @@ -141,7 +141,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::CatmullClark_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } @@ -153,7 +153,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::Loop_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Loop subdivision on 'opened' tri mesh @@ -164,7 +164,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::Loop_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Doo-Sabin subdivision on general mesh @@ -175,7 +175,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::DooSabin_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P, true)); } // test Doo-Sabin subdivision on 'opened' quad mesh @@ -186,7 +186,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::DooSabin_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Sqrt-3 subdivision on tri mesh @@ -197,7 +197,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::Sqrt3_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Sqrt-3 subdivision on 'opened' tri mesh @@ -208,7 +208,7 @@ void test_Subdivision_surface_3_SM() { mesh >> P; Subdivision_method_3::Sqrt3_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } } @@ -225,7 +225,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::CatmullClark_subdivision(P,Subdivision_method_3::parameters::vertex_point_map(get(vertex_point, P)) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Catmull-Clark subdivision on 'opened' quad mesh @@ -237,7 +237,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::CatmullClark_subdivision(P,Subdivision_method_3::parameters::vertex_point_map(get(vertex_point, P)) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } @@ -250,7 +250,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::Loop_subdivision(P,Subdivision_method_3::parameters::vertex_point_map(get(vertex_point, P)) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Loop subdivision on 'opened' tri mesh @@ -262,7 +262,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::Loop_subdivision(P,Subdivision_method_3::parameters::vertex_point_map(get(vertex_point, P)) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Doo-Sabin subdivision on 'opened' tri mesh @@ -274,7 +274,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::DooSabin_subdivision(P,Subdivision_method_3::parameters::vertex_point_map(get(vertex_point, P)) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Doo-Sabin subdivision on 'opened' quad mesh @@ -285,7 +285,7 @@ void test_Subdivision_surface_3_SM_NP() { mesh >> P; Subdivision_method_3::DooSabin_subdivision(P,TEST_DEPTH); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Sqrt-3 subdivision on tri mesh @@ -298,7 +298,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::Sqrt3_subdivision(P,Subdivision_method_3::parameters::vertex_point_map(get(vertex_point, P)) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Sqrt-3 subdivision on 'opened' tri mesh @@ -314,7 +314,7 @@ void test_Subdivision_surface_3_SM_NP() { std::ofstream out("out_0.off"); out << P; - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } // test Sqrt-3 subdivision on 'opened' tri mesh & with external property map @@ -347,7 +347,7 @@ void test_Subdivision_surface_3_SM_NP() { Subdivision_method_3::parameters::vertex_point_map(apm) .number_of_iterations(TEST_DEPTH)); - assert(P.is_valid()); + assert(CGAL::is_valid_polygon_mesh(P)); } } From 0cc59505b67c9c889da2102a12dd553ba98a958e Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 16 Jan 2018 12:25:09 +0100 Subject: [PATCH 02/15] add some doc --- BGL/include/CGAL/boost/graph/helpers.h | 44 +++++++++++++++----------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 02b3b6a3ce7..853aae5b8f6 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -356,19 +356,25 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des return true; } - -template -bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) +/*! + \ingroup PkgBGLHelperFct + * \brief is_valid_polygon_mesh checks the integrity of a `PolygonMesh`. + * \param g the `PolygonMesh` to test. + * \param verb : if `true`, the details of the check will be written in the standard output. + * \return `true` if the `PolygonMesh` is valid, `false` otherwise. + */ +template +bool is_valid_polygon_mesh(const PolygonMesh& 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::face_descriptor face_descriptor; - typedef typename boost::graph_traits::vertex_iterator vertex_const_iterator; - typedef typename boost::graph_traits::halfedge_iterator halfedge_const_iterator; - typedef typename boost::graph_traits::face_iterator face_const_iterator; - typedef typename boost::graph_traits::vertices_size_type vertex_size_type; - typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; - typedef typename boost::graph_traits::faces_size_type faces_size_type; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::vertex_iterator vertex_const_iterator; + typedef typename boost::graph_traits::halfedge_iterator halfedge_const_iterator; + typedef typename boost::graph_traits::face_iterator face_const_iterator; + typedef typename boost::graph_traits::vertices_size_type vertex_size_type; + typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; + typedef typename boost::graph_traits::faces_size_type faces_size_type; Verbose_ostream verr(verb); int num_v(std::distance(boost::begin(vertices(g)), boost::end(vertices(g)))), num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g)))), @@ -388,8 +394,8 @@ bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) if ( is_border(begin, g)) verr << " is border halfedge" << std::endl; // Pointer integrity. - valid = valid && ( next(begin, g) != boost::graph_traits::null_halfedge()); - valid = valid && ( opposite(begin, g) != boost::graph_traits::null_halfedge()); + 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; @@ -411,7 +417,7 @@ bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) break; } // vertex integrity. - valid = valid && ( target(begin, g) != boost::graph_traits::null_vertex()); + valid = valid && ( target(begin, g) != boost::graph_traits::null_vertex()); if ( ! valid) { verr << " vertex pointer integrity corrupted." << std::endl; @@ -448,7 +454,7 @@ bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) break; verr << "vertex " << v << std::endl; // Pointer integrity. - if ( halfedge(vbegin, g) != boost::graph_traits::null_halfedge()) + if ( halfedge(vbegin, g) != boost::graph_traits::null_halfedge()) valid = valid && ( target( halfedge(vbegin, g), g) == vbegin); else @@ -460,7 +466,7 @@ bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) } // 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; @@ -488,7 +494,7 @@ bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) break; verr << "face " << f << std::endl; // Pointer integrity. - if ( halfedge(fbegin, g) != boost::graph_traits::null_halfedge()) + if ( halfedge(fbegin, g) != boost::graph_traits::null_halfedge()) valid = valid && ( face(halfedge(fbegin, g), g) == fbegin); else @@ -499,7 +505,7 @@ bool is_valid_polygon_mesh(const FaceGraph& g, bool verb = false) } // 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; From fc729e770d6b61fa6d4c11cd10fa38d17cf9ce51 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 22 Jan 2018 15:17:26 +0100 Subject: [PATCH 03/15] update changes.md --- Installation/CHANGES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 00ab2430064..ee581d72898 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -175,7 +175,10 @@ Release date: April 2018 ### CGAL and the Boost Graph Library (BGL) -- Added helper function `CGAL::expand_face_selection_for_removal` that +- Add helper function `CGAL::is_valid_polygon_mesh` that checks the + validity of a polygon mesh using BGL functions. + +- Add helper function `CGAL::expand_face_selection_for_removal` that expands a face selection to avoid creating a non manifold mesh when removing the selected faces. From 153bc0c76a6c39c4c6912dbc2ae2d17e6811071a Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 22 Jan 2018 15:48:21 +0100 Subject: [PATCH 04/15] Fixes --- BGL/include/CGAL/boost/graph/helpers.h | 7 +++++-- HalfedgeDS/include/CGAL/HalfedgeDS_const_decorator.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 853aae5b8f6..a94d5035228 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -361,6 +361,8 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des * \brief is_valid_polygon_mesh checks the integrity of a `PolygonMesh`. * \param g the `PolygonMesh` to test. * \param verb : if `true`, the details of the check will be written in the standard output. + * + * \tparam PolygonMesh a model of `FaceListGraph` and `HalfedgeListGraph` * \return `true` if the `PolygonMesh` is valid, `false` otherwise. */ template @@ -376,7 +378,7 @@ bool is_valid_polygon_mesh(const PolygonMesh& g, bool verb = false) typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; typedef typename boost::graph_traits::faces_size_type faces_size_type; Verbose_ostream verr(verb); - int num_v(std::distance(boost::begin(vertices(g)), boost::end(vertices(g)))), + 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)))), num_f(std::distance(boost::begin(faces(g)), boost::end(faces(g)))); bool valid = ( 1 != (num_h& 1)); @@ -411,6 +413,7 @@ bool is_valid_polygon_mesh(const PolygonMesh& g, bool verb = false) } // 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; @@ -443,7 +446,7 @@ bool is_valid_polygon_mesh(const PolygonMesh& g, bool verb = false) if ( is_border(begin, g)) ++nb; } - verr << "summe border halfedges (2*nb) = " << 2 * nb << std::endl; + verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl; if ( valid && n != num_h) verr << "counting halfedges failed." << std::endl; // All vertices. diff --git a/HalfedgeDS/include/CGAL/HalfedgeDS_const_decorator.h b/HalfedgeDS/include/CGAL/HalfedgeDS_const_decorator.h index 62bd7971d1e..fe84a6c79aa 100644 --- a/HalfedgeDS/include/CGAL/HalfedgeDS_const_decorator.h +++ b/HalfedgeDS/include/CGAL/HalfedgeDS_const_decorator.h @@ -261,7 +261,7 @@ is_valid( bool verb, int level) const { if ( begin->is_border()) ++nb; } - verr << "summe border halfedges (2*nb) = " << 2 * nb << std::endl; + verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl; if ( valid && n != hds->size_of_halfedges()) verr << "counting halfedges failed." << std::endl; if ( valid && level >= 4 && (nb != hds->size_of_border_halfedges())) From 132cf694a065e01a56e3e33dc3e32df1e3581e50 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 15 Feb 2018 12:56:24 +0100 Subject: [PATCH 05/15] remove is_valid() from the graph_traits --- BGL/include/CGAL/boost/graph/Euler_operations.h | 2 +- .../boost/graph/Graph_with_descriptor_with_graph.h | 2 +- .../CGAL/boost/graph/graph_traits_OpenMesh.h | 6 ------ BGL/include/CGAL/boost/graph/helpers.h | 2 +- BGL/test/BGL/test_Manifold_face_removal.cpp | 2 +- BGL/test/BGL/test_graph_traits.cpp | 1 + .../internal/Isotropic_remeshing/remesh_impl.h | 4 ++-- .../CGAL/Polygon_mesh_processing/orientation.h | 2 +- .../include/CGAL/Polygon_mesh_processing/repair.h | 13 +++++++------ .../test_pmp_remove_border_edge.cpp | 6 +++--- .../test/Polygon_mesh_processing/test_stitching.cpp | 2 +- .../include/CGAL/IO/read_surf_trianglemesh.h | 2 +- .../CGAL/boost/graph/graph_traits_Polyhedron_3.h | 6 ------ .../CGAL/boost/graph/graph_traits_Surface_mesh.h | 6 ------ 14 files changed, 20 insertions(+), 36 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/Euler_operations.h b/BGL/include/CGAL/boost/graph/Euler_operations.h index 56d92e979ee..2472d30f220 100644 --- a/BGL/include/CGAL/boost/graph/Euler_operations.h +++ b/BGL/include/CGAL/boost/graph/Euler_operations.h @@ -1178,7 +1178,7 @@ collapse_edge(typename boost::graph_traits::edge_descriptor v0v1, lP_Erased = true ; } - CGAL_expensive_assertion(is_valid(g)); + CGAL_expensive_assertion(is_valid_polygon_mesh(g)); return lP_Erased ? q : p ; } diff --git a/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h b/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h index 11d5adeeb19..bec7a54b8fd 100644 --- a/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h +++ b/BGL/include/CGAL/boost/graph/Graph_with_descriptor_with_graph.h @@ -691,7 +691,7 @@ template bool is_valid(const Graph_with_descriptor_with_graph & w, bool verbose = false) { - return is_valid(*w.graph,verbose); + return is_valid_polygon_mesh(*w.graph,verbose); } diff --git a/BGL/include/CGAL/boost/graph/graph_traits_OpenMesh.h b/BGL/include/CGAL/boost/graph/graph_traits_OpenMesh.h index bf95392fdb4..59162ab70e2 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_OpenMesh.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_OpenMesh.h @@ -622,12 +622,6 @@ add_face(OPEN_MESH_CLASS& sm) return sm.new_face(); } -template -bool is_valid(OPEN_MESH_CLASS& sm, bool /* verbose */ = false) -{ - return CGAL::is_valid_polygon_mesh(sm); -} - } // namespace OpenMesh namespace CGAL { diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index a94d5035228..53ddc4fe478 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -557,7 +557,7 @@ valid = valid && (n == num_h); if ( n != num_h) verr << "counting halfedges failed." << std::endl; -verr << "end of CGAL::Polyhedron_3<...>::is_valid(): structure is " +verr << "end of CGAL::is_valid_polygon_mesh(): structure is " << ( valid ? "valid." : "NOT VALID.") << std::endl; return valid; } diff --git a/BGL/test/BGL/test_Manifold_face_removal.cpp b/BGL/test/BGL/test_Manifold_face_removal.cpp index adc6f3bbe49..918e5538b49 100644 --- a/BGL/test/BGL/test_Manifold_face_removal.cpp +++ b/BGL/test/BGL/test_Manifold_face_removal.cpp @@ -56,7 +56,7 @@ int main() } assert(index == 25); - assert(is_valid(sm)); + assert(is_valid_polygon_mesh(sm)); return 0; } diff --git a/BGL/test/BGL/test_graph_traits.cpp b/BGL/test/BGL/test_graph_traits.cpp index 73693da6736..3224d91c010 100644 --- a/BGL/test/BGL/test_graph_traits.cpp +++ b/BGL/test/BGL/test_graph_traits.cpp @@ -257,6 +257,7 @@ void test_read(const G& g) assert(CGAL::is_valid_polygon_mesh(g)); } + template void test(const std::vector& graphs) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index e5e71f80a5b..97a400388ce 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -1021,7 +1021,7 @@ namespace internal { put(vpmap_, vp.first, initial_pos);//cancel move } - CGAL_assertion(is_valid(mesh_)); + CGAL_assertion(is_valid_polygon_mesh(mesh_)); CGAL_assertion(is_triangle_mesh(mesh_)); }//end for loop (nit == nb_iterations) @@ -1055,7 +1055,7 @@ namespace internal { Point proj = trees[patch_id_to_index_map[get_patch_id(face(halfedge(v, mesh_), mesh_))]]->closest_point(get(vpmap_, v)); put(vpmap_, v, proj); } - CGAL_assertion(is_valid(mesh_)); + CGAL_assertion(is_valid_polygon_mesh(mesh_)); CGAL_assertion(is_triangle_mesh(mesh_)); #ifdef CGAL_PMP_REMESHING_DEBUG debug_self_intersections(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h index 45e20154ca7..7fa9845c48b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h @@ -480,7 +480,7 @@ void orient(TriangleMesh& tm, const NamedParameters& np) NamedParameters>::const_type Fid_map; CGAL_assertion(is_triangle_mesh(tm)); - CGAL_assertion(is_valid(tm)); + CGAL_assertion(is_valid_polygon_mesh(tm)); CGAL_assertion(is_closed(tm)); using boost::choose_param; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h index b44a11839e8..46a46db6e3b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -644,7 +644,7 @@ std::size_t remove_null_edges( if ( traits.equal_3_object()(get(vpmap, target(hd, tmesh)), get(vpmap, source(hd, tmesh))) ) null_edges_to_remove.insert(edge(hd, tmesh)); - CGAL_assertion( is_valid(tmesh) ); + CGAL_assertion( is_valid_polygon_mesh(tmesh) ); } } @@ -1409,10 +1409,11 @@ remove_self_intersections_one_step(TriangleMesh& tm, // some boundary cycle of halfedges bool topology_issue = false; if (verbose) + { std::cout << " DEBUG: is_valid in one_step(tm)? "; std::cout.flush(); - std::cout << is_valid(tm) << "\n"; + std::cout << is_valid_polygon_mesh(tm) << "\n"; } if(!faces_to_remove.empty()){ @@ -1693,7 +1694,7 @@ remove_self_intersections_one_step(TriangleMesh& tm, if (verbose) { std::cout << " DEBUG: is_valid(tm) in one_step, before mesh changes? "; - std::cout << is_valid(tm) << std::endl; + std::cout << is_valid_polygon_mesh(tm) << std::endl; } //try hole_filling. @@ -1858,7 +1859,7 @@ remove_self_intersections_one_step(TriangleMesh& tm, std::cout << " DEBUG: " << cc_faces.size() << " triangles removed, " << patch.size() << " created\n"; - CGAL_assertion(is_valid(tm)); + CGAL_assertion(is_valid_polygon_mesh(tm)); something_was_done = true; } @@ -1888,13 +1889,13 @@ bool remove_self_intersections(TriangleMesh& tm, const NamedParameters& np) bool preserve_genus = boost::choose_param(boost::get_param(np, internal_np::preserve_genus), true); if (verbose) - std::cout << "DEBUG: Starting remove_self_intersections, is_valid(tm)? " << is_valid(tm) << "\n"; + std::cout << "DEBUG: Starting remove_self_intersections, is_valid(tm)? " << is_valid_polygon_mesh(tm) << "\n"; // first handle the removal of degenerate faces remove_degenerate_faces(tm, np); if (verbose) - std::cout << "DEBUG: After degenerate faces removal, is_valid(tm)? " << is_valid(tm) << "\n"; + std::cout << "DEBUG: After degenerate faces removal, is_valid(tm)? " << is_valid_polygon_mesh(tm) << "\n"; // Look for self-intersections in the polyhedron and remove them int step=-1; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp index 2fa0e4cef27..0fed632c078 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp @@ -32,7 +32,7 @@ void test_middle_edge() CGAL_assertion( h!=GT::null_halfedge() ); CGAL::Polygon_mesh_processing::remove_a_border_edge(edge(h,tm), tm); - CGAL_assertion(is_valid(tm)); + CGAL_assertion(is_valid(is_valid_polygon_mesh)); CGAL_assertion(is_triangle_mesh(tm)); std::ofstream out("edge_middle_out.off"); out << tm; @@ -58,7 +58,7 @@ void test_edge_border_case1() CGAL_assertion( h!=GT::null_halfedge() ); CGAL::Polygon_mesh_processing::remove_a_border_edge(edge(h,tm), tm); - CGAL_assertion(is_valid(tm)); + CGAL_assertion(is_valid_polygon_mesh(tm)); CGAL_assertion(is_triangle_mesh(tm)); std::ofstream out("edge_border_case1_out.off"); out << tm; @@ -84,7 +84,7 @@ void test_edge_border_case2() CGAL_assertion( h!=GT::null_halfedge() ); CGAL::Polygon_mesh_processing::remove_a_border_edge(edge(h,tm), tm); - CGAL_assertion(is_valid(tm)); + CGAL_assertion(is_valid_polygon_mesh(tm)); CGAL_assertion(is_triangle_mesh(tm)); std::ofstream out("edge_border_case2_out.off"); out << tm; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_stitching.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_stitching.cpp index 14fc54b703e..0ba7ef7e471 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_stitching.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_stitching.cpp @@ -54,7 +54,7 @@ void test_surface_mesh(const char* fname) CGAL::Polygon_mesh_processing::stitch_borders(m); //todo : add a validity test - assert(is_valid(m)); + assert(is_valid_polygon_mesh(m)); std::cout << "OK\n"; } diff --git a/Polyhedron/demo/Polyhedron/include/CGAL/IO/read_surf_trianglemesh.h b/Polyhedron/demo/Polyhedron/include/CGAL/IO/read_surf_trianglemesh.h index 7a33c37ee5e..9c4c9041b0d 100644 --- a/Polyhedron/demo/Polyhedron/include/CGAL/IO/read_surf_trianglemesh.h +++ b/Polyhedron/demo/Polyhedron/include/CGAL/IO/read_surf_trianglemesh.h @@ -291,7 +291,7 @@ bool read_surf(std::istream& input, std::vector& output, converter(mesh, false/*insert_isolated_vertices*/); CGAL_assertion(PMP::remove_isolated_vertices(mesh) == 0); - CGAL_assertion(is_valid(mesh)); + CGAL_assertion(is_valid_polygon_mesh(mesh)); } // end loop on patches return true; diff --git a/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h b/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h index 3d1c005e3bc..89c572d690d 100644 --- a/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h +++ b/Polyhedron/include/CGAL/boost/graph/graph_traits_Polyhedron_3.h @@ -463,12 +463,6 @@ reserve(CGAL::Polyhedron_3& p, p.reserve(nv, 2*ne, nf); } -template -bool is_valid(const CGAL::Polyhedron_3& p, bool verbose = false) -{ - return p.is_valid(verbose); -} - template void normalize_border(CGAL::Polyhedron_3& p) { diff --git a/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h b/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h index 9f79653b7f1..f42cd99887e 100644 --- a/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h +++ b/Surface_mesh/include/CGAL/boost/graph/graph_traits_Surface_mesh.h @@ -522,12 +522,6 @@ add_face(InputIterator begin, InputIterator end, CGAL::Surface_mesh

& sm) return sm.add_face(v); } -template -bool is_valid(const CGAL::Surface_mesh

& sm, bool verbose = false) -{ - return sm.is_valid(verbose); -} - template void normalize_border(const CGAL::Surface_mesh

&) {} From b1b8e71b44a61409daa520aaebedc3ce8be3b6ee Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 15 Feb 2018 13:14:20 +0100 Subject: [PATCH 06/15] Remove unused typedef --- BGL/include/CGAL/boost/graph/helpers.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 53ddc4fe478..bdadf112a63 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -371,9 +371,6 @@ bool is_valid_polygon_mesh(const PolygonMesh& 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::face_descriptor face_descriptor; - typedef typename boost::graph_traits::vertex_iterator vertex_const_iterator; - typedef typename boost::graph_traits::halfedge_iterator halfedge_const_iterator; - typedef typename boost::graph_traits::face_iterator face_const_iterator; typedef typename boost::graph_traits::vertices_size_type vertex_size_type; typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; typedef typename boost::graph_traits::faces_size_type faces_size_type; From c68c1882864484115ff18c75f229fdac25c158b7 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 19 Feb 2018 09:55:49 +0100 Subject: [PATCH 07/15] Add definition of polygonmesh validity --- BGL/include/CGAL/boost/graph/helpers.h | 41 ++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index bdadf112a63..d2c63c58a28 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -362,8 +362,43 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des * \param g the `PolygonMesh` to test. * \param verb : if `true`, the details of the check will be written in the standard output. * - * \tparam PolygonMesh a model of `FaceListGraph` and `HalfedgeListGraph` + * \tparam PolygonMesh a model of `FaceListGraph`, `HalfedgeListGraph` and `VertexListGraph` * \return `true` if the `PolygonMesh` is valid, `false` otherwise. + * + * A `PolygonMesh` `g` is valid if: + +- it has an even number of halfedges +- for each halfedge `h` of `g`: + - halfedge(edge(h,g),g)==h + - next(h,g) != null_halfedge() + - opposite(h,g) != null_halfedge() + - opposite(h,g) != h + - opposite(opposite(h,g)) == h + - next(h, g) != h + - next(next(h,g),g) != h; + - target(h,g) != target(opposite(h,g),g) + - target(h,g) != target(next(h,g),g) + - target(h,g) != target(next(next(h,g),g),g) + - prev(next(h,g),g) == next(prev(h,g),g) == h + - target(h,g) != null_vertex() + - target(h,g) == target(opposite(next(h,g),g),g) + - face(h,g) == face(next(h,g),g) +- std::distance(halfedges(g).first, halfeges(g).second)) is the number of halfedges of `g` +- for each vertex `v` of `g`: + - halfedge(v,g) != null_halfedge() + - target(halfedge(v,g),g) == v + +- the sum of the halfedges around all the vertices of `g` is +std::distance(halfedges(g).first, halfeges(g).second)) +- std::distance(vertices(g).first, vertices(g).second)) is the number of vertices of `g` +- for each face `f` of `g`: + - halfedge(f,g) != null_face() + - face(halfedge(f,g),g) == f + +- the sum of halfedges around all the faces of `g` + the border halfedges of `g` is +std::distance(halfedges(g).first, halfeges(g).second)) +- The faces of `g` are at least triangles. +- `g` has distinct faces on each side of an edge. */ template bool is_valid_polygon_mesh(const PolygonMesh& g, bool verb = false) @@ -400,6 +435,8 @@ bool is_valid_polygon_mesh(const PolygonMesh& g, bool verb = false) << 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); @@ -542,7 +579,7 @@ bool is_valid_polygon_mesh(const PolygonMesh& g, bool verb = false) << std::endl; break; } - // Distinct facets on each side of an halfegde. + // Distinct facets on each side of an halfedge. valid = valid && (face(i, g) != face(opposite(i, g), g)); if ( ! valid) { verr << " both incident facets are equal." << std::endl; From 3d39a788389035f251cc50fdede16c801b34e7f1 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 19 Feb 2018 12:03:54 +0100 Subject: [PATCH 08/15] typo --- BGL/include/CGAL/boost/graph/helpers.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index d2c63c58a28..1de481e65f0 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -383,20 +383,20 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des - target(h,g) != null_vertex() - target(h,g) == target(opposite(next(h,g),g),g) - face(h,g) == face(next(h,g),g) -- std::distance(halfedges(g).first, halfeges(g).second)) is the number of halfedges of `g` +- std::distance(halfedges(g).first, halfedges(g).second)) is the number of halfedges of `g` - for each vertex `v` of `g`: - halfedge(v,g) != null_halfedge() - target(halfedge(v,g),g) == v - the sum of the halfedges around all the vertices of `g` is -std::distance(halfedges(g).first, halfeges(g).second)) +std::distance(halfedges(g).first, halfedges(g).second)) - std::distance(vertices(g).first, vertices(g).second)) is the number of vertices of `g` - for each face `f` of `g`: - - halfedge(f,g) != null_face() + - halfedge(f,g) != null_halfedge() - face(halfedge(f,g),g) == f - the sum of halfedges around all the faces of `g` + the border halfedges of `g` is -std::distance(halfedges(g).first, halfeges(g).second)) +std::distance(halfedges(g).first, halfedges(g).second)) - The faces of `g` are at least triangles. - `g` has distinct faces on each side of an edge. */ From 88899310ab6554e22c436a090f93abc7ee657356 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 20 Feb 2018 08:34:48 +0100 Subject: [PATCH 09/15] Fix massive typo in PMP test. --- .../Polygon_mesh_processing/test_pmp_remove_border_edge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp index 0fed632c078..a10c3b8a126 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_pmp_remove_border_edge.cpp @@ -32,7 +32,7 @@ void test_middle_edge() CGAL_assertion( h!=GT::null_halfedge() ); CGAL::Polygon_mesh_processing::remove_a_border_edge(edge(h,tm), tm); - CGAL_assertion(is_valid(is_valid_polygon_mesh)); + CGAL_assertion(is_valid_polygon_mesh(tm)); CGAL_assertion(is_triangle_mesh(tm)); std::ofstream out("edge_middle_out.off"); out << tm; From fd7def35c78cf4d46d5c5649e57cd187ad9c9478 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 26 Feb 2018 11:03:11 +0100 Subject: [PATCH 10/15] remove useless rule in doc --- BGL/include/CGAL/boost/graph/helpers.h | 1 - 1 file changed, 1 deletion(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 1de481e65f0..72d04d3707a 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -397,7 +397,6 @@ std::distance(halfedges(g).first, halfedges(g).second)) - the sum of halfedges around all the faces of `g` + the border halfedges of `g` is std::distance(halfedges(g).first, halfedges(g).second)) -- The faces of `g` are at least triangles. - `g` has distinct faces on each side of an edge. */ template From ed92767f1c6b6ff0f37705057581f18d4fdb4327 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Thu, 15 Mar 2018 09:37:35 +0100 Subject: [PATCH 11/15] add missing ref in the package description --- BGL/doc/BGL/PackageDescription.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 6bc7a8df81d..2dae2475ca4 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -618,6 +618,7 @@ user might encounter. - `CGAL::is_quad()` - `CGAL::is_quad_mesh()` - `CGAL::is_isolated_quad()` +- `CGAL::is_valid_polygon_mesh()` - `CGAL::is_tetrahedron()` - `CGAL::is_hexahedron()` From 9ec26cdccdc967451a0eb7d5ef65ab5631e3a017 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Fri, 23 Mar 2018 13:31:34 +0100 Subject: [PATCH 12/15] WIP : Split is_valid_polygon_mesh into 3 functions. --- BGL/include/CGAL/boost/graph/helpers.h | 411 +++++++++++++------------ BGL/test/BGL/test_graph_traits.cpp | 2 + 2 files changed, 223 insertions(+), 190 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 72d04d3707a..edc80a9834d 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -356,6 +356,224 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des return true; } +template +bool is_valid_halfedge_graph(const HalfedgeGraph& 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; + if ( is_border(begin, g)) + verr << " is border halfedge" << 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 && ( next(next(i, g), g) != i); + valid = valid && ( target(i, g) != target(opposite(i, g), g)); + 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; + } + ++n; +} +valid = valid && (n == num_h); +if ( n != num_h) + verr << "counting halfedges failed." << std::endl; + +verr << "end of CGAL::is_valid_polygon_mesh(): structure is " + << ( valid ? "valid." : "NOT VALID.") << std::endl; +return valid; +} + +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; + 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; + } + + // Distinct facets on each side of an halfedge. + valid = valid && (face(i, g) != face(opposite(i, g), g)); + if ( ! valid) { + verr << " both incident facets are equal." << 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 is_valid_polygon_mesh checks the integrity of a `PolygonMesh`. @@ -402,198 +620,11 @@ std::distance(halfedges(g).first, halfedges(g).second)) template bool is_valid_polygon_mesh(const PolygonMesh& 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::face_descriptor face_descriptor; - typedef typename boost::graph_traits::vertices_size_type vertex_size_type; - typedef typename boost::graph_traits::halfedges_size_type halfedges_size_type; - typedef typename boost::graph_traits::faces_size_type faces_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)))), - num_f(std::distance(boost::begin(faces(g)), boost::end(faces(g)))); - bool valid = ( 1 != (num_h& 1)); - if ( ! valid) - verr << "number of halfedges is odd." << std::endl; - - // All halfedges. - - halfedges_size_type n = 0; - halfedges_size_type nb = 0; - BOOST_FOREACH(halfedge_descriptor begin, halfedges(g)) { - if(!valid) - break; - verr << "halfedge " << n << std::endl; - if ( is_border(begin, g)) - verr << " is border halfedge" << 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; - } - // face integrity. - - valid = valid && ( face(begin, g) == face(next(begin, g), g)); - if ( ! valid) { - verr << " face pointer integrity2 corrupted." - << std::endl; - break; - } - - ++n; - if ( is_border(begin, g)) - ++nb; - } - verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl; - 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 faces. - faces_size_type f = 0; - n = 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; - 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; - // 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 && ( next(next(i, g), g) != i); - valid = valid && ( target(i, g) != target(opposite(i, g), g)); - 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; - } - // Distinct facets on each side of an halfedge. - valid = valid && (face(i, g) != face(opposite(i, g), g)); - if ( ! valid) { - verr << " both incident facets are equal." << std::endl; - break; - } - ++n; + bool valid=is_valid_face_graph(g, verb); + //test for 2-manifoldness + return valid; } -valid = valid && (n == num_h); -if ( n != num_h) - verr << "counting halfedges failed." << std::endl; -verr << "end of CGAL::is_valid_polygon_mesh(): structure is " - << ( valid ? "valid." : "NOT VALID.") << std::endl; -return valid; -} /*! \ingroup PkgBGLHelperFct diff --git a/BGL/test/BGL/test_graph_traits.cpp b/BGL/test/BGL/test_graph_traits.cpp index 3224d91c010..0652c47e8d0 100644 --- a/BGL/test/BGL/test_graph_traits.cpp +++ b/BGL/test/BGL/test_graph_traits.cpp @@ -255,6 +255,8 @@ template void test_read(const G& g) { assert(CGAL::is_valid_polygon_mesh(g)); + assert(CGAL::is_valid_face_graph(g)); + assert(CGAL::is_valid_halfedge_graph(g)); } From a45ac9e4703258e0948ed70e683b548928f636fd Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 26 Mar 2018 07:30:57 +0200 Subject: [PATCH 13/15] Split is_valid_polygon_mesh into 3 : adding is_valid_halfedge_graph() and is_valid_face_graph() --- BGL/doc/BGL/PackageDescription.txt | 2 + BGL/include/CGAL/boost/graph/helpers.h | 94 +++++++++++++------------- BGL/test/BGL/test_graph_traits.cpp | 2 - BGL/test/BGL/test_helpers.cpp | 78 ++++++++++++++++++++- 4 files changed, 125 insertions(+), 51 deletions(-) diff --git a/BGL/doc/BGL/PackageDescription.txt b/BGL/doc/BGL/PackageDescription.txt index 2dae2475ca4..d40b1ec6ecf 100644 --- a/BGL/doc/BGL/PackageDescription.txt +++ b/BGL/doc/BGL/PackageDescription.txt @@ -618,6 +618,8 @@ user might encounter. - `CGAL::is_quad()` - `CGAL::is_quad_mesh()` - `CGAL::is_isolated_quad()` +- `CGAL::is_valid_halfedge_graph()` +- `CGAL::is_valid_face_graph()` - `CGAL::is_valid_polygon_mesh()` - `CGAL::is_tetrahedron()` diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index edc80a9834d..d8f880bde8c 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -356,6 +356,16 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des return true; } +/*! + \ingroup PkgBGLHelperFct + * \brief is_valid_face_graph checks the integrity of a `HalfedgeGraph`. + * \param g the `HalfedgeGraph` to test. + * \param verb : if `true`, the details of the check will be written in the standard output. + * + * \tparam HalfedgeGraph a model of `HalfedgeGraph` + * \return `true` if the `FaceGraph` is valid, `false` otherwise. + * + */ template bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) { @@ -377,8 +387,6 @@ bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) if(!valid) break; verr << "halfedge " << n << std::endl; - if ( is_border(begin, g)) - verr << " is border halfedge" << std::endl; // Pointer integrity. valid = valid && ( next(begin, g) != boost::graph_traits::null_halfedge()); valid = valid && ( opposite(begin, g) != boost::graph_traits::null_halfedge()); @@ -471,12 +479,9 @@ bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) verr << "halfedge " << n << std::endl; // At least triangular facets and distinct geometry. valid = valid && ( next(i, g) != i); - valid = valid && ( next(next(i, g), g) != i); valid = valid && ( target(i, g) != target(opposite(i, g), g)); - 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." + verr << " pointer validity corrupted." << std::endl; break; } @@ -486,11 +491,21 @@ valid = valid && (n == num_h); if ( n != num_h) verr << "counting halfedges failed." << std::endl; -verr << "end of CGAL::is_valid_polygon_mesh(): structure is " +verr << "structure is " << ( valid ? "valid." : "NOT VALID.") << std::endl; return valid; } +/*! + \ingroup PkgBGLHelperFct + * \brief is_valid_face_graph checks the integrity of a `FaceGraph`. + * \param g the `FaceGraph` to test. + * \param verb : if `true`, the details of the check will be written in the standard output. + * + * \tparam FaceGraph a model of `FaceGraph` + * \return `true` if the `FaceGraph` is valid, `false` otherwise. + * + */ template bool is_valid_face_graph(const FaceGraph& g, bool verb = false) { @@ -557,13 +572,6 @@ bool is_valid_face_graph(const FaceGraph& g, bool verb = false) << std::endl; break; } - - // Distinct facets on each side of an halfedge. - valid = valid && (face(i, g) != face(opposite(i, g), g)); - if ( ! valid) { - verr << " both incident facets are equal." << std::endl; - break; - } } verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl; if ( valid && n + nb != num_h) @@ -580,48 +588,38 @@ bool is_valid_face_graph(const FaceGraph& g, bool verb = false) * \param g the `PolygonMesh` to test. * \param verb : if `true`, the details of the check will be written in the standard output. * - * \tparam PolygonMesh a model of `FaceListGraph`, `HalfedgeListGraph` and `VertexListGraph` + * \tparam PolygonMesh a model of \ref PMPDef "PolygonMesh" * \return `true` if the `PolygonMesh` is valid, `false` otherwise. * - * A `PolygonMesh` `g` is valid if: - -- it has an even number of halfedges -- for each halfedge `h` of `g`: - - halfedge(edge(h,g),g)==h - - next(h,g) != null_halfedge() - - opposite(h,g) != null_halfedge() - - opposite(h,g) != h - - opposite(opposite(h,g)) == h - - next(h, g) != h - - next(next(h,g),g) != h; - - target(h,g) != target(opposite(h,g),g) - - target(h,g) != target(next(h,g),g) - - target(h,g) != target(next(next(h,g),g),g) - - prev(next(h,g),g) == next(prev(h,g),g) == h - - target(h,g) != null_vertex() - - target(h,g) == target(opposite(next(h,g),g),g) - - face(h,g) == face(next(h,g),g) -- std::distance(halfedges(g).first, halfedges(g).second)) is the number of halfedges of `g` -- for each vertex `v` of `g`: - - halfedge(v,g) != null_halfedge() - - target(halfedge(v,g),g) == v - -- the sum of the halfedges around all the vertices of `g` is -std::distance(halfedges(g).first, halfedges(g).second)) -- std::distance(vertices(g).first, vertices(g).second)) is the number of vertices of `g` -- for each face `f` of `g`: - - halfedge(f,g) != null_halfedge() - - face(halfedge(f,g),g) == f - -- the sum of halfedges around all the faces of `g` + the border halfedges of `g` is -std::distance(halfedges(g).first, halfedges(g).second)) -- `g` has distinct faces on each side of an edge. */ template bool is_valid_polygon_mesh(const PolygonMesh& 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; } diff --git a/BGL/test/BGL/test_graph_traits.cpp b/BGL/test/BGL/test_graph_traits.cpp index 0652c47e8d0..3224d91c010 100644 --- a/BGL/test/BGL/test_graph_traits.cpp +++ b/BGL/test/BGL/test_graph_traits.cpp @@ -255,8 +255,6 @@ template void test_read(const G& g) { assert(CGAL::is_valid_polygon_mesh(g)); - assert(CGAL::is_valid_face_graph(g)); - assert(CGAL::is_valid_halfedge_graph(g)); } diff --git a/BGL/test/BGL/test_helpers.cpp b/BGL/test/BGL/test_helpers.cpp index e2096d4df5e..e4d0e145829 100644 --- a/BGL/test/BGL/test_helpers.cpp +++ b/BGL/test/BGL/test_helpers.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -25,9 +26,85 @@ test(const char *fname, bool triangle, bool quad, bool tetrahedron, bool hexahed assert(CGAL::is_hexahedron(hd, m) == hexahedron); } +template +void +test_validity(Mesh& mesh) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::property_map::type VPMap; + VPMap vpmap = get(CGAL::vertex_point, mesh); + vertex_descriptor vertices[4]; + edge_descriptor edges[4]; + vertices[0] = add_vertex(mesh); + vertices[1] = add_vertex(mesh); + vertices[2] = add_vertex(mesh); + vertices[3] = add_vertex(mesh); + + put(vpmap, vertices[0], Point_3(0,0,0)); + put(vpmap, vertices[1], Point_3(1,0,0)); + put(vpmap, vertices[2], Point_3(1,1,0)); + put(vpmap, vertices[3], Point_3(0,1,0)); + + edges[0] = add_edge(mesh); + edges[1] = add_edge(mesh); + edges[2] = add_edge(mesh); + edges[3] = add_edge(mesh); + + assert(!CGAL::is_valid_halfedge_graph(mesh)); + for(int i=0; i<4; ++i) + { + set_target(halfedge(edges[i], mesh), vertices[i], mesh); + set_halfedge(vertices[i], halfedge(edges[i], mesh), mesh); + } + + for(int i=0; i<4; ++i) + set_target(opposite(halfedge(edges[i], mesh), mesh), vertices[(i+1)%4], mesh); + for(int i=0; i<4; ++i) + { + set_next(halfedge(edges[(i+1)%4], mesh), halfedge(edges[i], mesh), mesh); + set_next(opposite(halfedge(edges[i], mesh), mesh), + opposite(halfedge(edges[(i+1)%4], mesh), mesh), mesh); + } + + assert(CGAL::is_valid_halfedge_graph(mesh)); + face_descriptor faces[1]; + faces[0] = add_face(mesh); + assert(!CGAL::is_valid_face_graph(mesh)); + + for(int i=0; i<4; ++i) + { + set_face(opposite(halfedge(edges[i], mesh), mesh), faces[0], mesh); + } + set_halfedge(faces[0], opposite(halfedge(edges[0], mesh), mesh), mesh); + assert(CGAL::is_valid_face_graph(mesh)); + assert(CGAL::is_valid_polygon_mesh(mesh)); + + Mesh dummy; + vertices[0] = add_vertex(dummy); + vertices[1] = add_vertex(dummy); + edges[0] = add_edge(dummy); + set_target(halfedge(edges[0], dummy), vertices[0], dummy); + set_halfedge(vertices[0], halfedge(edges[0], dummy), dummy); + set_target(opposite(halfedge(edges[0], dummy), dummy), vertices[1], dummy); + set_halfedge(vertices[1], opposite(halfedge(edges[0], dummy), dummy), dummy); + set_next(halfedge(edges[0], dummy), opposite(halfedge(edges[0], dummy), dummy), dummy); + set_next(opposite(halfedge(edges[0], dummy), dummy), halfedge(edges[0], dummy), dummy); + faces[0] = add_face(dummy); + set_halfedge(faces[0], opposite(halfedge(edges[0], dummy), dummy), dummy); + set_face(halfedge(edges[0], dummy), faces[0], dummy); + set_face(opposite(halfedge(edges[0], dummy), dummy), faces[0], dummy); + assert(CGAL::is_valid_face_graph(dummy)); + assert(!CGAL::is_valid_polygon_mesh(dummy)); + +} + int main() { typedef CGAL::Surface_mesh Mesh; + Mesh mesh; + test_validity(mesh); // triangle quad tetra hexa test("data/triangle.off", true, false, false, false ); test("data/quad.off", false, true, false, false ); @@ -79,7 +156,6 @@ int main() assert(num_faces(m) == 9); assert(CGAL::is_quad_mesh(m)); assert(CGAL::is_valid_polygon_mesh(m)); - std::cerr << "done" << std::endl; return 0; } From 4c309c4564df5df90c29c4970443eb0bca6ce0fe Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 26 Mar 2018 10:39:41 +0200 Subject: [PATCH 14/15] Fix doc --- BGL/include/CGAL/boost/graph/helpers.h | 27 +++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index d8f880bde8c..84711f40297 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -358,12 +358,12 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des /*! \ingroup PkgBGLHelperFct - * \brief is_valid_face_graph checks the integrity of a `HalfedgeGraph`. - * \param g the `HalfedgeGraph` to test. + * \brief checks the integrity of `g`. + * \param g the HalfedgeGraph to test. * \param verb : if `true`, the details of the check will be written in the standard output. * - * \tparam HalfedgeGraph a model of `HalfedgeGraph` - * \return `true` if the `FaceGraph` is valid, `false` otherwise. + * \tparam HalfedgeGraph a model of `HalfedgeListGraph` + * \return `true` if `g` is valid, `false` otherwise. * */ template @@ -498,12 +498,14 @@ return valid; /*! \ingroup PkgBGLHelperFct - * \brief is_valid_face_graph checks the integrity of a `FaceGraph`. - * \param g the `FaceGraph` to test. + * \brief checks the integrity of `g`. + * + * calls `is_valid_halfedge_graph()` + * \param g the FaceGraph to test. * \param verb : if `true`, the details of the check will be written in the standard output. * - * \tparam FaceGraph a model of `FaceGraph` - * \return `true` if the `FaceGraph` is valid, `false` otherwise. + * \tparam FaceGraph a model of `FaceListGraph` + * \return `true` if `g` is valid, `false` otherwise. * */ template @@ -584,12 +586,15 @@ bool is_valid_face_graph(const FaceGraph& g, bool verb = false) } /*! \ingroup PkgBGLHelperFct - * \brief is_valid_polygon_mesh checks the integrity of a `PolygonMesh`. + * \brief checks the integrity of `g`. + * + * calls `is_valid_face_graph()` * \param g the `PolygonMesh` to test. * \param verb : if `true`, the details of the check will be written in the standard output. * - * \tparam PolygonMesh a model of \ref PMPDef "PolygonMesh" - * \return `true` if the `PolygonMesh` is valid, `false` otherwise. + * \tparam PolygonMesh a model of `FaceListGraph` and `HalfedgeListGraph`, and follows + * the definition of a \ref PMPDef "PolygonMesh" + * \return `true` if `g` is valid, `false` otherwise. * */ template From d3c874bd83dcf9543898bcc2a57701e3579ed443 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Mon, 26 Mar 2018 11:45:45 +0200 Subject: [PATCH 15/15] Add some info about what a valid graph is. --- BGL/include/CGAL/boost/graph/helpers.h | 72 +++++++++++++++----------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/helpers.h b/BGL/include/CGAL/boost/graph/helpers.h index 84711f40297..5e2c03e95e9 100644 --- a/BGL/include/CGAL/boost/graph/helpers.h +++ b/BGL/include/CGAL/boost/graph/helpers.h @@ -359,20 +359,25 @@ bool is_valid_face_descriptor( typename boost::graph_traits::face_des /*! \ingroup PkgBGLHelperFct * \brief checks the integrity of `g`. - * \param g the HalfedgeGraph to test. + * + * `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 HalfedgeGraph a model of `HalfedgeListGraph` + * \tparam `Graph` a model of `HalfedgeListGraph` * \return `true` if `g` is valid, `false` otherwise. * */ -template -bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) +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; + 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)))); @@ -388,8 +393,8 @@ bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) 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()); + 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; @@ -414,7 +419,7 @@ bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) break; } // vertex integrity. - valid = valid && ( target(begin, g) != boost::graph_traits::null_vertex()); + valid = valid && ( target(begin, g) != boost::graph_traits::null_vertex()); if ( ! valid) { verr << " vertex pointer integrity corrupted." << std::endl; @@ -440,7 +445,7 @@ bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) break; verr << "vertex " << v << std::endl; // Pointer integrity. - if ( halfedge(vbegin, g) != boost::graph_traits::null_halfedge()) + if ( halfedge(vbegin, g) != boost::graph_traits::null_halfedge()) valid = valid && ( target( halfedge(vbegin, g), g) == vbegin); else @@ -452,7 +457,7 @@ bool is_valid_halfedge_graph(const HalfedgeGraph& g, bool verb = false) } // 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; @@ -500,21 +505,25 @@ 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 FaceGraph to test. + * \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` + * \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 FaceGraph& g, bool verb = false) +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; + 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)))); @@ -534,7 +543,7 @@ bool is_valid_face_graph(const FaceGraph& g, bool verb = false) break; verr << "face " << f << std::endl; // Pointer integrity. - if ( halfedge(fbegin, g) != boost::graph_traits::null_halfedge()) + if ( halfedge(fbegin, g) != boost::graph_traits::null_halfedge()) valid = valid && ( face(halfedge(fbegin, g), g) == fbegin); else @@ -545,7 +554,7 @@ bool is_valid_face_graph(const FaceGraph& g, bool verb = false) } // 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; @@ -588,19 +597,24 @@ bool is_valid_face_graph(const FaceGraph& g, bool verb = false) \ingroup PkgBGLHelperFct * \brief checks the integrity of `g`. * - * calls `is_valid_face_graph()` - * \param g the `PolygonMesh` to test. + * `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 PolygonMesh 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 PolygonMesh& g, bool verb = false) +template +bool is_valid_polygon_mesh(const Mesh& g, bool verb = false) { - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + 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