Skip to content

Commit 8e0d7f9

Browse files
committed
[feat] update mesheuler, add test to v2s grayscale, finddisconnsurf
1 parent c5c3c81 commit 8e0d7f9

File tree

3 files changed

+58
-21
lines changed

3 files changed

+58
-21
lines changed

iso2mesh/core.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ def vol2surf(img, ix, iy, iz, opt, dofix=0, method="cgalsurf", isovalues=None):
325325

326326
keepratio = (
327327
opt.get("keepratio", 1)
328-
if len(opt) == 1
328+
if isinstance(opt, dict)
329329
else opt[i].get("keepratio", 1)
330330
)
331331
print(f"Resampling surface mesh for level {i + 1}...")
@@ -337,21 +337,23 @@ def vol2surf(img, ix, iy, iz, opt, dofix=0, method="cgalsurf", isovalues=None):
337337
else:
338338
radbound = (
339339
opt.get("radbound", 1)
340-
if len(opt) == 1
340+
if isinstance(opt, dict)
341341
else opt[i].get("radbound", 1)
342342
)
343343
distbound = (
344344
opt.get("distbound", radbound)
345-
if len(opt) == 1
345+
if isinstance(opt, dict)
346346
else opt[i].get("distbound", radbound)
347347
)
348348
maxsurfnode = (
349349
opt.get("maxnode", 40000)
350-
if len(opt) == 1
350+
if isinstance(opt, dict)
351351
else opt[i].get("maxnode", 40000)
352352
)
353353
surfside = (
354-
opt.get("side", "") if len(opt) == 1 else opt[i].get("side", "")
354+
opt.get("side", "")
355+
if isinstance(opt, dict)
356+
else opt[i].get("side", "")
355357
)
356358

357359
if surfside == "upper":

iso2mesh/trait.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ def extractloops(edges):
193193
# Remove degenerate edges (edges where the start and end points are the same)
194194
edges = edges[edges[:, 0] != edges[:, 1], :]
195195

196+
if len(edges) == 0:
197+
return loops
198+
196199
# Initialize the loop with the first edge
197200
loops.extend(edges[0, :])
198201
loophead = edges[0, 0]
@@ -751,18 +754,21 @@ def flatsegment(node, edge):
751754

