From a43b79a69ff443390c403bdd9095682f71ac45bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 23 Mar 2022 13:33:00 +0100 Subject: [PATCH] Test code fixes --- .../test/Alpha_wrap_3/alpha_wrap_validation.h | 46 +++++++++++++++---- .../test_AW3_cavity_initializations.cpp | 39 +++++++++------- .../Alpha_wrap_3/test_AW3_manifoldness.cpp | 23 ++++++---- .../Alpha_wrap_3/test_AW3_multiple_calls.cpp | 43 +++++++++-------- .../Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp | 20 +++++--- .../poisson_reconstruction.cpp | 8 ++-- 6 files changed, 114 insertions(+), 65 deletions(-) diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/alpha_wrap_validation.h b/Alpha_wrap_3/test/Alpha_wrap_3/alpha_wrap_validation.h index 0e6de1863db..85307860f9e 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/alpha_wrap_validation.h +++ b/Alpha_wrap_3/test/Alpha_wrap_3/alpha_wrap_validation.h @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace CGAL { @@ -124,6 +125,22 @@ bool is_valid_wrap(const TriangleMesh& wrap, { namespace PMP = CGAL::Polygon_mesh_processing; + if(is_empty(wrap)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Error: empty wrap" << std::endl; +#endif + return false; + } + + if(!is_valid_polygon_mesh(wrap)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Error: Invalid wrap mesh" << std::endl; +#endif + return false; + } + if(!is_triangle_mesh(wrap)) { #ifdef CGAL_AW3_DEBUG @@ -134,8 +151,24 @@ bool is_valid_wrap(const TriangleMesh& wrap, if(!is_closed(wrap)) { + if(check_manifoldness) + { #ifdef CGAL_AW3_DEBUG - std::cerr << "Error: Wrap is not closed" << std::endl; + std::cerr << "Error: Wrap is not closed" << std::endl; +#endif + return false; + } + else + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "W: Wrap is not closed" << std::endl; +#endif + } + } + else if(!PMP::does_bound_a_volume(wrap, np)) + { +#ifdef CGAL_AW3_DEBUG + std::cerr << "Error: Wrap does not bound a volume" << std::endl; #endif return false; } @@ -166,18 +199,10 @@ bool is_valid_wrap(const TriangleMesh& wrap, return false; } #ifdef CGAL_AW3_DEBUG - std::cerr << "Warning: Wrap self-intersects" << std::endl; + std::cerr << "W: Wrap self-intersects" << std::endl; #endif } - if(!PMP::does_bound_a_volume(wrap, np)) - { -#ifdef CGAL_AW3_DEBUG - std::cerr << "Error: Wrap does not bound a volume" << std::endl; -#endif - return false; - } - return true; } @@ -268,6 +293,7 @@ bool is_outer_wrap_of_triangle_soup(const TriangleMesh& wrap, namespace PMP = CGAL::Polygon_mesh_processing; // Make a mesh out of the soup + PMP::repair_polygon_soup(points, faces); PMP::orient_polygon_soup(points, faces); CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(faces)); diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp index d10f48b7bea..d03140a2dd0 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp @@ -1,6 +1,6 @@ #define CGAL_AW3_TIMER #define CGAL_AW3_DEBUG -#define CGAL_AW3_DEBUG_INITIALIZATION +// #define CGAL_AW3_DEBUG_INITIALIZATION #include #include @@ -21,24 +21,21 @@ using Mesh = CGAL::Surface_mesh; using Seeds = std::vector; -Point_3 generate_point(const CGAL::Bbox_3 bbox, - CGAL::Random& r) -{ - return Point_3(bbox.xmin() + bbox.x_span() * r.get_double(), - bbox.ymin() + bbox.y_span() * r.get_double(), - bbox.zmin() + bbox.z_span() * r.get_double()); -} - template void generate_random_seeds(const Oracle& oracle, const double offset, Seeds& seeds, CGAL::Random& r) { - auto sq_offset = CGAL::square(offset); + const auto bbox = CGAL::Alpha_wraps_3::internal::Alpha_wrap_3(oracle).construct_bbox(offset); + const double sq_offset = CGAL::square(offset); + while(seeds.size() < 3) { - const Point_3 seed = generate_point(oracle.bbox(), r); + const Point_3 seed (bbox.xmin() + r.get_double(0., 1.) * (bbox.xmax() - bbox.xmin()), + bbox.ymin() + r.get_double(0., 1.) * (bbox.ymax() - bbox.ymin()), + bbox.zmin() + r.get_double(0., 1.) * (bbox.zmax() - bbox.zmin())); + const FT sqd = oracle.squared_distance(seed); #ifdef CGAL_AW3_DEBUG std::cout << "Generate " << seed << " at squared distance " << sqd << " (sqo: " << sq_offset << ")" << std::endl; @@ -66,6 +63,7 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, if(has_degeneracies) std::cerr << "Warning: Failed to remove some degenerate faces." << std::endl; + std::cout << "Processed input: " << vertices(input_mesh).size() << " vertices, " << faces(input_mesh).size() << " faces" << std::endl; // CGAL::IO::write_polygon_mesh("input.off", input_mesh, CGAL::parameters::stream_precision(17)); Oracle oracle; @@ -81,23 +79,32 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, assert(!seeds.empty()); + const bool enforce_manifoldness = true; + Mesh wrap; aw3(alpha, offset, wrap, CGAL::parameters::seed_points(std::ref(seeds)) - .do_enforce_manifoldness(true)); + .do_enforce_manifoldness(enforce_manifoldness)); std::cout << "Result: " << vertices(wrap).size() << " vertices, " << faces(wrap).size() << " faces" << std::endl; + // Tolerate failed initialization since we use random seeds and it's difficult to guarantee it + if(is_empty(wrap)) + return; + // CGAL::IO::write_polygon_mesh("last.off", wrap, CGAL::parameters::stream_precision(17)); if(!has_degeneracies) { assert(AW3::internal::is_valid_wrap(wrap, true /*manifoldness*/)); assert(AW3::internal::is_outer_wrap_of_triangle_mesh(wrap, input_mesh)); - // assert(AW3::internal::has_expected_Hausdorff_distance(wrap, input_mesh, alpha, offset)); + + if(!enforce_manifoldness) + assert(AW3::internal::has_expected_Hausdorff_distance(wrap, input_mesh, alpha, offset)); } - // assert(AW3::internal::check_edge_length(wrap, alpha)); + if(!enforce_manifoldness) + assert(AW3::internal::check_edge_length(wrap, alpha)); } void alpha_wrap_triangle_mesh(Mesh& input_mesh, @@ -125,8 +132,8 @@ void alpha_wrap_triangle_mesh(const std::string& filename) { CGAL::Random r; - const double alpha_expo = r.get_double(0., 7.5); // to have alpha_rel between 1 and ~200 - const double offset_expo = r.get_double(0., 7.5); + const double alpha_expo = r.get_double(0., 6); // to have alpha_rel between 1 and 64 + const double offset_expo = r.get_double(0., 6); const double alpha_rel = std::pow(2, alpha_expo); const double offset_rel = std::pow(2, offset_expo); const double alpha = longest_diag_length / alpha_rel; diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp index d079005ad6a..928cade6495 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_manifoldness.cpp @@ -33,6 +33,7 @@ void alpha_wrap_triangle_manifoldness(Mesh& input_mesh, namespace PMP = CGAL::Polygon_mesh_processing; std::cout << "Input: " << num_vertices(input_mesh) << " vertices, " << num_faces(input_mesh) << " faces" << std::endl; + std::cout << "Alpha: " << alpha << " Offset: " << offset << std::endl; const bool has_degeneracies = !PMP::remove_degenerate_faces(input_mesh); if(has_degeneracies) @@ -49,9 +50,18 @@ void alpha_wrap_triangle_manifoldness(Mesh& input_mesh, std::cout << "Result: " << vertices(nm_wrap).size() << " vertices, " << faces(nm_wrap).size() << " faces" << std::endl; + if(!has_degeneracies) + { + assert(AW3::internal::is_valid_wrap(nm_wrap, false)); + assert(AW3::internal::is_outer_wrap_of_triangle_mesh(nm_wrap, input_mesh)); + assert(AW3::internal::has_expected_Hausdorff_distance(nm_wrap, input_mesh, alpha, offset)); + } + + assert(AW3::internal::check_edge_length(nm_wrap, alpha)); + FT base_vol = 0; if(!is_closed(nm_wrap)) - std::cerr << "Warning: non-manifold wrap is not closed" << std::endl; + std::cerr << "W: non-manifold wrap is not closed" << std::endl; else base_vol = PMP::volume(nm_wrap); @@ -66,13 +76,8 @@ void alpha_wrap_triangle_manifoldness(Mesh& input_mesh, { assert(AW3::internal::is_valid_wrap(m_wrap, true /*manifoldness*/)); assert(AW3::internal::is_outer_wrap_of_triangle_mesh(m_wrap, input_mesh)); - - // These assertions might not be honored since we have added material - // assert(AW3::internal::has_expected_Hausdorff_distance(m_wrap, input_mesh, alpha, offset)); } - // assert(AW3::internal::check_edge_length(wrap, alpha)); - const FT final_vol = PMP::volume(m_wrap); if(base_vol != 0) @@ -84,7 +89,7 @@ void alpha_wrap_triangle_manifoldness(Mesh& input_mesh, << "after: " << final_vol << "\n" << "ratio: " << ratio << std::endl; if(ratio > 1.1) // more than 10% extra volume - std::cerr << "Warning: large increase of volume after manifoldness resolution" << std::endl; + std::cerr << "W: large increase of volume after manifoldness resolution" << std::endl; } } @@ -124,8 +129,8 @@ void alpha_wrap_triangle_manifoldness(const std::string& filename) for(int i=0; i<2; ++i) { - const double alpha_expo = r.get_double(0., 7.5); // to have alpha_rel between 1 and ~200 - const double offset_expo = r.get_double(0., 7.5); + const double alpha_expo = r.get_double(0., 6); // to have alpha_rel between 1 and 64 + const double offset_expo = r.get_double(0., 6); const double alpha_rel = std::pow(2, alpha_expo); const double offset_rel = std::pow(2, offset_expo); const double alpha = longest_diag_length / alpha_rel; diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp index 629cba3ce2f..a9b57a28a64 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp @@ -23,32 +23,30 @@ using Point_3 = Kernel::Point_3; using Vector_3 = Kernel::Vector_3; using Points = std::vector; -using Face = std::array; +using Face = std::vector; using Faces = std::vector; using Mesh = CGAL::Surface_mesh; void alpha_wrap_triangle_soup(Points& pr, Faces& fr, - const double alpha, - const double offset) + double alpha, + double offset) { namespace AW3 = CGAL::Alpha_wraps_3; namespace PMP = CGAL::Polygon_mesh_processing; - using Oracle = AW3::internal::Triangle_soup_oracle; + using Oracle = AW3::internal::Triangle_soup_oracle; std::cout << "Input: " << pr.size() << " points, " << fr.size() << " faces" << std::endl; + + PMP::repair_polygon_soup(pr, fr); + std::cout << "Processed input: " << pr.size() << " points, " << fr.size() << " faces" << std::endl; // CGAL::IO::write_polygon_soup("input.off", pr, fr, CGAL::parameters::stream_precision(17)); - Mesh input_mesh; - if(!PMP::orient_polygon_soup(pr, fr) || - !PMP::is_polygon_soup_a_polygon_mesh(fr)) - { - std::cerr << "Warning: polygon soup does not describe a polygon mesh" << std::endl; - return; - } - + Mesh input_mesh; // only required for Hausdorff + PMP::orient_polygon_soup(pr, fr); + assert(PMP::is_polygon_soup_a_polygon_mesh(fr)); PMP::polygon_soup_to_polygon_mesh(pr, fr, input_mesh); // AW3 @@ -59,7 +57,7 @@ void alpha_wrap_triangle_soup(Points& pr, Mesh wrap; aw3(alpha, offset, wrap, CGAL::parameters::do_enforce_manifoldness(false)); - std::cout << "Result: " << vertices(wrap).size() << " vertices, " << faces(wrap).size() << " faces" << std::endl; + std::cout << "First call result: " << vertices(wrap).size() << " vertices, " << faces(wrap).size() << " faces" << std::endl; // CGAL::IO::write_polygon_mesh("last.off", wrap, CGAL::parameters::stream_precision(17)); @@ -68,8 +66,15 @@ void alpha_wrap_triangle_soup(Points& pr, assert(AW3::internal::has_expected_Hausdorff_distance(wrap, input_mesh, alpha, offset)); assert(AW3::internal::check_edge_length(wrap, alpha)); + alpha *= 2; + offset *= 2; + Mesh wrap_2; - aw3(2 * alpha, 2 * offset, wrap, CGAL::parameters::do_enforce_manifoldness(false)); + aw3(alpha, offset, wrap_2, CGAL::parameters::do_enforce_manifoldness(false)); + + std::cout << "Second call result: " << vertices(wrap).size() << " vertices, " << faces(wrap).size() << " faces" << std::endl; + +// CGAL::IO::write_polygon_mesh("last.off", wrap, CGAL::parameters::stream_precision(17)); assert(num_vertices(wrap_2) <= num_vertices(wrap) && num_faces(wrap_2) <= num_faces(wrap)); assert(AW3::internal::is_valid_wrap(wrap_2, false /*manifoldness*/)); @@ -95,12 +100,12 @@ void alpha_wrap_triangle_soup(const std::string& filename) Point_3(bbox.xmin(), bbox.ymin(), bbox.zmin()); double longest_diag_length = CGAL::to_double(CGAL::approximate_sqrt(longest_diag.squared_length())); + CGAL::Random r; + for(int i=0; i<2; ++i) { - CGAL::Random r; - - const double alpha_expo = r.get_double(0., 7.5); // to have alpha_rel between 1 and ~200 - const double offset_expo = r.get_double(0., 7.5); + const double alpha_expo = r.get_double(0., 6); // to have alpha_rel between 1 and 64 + const double offset_expo = r.get_double(0., 6); const double alpha_rel = std::pow(2, alpha_expo); const double offset_rel = std::pow(2, offset_expo); const double alpha = longest_diag_length / alpha_rel; @@ -139,7 +144,7 @@ int main(int argc, char** argv) alpha_wrap_triangle_soup("data/tetrahedron_self_intersection_tip.off"); alpha_wrap_triangle_soup("data/tetrahedron_twisted_tip.off"); alpha_wrap_triangle_soup("data/tetrahedron_random_perturbation.off"); - alpha_wrap_triangle_soup("data/overlay_triangulation.off"); +// alpha_wrap_triangle_soup("data/overlay_triangulation.off"); // due to geometrically degenerate faces + using soups here alpha_wrap_triangle_soup("data/two_knives.off"); alpha_wrap_triangle_soup("data/three_knives.off"); alpha_wrap_triangle_soup("data/bunny_random_perturbation.off"); diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp index daae69317e7..86639f706a8 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_alpha_wrap_3_mesh.cpp @@ -1,6 +1,6 @@ #define CGAL_AW3_TIMER -#define CGAL_AW3_DEBUG -#define CGAL_AW3_DEBUG_MANIFOLDNESS +//#define CGAL_AW3_DEBUG +//#define CGAL_AW3_DEBUG_MANIFOLDNESS //#define CGAL_AW3_DEBUG_STEINER_COMPUTATION //#define CGAL_AW3_DEBUG_INITIALIZATION //#define CGAL_AW3_DEBUG_QUEUE @@ -33,6 +33,7 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, namespace PMP = CGAL::Polygon_mesh_processing; std::cout << "Input: " << num_vertices(input_mesh) << " vertices, " << num_faces(input_mesh) << " faces" << std::endl; + std::cout << "Alpha: " << alpha << " Offset: " << offset << std::endl; bool has_degeneracies = !PMP::remove_degenerate_faces(input_mesh); if(has_degeneracies) @@ -42,10 +43,12 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, // CGAL::IO::write_polygon_mesh("input.off", input_mesh, CGAL::parameters::stream_precision(17)); + const bool enforce_manifoldness = true; + Mesh wrap; CGAL::alpha_wrap_3(input_mesh, alpha, offset, wrap, CGAL::parameters::default_values(), - CGAL::parameters::do_enforce_manifoldness(true)); + CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness)); std::cout << "Result: " << vertices(wrap).size() << " vertices, " << faces(wrap).size() << " faces" << std::endl; @@ -55,10 +58,13 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, { assert(AW3::internal::is_valid_wrap(wrap, true /*manifoldness*/)); assert(AW3::internal::is_outer_wrap_of_triangle_mesh(wrap, input_mesh)); - assert(AW3::internal::has_expected_Hausdorff_distance(wrap, input_mesh, alpha, offset)); + + if(!enforce_manifoldness) + assert(AW3::internal::has_expected_Hausdorff_distance(wrap, input_mesh, alpha, offset)); } - assert(AW3::internal::check_edge_length(wrap, alpha)); + if(!enforce_manifoldness) + assert(AW3::internal::check_edge_length(wrap, alpha)); } void alpha_wrap_triangle_mesh(const std::string& filename, @@ -97,8 +103,8 @@ void alpha_wrap_triangle_mesh(const std::string& filename) for(int i=0; i<2; ++i) { - const double alpha_expo = r.get_double(0., 7.5); // to have alpha_rel between 1 and ~200 - const double offset_expo = r.get_double(0., 7.5); + const double alpha_expo = r.get_double(0., 6); // to have alpha_rel between 1 and 64 + const double offset_expo = r.get_double(0., 6); const double alpha_rel = std::pow(2, alpha_expo); const double offset_rel = std::pow(2, offset_expo); const double alpha = longest_diag_length / alpha_rel; diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp index b96cebf39d1..f552cf357dc 100644 --- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp +++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/poisson_reconstruction.cpp @@ -104,12 +104,12 @@ int main(int argc, char * argv[]) //*************************************** // usage - if (argc-1 < 2) + if(argc == 1) { std::cerr << "Reads a point set or a mesh's set of vertices, reconstructs a surface using Poisson,\n"; std::cerr << "and saves the surface.\n"; std::cerr << "\n"; - std::cerr << "Usage: " << argv[0] << " file_in file_out [options]\n"; + std::cerr << "Usage: " << argv[0] << " [file_in] [file_out] [options]\n"; std::cerr << "Input file formats are .off (mesh) and .xyz or .pwn (point set).\n"; std::cerr << "Output file format is .off.\n"; std::cerr << "Options:\n"; @@ -127,8 +127,8 @@ int main(int argc, char * argv[]) double average_spacing_ratio = 5; // decode parameters - std::string input_filename = argc == 1 ? CGAL::data_file_path("points_3/kitten.xyz") : argv[1]; - std::string output_filename = argc == 1 ? "kitten_poisson-20-100-0.5.off" : argv[2]; + std::string input_filename = (argc > 1) ? argv[1] : CGAL::data_file_path("points_3/kitten.xyz"); + std::string output_filename = (argc > 2) ? argv[2] : "kitten_poisson-20-100-0.5.off"; for (int i=3; i+1