From c9c1770c18b6bb3e8502a8e0fd12f21ff4abdd16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 14 Nov 2024 11:53:53 +0100 Subject: [PATCH 01/12] in case an edge is both a cap and a needle but that is not collapsable try to flip --- .../repair_degeneracies.h | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 40f480cbb7c5..2072fdd93002 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -69,6 +69,8 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); + std::array retval = make_array(null_h, null_h); + halfedge_descriptor res = PMP::is_needle_triangle_face(f, tmesh, needle_threshold, parameters::vertex_point_map(vpm) .geom_traits(gt)); @@ -78,7 +80,7 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto if(collapse_length_threshold == 0 || edge_length(res, tmesh, parameters::vertex_point_map(vpm).geom_traits(gt)) <= collapse_length_threshold) { - return make_array(res, null_h); + retval[0]=res; } } @@ -89,10 +91,10 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto typename Traits::Line_3(get(vpm, source(res,tmesh)), get(vpm, target(res,tmesh))), flip_triangle_height_threshold_squared) != LARGER )) { - return make_array(null_h, res); + retval[1]=res; } - return make_array(null_h, null_h); + return retval; } template ::null_halfedge()) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "add new needle: " << edge(res[0], tmesh) << std::endl; + if (res[1] == boost::graph_traits::null_halfedge()) + std::cout << "add new needle: " << edge(res[0], tmesh) << std::endl; + else + std::cout << "add new needle (also a cap): " << edge(res[0], tmesh) << std::endl; #endif CGAL_assertion(!is_border(res[0], tmesh)); CGAL_assertion(!get(ecm, edge(res[0], tmesh))); @@ -738,13 +743,13 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, << " (" << source(e, tmesh) << " " << tmesh.point(source(h, tmesh)) << " --- " << source(e, tmesh) << " " << tmesh.point(target(h, tmesh)) << ")" << std::endl; #endif + + // Verify that the element is still badly shaped + const std::array nc = + internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, needle_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); if(CGAL::Euler::does_satisfy_link_condition(e, tmesh)) { - // Verify that the element is still badly shaped - const std::array nc = - internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); - if(nc[0] != h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA @@ -862,7 +867,15 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Uncollapsable edge!" << std::endl; #endif - next_edges_to_collapse.insert(h); + if (nc[1]==boost::graph_traits::null_halfedge()) + next_edges_to_collapse.insert(h); + else + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t Uncollapsable edge --> register it as cap!" << std::endl; +#endif + edges_to_flip.insert(nc[1]); + } } } From b60b203c56a058af417d86fa0fd6cd1b7a534fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 20 Nov 2024 09:11:48 +0100 Subject: [PATCH 02/12] add missing cap collection in case of non-collapsed edge --- .../Polygon_mesh_processing/repair_degeneracies.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 2072fdd93002..eb4c86f51938 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -755,9 +755,11 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Needle criteria no longer verified" << std::endl; #endif + if (nc[1]!=boost::graph_traits::null_halfedge()) edges_to_flip.insert(nc[1]); continue; } + // pick the orientation of edge to keep the vertex minimizing the volume variation const halfedge_descriptor best_h = internal::get_best_edge_orientation(e, tmesh, vpm, vcm, gt); if(best_h == boost::graph_traits::null_halfedge()) @@ -765,7 +767,10 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Geometrically invalid edge collapse!" << std::endl; #endif - next_edges_to_collapse.insert(h); + if (nc[1]!=boost::graph_traits::null_halfedge()) + edges_to_flip.insert(nc[1]); + else + next_edges_to_collapse.insert(h); continue; } @@ -774,7 +779,10 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t edge collapse prevented by the user functor" << std::endl; #endif - next_edges_to_collapse.insert(h); + if (nc[1]!=boost::graph_traits::null_halfedge()) + edges_to_flip.insert(nc[1]); + else + next_edges_to_collapse.insert(h); continue; } From 41d37ac2a98c7f75b18787c9110415f25e7b3049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 20 Nov 2024 09:40:13 +0100 Subject: [PATCH 03/12] split badly shaped triangle check and delay the check calls --- .../repair_degeneracies.h | 105 ++++++++++++------ 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index eb4c86f51938..fd9488fa54cf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -51,26 +51,20 @@ namespace Polygon_mesh_processing { namespace internal { template -std::array::halfedge_descriptor, 2> -is_badly_shaped(const typename boost::graph_traits::face_descriptor f, - TriangleMesh& tmesh, - const VPM& vpm, - const VCM& vcm, - const ECM& ecm, - const Traits& gt, - const double cap_threshold, // angle over 160° ==> cap - const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle - const double collapse_length_threshold, // max length of edges allowed to be collapsed - const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped +typename boost::graph_traits::halfedge_descriptor +is_it_a_needle(const typename boost::graph_traits::face_descriptor f, + TriangleMesh& tmesh, + const VPM& vpm, + const VCM& vcm, + const ECM& /* ecm */, //not used because vcm is filled with end points of edges in ecm + const Traits& gt, + const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle + const double collapse_length_threshold) // max length of edges allowed to be collapsed { namespace PMP = CGAL::Polygon_mesh_processing; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); - std::array retval = make_array(null_h, null_h); - halfedge_descriptor res = PMP::is_needle_triangle_face(f, tmesh, needle_threshold, parameters::vertex_point_map(vpm) .geom_traits(gt)); @@ -80,20 +74,63 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto if(collapse_length_threshold == 0 || edge_length(res, tmesh, parameters::vertex_point_map(vpm).geom_traits(gt)) <= collapse_length_threshold) { - retval[0]=res; + return res; } } - res = PMP::is_cap_triangle_face(f, tmesh, cap_threshold, parameters::vertex_point_map(vpm).geom_traits(gt)); + return null_h; +} + +template +typename boost::graph_traits::halfedge_descriptor +is_it_a_cap(const typename boost::graph_traits::face_descriptor f, + TriangleMesh& tmesh, + const VPM& vpm, + const VCM& /* vcm */, + const ECM& ecm, + const Traits& gt, + const double cap_threshold, // angle over 160° ==> cap + const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped +{ + namespace PMP = CGAL::Polygon_mesh_processing; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); + + halfedge_descriptor res = + PMP::is_cap_triangle_face(f, tmesh, cap_threshold, parameters::vertex_point_map(vpm).geom_traits(gt)); if( res != null_h && !get(ecm, edge(res, tmesh) ) && (flip_triangle_height_threshold_squared == 0 || typename Traits::Compare_squared_distance_3()( get(vpm, target(next(res,tmesh), tmesh)), typename Traits::Line_3(get(vpm, source(res,tmesh)), get(vpm, target(res,tmesh))), flip_triangle_height_threshold_squared) != LARGER )) { - retval[1]=res; + return res; } + return null_h; +} + +template +std::array::halfedge_descriptor, 2> +is_badly_shaped(const typename boost::graph_traits::face_descriptor f, + TriangleMesh& tmesh, + const VPM& vpm, + const VCM& vcm, + const ECM& ecm, + const Traits& gt, + const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle + const double cap_threshold, // angle over 160° ==> cap + const double collapse_length_threshold, // max length of edges allowed to be collapsed + const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped +{ + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); + std::array retval = make_array(null_h, null_h); + + retval[0] = is_it_a_needle(f, tmesh, vpm, vcm, ecm, gt, needle_threshold, collapse_length_threshold); + retval[1] = is_it_a_cap(f, tmesh, vpm, vcm, ecm, gt, cap_threshold, flip_triangle_height_threshold_squared); + return retval; } @@ -114,8 +151,8 @@ void collect_badly_shaped_triangles(const typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - std::array res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt, cap_threshold, - needle_threshold, + std::array res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt, + needle_threshold, cap_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); if(res[0] != boost::graph_traits::null_halfedge()) @@ -744,12 +781,13 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, << " --- " << source(e, tmesh) << " " << tmesh.point(target(h, tmesh)) << ")" << std::endl; #endif - // Verify that the element is still badly shaped - const std::array nc = - internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); if(CGAL::Euler::does_satisfy_link_condition(e, tmesh)) { + // Verify that the element is still badly shaped + const std::array nc = + internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + needle_threshold, cap_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); + if(nc[0] != h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA @@ -875,14 +913,19 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Uncollapsable edge!" << std::endl; #endif - if (nc[1]==boost::graph_traits::null_halfedge()) + + halfedge_descriptor nc = + internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + + if (nc==boost::graph_traits::null_halfedge()) next_edges_to_collapse.insert(h); else { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Uncollapsable edge --> register it as cap!" << std::endl; #endif - edges_to_flip.insert(nc[1]); + edges_to_flip.insert(nc); } } } @@ -910,11 +953,11 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, << " --- " << target(e, tmesh) << " " << tmesh.point(target(h, tmesh)) << ")" << std::endl; #endif - std::array nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, - collapse_length_threshold, flip_triangle_height_threshold_squared); + halfedge_descriptor nc = + internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); // Check the triangle is still a cap - if(nc[1] != h) + if(nc != h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Cap criteria no longer verified" << std::endl; @@ -986,7 +1029,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, CGAL_assertion(!is_border(h, tmesh)); std::array nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, + needle_threshold, cap_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); if(nc[1] != boost::graph_traits::null_halfedge() && nc[1] != h) From 0b3c27e584d90636daf364856cc050089d4a27b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 21 Nov 2024 09:04:17 +0100 Subject: [PATCH 04/12] swap the parameters also here --- .../internal/Isotropic_remeshing/remesh_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9cdb76ac76b0..10327dfba58b 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 @@ -871,14 +871,14 @@ namespace internal { std::array r1 = internal::is_badly_shaped( face(he, mesh_), mesh_, vpmap_, vcmap_, ecmap_, gt_, - cap_threshold, // bound on the angle: above 160 deg => cap 4, // bound on shortest/longest edge above 4 => needle + cap_threshold, // bound on the angle: above 160 deg => cap 0,// collapse length threshold : not needed here 0); // flip triangle height threshold std::array r2 = internal::is_badly_shaped( face(opposite(he, mesh_), mesh_), - mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, 4, 0, 0); + mesh_, vpmap_, vcmap_, ecmap_, gt_, 4, cap_threshold, 0, 0); const bool badly_shaped = (r1[0] != boost::graph_traits::null_halfedge()//needle || r1[1] != boost::graph_traits::null_halfedge()//cap From eb5ff9b33e5bdd9e5ecd4e5a4af60b0e32ac0cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Sat, 7 Dec 2024 23:28:20 +0100 Subject: [PATCH 05/12] Fix collect_badly_shaped_triangles not actually filling both ranges --- .../repair_degeneracies.h | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index fd9488fa54cf..5460d7a9077d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -151,33 +151,30 @@ void collect_badly_shaped_triangles(const typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); + std::array res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt, needle_threshold, cap_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); - if(res[0] != boost::graph_traits::null_halfedge()) + if(res[0] != null_h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - if (res[1] == boost::graph_traits::null_halfedge()) - std::cout << "add new needle: " << edge(res[0], tmesh) << std::endl; - else - std::cout << "add new needle (also a cap): " << edge(res[0], tmesh) << std::endl; + std::cout << "add new needle: " << edge(res[0], tmesh) << std::endl; #endif CGAL_assertion(!is_border(res[0], tmesh)); CGAL_assertion(!get(ecm, edge(res[0], tmesh))); edges_to_collapse.insert(res[0]); } - else // let's not make it possible to have a face be both a cap and a needle (for now) + + if(res[1] != null_h) { - if(res[1] != boost::graph_traits::null_halfedge()) - { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "add new cap: " << edge(res[1],tmesh) << std::endl; + std::cout << "add new cap: " << edge(res[1],tmesh) << std::endl; #endif - CGAL_assertion(!is_border(res[1], tmesh)); - CGAL_assertion(!get(ecm, edge(res[1], tmesh))); - edges_to_flip.insert(res[1]); - } + CGAL_assertion(!is_border(res[1], tmesh)); + CGAL_assertion(!get(ecm, edge(res[1], tmesh))); + edges_to_flip.insert(res[1]); } } From a4cb48a1455028e11f2cae0e906c874aa06c4fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Sat, 7 Dec 2024 23:29:04 +0100 Subject: [PATCH 06/12] Fix never trying again a user-rejected cap --- .../include/CGAL/Polygon_mesh_processing/repair_degeneracies.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 5460d7a9077d..7da99a4f1e6d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -1006,11 +1006,12 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, continue; } - if (!accept_change.flip(h)) + if(!accept_change.flip(h)) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Flipping prevented: rejected by user functor" << std::endl; #endif + next_edges_to_flip.insert(h); continue; } From fda7b1ae6aae187e5e74f2e679092814b5e53624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Sat, 7 Dec 2024 23:31:40 +0100 Subject: [PATCH 07/12] Avoid a lot of useless shape predicate calls Here are some changes: - Avoid a lot of redundant calls of is_it_a_needle / is_it_a_cap - Do not test for cap-ness if it's already a needle - Do not fill both ranges at the beginning, but fill with everything: on the first round, needle-ness will be tested, and the exit towards cap-ness will happen - Wait for a needle to no longer be a needle, or not be treatable to actually test cap-ness - When the mesh is modified, do not test everything immediately, just put them in the queue of the next iteration Result: Fewer calls to shape predicates - master - needle calls = 828 668 cap calls = 803 330 - PR - needle calls = 803 554 cap calls = 795 317 Should be fewer but two effects are balacing each other for the calls: - much fewer calls to shape predicates (is_it_a_needle, is_it_a_cap) by not calling until absolutely necessary (but still checking at pop time). - when we modify the mesh, I no longer fill the CURRENT cap and needle ranges, but the next ones. The point is to really prioritize all caps BEFORE treating needles, whereas otherwise we would treat some needles at the current iteration while there are still caps to treat. So there are more iterations which add more useless calls (see below) --- .../repair_degeneracies.h | 186 ++++++++++-------- 1 file changed, 100 insertions(+), 86 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 7da99a4f1e6d..56d5f93615a7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -646,6 +646,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); + typedef Static_boolean_property_map Default_VCM; typedef typename internal_np::Lookup_named_param_def edges_to_collapse; - std::set edges_to_flip; + // @todo maybe using a priority queue handling the more almost degenerate elements first should be used + std::unordered_set edges_to_collapse; + std::unordered_set edges_to_flip; - // @todo could probably do something a bit better by looping edges, consider the incident faces - // f1 / f2 and look at f1 if f1 next_edges_to_collapse; - std::set next_edges_to_flip; + std::unordered_set next_edges_to_collapse; + std::unordered_set next_edges_to_flip; // Treat needles =============================================================================== #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA @@ -761,16 +753,40 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #endif while(!edges_to_collapse.empty()) { + // note that on the first iteration, 'h' does not indicate a known needle halfedge_descriptor h = *edges_to_collapse.begin(); edges_to_collapse.erase(edges_to_collapse.begin()); + CGAL_assertion(is_valid_halfedge_descriptor(h, tmesh)); + + // Verify that the element is still badly shaped + halfedge_descriptor needle_h = internal::is_it_a_needle(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + needle_threshold, collapse_length_threshold); + if(needle_h == null_h) + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t Needle criterion no longer verified" << std::endl; +#endif + halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + if(cap_h != null_h) + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t\t But the face is a cap" << std::endl; +#endif + edges_to_flip.insert(cap_h); + } + continue; + } + else + { + h = needle_h; + } CGAL_assertion(!is_border(h, tmesh)); const edge_descriptor e = edge(h, tmesh); CGAL_assertion(!get(ecm, edge(h, tmesh))); - - if(get(vcm, source(h, tmesh)) && get(vcm, target(h, tmesh))) - continue; + CGAL_assertion(!get(vcm, source(h, tmesh)) && !get(vcm, target(h, tmesh))); #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << " treat needle: " << e @@ -780,44 +796,49 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, if(CGAL::Euler::does_satisfy_link_condition(e, tmesh)) { - // Verify that the element is still badly shaped - const std::array nc = - internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - needle_threshold, cap_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); - - if(nc[0] != h) - { -#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t Needle criteria no longer verified" << std::endl; -#endif - if (nc[1]!=boost::graph_traits::null_halfedge()) edges_to_flip.insert(nc[1]); - continue; - } - - // pick the orientation of edge to keep the vertex minimizing the volume variation const halfedge_descriptor best_h = internal::get_best_edge_orientation(e, tmesh, vpm, vcm, gt); - if(best_h == boost::graph_traits::null_halfedge()) + if(best_h == null_h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Geometrically invalid edge collapse!" << std::endl; #endif - if (nc[1]!=boost::graph_traits::null_halfedge()) - edges_to_flip.insert(nc[1]); + halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + if(cap_h != null_h) + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t\t But the face is a cap" << std::endl; +#endif + edges_to_flip.insert(cap_h); + } else + { next_edges_to_collapse.insert(h); + } + continue; } - if (!accept_change.collapse(edge(best_h, tmesh))) + if(!accept_change.collapse(edge(best_h, tmesh))) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t edge collapse prevented by the user functor" << std::endl; #endif - if (nc[1]!=boost::graph_traits::null_halfedge()) - edges_to_flip.insert(nc[1]); + halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + if(cap_h != null_h) + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t\t But the face is a cap" << std::endl; +#endif + edges_to_flip.insert(cap_h); + } else + { next_edges_to_collapse.insert(h); + } + continue; } @@ -888,10 +909,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, { if(!is_border(hv, tmesh)) { - internal::collect_badly_shaped_triangles(face(hv, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, - collapse_length_threshold, flip_triangle_height_threshold_squared, - edges_to_collapse, edges_to_flip); + next_edges_to_collapse.insert(hv); // shape will be tested when popped } } @@ -911,24 +929,23 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, std::cout << "\t Uncollapsable edge!" << std::endl; #endif - halfedge_descriptor nc = - internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, flip_triangle_height_threshold_squared); - - if (nc==boost::graph_traits::null_halfedge()) - next_edges_to_collapse.insert(h); - else + halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + if(cap_h != null_h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t Uncollapsable edge --> register it as cap!" << std::endl; + std::cout << "\t\t But the face is a cap" << std::endl; #endif - edges_to_flip.insert(nc); + edges_to_flip.insert(cap_h); + } + else + { + next_edges_to_collapse.insert(h); } } } // Treat caps ================================================================================== - CGAL_assertion(next_edges_to_flip.empty()); #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA kk=0; @@ -938,9 +955,25 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, { halfedge_descriptor h = *edges_to_flip.begin(); edges_to_flip.erase(edges_to_flip.begin()); - + CGAL_assertion(is_valid_halfedge_descriptor(h, tmesh)); CGAL_assertion(!is_border(h, tmesh)); + // check if the face is still a cap + halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + + if(cap_h == null_h) + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t Cap criterion no longer verified" << std::endl; +#endif + continue; + } + else + { + h = cap_h; + } + const edge_descriptor e = edge(h, tmesh); CGAL_assertion(!get(ecm, e)); @@ -950,23 +983,11 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, << " --- " << target(e, tmesh) << " " << tmesh.point(target(h, tmesh)) << ")" << std::endl; #endif - halfedge_descriptor nc = - internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, flip_triangle_height_threshold_squared); - // Check the triangle is still a cap - if(nc != h) - { -#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t Cap criteria no longer verified" << std::endl; -#endif - continue; - } - // special case of `edge(h, tmesh)` being a border edge --> remove the face if(is_border(opposite(h, tmesh), tmesh)) { - // check a non-manifold vertex won't be created - bool removal_is_nm=false; + // check that a non-manifold vertex won't be created + bool removal_is_nm = false; for(halfedge_descriptor hh : CGAL::halfedges_around_target(next(h, tmesh), tmesh)) { if (is_border(hh, tmesh)) @@ -975,11 +996,13 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, break; } } - if (removal_is_nm) continue; + + if(removal_is_nm) + continue; for(halfedge_descriptor hh : CGAL::halfedges_around_face(h, tmesh)) { - // Remove from even 'next_edges_to_flip' because it might have been re-added from a flip + // Remove from 'next_edges_to_flip' because it might have been re-added from a flip edges_to_flip.erase(hh); next_edges_to_flip.erase(hh); next_edges_to_collapse.erase(hh); @@ -1025,16 +1048,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, for(int i=0; i<2; ++i) { CGAL_assertion(!is_border(h, tmesh)); - std::array nc = - internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - needle_threshold, cap_threshold, - collapse_length_threshold, flip_triangle_height_threshold_squared); - - if(nc[1] != boost::graph_traits::null_halfedge() && nc[1] != h) - next_edges_to_flip.insert(nc[1]); - else if(nc[0] != boost::graph_traits::null_halfedge()) - next_edges_to_collapse.insert(nc[0]); - + next_edges_to_collapse.insert(h); h = opposite(h, tmesh); } From eb668da9ea12d29a92a2014bf7b47357b8449a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Sat, 7 Dec 2024 23:34:23 +0100 Subject: [PATCH 08/12] Misc cleaning --- .../Polygon_mesh_processing/repair_degeneracies.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 56d5f93615a7..2371d2e8e6e7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -62,7 +62,9 @@ is_it_a_needle(const typename boost::graph_traits::face_descriptor const double collapse_length_threshold) // max length of edges allowed to be collapsed { namespace PMP = CGAL::Polygon_mesh_processing; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); halfedge_descriptor res = PMP::is_needle_triangle_face(f, tmesh, needle_threshold, @@ -93,7 +95,9 @@ is_it_a_cap(const typename boost::graph_traits::face_descriptor f, const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped { namespace PMP = CGAL::Polygon_mesh_processing; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); halfedge_descriptor res = @@ -110,6 +114,7 @@ is_it_a_cap(const typename boost::graph_traits::face_descriptor f, return null_h; } +// This function tests both needle-ness and cap-ness template std::array::halfedge_descriptor, 2> is_badly_shaped(const typename boost::graph_traits::face_descriptor f, @@ -123,8 +128,8 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto const double collapse_length_threshold, // max length of edges allowed to be collapsed const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped { - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + const halfedge_descriptor null_h = boost::graph_traits::null_halfedge(); std::array retval = make_array(null_h, null_h); @@ -134,6 +139,7 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto return retval; } +// This function tests both needle-ness and cap-ness and fills both ranges template void collect_badly_shaped_triangles(const typename boost::graph_traits::face_descriptor f, @@ -695,6 +701,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, CGAL_precondition(is_valid_polygon_mesh(tmesh)); CGAL_precondition(is_triangle_mesh(tmesh)); + // constrain extremities of constrained edges for(face_descriptor f : face_range) { if(f == boost::graph_traits::null_face()) @@ -899,7 +906,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, else v = Euler::collapse_edge(edge(best_h, tmesh), tmesh); - // moving to the midpoint is not a good idea. On a circle for example you might endpoint with + // moving to the midpoint is not a good idea. On a circle for example you might end with // a bad geometry because you iteratively move one point // auto mp = midpoint(tmesh.point(source(h, tmesh)), tmesh.point(target(h, tmesh))); // tmesh.point(v) = mp; @@ -951,6 +958,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, kk=0; std::ofstream(std::string("tmp/c-000.off")) << tmesh; #endif + while(!edges_to_flip.empty()) { halfedge_descriptor h = *edges_to_flip.begin(); From e9de7e88adc7cd3abb0c43b44eddd21a37833463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Sat, 7 Dec 2024 23:34:58 +0100 Subject: [PATCH 09/12] Fix test pretty much never testing envelope tests + read all formats --- .../test_remove_caps_needles.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp index fa80d93caf0b..548d15e8b012 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp @@ -28,7 +28,7 @@ void general_test(std::string filename) std::ifstream input(filename); Mesh mesh; - if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) { + if (!CGAL::IO::read_polygon_mesh(filename, mesh) || !CGAL::is_triangle_mesh(mesh)) { std::cerr << "Not a valid input file." << std::endl; exit(EXIT_FAILURE); } @@ -56,7 +56,8 @@ void test_with_envelope(std::string filename, double eps) std::ifstream input(filename); Mesh mesh, bk; - if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) { + if (!CGAL::IO::read_polygon_mesh(filename, mesh) || !CGAL::is_triangle_mesh(mesh)) + { std::cerr << "Not a valid input file." << std::endl; exit(EXIT_FAILURE); } @@ -131,7 +132,8 @@ void test_parameters_on_pig(std::string filename) std::ifstream input(filename); Mesh mesh, bk; - if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) { + if (!CGAL::IO::read_polygon_mesh(filename, mesh) || !CGAL::is_triangle_mesh(mesh)) + { std::cerr << "Not a valid input file." << std::endl; exit(EXIT_FAILURE); } @@ -164,13 +166,11 @@ void test_parameters_on_pig(std::string filename) int main(int argc, char** argv) { const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/pig.off"); + double eps = (argc > 2) ? atof(argv[2]) : 0.01; general_test(filename); - if (argc==2) - test_with_envelope(filename, 0.01); - else - if (argc==3) - test_with_envelope(filename, atof(argv[2])); + + test_with_envelope(filename, eps); // only run that test with pig.off if (argc==1) From 116c0ec5d99a8361c123bc5780aabdfa8891ae75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 10 Dec 2024 15:18:24 +0100 Subject: [PATCH 10/12] only use one container for the next loop --> make the output of the function idempotent --- .../Polygon_mesh_processing/repair_degeneracies.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 2371d2e8e6e7..a4bf4e5720a4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -751,7 +751,6 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, return true; std::unordered_set next_edges_to_collapse; - std::unordered_set next_edges_to_flip; // Treat needles =============================================================================== #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA @@ -771,7 +770,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, if(needle_h == null_h) { #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t Needle criterion no longer verified" << std::endl; + std::cout << "\t Needle criterion not verified" << std::endl; #endif halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, cap_threshold, flip_triangle_height_threshold_squared); @@ -1010,9 +1009,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, for(halfedge_descriptor hh : CGAL::halfedges_around_face(h, tmesh)) { - // Remove from 'next_edges_to_flip' because it might have been re-added from a flip edges_to_flip.erase(hh); - next_edges_to_flip.erase(hh); next_edges_to_collapse.erase(hh); } @@ -1033,7 +1030,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Flipping prevented: not the best diagonal" << std::endl; #endif - next_edges_to_flip.insert(h); + next_edges_to_collapse.insert(h); continue; } @@ -1042,7 +1039,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Flipping prevented: rejected by user functor" << std::endl; #endif - next_edges_to_flip.insert(h); + next_edges_to_collapse.insert(h); continue; } @@ -1068,7 +1065,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, std::cout << "\t Unflippable edge!" << std::endl; #endif CGAL_assertion(!is_border(h, tmesh)); - next_edges_to_flip.insert(h); + next_edges_to_collapse.insert(h); } #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA @@ -1085,7 +1082,6 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, return false; std::swap(edges_to_collapse, next_edges_to_collapse); - std::swap(edges_to_flip, next_edges_to_flip); } return false; From c3e4e32fb7368a09782a642a179c67a7ee5505b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 10 Dec 2024 15:37:53 +0100 Subject: [PATCH 11/12] factorize cap checks --- .../repair_degeneracies.h | 73 ++++++------------- 1 file changed, 22 insertions(+), 51 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index a4bf4e5720a4..5e51794a21a0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -757,6 +757,24 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, int kk=0; std::ofstream(std::string("tmp/n-00000.off")) << tmesh; #endif + + auto run_cap_check = [&](halfedge_descriptor h, bool consider_for_collapse=true) + { + halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + if(cap_h != null_h) + { +#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA + std::cout << "\t\t But the face is a cap" << std::endl; +#endif + edges_to_flip.insert(cap_h); + } + else + { + if (consider_for_collapse) next_edges_to_collapse.insert(h); + } + }; + while(!edges_to_collapse.empty()) { // note that on the first iteration, 'h' does not indicate a known needle @@ -772,15 +790,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Needle criterion not verified" << std::endl; #endif - halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, flip_triangle_height_threshold_squared); - if(cap_h != null_h) - { -#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t\t But the face is a cap" << std::endl; -#endif - edges_to_flip.insert(cap_h); - } + run_cap_check(h, false); continue; } else @@ -809,20 +819,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Geometrically invalid edge collapse!" << std::endl; #endif - halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, flip_triangle_height_threshold_squared); - if(cap_h != null_h) - { -#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t\t But the face is a cap" << std::endl; -#endif - edges_to_flip.insert(cap_h); - } - else - { - next_edges_to_collapse.insert(h); - } - + run_cap_check(h); continue; } @@ -831,20 +828,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t edge collapse prevented by the user functor" << std::endl; #endif - halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, flip_triangle_height_threshold_squared); - if(cap_h != null_h) - { -#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t\t But the face is a cap" << std::endl; -#endif - edges_to_flip.insert(cap_h); - } - else - { - next_edges_to_collapse.insert(h); - } - + run_cap_check(h); continue; } @@ -934,20 +918,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA std::cout << "\t Uncollapsable edge!" << std::endl; #endif - - halfedge_descriptor cap_h = internal::is_it_a_cap(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, flip_triangle_height_threshold_squared); - if(cap_h != null_h) - { -#ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES_EXTRA - std::cout << "\t\t But the face is a cap" << std::endl; -#endif - edges_to_flip.insert(cap_h); - } - else - { - next_edges_to_collapse.insert(h); - } + run_cap_check(h); } } From 0737a8f99b3fd9c010cb4a0c5da7d1b5bfaff30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 10 Dec 2024 15:58:53 +0100 Subject: [PATCH 12/12] do not put all the faces of the mesh in the hash map --- .../repair_degeneracies.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 5e51794a21a0..d6ac3595d804 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -725,10 +725,21 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, std::unordered_set edges_to_collapse; std::unordered_set edges_to_flip; - // Needless-ness and cap-ness is verified at pop time, so we might as well just - // fill the set fully, it's equivalent to saying "check everything" + // initial needless-ness and cap-ness checks for(face_descriptor f : face_range) - edges_to_collapse.insert(halfedge(f, tmesh)); + { + halfedge_descriptor needle_h = internal::is_it_a_needle(f, tmesh, vpm, vcm, ecm, gt, + needle_threshold, collapse_length_threshold); + if(needle_h != null_h) + edges_to_collapse.insert(needle_h); + else + { + halfedge_descriptor cap_h = internal::is_it_a_cap(f, tmesh, vpm, vcm, ecm, gt, + cap_threshold, flip_triangle_height_threshold_squared); + if(cap_h != null_h) + edges_to_flip.insert(cap_h); + } + } // Start the process of removing bad elements #ifdef CGAL_PMP_DEBUG_REMOVE_DEGENERACIES