752755
def mesheuler(face):
753756
"""
754-
X, V, E, F = mesheuler(face)
757+
X, V, E, F, b, g, C = mesheuler(face)
755758
756759
Compute Euler's characteristic of a mesh.
757760
758761
Arguments:
759762
face : a closed surface mesh (Mx3 array where M is the number of faces and each row contains vertex indices)
760763
761764
Output:
762-
X : Euler's characteristic (X = 2 - 2 * g, where g is the genus)
765+
X : Euler's characteristic (X = V - E + F - C)
763766
V : number of vertices
764767
E : number of edges
765-
F : number of faces
768+
F : number of triangles (if face is tetrahedral mesh, exterior surface)
769+
b : number of boundary loops (for surfaces)
770+
g : genus (holes)
771+
C : number of tetrahedra
766772
767773
Author: Qianqian Fang
768774
This function is part of the iso2mesh toolbox (http://iso2mesh.sf.net)
@@ -771,16 +777,30 @@ def mesheuler(face):
771777
# Number of vertices
772778
V = len(np.unique(face))
773779

774-
# Construct edges from faces
780+
# Number of unique edges
775781
E = uniqedges(face)[0].shape[0]
776782

777-
# Number of faces
778-
F = face.shape[0]
783+
b = 0 # open-boundary loops
784+
g = 0 # genus
785+
C = 0 # tet cells
786+
787+
# Number of unique faces
788+
if face.shape[1] == 4:
789+
F = uniqfaces(face)[0].shape[0]
790+
C = face.shape[0]
791+
else:
792+
ed = surfedge(face)[0]
793+
loops = extractloops(ed)
794+
b = np.sum(np.isnan(loops))
795+
F = face.shape[0]
796+
797+
# Euler's formula, X = V - E + F - C - 2*g
798+
X = V - E + F - C
779799

780-
# Euler's characteristic formula: X = V - E + F
781-
X = V - E + F
800+
if face.shape[1] == 3:
801+
g = (X + b - 2) // 2
782802

783-
return X, V, E, F
803+
return X, V, E, F, b, g, C
784804

785805

786806
def orderloopedge(edge):

test/run_test.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,13 @@ def test_meshconn(self):
441441

442442
def test_mesheuler(self):
443443
eu = mesheuler(self.el)
444-
self.assertEqual(eu, (-9, 12, 33, 12))
444+
self.assertEqual(eu, (1, 12, 33, 34, 0, 0, 12))
445445

446446
eu = mesheuler(self.fc)
447-
self.assertEqual(eu, (2, 12, 30, 20))
447+
self.assertEqual(eu, (2, 12, 30, 20, 0, 0, 0))
448+
449+
eu = mesheuler(self.fc[1:-2, :])
450+
self.assertEqual(eu, (0, 12, 29, 17, 2, 0, 0))
448451

449452
def test_neighborelem(self):
450453
expected = [
@@ -936,8 +939,9 @@ def __init__(self, *args, **kwargs):
936939
xi, yi, zi = np.meshgrid(
937940
np.arange(0, 61), np.arange(0, 58), np.arange(0, 55), indexing="ij"
938941
)
939-
dist = (xi - 30) ** 2 + (yi - 30) ** 2 + (zi - 30) ** 2
940-
self.mask = dist < 400
942+
self.dist = (xi - 30) ** 2 + (yi - 30) ** 2 + (zi - 30) ** 2
943+
self.dist = self.dist.astype(float)
944+
self.mask = self.dist < 400
941945
self.mask = self.mask.astype(float)
942946
self.mask[25:35, 25:35, :] = 2
943947

@@ -1014,11 +1018,22 @@ def test_cgalv2m(self):
10141018
self.assertAlmostEqual(sum(elemvolume(no[:, :3], el[:, :4])), 0.7455, 3)
10151019

10161020
def test_v2s_label(self):
1017-
no, fc, _, _ = v2s(self.mask, 0.04, 1)
1021+
no, fc, _, _ = v2s(self.mask, 0.5, 1)
10181022
self.assertAlmostEqual(
1019-
sum(elemvolume(no[:, :3], fc[:, :3])) * 0.001, 6.356848339883229, 3
1023+
sum(elemvolume(no[:, :3], fc[:, :3])) * 0.001, 5.802998130608866, 2
10201024
)
10211025

1026+
def test_v2s_grayscale(self):
1027+
no, fc, _, _ = v2s(self.dist, [200, 400], 1)
1028+
self.assertAlmostEqual(
1029+
sum(elemvolume(no[:, :3], fc[:, :3])) * 0.0001, 4.816236473144449, 3
1030+
)
1031+
1032+
def test_finddisconnsurf(self):
1033+
no, fc, _, _ = v2s(self.dist, [90, 200, 400], 5)
1034+
fcs = finddisconnsurf(fc[:, :3])
1035+
self.assertEqual(len(fcs), 5)
1036+
10221037
def test_v2m_cgalmesh(self):
10231038
no, el, _ = v2m(
10241039
self.mask.astype(np.uint8),
@@ -1036,7 +1051,7 @@ def test_v2m_simplify(self):
10361051
self.mask.astype(np.uint8), 1.5, {"keepratio": 0.5}, 10, "simplify"
10371052
)
10381053
self.assertAlmostEqual(
1039-
sum(elemvolume(no[:, :3], el[:, :4])), 5456.390624999979, 0
1054+
sum(elemvolume(no[:, :3], el[:, :4])) * 0.001, 5.456390624999979, 2
10401055
)
10411056

10421057

0 commit comments

Comments
 (0)