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>
27#include <lagrange/python/binding.h>
31namespace lagrange::python {
33template <
typename Scalar,
typename Index>
34void bind_mesh_cleanup(nanobind::module_& m)
36 namespace nb = nanobind;
37 using namespace nb::literals;
38 using MeshType = SurfaceMesh<Scalar, Index>;
41 "remove_isolated_vertices",
44 R
"(Remove isolated vertices from a mesh.
47 A vertex is considered isolated if it is not referenced by any facet.
49:param mesh: Input mesh (modified in place).)");
52 "detect_degenerate_facets",
55 R
"(Detect degenerate facets in a mesh.
58 Only exactly degenerate facets are detected.
60:param mesh: Input mesh.
62:returns: List of degenerate facet indices.)");
65 "remove_null_area_facets",
67 RemoveNullAreaFacetsOptions opts;
68 opts.null_area_threshold = null_area_threshold;
73 "null_area_threshold"_a = 0,
74 "remove_isolated_vertices"_a =
false,
75 R
"(Remove facets with unsigned facets area <= `null_area_threhsold`.
77:param mesh: Input mesh (modified in place).
78:param null_area_threshold: Area threshold below which facets are considered null.
79:param remove_isolated_vertices: Whether to remove isolated vertices after removing null area facets.)");
82 "remove_duplicate_vertices",
84 std::optional<std::vector<AttributeId>> extra_attributes,
86 RemoveDuplicateVerticesOptions opts;
87 if (extra_attributes.has_value()) {
88 opts.extra_attributes = std::move(extra_attributes.value());
90 opts.boundary_only = boundary_only;
94 "extra_attributes"_a = nb::none(),
95 "boundary_only"_a =
false,
96 R
"(Remove duplicate vertices from a mesh.
98:param mesh: Input mesh (modified in place).
99:param extra_attributes: Additional attributes to consider when detecting duplicates.
100:param boundary_only: Only remove duplicate vertices on the boundary.)");
103 "remove_duplicate_facets",
104 [](MeshType& mesh,
bool consider_orientation) {
105 RemoveDuplicateFacetOptions opts;
106 opts.consider_orientation = consider_orientation;
110 "consider_orientation"_a =
false,
111 R
"(Remove duplicate facets from a mesh.
113Facets with different orientations (e.g. (0,1,2) and (2,1,0)) are considered duplicates.
114If both orientations have equal counts, all are removed.
115If one orientation has more duplicates, all but one of the majority orientation are kept.
117:param mesh: Input mesh (modified in place).
118:param consider_orientation: Whether to consider orientation when detecting duplicates.)");
121 "remove_topologically_degenerate_facets",
124 R
"(Remove topologically degenerate facets such as (0,1,1).
126For polygons, topological degeneracy means the polygon has at most two unique vertices.
127E.g. quad (0,0,1,1) is degenerate, while (1,1,2,3) is not.
129:param mesh: Input mesh (modified in place).)");
132 "remove_short_edges",
136 R
"(Remove short edges from a mesh.
138:param mesh: Input mesh (modified in place).
139:param threshold: Minimum edge length below which edges are considered short.)");
142 "resolve_vertex_nonmanifoldness",
145 R
"(Resolve vertex non-manifoldness in a mesh.
147:param mesh: Input mesh (modified in place).
149:raises RuntimeError: If the input mesh is not edge-manifold.)");
152 "resolve_nonmanifoldness",
155 R
"(Resolve both vertex and edge nonmanifoldness in a mesh.
157:param mesh: Input mesh (modified in place).)");
162 float max_edge_length,
164 std::optional<std::string_view> active_region_attribute,
165 std::optional<std::string_view> edge_length_attribute) {
166 SplitLongEdgesOptions opts;
167 opts.max_edge_length = max_edge_length;
168 opts.recursive = recursive;
169 if (active_region_attribute.has_value())
170 opts.active_region_attribute = active_region_attribute.value();
171 if (edge_length_attribute.has_value())
172 opts.edge_length_attribute = edge_length_attribute.value();
176 "max_edge_length"_a = 0.1f,
177 "recursive"_a =
true,
178 "active_region_attribute"_a = nb::none(),
179 "edge_length_attribute"_a = nb::none(),
180 R
"(Split edges longer than max_edge_length.
182:param mesh: Input mesh (modified in place).
183:param max_edge_length: Maximum edge length threshold.
184:param recursive: If true, apply recursively until no edge exceeds threshold.
185:param active_region_attribute: Facet attribute name for active region (uint8_t type).
186 If None, all edges are considered.
187:param edge_length_attribute: Edge length attribute name.
188 If None, edge lengths are computed.
192 "remove_degenerate_facets",
195 R
"(Remove degenerate facets from a mesh.
198 Assumes triangular mesh. Use `triangulate_polygonal_facets` for non-triangular meshes.
199 Adjacent non-degenerate facets may be re-triangulated during removal.
201:param mesh: Input mesh (modified in place).)");
205 [](MeshType& mesh,
size_t max_hole_size,
bool triangulate_holes) {
206 CloseSmallHolesOptions options;
207 options.max_hole_size = max_hole_size;
208 options.triangulate_holes = triangulate_holes;
212 "max_hole_size"_a = CloseSmallHolesOptions().max_hole_size,
213 "triangulate_holes"_a = CloseSmallHolesOptions().triangulate_holes,
214 R
"(Close small holes in a mesh.
216:param mesh: Input mesh (modified in place).
217:param max_hole_size: Maximum number of vertices on a hole to be closed.
218:param triangulate_holes: Whether to triangulate holes (if false, fill with polygons).)");
223 std::string_view uv_attribute_name,
224 std::string_view chart_id_attribute_name,
225 double uv_area_threshold) {
226 RescaleUVOptions options;
227 options.uv_attribute_name = uv_attribute_name;
228 options.chart_id_attribute_name = chart_id_attribute_name;
229 options.uv_area_threshold = uv_area_threshold;
233 "uv_attribute_name"_a = RescaleUVOptions().uv_attribute_name,
234 "chart_id_attribute_name"_a = RescaleUVOptions().chart_id_attribute_name,
235 "uv_area_threshold"_a = RescaleUVOptions().uv_area_threshold,
236 R
"(Rescale UV charts to match their 3D aspect ratios.
238:param mesh: Input mesh (modified in place).
239:param uv_attribute_name: UV attribute name for rescaling.
240 If empty, uses first UV attribute found.
241:param chart_id_attribute_name: Patch ID attribute name.
242 If empty, computes patches from UV chart connectivity.
243:param uv_area_threshold: UV area threshold.
244 Triangles below this threshold don't contribute to scale computation.
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 resolve_vertex_nonmanifoldness(SurfaceMesh< Scalar, Index > &mesh)
Resolve nonmanifold vertices by pulling disconnected 1-ring neighborhood apart.
Definition resolve_vertex_nonmanifoldness.cpp:35
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_topologically_degenerate_facets(SurfaceMesh< Scalar, Index > &mesh)
Remove topologically degenerate facets (i.e.
Definition remove_topologically_degenerate_facets.cpp:21
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:65
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
void remove_degenerate_facets(SurfaceMesh< Scalar, Index > &mesh)
Removes degenerate facets from a mesh.
Definition remove_degenerate_facets.cpp:32
std::vector< Index > detect_degenerate_facets(const SurfaceMesh< Scalar, Index > &mesh)
Detects degenerate facets in a mesh.
Definition detect_degenerate_facets.cpp:32
void remove_short_edges(SurfaceMesh< Scalar, Index > &mesh, Scalar threshold=0)
Collapse all edges shorter than a given tolerance.
Definition remove_short_edges.cpp:29
void resolve_nonmanifoldness(SurfaceMesh< Scalar, Index > &mesh)
Resolve both non-manifold vertices and non-manifold edges in the input mesh.
Definition resolve_nonmanifoldness.cpp:35