Merge pull request #6772 from sloriot/PMP-remove_caps_needles_doc

Document remove_almost_degenerate_faces()
This commit is contained in:
Sebastien Loriot 2022-08-10 18:31:52 +02:00 committed by GitHub
commit d64d243bf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 268 additions and 140 deletions

View File

@ -15,6 +15,8 @@ Release date: December 2022
- Added the function `CGAL::Polygon_mesh_processing::surface_Delaunay_remeshing()`, that remeshes a surface triangle mesh following the - Added the function `CGAL::Polygon_mesh_processing::surface_Delaunay_remeshing()`, that remeshes a surface triangle mesh following the
CGAL tetrahedral Delaunay refinement algorithm. 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) ### [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. - 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.

View File

@ -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::duplicate_non_manifold_vertices()`
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()` - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()` - `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()`
- `CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces()`
\cgalCRPSection{Connected Components} \cgalCRPSection{Connected Components}
- `CGAL::Polygon_mesh_processing::connected_component()` - `CGAL::Polygon_mesh_processing::connected_component()`

View File

@ -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 `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`, which merge
vertices at identical positions, can be used to repair this configuration. vertices at identical positions, can be used to repair this configuration.
\subsection PMPRemoveCapsNeedles Removal of Almost Degenerate Triangle Faces
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()` enables removing such elements,
with user-defined parameters to qualify what <i>almost</i> 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`).
**************************************** ****************************************
\section PMPNormalComp Computing Normals \section PMPNormalComp Computing Normals

View File

@ -536,15 +536,95 @@ struct Filter_wrapper_for_cap_needle_removal<TriangleMesh, VPM, Traits, Identity
} // namespace internal } // namespace internal
namespace experimental { /// \ingroup PMP_repairing_grp
///
// @todo check what to use as priority queue with removable elements, set might not be optimal /// removes almost degenerate faces in a range of faces from a triangulated surface mesh.
/// Almost degenerated triangle faces are classified as caps or needles: a triangle is said to be a <i>needle</i>
/// if its longest edge is much longer than its shortest edge. A triangle is said to be a <i>cap</i> 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).
///
/// @pre `CGAL::is_triangle_mesh(tmesh)`
///
/// @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph`
/// @tparam FaceRange a model of `ConstRange` with `boost::graph_traits<TriangleMesh>::%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 `tmesh` are 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{double}
/// \cgalParamDefault{the cosinus corresponding to an angle of 160 degrees}
/// \cgalParamNEnd
/// \cgalParamNBegin{needle_threshold}
/// \cgalParamDescription{a bound on the ratio of the lengths of the longest edge and the shortest edge, such that a face having a ratio
/// larger than the threshold is a needle.}
/// \cgalParamType{double}
/// \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{double}
/// \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 (whose base is the edge to be flipped)
/// is longer than the threshold given.}
/// \cgalParamType{double}
/// \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<TriangleMesh>::%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 `ReadablePropertyMap` with `boost::graph_traits<PolygonMesh>::%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 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 `ReadablePropertyMap` with `boost::graph_traits<PolygonMesh>::%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 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
///
/// \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 <typename FaceRange, typename TriangleMesh, typename NamedParameters = parameters::Default_named_parameters> template <typename FaceRange, typename TriangleMesh, typename NamedParameters = parameters::Default_named_parameters>
bool remove_almost_degenerate_faces(const FaceRange& face_range, bool remove_almost_degenerate_faces(const FaceRange& face_range,
TriangleMesh& tmesh, TriangleMesh& tmesh,
const double cap_threshold,
const double needle_threshold,
const double collapse_length_threshold,
const NamedParameters& np = parameters::default_values()) const NamedParameters& np = parameters::default_values())
{ {
using CGAL::parameters::choose_parameter; using CGAL::parameters::choose_parameter;
@ -589,6 +669,13 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
typedef typename boost::property_map<TriangleMesh, Vertex_property_tag>::type DVCM; typedef typename boost::property_map<TriangleMesh, Vertex_property_tag>::type DVCM;
DVCM vcm = get(Vertex_property_tag(), tmesh); DVCM vcm = get(Vertex_property_tag(), tmesh);
// parameters
const double cap_threshold =
choose_parameter(get_parameter(np, internal_np::cap_threshold), -0.939692621); // cos(160)
const double needle_threshold =
choose_parameter(get_parameter(np, internal_np::needle_threshold), 4.);
const double collapse_length_threshold =
choose_parameter(get_parameter(np, internal_np::collapse_length_threshold), 0.);
const double flip_triangle_height_threshold_squared = const double flip_triangle_height_threshold_squared =
CGAL::square(choose_parameter(get_parameter(np, internal_np::flip_triangle_height_threshold), 0)); CGAL::square(choose_parameter(get_parameter(np, internal_np::flip_triangle_height_threshold), 0));
@ -936,18 +1023,16 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range,
return false; 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 <typename TriangleMesh, typename CGAL_NP_TEMPLATE_PARAMETERS> template <typename TriangleMesh, typename CGAL_NP_TEMPLATE_PARAMETERS>
bool remove_almost_degenerate_faces(TriangleMesh& tmesh, 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()) const CGAL_NP_CLASS& np = parameters::default_values())
{ {
return remove_almost_degenerate_faces(faces(tmesh), tmesh, cap_threshold, needle_threshold, return remove_almost_degenerate_faces(faces(tmesh), tmesh, np);
collapse_length_threshold, np);
} }
} // namespace experimental
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -388,6 +388,7 @@ struct Is_edge_length_ratio_over_threshold<K, true>
/// If the face contains degenerate edges, a halfedge corresponding to one of these edges is returned. /// If the face contains degenerate edges, a halfedge corresponding to one of these edges is returned.
/// ///
/// \sa `is_cap_triangle_face()` /// \sa `is_cap_triangle_face()`
/// \sa `remove_almost_degenerate_faces()`
template <typename TriangleMesh, typename NamedParameters = parameters::Default_named_parameters> template <typename TriangleMesh, typename NamedParameters = parameters::Default_named_parameters>
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
is_needle_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f, is_needle_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,
@ -536,6 +537,7 @@ struct Is_cap_angle_over_threshold<K, true>
/// \return the halfedge opposite of the largest angle if the face is a cap, and a null halfedge otherwise. /// \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 `is_needle_triangle_face()`
/// \sa `remove_almost_degenerate_faces()`
template <typename TriangleMesh, typename NamedParameters = parameters::Default_named_parameters> template <typename TriangleMesh, typename NamedParameters = parameters::Default_named_parameters>
typename boost::graph_traits<TriangleMesh>::halfedge_descriptor typename boost::graph_traits<TriangleMesh>::halfedge_descriptor
is_cap_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f, is_cap_triangle_face(typename boost::graph_traits<TriangleMesh>::face_descriptor f,

View File

@ -18,6 +18,7 @@ typedef boost::graph_traits<Mesh>::edge_descriptor edge_descriptor;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor; typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
namespace PMP = CGAL::Polygon_mesh_processing; namespace PMP = CGAL::Polygon_mesh_processing;
namespace params = CGAL::parameters;
typedef CGAL::Polyhedral_envelope<K> Envelope; typedef CGAL::Polyhedral_envelope<K> Envelope;
@ -36,10 +37,10 @@ void general_test(std::string filename)
if (PMP::does_self_intersect(mesh)) if (PMP::does_self_intersect(mesh))
std::cout << " Input mesh has self-intersections\n"; std::cout << " Input mesh has self-intersections\n";
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4)
0.14); .collapse_length_threshold(0.14));
CGAL::IO::write_polygon_mesh("cleaned_mesh.off", mesh, CGAL::parameters::stream_precision(17)); 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; No_modification_allowed no_modif;
const std::size_t nbv = vertices(mesh).size(); const std::size_t nbv = vertices(mesh).size();
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4)
0.14, .collapse_length_threshold(0.14)
CGAL::parameters::filter(no_modif)); .filter(no_modif));
assert(nbv == vertices(mesh).size()); assert(nbv == vertices(mesh).size());
// now the real test with a fixed envelope // 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"; std::cout << " Input mesh has " << edges(mesh).size() << " edges\n";
bk=mesh; bk=mesh;
Envelope envelope(mesh, eps); Envelope envelope(mesh, eps);
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4)
0.14, .collapse_length_threshold(0.14)
CGAL::parameters::filter(std::ref(envelope))); .filter(std::ref(envelope)));
CGAL::IO::write_polygon_mesh("cleaned_mesh_with_envelope.off", mesh, CGAL::parameters::stream_precision(17)); 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); return Envelope(frange, mesh, eps);
}; };
std::function<Envelope(const std::vector<Mesh::Face_index>&)> filter(create_envelope); std::function<Envelope(const std::vector<Mesh::Face_index>&)> filter(create_envelope);
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4)
0.14, .collapse_length_threshold(0.14)
CGAL::parameters::filter(filter)); .filter(filter));
CGAL::IO::write_polygon_mesh("cleaned_mesh_with_iterative_envelope.off", mesh, CGAL::parameters::stream_precision(17)); 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; bk=mesh;
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4));
9999 /*no_constraints*/);
assert(vertices(mesh).size()!=vertices(bk).size()); assert(vertices(mesh).size()!=vertices(bk).size());
mesh=bk; mesh=bk;
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4)
0.000000000000001); // no-collapse but flips .collapse_length_threshold(0.000000000000001)); // no-collapse but flips
assert(vertices(mesh).size()==vertices(bk).size()); assert(vertices(mesh).size()==vertices(bk).size());
assert(!same_meshes(mesh,bk)); assert(!same_meshes(mesh,bk));
mesh=bk; mesh=bk;
PMP::experimental::remove_almost_degenerate_faces(mesh, PMP::remove_almost_degenerate_faces(mesh,
std::cos(160. / 180 * CGAL_PI), params::cap_threshold(std::cos(160. / 180 * CGAL_PI))
4, .needle_threshold(4)
0.000000000000001, .collapse_length_threshold(0.000000000000001)
CGAL::parameters::flip_triangle_height_threshold(0.000000000000001)); // no-collapse and no flip .flip_triangle_height_threshold(0.000000000000001)); // no-collapse and no flip
assert(vertices(mesh).size()==vertices(bk).size()); assert(vertices(mesh).size()==vertices(bk).size());
assert(same_meshes(mesh,bk)); assert(same_meshes(mesh,bk));
} }

