14#include <lagrange/mesh_cleanup/close_small_holes.h>
15#include <lagrange/mesh_cleanup/detect_degenerate_facets.h>
16#include <lagrange/mesh_cleanup/remove_degenerate_facets.h>
17#include <lagrange/mesh_cleanup/remove_duplicate_facets.h>
18#include <lagrange/mesh_cleanup/remove_duplicate_vertices.h>
19#include <lagrange/mesh_cleanup/remove_isolated_vertices.h>
20#include <lagrange/mesh_cleanup/remove_null_area_facets.h>
21#include <lagrange/mesh_cleanup/remove_short_edges.h>
22#include <lagrange/mesh_cleanup/remove_topologically_degenerate_facets.h>
23#include <lagrange/mesh_cleanup/rescale_uv_charts.h>
24#include <lagrange/mesh_cleanup/resolve_nonmanifoldness.h>
25#include <lagrange/mesh_cleanup/resolve_vertex_nonmanifoldness.h>
26#include <lagrange/mesh_cleanup/split_long_edges.h>
29#include <lagrange/utils/warnoff.h>
30#include <nanobind/nanobind.h>
31#include <nanobind/stl/optional.h>
32#include <nanobind/stl/vector.h>
33#include <lagrange/utils/warnon.h>
38namespace lagrange::python {
40template <
typename Scalar,
typename Index>
41void bind_mesh_cleanup(nanobind::module_& m)
43 namespace nb = nanobind;
44 using namespace nb::literals;
48 "remove_isolated_vertices",
49 &remove_isolated_vertices<Scalar, Index>,
51 R
"(Remove isolated vertices from a mesh.
54 A vertex is considered isolated if it is not referenced by any facet.
56:param mesh: The input mesh for inplace modification.)");
59 "detect_degenerate_facets",
60 &detect_degenerate_facets<Scalar, Index>,
62 R
"(Detect degenerate facets in a mesh.
65 Only __exaxtly__ degenerate facets are detected.
67:param mesh: The input mesh.
69:returns: A list of indices of degenerate facets.)");
72 "remove_null_area_facets",
74 RemoveNullAreaFacetsOptions opts;
75 opts.null_area_threshold = null_area_threshold;
80 "null_area_threshold"_a = 0,
81 "remove_isolated_vertices"_a =
false,
82 R
"(Remove facets with unsigned facets area <= `null_area_threhsold`.
84:param mesh: The input mesh.
85:param null_area_threshold: The area threshold below which a facet is considered as null facet.
86:param remove_isolated_vertices: Whether to remove isolated vertices after removing null area facets.)");
89 "remove_duplicate_vertices",
91 std::optional<std::vector<AttributeId>> extra_attributes,
93 RemoveDuplicateVerticesOptions opts;
94 if (extra_attributes.has_value()) {
95 opts.extra_attributes = std::move(extra_attributes.value());
97 opts.boundary_only = boundary_only;
101 "extra_attributes"_a = nb::none(),
102 "boundary_only"_a =
false,
103 R
"(Remove duplicate vertices from a mesh.
105:param mesh: The input mesh.
106:param extra_attributes: Two vertices are considered duplicates if they have the same position and the same values for all attributes in `extra_attributes`.
107:param boundary_only: Only remove duplicate vertices on the boundary.)");
110 "remove_duplicate_facets",
111 [](
MeshType& mesh,
bool consider_orientation) {
112 RemoveDuplicateFacetOptions opts;
113 opts.consider_orientation = consider_orientation;
117 "consider_orientation"_a =
false,
118 R
"(Remove duplicate facets from a mesh.
120Facets of different orientations (e.g. (0, 1, 2) and (2, 1, 0)) are considered as duplicates.
121If both orientations have equal number of duplicate facets, all of them are removed.
122If one orientation has more duplicate facets, all but one facet with the majority orientation are removed.
124:param mesh: The input mesh. The mesh is modified in place.
125:param consider_orientation: Whether to consider orientation when detecting duplicate facets.)");
128 "remove_topologically_degenerate_facets",
129 &remove_topologically_degenerate_facets<Scalar, Index>,
131 R
"(Remove topologically degenerate facets such as (0, 1, 1)
133For general polygons, topologically degeneracy means that the polygon is made of at most two unique
134vertices. E.g. a quad of the form (0, 0, 1, 1) is degenerate, while a quad of the form (1, 1, 2, 3)
137:param mesh: The input mesh for inplace modification.)");
140 "remove_short_edges",
141 &remove_short_edges<Scalar, Index>,
144 R
"(Remove short edges from a mesh.
146:param mesh: The input mesh for inplace modification.
147:param threshold: The minimum edge length below which an edge is considered short.)");
150 "resolve_vertex_nonmanifoldness",
151 &resolve_vertex_nonmanifoldness<Scalar, Index>,
153 R
"(Resolve vertex non-manifoldness in a mesh.
155:param mesh: The input mesh for inplace modification.
157:raises RuntimeError: If the input mesh is not edge-manifold.)");
160 "resolve_nonmanifoldness",
161 &resolve_nonmanifoldness<Scalar, Index>,
163 R
"(Resolve both vertex and edge nonmanifoldness in a mesh.
165:param mesh: The input mesh for inplace modification.)");
170 float max_edge_length,
172 std::optional<std::string_view> active_region_attribute,
173 std::optional<std::string_view> edge_length_attribute) {
174 SplitLongEdgesOptions opts;
175 opts.max_edge_length = max_edge_length;
176 opts.recursive = recursive;
177 if (active_region_attribute.has_value())
178 opts.active_region_attribute = active_region_attribute.value();
179 if (edge_length_attribute.has_value())
180 opts.edge_length_attribute = edge_length_attribute.value();
184 "max_edge_length"_a = 0.1f,
185 "recursive"_a =
true,
186 "active_region_attribute"_a = nb::none(),
187 "edge_length_attribute"_a = nb::none(),
188 R
"(Split edges that are longer than `max_edge_length`.
190:param mesh: The input mesh for inplace modification.
191:param max_edge_length: Maximum edge length. Edges longer than this value will be split.
192:param recursive: If true, the operation will be applied recursively until no edge is longer than `max_edge_length`.
193:param active_region_attribute: The facet attribute name that will be used to determine the active region.
194 If `None`, all edges will be considered.
195 Otherwise, only edges that are part of the active region will be split.
196 The attribute must be of value type `uint8_t`.
197:param edge_length_attribute: The edge length attribute name that will be used to determine the edge length.
198 If `None`, the function will compute the edge lengths.
202 "remove_degenerate_facets",
203 &remove_degenerate_facets<Scalar, Index>,
205 R
"(Remove degenerate facets from a mesh.
208 The current method assumes input mesh is triangular.
209 Use `triangulate_polygonal_facets` if the input mesh is not triangular.
210 Non-degenerate facets adjacent to degenerte facets may be re-triangulated as a result of the removal.
212:param mesh: The mesh for inplace modification.)");
216 [](
MeshType& mesh,
size_t max_hole_size,
bool triangulate_holes) {
217 CloseSmallHolesOptions options;
218 options.max_hole_size = max_hole_size;
219 options.triangulate_holes = triangulate_holes;
223 "max_hole_size"_a = CloseSmallHolesOptions().max_hole_size,
224 "triangulate_holes"_a = CloseSmallHolesOptions().triangulate_holes,
225 R
"(Close small holes in a mesh.
227:param mesh: The input mesh for inplace modification.
228:param max_hole_size: The maximum number of vertices on a hole to be closed.
229:param triangulate_holes: Whether to triangulate holes. If false, holes will be filled by polygons.)");
234 std::string_view uv_attribute_name,
235 std::string_view chart_id_attribute_name,
236 double uv_area_threshold) {
237 RescaleUVOptions options;
238 options.uv_attribute_name = uv_attribute_name;
239 options.chart_id_attribute_name = chart_id_attribute_name;
240 options.uv_area_threshold = uv_area_threshold;
244 "uv_attribute_name"_a = RescaleUVOptions().uv_attribute_name,
245 "chart_id_attribute_name"_a = RescaleUVOptions().chart_id_attribute_name,
246 "uv_area_threshold"_a = RescaleUVOptions().uv_area_threshold,
247 R
"(Rescale UV charts such that their aspect ratios match their 3D images.
249:param mesh: The input mesh for inplace modification.
250:param uv_attribute_name: The uv attribute name to use for rescaling.
251 If empty, the first UV attribute found will be used.
252:param chart_id_attribute_name: The name used for storing the patch ID attribute.
253 If empty, patches will be computed based on UV chart connectivity.
254:param uv_area_threshold: The threshold for UV area.
255 UV triangles with area smaller than this threshold will not contribute to scale factor computation.
A general purpose polygonal mesh class.
Definition: SurfaceMesh.h:66
void remove_duplicate_vertices(SurfaceMesh< Scalar, Index > &mesh, const RemoveDuplicateVerticesOptions &options={})
Removes duplicate vertices from a mesh.
Definition: remove_duplicate_vertices.cpp:33
void remove_duplicate_facets(SurfaceMesh< Scalar, Index > &mesh, const RemoveDuplicateFacetOptions &opts={})
Remove duplicate facets in the mesh.
Definition: remove_duplicate_facets.cpp:235
void rescale_uv_charts(SurfaceMesh< Scalar, Index > &mesh, const RescaleUVOptions &options={})
Rescale UV charts such that they are isotropic to their 3D images.
Definition: rescale_uv_charts.cpp:70
void remove_isolated_vertices(SurfaceMesh< Scalar, Index > &mesh)
Removes isolated vertices of a mesh.
Definition: remove_isolated_vertices.cpp:20
void split_long_edges(SurfaceMesh< Scalar, Index > &mesh, SplitLongEdgesOptions options={})
Split edges that are longer than options.max_edge_length.
Definition: split_long_edges.cpp:66
void close_small_holes(SurfaceMesh< Scalar, Index > &mesh, CloseSmallHolesOptions options={})
Close small topological holes.
Definition: close_small_holes.cpp:538
void remove_null_area_facets(SurfaceMesh< Scalar, Index > &mesh, const RemoveNullAreaFacetsOptions &options={})
Removes all facets with unsigned area <= options.null_area_threshold.
Definition: remove_null_area_facets.cpp:22