From b1ee7ba78ecdd906df0697e0db586a2205991c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 26 Jul 2022 15:06:15 +0200 Subject: [PATCH 1/7] move outside experimental namespace with a better API and doc --- .../PackageDescription.txt | 1 + .../repair_degeneracies.h | 110 +++++++-- .../test_remove_caps_needles.cpp | 64 +++--- .../Plugins/PMP/RemoveNeedlesDialog.ui | 209 ++++++++++-------- .../Plugins/PMP/Repair_polyhedron_plugin.cpp | 9 +- .../internal/parameters_interface.h | 3 + 6 files changed, 255 insertions(+), 141 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 34d2f83f08e..1699ca2a0f9 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -179,6 +179,7 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. - `CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices()` - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()` +- `CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()` \cgalCRPSection{Connected Components} - `CGAL::Polygon_mesh_processing::connected_component()` 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 08ebeb50828..8bbbf3a275c 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 @@ -536,15 +536,94 @@ struct Filter_wrapper_for_cap_needle_removal::%face_descriptor` as value type +/// @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" +/// +/// @param face_range the initial range of faces to be considered to look for badly shaped triangles. +/// Note that modifications of the `tmesh` is not limited to faces in `face_range` +/// and neighbor faces might also be impacted. +/// @param tmesh the triangulated surface mesh to be modified +/// @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below +/// +/// \cgalNamedParamsBegin +/// \cgalParamNBegin{cap_threshold} +/// \cgalParamDescription{the cosine of a minimum angle such that if a face has an angle greater than this bound, +/// it is a cap. The threshold is in range `[-1 0]` and corresponds to an angle between `90` and `180` degrees.} +/// \cgalParamType{`geom_traits::FT`} +/// \cgalParamDefault{the cosinus corresponding to an angle of 160 degrees} +/// \cgalParamNEnd +/// \cgalParamNBegin{needle_threshold} +/// \cgalParamDescription{a bound on the ratio of the longest edge length and the shortest edge length such that a face having a ratio} +/// \cgalParamType{`geom_traits::FT`} +/// \cgalParamDefault{4} +/// \cgalParamNEnd +/// \cgalParamNBegin{collapse_length_threshold} +/// \cgalParamDescription{if different from 0, an edge collapsed will be prevented if the edge is longer than the threshold given.} +/// \cgalParamType{`geom_traits::FT`} +/// \cgalParamDefault{0} +/// \cgalParamNEnd +/// \cgalParamNBegin{flip_triangle_height_threshold} +/// \cgalParamDescription{if different from 0, an edge flip will be prevented if the height of the triangle (with base being the edge to be flipped) +/// is longer than the threshold given.} +/// \cgalParamType{`geom_traits::FT`} +/// \cgalParamDefault{0} +/// \cgalParamNEnd +/// \cgalParamNBegin{vertex_point_map} +/// \cgalParamDescription{a property map associating points to the vertices of `tmesh`.} +/// \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` +/// as key type and `%Point_3` as value type} +/// \cgalParamDefault{`boost::get(CGAL::vertex_point, tmesh)`.} +/// \cgalParamNEnd +/// \cgalParamNBegin{geom_traits} +/// \cgalParamDescription{an instance of a geometric traits class.} +/// \cgalParamType{A model of `Kernel`.} +/// \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`.} +/// \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.} +/// \cgalParamNEnd +/// \cgalParamNBegin{edge_is_constrained_map} +/// \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `tmesh`.} +/// \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits::%edge_descriptor` +/// as key type and `bool` as value type.} +/// \cgalParamDefault{a default property map where no edge is constrained.} +/// \cgalParamExtra{A constrained edge can not be collapsed or flipped.} +/// \cgalParamNEnd +/// \cgalParamNBegin{vertex_is_constrained_map} +/// \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.} +/// \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits::%vertex_descriptor` +/// as key type and `bool` as value type.} +/// \cgalParamDefault{a default property map where no vertex is constrained.} +/// \cgalParamExtra{A constrained vertex is guaranteed to be present in `tmesh` after the function call.} +/// \cgalParamNEnd +/// \cgalParamNBegin{filter} +/// \cgalParamDescription{A function object providing `bool operator()('geom_traits::Point_3,geom_traits::Point_3,geom_traits::Point_3)`.} +/// \cgalParamType{The function object is queried each time a new triangle is created by passing the three points and the flip or collapsed +/// responsible for the creation of that triangle is rejected if `false` is returned.} +/// \cgalParamDefault{a functor always returning `true`.} +/// \cgalParamNEnd +/// \cgalNamedParamsEnd +/// +/// \return `true` if no almost degenerate face could not be removed (due to topological constraints), and `false` otherwise. +/// +/// \sa `is_needle_triangle_face()` +/// \sa `is_cap_triangle_face()` +/// +/// @todo check what to use as priority queue with removable elements, set might not be optimal +/// template bool remove_almost_degenerate_faces(const FaceRange& face_range, TriangleMesh& tmesh, - const double cap_threshold, - const double needle_threshold, - const double collapse_length_threshold, const NamedParameters& np = parameters::default_values()) { using CGAL::parameters::choose_parameter; @@ -589,7 +668,14 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, typedef typename boost::property_map::type DVCM; DVCM vcm = get(Vertex_property_tag(), tmesh); - const double flip_triangle_height_threshold_squared = + // parameters + const typename Traits::FT cap_threshold = + choose_parameter(get_parameter(np, internal_np::cap_threshold), -0.939692621); // cos(160) + const typename Traits::FT needle_threshold = + choose_parameter(get_parameter(np, internal_np::cap_threshold), 4.); + const typename Traits::FT collapse_length_threshold = + choose_parameter(get_parameter(np, internal_np::collapse_length_threshold), 0.); + const typename Traits::FT flip_triangle_height_threshold_squared = CGAL::square(choose_parameter(get_parameter(np, internal_np::flip_triangle_height_threshold), 0)); CGAL_precondition(is_valid_polygon_mesh(tmesh)); @@ -936,18 +1022,16 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, return false; } +/// \ingroup PMP_repairing_grp +/// removes all almost degenerate faces from a triangulated surface mesh. +/// Equivalent to `remove_almost_degenerate_faces(faces(tmesh), tmesh, np)` template bool remove_almost_degenerate_faces(TriangleMesh& tmesh, - const double cap_threshold, - const double needle_threshold, - const double collapse_length_threshold, const CGAL_NP_CLASS& np = parameters::default_values()) { - return remove_almost_degenerate_faces(faces(tmesh), tmesh, cap_threshold, needle_threshold, - collapse_length_threshold, np); + return remove_almost_degenerate_faces(faces(tmesh), tmesh, np); } -} // namespace experimental //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// 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 b57a3dc8e8d..fa80d93caf0 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 @@ -18,6 +18,7 @@ typedef boost::graph_traits::edge_descriptor edge_descriptor; typedef boost::graph_traits::face_descriptor face_descriptor; namespace PMP = CGAL::Polygon_mesh_processing; +namespace params = CGAL::parameters; typedef CGAL::Polyhedral_envelope Envelope; @@ -36,10 +37,10 @@ void general_test(std::string filename) if (PMP::does_self_intersect(mesh)) std::cout << " Input mesh has self-intersections\n"; - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 0.14); + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4) + .collapse_length_threshold(0.14)); CGAL::IO::write_polygon_mesh("cleaned_mesh.off", mesh, CGAL::parameters::stream_precision(17)); @@ -70,11 +71,11 @@ void test_with_envelope(std::string filename, double eps) }; No_modification_allowed no_modif; const std::size_t nbv = vertices(mesh).size(); - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 0.14, - CGAL::parameters::filter(no_modif)); + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4) + .collapse_length_threshold(0.14) + .filter(no_modif)); assert(nbv == vertices(mesh).size()); // now the real test with a fixed envelope @@ -82,11 +83,11 @@ void test_with_envelope(std::string filename, double eps) std::cout << " Input mesh has " << edges(mesh).size() << " edges\n"; bk=mesh; Envelope envelope(mesh, eps); - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 0.14, - CGAL::parameters::filter(std::ref(envelope))); + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4) + .collapse_length_threshold(0.14) + .filter(std::ref(envelope))); CGAL::IO::write_polygon_mesh("cleaned_mesh_with_envelope.off", mesh, CGAL::parameters::stream_precision(17)); @@ -104,11 +105,11 @@ void test_with_envelope(std::string filename, double eps) return Envelope(frange, mesh, eps); }; std::function&)> filter(create_envelope); - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 0.14, - CGAL::parameters::filter(filter)); + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4) + .collapse_length_threshold(0.14) + .filter(filter)); CGAL::IO::write_polygon_mesh("cleaned_mesh_with_iterative_envelope.off", mesh, CGAL::parameters::stream_precision(17)); @@ -137,26 +138,25 @@ void test_parameters_on_pig(std::string filename) bk=mesh; - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 9999 /*no_constraints*/); + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4)); assert(vertices(mesh).size()!=vertices(bk).size()); mesh=bk; - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 0.000000000000001); // no-collapse but flips + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4) + .collapse_length_threshold(0.000000000000001)); // no-collapse but flips assert(vertices(mesh).size()==vertices(bk).size()); assert(!same_meshes(mesh,bk)); mesh=bk; - PMP::experimental::remove_almost_degenerate_faces(mesh, - std::cos(160. / 180 * CGAL_PI), - 4, - 0.000000000000001, - CGAL::parameters::flip_triangle_height_threshold(0.000000000000001)); // no-collapse and no flip + PMP::remove_almost_degenerate_faces(mesh, + params::cap_threshold(std::cos(160. / 180 * CGAL_PI)) + .needle_threshold(4) + .collapse_length_threshold(0.000000000000001) + .flip_triangle_height_threshold(0.000000000000001)); // no-collapse and no flip assert(vertices(mesh).size()==vertices(bk).size()); assert(same_meshes(mesh,bk)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/RemoveNeedlesDialog.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/RemoveNeedlesDialog.ui index dd151b44f18..2718e2e1180 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/RemoveNeedlesDialog.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/RemoveNeedlesDialog.ui @@ -6,113 +6,138 @@ 0 0 - 607 - 368 + 744 + 373 Remove Needles and Cap - + - - - - - Threshold in degrees - - - Cap threshold (max. angle allowed within a triangle): - - + + + Threshold in degrees + + + Cap threshold (max. angle in degrees allowed within a triangle): + + + + - - - - - Angle in degrees - - - - - - 2 - - - 360.000000000000000 - - - 160.000000000000000 - - - - + + + Angle in degrees + + + + + + 2 + + + 360.000000000000000 + + + 160.000000000000000 + + - - - - - - (size+big edge )/(size+small edge) - - - Needle threshold (max. edge length ratio (longest/shortest) allowed within a triangle): - - + + + + + + + + (size+big edge )/(size+small edge) + + + Needle threshold (max. edge length ratio (longest/shortest) allowed within a triangle): + + + + - - - - - Length Ratio - - - 2 - - - 1000.000000000000000 - - - 4.000000000000000 - - - - + + + Length Ratio + + + 2 + + + 1000.000000000000000 + + + 4.000000000000000 + + - - - - - - Do not collapse edges begger than this threshold. - - - Do not collapse needles (according to the criterion above) whose shortest edge has a length greater than: - - + + + + + + + + Do not collapse edges begger than this threshold. + + + Do not collapse needle edge larger than: + + + + - - - - - Length - - - 25 - - - 99999999.000000000000000 - - - - + + + Length + + + 25 + + + 99999999.000000000000000 + + - - - + + + + + + + + Do not collapse edges begger than this threshold. + + + Do not flip cap edge (according to the criterion above) if height is greater than: + + + + + + + + Length + + + 25 + + + 99999999.000000000000000 + + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp index 52510d174e9..a806f73e76f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp @@ -195,10 +195,11 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveNeedlesAndCaps_tri ui.collapseBox->setValue(sm_item->diagonalBbox()*0.01); if(dialog.exec() != QDialog::Accepted) return; - CGAL::Polygon_mesh_processing::experimental::remove_almost_degenerate_faces(*sm_item->face_graph(), - std::cos((ui.capBox->value()/180.0) * CGAL_PI), - ui.needleBox->value(), - ui.collapseBox->value()); + CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces(*sm_item->face_graph(), + CGAL::parameters::cap_threshold(std::cos((ui.capBox->value()/180.0) * CGAL_PI)) + .needle_threshold(ui.needleBox->value()) + .collapse_length_threshold(ui.collapseBox->value()) + .flip_triangle_height_threshold(ui.flipBox->value())); sm_item->invalidateOpenGLBuffers(); sm_item->itemChanged(); } diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index f798666ab28..6e25c8d438a 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -132,7 +132,10 @@ CGAL_add_named_parameter(match_faces_t, match_faces, match_faces) CGAL_add_named_parameter(face_epsilon_map_t, face_epsilon_map, face_epsilon_map) CGAL_add_named_parameter(maximum_number_t, maximum_number, maximum_number) CGAL_add_named_parameter(use_one_sided_hausdorff_t, use_one_sided_hausdorff, use_one_sided_hausdorff) +CGAL_add_named_parameter(cap_threshold_t, cap_threshold, cap_threshold) +CGAL_add_named_parameter(needle_threshold_t, needle_threshold, needle_threshold) CGAL_add_named_parameter(flip_triangle_height_threshold_t, flip_triangle_height_threshold, flip_triangle_height_threshold) +CGAL_add_named_parameter(collapse_length_threshold_t, collapse_length_threshold, collapse_length_threshold) CGAL_add_named_parameter(features_angle_bound_t, features_angle_bound, features_angle_bound) CGAL_add_named_parameter(mesh_edge_size_t, mesh_edge_size, mesh_edge_size) CGAL_add_named_parameter(mesh_facet_size_t, mesh_facet_size, mesh_facet_size) From a1c03cdbb83a47eaabe7683ee259e85177f43fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 26 Jul 2022 15:11:40 +0200 Subject: [PATCH 2/7] update CHANGES --- Installation/CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index a8ca834b0f8..85046d0c646 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -11,6 +11,8 @@ Release date: December 2022 - Added the function `CGAL::Polygon_mesh_processing::surface_Delaunay_remeshing()`, that remeshes a surface triangle mesh following the CGAL tetrahedral Delaunay refinement algorithm. +- Added the function `CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()` to remove badly shaped triangles faces in a mesh. + ### [3D Simplicial Mesh Data Structure](https://doc.cgal.org/5.6/Manual/packages.html#PkgSMDS3) (new package) - This new package wraps all the existing code that deals with a `MeshComplex_3InTriangulation_3` to describe 3D simplicial meshess, and makes the data structure independent from the tetrahedral mesh generation package. From f7358a0a0d3a188fda644e9216b2f80572549516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 26 Jul 2022 15:34:21 +0200 Subject: [PATCH 3/7] fix typos in doc --- .../CGAL/Polygon_mesh_processing/repair_degeneracies.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 8bbbf3a275c..c04762b61f2 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 @@ -548,7 +548,7 @@ struct Filter_wrapper_for_cap_needle_removal::%face_descriptor` as value type +/// @tparam `FaceRange` a model of `ConstRange` with `boost::graph_traits::%face_descriptor` as value type /// @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" /// /// @param face_range the initial range of faces to be considered to look for badly shaped triangles. @@ -607,9 +607,9 @@ struct Filter_wrapper_for_cap_needle_removal Date: Tue, 26 Jul 2022 15:48:12 +0200 Subject: [PATCH 4/7] more doc fixes --- .../CGAL/Polygon_mesh_processing/repair_degeneracies.h | 5 +++-- 1 file changed, 3 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 c04762b61f2..b9a7d231023 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 @@ -565,7 +565,8 @@ struct Filter_wrapper_for_cap_needle_removal Date: Tue, 26 Jul 2022 15:55:52 +0200 Subject: [PATCH 5/7] fix copy/paste error and use double for parameters to be compatible with predicates --- .../repair_degeneracies.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 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 b9a7d231023..2456380e7f8 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 @@ -561,24 +561,24 @@ struct Filter_wrapper_for_cap_needle_removal Date: Tue, 26 Jul 2022 16:42:24 +0200 Subject: [PATCH 6/7] improve doc --- .../Polygon_mesh_processing/Polygon_mesh_processing.txt | 9 +++++++++ .../CGAL/Polygon_mesh_processing/repair_degeneracies.h | 6 +++--- .../CGAL/Polygon_mesh_processing/shape_predicates.h | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 743d6bc3507..04016d0f25d 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -835,6 +835,15 @@ more than once (although, with different vertices) before reaching the initial b `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`, which merge vertices at identical positions, can be used to repair this configuration. +\subsection PMPRemoveCapsNeedles Removal of Almost Degenerate Triangle Faces +Triangle faces of a mesh defined by almost collinear points are badly shaped elements that +might not be desirable to have in a mesh. The function +`CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()` allows to remove such elements +using user parameters to quality what almost means (`cap_threshold` and `needle_threshold`). +As some badly shaped elements are inevitable (triangulation of a long cylinder +with only vertices on the top and bottom circles for example), extra parameters can be passed +to prevent the removal of such elements (`collapse_length_threshold` and `flip_triangle_height_threshold`). + **************************************** \section PMPNormalComp Computing Normals 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 2456380e7f8..ef146fb3ea7 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 @@ -539,8 +539,8 @@ struct Filter_wrapper_for_cap_needle_removalneedle +/// if its longest edge is much longer than its shortest edge. A triangle is said to be a cap if one of /// its angles is close to `180` degrees. Needles are removed by collapsing their shortest edges, while caps are /// removed by flipping the edge opposite to the largest angle (with the exception of caps on the boundary that are /// simply removed from the mesh). @@ -548,7 +548,7 @@ struct Filter_wrapper_for_cap_needle_removal::%face_descriptor` as value type +/// @tparam FaceRange a model of `ConstRange` with `boost::graph_traits::%face_descriptor` as value type /// @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" /// /// @param face_range the initial range of faces to be considered to look for badly shaped triangles. diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h index 3eb3fa892e6..63813d2186a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h @@ -388,6 +388,7 @@ struct Is_edge_length_ratio_over_threshold /// If the face contains degenerate edges, a halfedge corresponding to one of these edges is returned. /// /// \sa `is_cap_triangle_face()` +/// \sa `remove_almost_degenerate_faces()` template typename boost::graph_traits::halfedge_descriptor is_needle_triangle_face(typename boost::graph_traits::face_descriptor f, @@ -536,6 +537,7 @@ struct Is_cap_angle_over_threshold /// \return the halfedge opposite of the largest angle if the face is a cap, and a null halfedge otherwise. /// /// \sa `is_needle_triangle_face()` +/// \sa `remove_almost_degenerate_faces()` template typename boost::graph_traits::halfedge_descriptor is_cap_triangle_face(typename boost::graph_traits::face_descriptor f, From beb57433c4ea2b6933b88e786912394190f2d89f Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Thu, 4 Aug 2022 10:30:02 +0200 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: Mael --- .../Polygon_mesh_processing.txt | 8 ++++---- .../Polygon_mesh_processing/repair_degeneracies.h | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 04016d0f25d..08e11df647d 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -836,11 +836,11 @@ more than once (although, with different vertices) before reaching the initial b vertices at identical positions, can be used to repair this configuration. \subsection PMPRemoveCapsNeedles Removal of Almost Degenerate Triangle Faces -Triangle faces of a mesh defined by almost collinear points are badly shaped elements that +Triangle faces of a mesh made up of almost collinear points are badly shaped elements that might not be desirable to have in a mesh. The function -`CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()` allows to remove such elements -using user parameters to quality what almost means (`cap_threshold` and `needle_threshold`). -As some badly shaped elements are inevitable (triangulation of a long cylinder +`CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()` enables removing such elements, +with user-defined parameters to qualify what almost means (`cap_threshold` and `needle_threshold`). +As some badly shaped elements are inevitable (the triangulation of a long cylinder with only vertices on the top and bottom circles for example), extra parameters can be passed to prevent the removal of such elements (`collapse_length_threshold` and `flip_triangle_height_threshold`). 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 ef146fb3ea7..fbe30e7e26f 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 @@ -552,7 +552,7 @@ struct Filter_wrapper_for_cap_needle_removal::%edge_descriptor` +/// \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` /// as key type and `bool` as value type.} /// \cgalParamDefault{a default property map where no edge is constrained.} -/// \cgalParamExtra{A constrained edge can not be collapsed or flipped.} +/// \cgalParamExtra{A constrained edge can not be collapsed nor flipped.} /// \cgalParamNEnd /// \cgalParamNBegin{vertex_is_constrained_map} /// \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.} -/// \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits::%vertex_descriptor` +/// \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` /// as key type and `bool` as value type.} /// \cgalParamDefault{a default property map where no vertex is constrained.} /// \cgalParamExtra{A constrained vertex is guaranteed to be present in `tmesh` after the function call.} /// \cgalParamNEnd /// \cgalParamNBegin{filter} /// \cgalParamDescription{A function object providing `bool operator()(geom_traits::Point_3,geom_traits::Point_3,geom_traits::Point_3)`.} -/// \cgalParamType{The function object is queried each time a new triangle is created by passing the three points of the triangle. -/// The flip or collapse responsible for the creation of that triangle is rejected if `false` is returned.} +/// \cgalParamType{The function object is queried each time a new triangle is about to be created by a flip or a collapse operation. +/// If `false` is returned, the operation is cancelled.} /// \cgalParamDefault{a functor always returning `true`.} /// \cgalParamNEnd /// \cgalNamedParamsEnd