mirror of https://github.com/CGAL/cgal
Merge pull request #6772 from sloriot/PMP-remove_caps_needles_doc
Document remove_almost_degenerate_faces()
This commit is contained in:
commit
d64d243bf5
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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()`
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue