@@ -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