Skip to content

Commit 3319628

Browse files
committed
[feat] add meshrefine test, use keywords in meshrefine, 0.3.7
1 parent 78cedea commit 3319628

File tree

6 files changed

+63
-24
lines changed

6 files changed

+63
-24
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
* **Copyright**: (C) Qianqian Fang (2024-2025) <q.fang at neu.edu>
66
* **License**: GNU Public License V3 or later
7-
* **Version**: 0.3.6
7+
* **Version**: 0.3.7
88
* **URL**: [https://pypi.org/project/iso2mesh/](https://pypi.org/project/iso2mesh/)
99
* **Homepage**: [https://iso2mesh.sf.net](https://iso2mesh.sf.net)
1010
* **Github**: [https://github.com/NeuroJSON/pyiso2mesh](https://github.com/NeuroJSON/pyiso2mesh)
@@ -277,7 +277,7 @@ tracked in https://github.com/NeuroJSON/pyiso2mesh/issues/1
277277
|`smoothsurf.m` | ✅ tested |
278278
|`sortmesh.m` | ⭕️ tested |
279279
|`mergemesh.m` | ⭕️ tested |
280-
|`meshrefine.m` | ⭕️ tested |
280+
|`meshrefine.m` | tested |
281281
|`mergesurf.m` | ⭕️ tested |
282282
|`surfboolean.m` | ✅ tested |
283283
|`fillsurf.m` | ⭕️ tested |

iso2mesh/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
regpt2surf,
158158
)
159159

160-
__version__ = "0.3.6"
160+
__version__ = "0.3.7"
161161
__all__ = [
162162
"advancefront",
163163
"barycentricgrid",

iso2mesh/core.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ def remeshsurf(node, face, opt):
12381238
return newno, newfc
12391239

12401240

1241-
def meshrefine(node, elem, *args):
1241+
def meshrefine(node, elem, *args, **kwargs):
12421242
"""
12431243
meshrefine - refine a tetrahedral mesh by adding new nodes or constraints
12441244
@@ -1311,13 +1311,11 @@ def meshrefine(node, elem, *args):
13111311
sizefield = np.array(args[1])
13121312
else:
13131313
newpt = np.array(args[1])
1314-
else:
1315-
raise ValueError("meshrefine requires at least 3 inputs")
13161314

1317-
if isinstance(opt, dict) and "newnode" in opt:
1318-
newpt = np.array(opt["newnode"])
1319-
if isinstance(opt, dict) and "sizefield" in opt:
1320-
sizefield = np.array(opt["sizefield"])
1315+
if newpt is None and "newnode" in kwargs:
1316+
newpt = np.array(kwargs["newnode"])
1317+
if sizefield is None and "sizefield" in kwargs:
1318+
sizefield = np.array(kwargs["sizefield"])
13211319

13221320
exesuff = fallbackexeext(getexeext(), "tetgen")
13231321

@@ -1327,14 +1325,14 @@ def meshrefine(node, elem, *args):
13271325
moreopt = ""
13281326
setquality = False
13291327

1330-
if isinstance(opt, dict) and "reratio" in opt:
1331-
moreopt += f" -q {opt['reratio']:.10f} "
1328+
if "reratio" in kwargs:
1329+
moreopt += f" -q {kwargs['reratio']:.10f} "
13321330
setquality = True
1333-
if isinstance(opt, dict) and "maxvol" in opt:
1334-
moreopt += f" -a{opt['maxvol']:.10f} "
1331+
if "maxvol" in kwargs:
1332+
moreopt += f" -a{kwargs['maxvol']:.10f} "
13351333

13361334
externalpt = np.empty((0, 3))
1337-
if isinstance(opt, dict) and "extcmdopt" in opt and newpt is not None:
1335+
if "extcmdopt" in kwargs and newpt is not None:
13381336
from scipy.spatial import Delaunay
13391337

13401338
try:
@@ -1439,7 +1437,7 @@ def meshrefine(node, elem, *args):
14391437
holelist = surfseeds(newnode, face[:, :3])
14401438

14411439
# mesh the extended space
1442-
ISO2MESH_TETGENOPT = jsonopt("extcmdopt", "-Y", opt)
1440+
ISO2MESH_TETGENOPT = kwargs.get("extcmdopt", "-Y")
14431441
try:
14441442
if bothsides.shape[0] >= inface.shape[0]:
14451443
no, el, _ = surf2mesh(
@@ -1514,7 +1512,7 @@ def meshrefine(node, elem, *args):
15141512
map[map == 0] = np.arange(oldsize, allnode.shape[0]) + 1
15151513

15161514
# merge the external space with the original mesh
1517-
el2 = map[el[:, :4] - 1] + 1
1515+
el2 = map[el[:, :4] - 1]
15181516

15191517
# label all new elements with -1
15201518
if newelem.shape[1] == 5:

iso2mesh/plot.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def plotsurf(node, face, *args, **kwargs):
113113
if "colormap" in locals() and len(colormap) > 0 and not "facecolors" in kwargs:
114114
kwargs["facecolors"] = colormap
115115

116-
if "cmap" in kwargs and not "facecolors" in kwargs:
116+
if "cmap" in kwargs and not "facecolors" in kwargs and face:
117117
node_values = node[:, 3] if node.shape[1] > 3 else node[:, 2]
118118
face_values = np.array([np.mean(node_values[f]) for f in face[:, :3] - 1])
119119
norm = Normalize(vmin=face_values.min(), vmax=face_values.max())
@@ -337,6 +337,7 @@ def plotmesh(node, *args, **kwargs):
337337
opt = []
338338
face = None
339339
elem = None
340+
node = np.array(node)
340341

341342
# Parse inputs: detect selector strings, face/elem arrays, opts
342343
for i, a in enumerate(args):
@@ -436,11 +437,15 @@ def plotmesh(node, *args, **kwargs):
436437

437438
def _autoscale_3d(ax, points):
438439
x, y, z = points[:, 0], points[:, 1], points[:, 2]
439-
ax.set_xlim([x.min(), x.max()])
440-
ax.set_ylim([y.min(), y.max()])
441-
ax.set_zlim([z.min(), z.max()])
442-
boxas = [x.max() - x.min(), y.max() - y.min(), z.max() - z.min()]
443-
ax.set_box_aspect(boxas)
440+
boxas = np.array([x.max() - x.min(), y.max() - y.min(), z.max() - z.min()])
441+
if boxas[0] > 0:
442+
ax.set_xlim([x.min(), x.max()])
443+
if boxas[1] > 0:
444+
ax.set_ylim([y.min(), y.max()])
445+
if boxas[2] > 0:
446+
ax.set_zlim([z.min(), z.max()])
447+
if np.all(boxas > 0):
448+
ax.set_box_aspect(boxas)
444449

445450

446451
def _createaxis(*args, **kwargs):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
setup(
77
name="iso2mesh",
88
packages=["iso2mesh"],
9-
version="0.3.6",
9+
version="0.3.7",
1010
license="GPLv3+",
1111
description="One-liner 3D Surface and Tetrahedral Mesh Generation Toolbox",
1212
long_description=readme,

test/run_test.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,42 @@ def test_extractloops(self):
941941
bcutloop.pop()
942942
self.assertEqual(bcutloop, expected_fc)
943943

944+
def test_meshrefine_addnode(self):
945+
no1, el1, fc1 = meshrefine(self.nbox, self.ebox, [[0.2, 1, 1], [0.2, 1, 2]])
946+
self.assertEqual(no1.shape[0] - self.nbox.shape[0], 2)
947+
self.assertEqual(el1.shape[0] - self.ebox.shape[0], 7)
948+
self.assertEqual(no1[-2:, :].tolist(), [[0.2, 1, 1], [0.2, 1, 2]])
949+
no1, el1, fc1 = meshrefine(
950+
self.nbox, self.ebox, newnode=[[0.2, 1, 1], [0.2, 1, 2]]
951+
)
952+
self.assertEqual(no1[-2:, :].tolist(), [[0.2, 1, 1], [0.2, 1, 2]])
953+
954+
def test_meshrefine_maxvol(self):
955+
no1, el1, fc1 = meshrefine(self.nbox, self.ebox, maxvol=0.02)
956+
self.assertEqual(np.sum(elemvolume(no1[:, :3], el1[:, :4])), 2)
957+
self.assertEqual(np.sum(elemvolume(no1[:, :3], fc1[:, :3])), 10)
958+
self.assertTrue(np.max(elemvolume(no1[:, :3], el1[:, :4])) < 0.02)
959+
no1, el1, fc1 = meshrefine(self.nbox, self.ebox, maxvol=0.01)
960+
self.assertTrue(np.max(elemvolume(no1[:, :3], el1[:, :4])) < 0.01)
961+
962+
def test_meshrefine_sizefield(self):
963+
no1, el1, fc1 = meshrefine(
964+
self.nbox, self.ebox, sizefield=(self.nbox[:, 0] + 0.1) * 0.3
965+
)
966+
self.assertEqual(np.sum(elemvolume(no1[:, :3], el1[:, :4])), 2)
967+
self.assertAlmostEqual(
968+
np.mean(elemvolume(no1[:, :3], el1[:, :4])), 0.00019615535504119262, 8
969+
)
970+
971+
def test_meshrefine_externalnode(self):
972+
node, face, elem = meshasphere([0, 0, 0], 24, 5, 100)
973+
extnodes = [[-5, -5, 25], [-5, 5, 25], [5, 5, 25], [5, -5, 25]]
974+
no1, el1, fc1 = meshrefine(node, elem, newnode=extnodes, extcmdopt="-Y")
975+
self.assertEqual(no1.shape[0] - node.shape[0], 4)
976+
self.assertAlmostEqual(
977+
np.sum(elemvolume(no1[:, :3], el1[:, :4])), 56628.62907381002, 2
978+
)
979+
944980

945981
class Test_surfboolean(unittest.TestCase):
946982
def __init__(self, *args, **kwargs):

0 commit comments

Comments
 (0)