View File

@ -6,113 +6,138 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>607</width> <width>744</width>
<height>368</height> <height>373</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Remove Needles and Cap</string> <string>Remove Needles and Cap</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout"> <widget class="QGroupBox" name="Box1">
<item> <property name="toolTip">
<widget class="QGroupBox" name="Box1"> <string>Threshold in degrees</string>
<property name="toolTip"> </property>
<string>Threshold in degrees</string> <property name="title">
</property> <string>Cap threshold (max. angle in degrees allowed within a triangle): </string>
<property name="title"> </property>
<string>Cap threshold (max. angle allowed within a triangle): </string> <layout class="QHBoxLayout" name="horizontalLayout">
</property> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_3"> <widget class="QDoubleSpinBox" name="capBox">
<item> <property name="toolTip">
<widget class="QDoubleSpinBox" name="capBox"> <string>Angle in degrees</string>
<property name="toolTip"> </property>
<string>Angle in degrees</string> <property name="suffix">
</property> <string/>
<property name="suffix"> </property>
<string/> <property name="decimals">
</property> <number>2</number>
<property name="decimals"> </property>
<number>2</number> <property name="maximum">
</property> <double>360.000000000000000</double>
<property name="maximum"> </property>
<double>360.000000000000000</double> <property name="value">
</property> <double>160.000000000000000</double>
<property name="value"> </property>
<double>160.000000000000000</double> </widget>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </item>
</item> </layout>
<item> </widget>
<widget class="QGroupBox" name="Box2"> </item>
<property name="toolTip"> <item>
<string>(size+big edge )/(size+small edge)</string> <widget class="QGroupBox" name="Box2">
</property> <property name="toolTip">
<property name="title"> <string>(size+big edge )/(size+small edge)</string>
<string>Needle threshold (max. edge length ratio (longest/shortest) allowed within a triangle):</string> </property>
</property> <property name="title">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <string>Needle threshold (max. edge length ratio (longest/shortest) allowed within a triangle):</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_4"> <widget class="QDoubleSpinBox" name="needleBox">
<item> <property name="toolTip">
<widget class="QDoubleSpinBox" name="needleBox"> <string>Length Ratio</string>
<property name="toolTip"> </property>
<string>Length Ratio</string> <property name="decimals">
</property> <number>2</number>
<property name="decimals"> </property>
<number>2</number> <property name="maximum">
</property> <double>1000.000000000000000</double>
<property name="maximum"> </property>
<double>1000.000000000000000</double> <property name="value">
</property> <double>4.000000000000000</double>
<property name="value"> </property>
<double>4.000000000000000</double> </widget>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </item>
</item> </layout>
<item> </widget>
<widget class="QGroupBox" name="Box3"> </item>
<property name="toolTip"> <item>
<string>Do not collapse edges begger than this threshold.</string> <widget class="QGroupBox" name="Box3">
</property> <property name="toolTip">
<property name="title"> <string>Do not collapse edges begger than this threshold.</string>
<string>Do not collapse needles (according to the criterion above) whose shortest edge has a length greater than:</string> </property>
</property> <property name="title">
<layout class="QHBoxLayout" name="horizontalLayout_3"> <string>Do not collapse needle edge larger than:</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_5"> <widget class="QDoubleSpinBox" name="collapseBox">
<item> <property name="toolTip">
<widget class="QDoubleSpinBox" name="collapseBox"> <string>Length</string>
<property name="toolTip"> </property>
<string>Length</string> <property name="decimals">
</property> <number>25</number>
<property name="decimals"> </property>
<number>25</number> <property name="maximum">
</property> <double>99999999.000000000000000</double>
<property name="maximum"> </property>
<double>99999999.000000000000000</double> </widget>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </item>
</item> </layout>
</layout> </widget>
</item>
<item>
<widget class="QGroupBox" name="Box4">
<property name="toolTip">
<string>Do not collapse edges begger than this threshold.</string>
</property>
<property name="title">
<string>Do not flip cap edge (according to the criterion above) if height is greater than:</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QDoubleSpinBox" name="flipBox">
<property name="toolTip">
<string>Length</string>
</property>
<property name="decimals">
<number>25</number>
</property>
<property name="maximum">
<double>99999999.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item> </item>
<item> <item>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">

