Skip to content

Commit 7267f7d

Browse files
committed
added option to remove negative surface area elements
1 parent 2ab1adb commit 7267f7d

File tree

1 file changed

+41
-4
lines changed

1 file changed

+41
-4
lines changed

DeepSDFStruct/mesh.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def to_trimesh():
186186
raise NotImplementedError("To trimesh functionality not implemented yet.")
187187
pass
188188

189-
def clean(self):
189+
def clean(self, clean_jacobian=True):
190190
"""
191191
Remove unused vertices and remap face indices.
192192
@@ -195,6 +195,35 @@ def clean(self):
195195
torchSurfMesh
196196
A new cleaned mesh with only the vertices used by faces.
197197
"""
198+
n_elements_orig = self.faces.shape[0]
199+
n_vertices_orig = self.vertices.shape[0]
200+
if clean_jacobian:
201+
v0 = self.vertices[self.faces[:, 0]]
202+
v1 = self.vertices[self.faces[:, 1]]
203+
v2 = self.vertices[self.faces[:, 2]]
204+
205+
if self.vertices.shape[1] == 2:
206+
# 2D Jacobian: signed area of triangle
207+
# det( [v1-v0, v2-v0] ) = e1.x*e2.y - e1.y*e2.x
208+
e1 = v1 - v0
209+
e2 = v2 - v0
210+
jac_det = e1[:, 0] * e2[:, 1] - e1[:, 1] * e2[:, 0]
211+
elif self.vertices.shape[1] == 3:
212+
# 3D Jakob: sign from oriented area using cross product direction
213+
e1 = v1 - v0
214+
e2 = v2 - v0
215+
cross = torch.cross(e1, e2, dim=-1) # (F,3)
216+
# Signed Jacobian: oriented area relative to a stable axis
217+
# Use the largest-magnitude axis to avoid degeneracy
218+
abs_cross = cross.abs()
219+
axis = abs_cross.argmax(dim=1) # (F,)
220+
221+
signed_area = cross[torch.arange(cross.size(0)), axis]
222+
jac_det = signed_area # sign preserved
223+
224+
# remove elements with zero surface area
225+
valid_mask = jac_det > 0
226+
self.faces = self.faces[valid_mask]
198227

199228
# Find unique vertices referenced by faces
200229
used_idx = _torch.unique(self.faces.reshape(-1))
@@ -212,7 +241,15 @@ def clean(self):
212241

213242
# Remap face indices
214243
new_faces = new_index[self.faces]
215-
244+
n_elements_after = new_faces.shape[0]
245+
n_vertices_after = new_vertices.shape[0]
246+
info_string = ""
247+
if n_elements_after < n_elements_orig:
248+
info_string += f"removed {n_elements_orig-n_elements_after} elements"
249+
if n_vertices_after < n_vertices_orig:
250+
info_string += f" removed {n_vertices_orig-n_vertices_after} vertices"
251+
if info_string != "":
252+
logger.info(info_string)
216253
return torchSurfMesh(new_vertices, new_faces)
217254

218255

@@ -764,7 +801,7 @@ def create_2D_mesh(
764801
min_dist, min_idx = dist.min(dim=1)
765802

766803
# mask where surf vertex matches original vertex
767-
mask = min_dist < 1e-7 # or some tolerance
804+
mask = min_dist < 1e-10 # or some tolerance
768805
orig_idx = min_idx
769806
surf_mesh.vertices = torch.where(
770807
mask[:, None], line_mesh.vertices[orig_idx], surf_mesh.vertices
@@ -946,7 +983,7 @@ def export_surface_mesh(
946983
gus.io.meshio.export(export_filename, mesh)
947984

948985

949-
def mergeMeshs(mesh1, mesh2, tol=1e-8):
986+
def mergeMeshs(mesh1, mesh2, tol=1e-10):
950987
vertices1 = mesh1.vertices
951988
vertices2 = mesh2.vertices
952989

0 commit comments

Comments
 (0)