View File

@ -195,10 +195,11 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveNeedlesAndCaps_tri
ui.collapseBox->setValue(sm_item->diagonalBbox()*0.01); ui.collapseBox->setValue(sm_item->diagonalBbox()*0.01);
if(dialog.exec() != QDialog::Accepted) if(dialog.exec() != QDialog::Accepted)
return; return;
CGAL::Polygon_mesh_processing::experimental::remove_almost_degenerate_faces(*sm_item->face_graph(), CGAL::Polygon_mesh_processing::remove_almost_degenerate_faces(*sm_item->face_graph(),
std::cos((ui.capBox->value()/180.0) * CGAL_PI), CGAL::parameters::cap_threshold(std::cos((ui.capBox->value()/180.0) * CGAL_PI))
ui.needleBox->value(), .needle_threshold(ui.needleBox->value())
ui.collapseBox->value()); .collapse_length_threshold(ui.collapseBox->value())
.flip_triangle_height_threshold(ui.flipBox->value()));
sm_item->invalidateOpenGLBuffers(); sm_item->invalidateOpenGLBuffers();
sm_item->itemChanged(); sm_item->itemChanged();
} }

View File

@ -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(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(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(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(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(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_edge_size_t, mesh_edge_size, mesh_edge_size)
CGAL_add_named_parameter(mesh_facet_size_t, mesh_facet_size, mesh_facet_size) CGAL_add_named_parameter(mesh_facet_size_t, mesh_facet_size, mesh_facet_size)