Skip to content
Snippets Groups Projects
Commit 91148e64 authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Mesh unit tests updated

parent 1f783253
No related branches found
No related tags found
No related merge requests found
...@@ -6,10 +6,6 @@ ...@@ -6,10 +6,6 @@
# #
import os.path as op
import shutil
import tempfile
import numpy as np import numpy as np
import mock import mock
import pytest import pytest
...@@ -18,9 +14,6 @@ import fsl.utils.transform as transform ...@@ -18,9 +14,6 @@ import fsl.utils.transform as transform
import fsl.data.mesh as fslmesh import fsl.data.mesh as fslmesh
datadir = op.join(op.dirname(__file__), 'testdata')
# vertices of a cube # vertices of a cube
CUBE_VERTICES = np.array([ CUBE_VERTICES = np.array([
[-1, -1, -1], [-1, -1, -1],
...@@ -49,119 +42,96 @@ CUBE_TRIANGLES_CW = np.array([ ...@@ -49,119 +42,96 @@ CUBE_TRIANGLES_CW = np.array([
CUBE_TRIANGLES_CCW = np.array(CUBE_TRIANGLES_CW) CUBE_TRIANGLES_CCW = np.array(CUBE_TRIANGLES_CW)
CUBE_TRIANGLES_CCW[:, [1, 2]] = CUBE_TRIANGLES_CCW[:, [2, 1]] CUBE_TRIANGLES_CCW[:, [1, 2]] = CUBE_TRIANGLES_CCW[:, [2, 1]]
CUBE_CCW_FACE_NORMALS = np.array([
[ 0, 0, -1], [ 0, 0, -1],
[ 0, 0, 1], [ 0, 0, 1],
[ 0, -1, 0], [ 0, -1, 0],
[ 0, 1, 0], [ 0, 1, 0],
[-1, 0, 0], [-1, 0, 0],
[ 1, 0, 0], [ 1, 0, 0],
])
def test_create_mesh(): CUBE_CCW_VERTEX_NORMALS = np.zeros((8, 3))
for i in range(8):
# Test: faces = np.where(CUBE_TRIANGLES_CCW == i)[0]
# - create from file CUBE_CCW_VERTEX_NORMALS[i] = CUBE_CCW_FACE_NORMALS[faces].sum(axis=0)
# - create from inmem data CUBE_CCW_VERTEX_NORMALS = transform.normalise(CUBE_CCW_VERTEX_NORMALS)
testbase = 'test_mesh.vtk'
testfile = op.join(datadir, testbase)
verts, lens, indices = fslmesh.loadVTKPolydataFile(testfile)
mesh1 = fslmesh.TriangleMesh(testfile)
mesh2 = fslmesh.TriangleMesh(verts, indices)
assert mesh1.name == testbase
assert mesh2.name == 'TriangleMesh'
assert mesh1.dataSource == testfile
assert mesh2.dataSource is None
assert mesh1.vertices.shape == (642, 3)
assert mesh2.vertices.shape == (642, 3)
assert mesh1.indices.shape == (1280, 3)
assert mesh2.indices.shape == (1280, 3)
minbounds = np.array([ 59.50759888, 88.43039703, 72.10890198])
maxbounds = np.array([ 77.72619629, 128.40600586, 94.82050323])
mesh1Bounds = mesh1.getBounds()
mesh2Bounds = mesh2.getBounds()
assert np.all(np.isclose(mesh1Bounds[0], minbounds))
assert np.all(np.isclose(mesh1Bounds[1], maxbounds))
assert np.all(np.isclose(mesh2Bounds[0], minbounds))
assert np.all(np.isclose(mesh2Bounds[1], maxbounds))
def test_mesh_loadVertexData():
meshfile = op.join(datadir, 'test_mesh.vtk') def test_mesh_create():
datafile = op.join(datadir, 'test_mesh_data.txt')
memdata = np.random.randint(1, 100, 642)
mesh = fslmesh.TriangleMesh(meshfile)
assert mesh.loadVertexData(datafile).shape == (642,) verts = np.array(CUBE_VERTICES)
assert np.all(mesh.loadVertexData('inmemdata', memdata) == memdata) tris = np.array(CUBE_TRIANGLES_CCW)
assert mesh.getVertexData(datafile).shape == (642,) mesh = fslmesh.Mesh(tris, vertices=verts)
assert np.all(mesh.getVertexData('inmemdata') == memdata)
mesh.clearVertexData() assert mesh.name == 'mesh'
assert mesh.dataSource is None
assert np.all(np.isclose(mesh.vertices, verts))
assert np.all(np.isclose(mesh.indices, tris))
assert mesh.getVertexData(datafile).shape == (642,) blo, bhi = mesh.bounds
assert np.all(mesh.loadVertexData('inmemdata', memdata) == memdata)
assert np.all(np.isclose(blo, verts.min(axis=0)))
assert np.all(np.isclose(bhi, verts.max(axis=0)))
def test_loadVTKPolydataFile():
testfile = op.join(datadir, 'test_mesh.vtk') def test_mesh_addVertices():
verts, lens, indices = fslmesh.loadVTKPolydataFile(testfile)
assert verts.shape == (642, 3) tris = np.array(CUBE_TRIANGLES_CCW)
assert indices.shape == (3840, ) verts = np.array(CUBE_VERTICES)
assert lens.shape == (1280, ) verts2 = np.array(CUBE_VERTICES) * 2
assert np.all(lens == 3) verts3 = np.array(CUBE_VERTICES) * 3
mesh = fslmesh.Mesh(tris, vertices=verts)
def test_getFIRSTPrefix(): assert mesh.selectedVertices() == 'default'
assert np.all(np.isclose(mesh.vertices, verts))
failures = [ mesh.addVertices(verts2, 'twotimes')
'blob.txt',
'blob.vtk',
'blob.nii.gz']
passes = [ assert mesh.selectedVertices() == 'twotimes'
('blurgh-L_Thal_first.vtk', 'blurgh'), assert np.all(np.isclose(mesh.vertices, verts2))
('blurgh-L_Accu_first.vtk', 'blurgh'),
('blurgh_bufuu-R_Hipp_first.vtk', 'blurgh_bufuu'),
]
for f in failures: mesh.addVertices(verts3, 'threetimes', select=False)
with pytest.raises(ValueError):
fslmesh.getFIRSTPrefix(f)
for fname, expected in passes: assert mesh.selectedVertices() == 'twotimes'
assert fslmesh.getFIRSTPrefix(fname) == expected assert np.all(np.isclose(mesh.vertices, verts2))
mesh.vertices = 'threetimes'
assert mesh.selectedVertices() == 'threetimes'
assert np.all(np.isclose(mesh.vertices, verts3))
def test_findReferenceImage():
testdir = tempfile.mkdtemp() def test_mesh_addVertexData():
vtkfiles = ['struc-L_Thal_first.vtk',
'struc_first-L_Thal_first.vtk']
assert fslmesh.findReferenceImage('nofile') is None mesh = fslmesh.Mesh(np.array(CUBE_TRIANGLES_CCW),
vertices=np.array(CUBE_VERTICES))
try: nverts = CUBE_VERTICES.shape[0]
for fname in vtkfiles: data3D = np.random.randint(1, 100, nverts)
data3_1D = np.random.randint(1, 100, (nverts, 1))
data4D = np.random.randint(1, 100, (nverts, 20))
assert fslmesh.findReferenceImage(fname) is None mesh.addVertexData('3d', data3D)
mesh.addVertexData('3_1d', data3_1D)
mesh.addVertexData('4d', data4D)
prefix = fslmesh.getFIRSTPrefix(fname) assert mesh.getVertexData('3d') .shape == (nverts, 1)
imgfname = op.join(testdir, '{}.nii.gz'.format(prefix)) assert mesh.getVertexData('3_1d').shape == (nverts, 1)
fname = op.join(testdir, fname) assert mesh.getVertexData('4d') .shape == (nverts, 20)
with open(fname, 'wt') as f: f.write(fname) assert np.all(np.isclose(data3D.reshape(-1, 1), mesh.getVertexData('3d')))
with open(imgfname, 'wt') as f: f.write(imgfname) assert np.all(np.isclose(data3_1D, mesh.getVertexData('3_1d')))
assert np.all(np.isclose(data4D, mesh.getVertexData('4d')))
assert fslmesh.findReferenceImage(fname) == imgfname mesh.clearVertexData()
finally: with pytest.raises(KeyError): mesh.getVertexData('3d')
shutil.rmtree(testdir) with pytest.raises(KeyError): mesh.getVertexData('3_1d')
with pytest.raises(KeyError): mesh.getVertexData('4d')
def test_normals(): def test_normals():
...@@ -170,34 +140,18 @@ def test_normals(): ...@@ -170,34 +140,18 @@ def test_normals():
verts = np.array(CUBE_VERTICES) verts = np.array(CUBE_VERTICES)
triangles_cw = np.array(CUBE_TRIANGLES_CW) triangles_cw = np.array(CUBE_TRIANGLES_CW)
triangles_ccw = np.array(CUBE_TRIANGLES_CCW) triangles_ccw = np.array(CUBE_TRIANGLES_CCW)
fnormals = np.array(CUBE_CCW_FACE_NORMALS)
vnormals = np.array(CUBE_CCW_VERTEX_NORMALS)
cw_nofix = fslmesh.Mesh(np.array(triangles_cw))
cw_fix = fslmesh.Mesh(np.array(triangles_cw))
ccw_nofix = fslmesh.Mesh(np.array(triangles_ccw))
ccw_fix = fslmesh.Mesh(np.array(triangles_ccw))
# face normals cw_nofix .addVertices(np.array(verts))
fnormals = np.array([ cw_fix .addVertices(np.array(verts), fixWinding=True)
[ 0, 0, -1], [ 0, 0, -1], ccw_nofix.addVertices(np.array(verts))
[ 0, 0, 1], [ 0, 0, 1], ccw_fix .addVertices(np.array(verts), fixWinding=True)
[ 0, -1, 0], [ 0, -1, 0],
[ 0, 1, 0], [ 0, 1, 0],
[-1, 0, 0], [-1, 0, 0],
[ 1, 0, 0], [ 1, 0, 0],
])
# vertex normals
vnormals = np.zeros((8, 3))
for i in range(8):
faces = np.where(triangles_cw == i)[0]
vnormals[i] = fnormals[faces].sum(axis=0)
vnormals = transform.normalise(vnormals)
cw_nofix = fslmesh.TriangleMesh(np.array(verts),
np.array(triangles_cw))
cw_fix = fslmesh.TriangleMesh(np.array(verts),
np.array(triangles_cw),
fixWinding=True)
ccw_nofix = fslmesh.TriangleMesh(np.array(verts),
np.array(triangles_ccw))
ccw_fix = fslmesh.TriangleMesh(np.array(verts),
np.array(triangles_ccw),
fixWinding=True)
# ccw triangles should give correct # ccw triangles should give correct
# normals without unwinding # normals without unwinding
...@@ -206,29 +160,54 @@ def test_normals(): ...@@ -206,29 +160,54 @@ def test_normals():
assert np.all(np.isclose(cw_fix .normals, fnormals)) assert np.all(np.isclose(cw_fix .normals, fnormals))
assert np.all(np.isclose(cw_fix .vnormals, vnormals)) assert np.all(np.isclose(cw_fix .vnormals, vnormals))
assert np.all(np.isclose(ccw_nofix.normals, fnormals)) assert np.all(np.isclose(ccw_nofix.normals, fnormals))
assert np.all(np.isclose(ccw_nofix.vnormals, vnormals)) assert np.all(np.isclose(ccw_nofix.vnormals, vnormals))
assert np.all(np.isclose(ccw_fix .normals, fnormals)) assert np.all(np.isclose(ccw_fix .normals, fnormals))
assert np.all(np.isclose(ccw_fix .vnormals, vnormals)) assert np.all(np.isclose(ccw_fix .vnormals, vnormals))
# Test standalone calcFaceNormals/
# calcVertexNormals functions
assert np.all(np.isclose(
-fnormals, fslmesh.calcFaceNormals(verts, triangles_cw)))
assert np.all(np.isclose(
fnormals, fslmesh.calcFaceNormals(verts, triangles_ccw)))
assert np.all(np.isclose(
-vnormals, fslmesh.calcVertexNormals(verts, triangles_cw, -fnormals)))
assert np.all(np.isclose(
vnormals, fslmesh.calcVertexNormals(verts, triangles_ccw, fnormals)))
def test_needsFixing():
verts = np.array(CUBE_VERTICES)
tris_cw = np.array(CUBE_TRIANGLES_CW)
tris_ccw = np.array(CUBE_TRIANGLES_CCW)
fnormals = np.array(CUBE_CCW_VERTEX_NORMALS)
blo = verts.min(axis=0)
bhi = verts.max(axis=0)
assert not fslmesh.needsFixing(verts, tris_ccw, fnormals, blo, bhi)
assert fslmesh.needsFixing(verts, tris_cw, -fnormals, blo, bhi)
def test_trimesh_no_trimesh(): def test_trimesh_no_trimesh():
testbase = 'test_mesh.vtk' verts = np.array(CUBE_VERTICES)
testfile = op.join(datadir, testbase) tris = np.array(CUBE_TRIANGLES_CCW)
mods = ['trimesh', 'rtree'] mods = ['trimesh', 'rtree']
for mod in mods: for mod in mods:
with mock.patch.dict('sys.modules', **{mod : None}): with mock.patch.dict('sys.modules', **{mod : None}):
mesh = fslmesh.TriangleMesh(testfile)
mesh = fslmesh.Mesh(tris, vertices=verts)
assert mesh.trimesh() is None assert mesh.trimesh() is None
locs, tris = mesh.rayIntersection([[0, 0, 0]], [[0, 0, 1]]) locs, tris = mesh.rayIntersection([[0, 0, 0]], [[0, 0, 1]])
assert locs.size == 0 assert locs.size == 0
assert tris.size == 0 assert tris.size == 0
verts, idxs, dists = mesh.nearestVertex([[0, 0, 0]]) nverts, idxs, dists = mesh.nearestVertex([[0, 0, 0]])
assert verts.size == 0 assert nverts.size == 0
assert idxs.size == 0 assert idxs.size == 0
assert dists.size == 0 assert dists.size == 0
...@@ -241,9 +220,10 @@ def test_trimesh(): ...@@ -241,9 +220,10 @@ def test_trimesh():
import trimesh import trimesh
testbase = 'test_mesh.vtk' verts = np.array(CUBE_VERTICES)
testfile = op.join(datadir, testbase) tris = np.array(CUBE_TRIANGLES_CCW)
mesh = fslmesh.TriangleMesh(testfile)
mesh = fslmesh.Mesh(tris, vertices=verts)
assert isinstance(mesh.trimesh(), trimesh.Trimesh) assert isinstance(mesh.trimesh(), trimesh.Trimesh)
...@@ -251,7 +231,7 @@ def test_rayIntersection(): ...@@ -251,7 +231,7 @@ def test_rayIntersection():
verts = np.array(CUBE_VERTICES) verts = np.array(CUBE_VERTICES)
triangles = np.array(CUBE_TRIANGLES_CCW) triangles = np.array(CUBE_TRIANGLES_CCW)
mesh = fslmesh.TriangleMesh(verts, triangles) mesh = fslmesh.Mesh(triangles, vertices=verts)
for axis in range(3): for axis in range(3):
rayOrigin = [0, 0, 0] rayOrigin = [0, 0, 0]
...@@ -279,7 +259,7 @@ def test_nearestVertex(): ...@@ -279,7 +259,7 @@ def test_nearestVertex():
verts = np.array(CUBE_VERTICES) verts = np.array(CUBE_VERTICES)
triangles = np.array(CUBE_TRIANGLES_CCW) triangles = np.array(CUBE_TRIANGLES_CCW)
mesh = fslmesh.TriangleMesh(verts, triangles) mesh = fslmesh.Mesh(triangles, vertices=verts)
nverts, nidxs, ndists = mesh.nearestVertex(verts * 2) nverts, nidxs, ndists = mesh.nearestVertex(verts * 2)
...@@ -292,7 +272,7 @@ def test_planeIntersection(): ...@@ -292,7 +272,7 @@ def test_planeIntersection():
verts = np.array(CUBE_VERTICES) verts = np.array(CUBE_VERTICES)
triangles = np.array(CUBE_TRIANGLES_CCW) triangles = np.array(CUBE_TRIANGLES_CCW)
mesh = fslmesh.TriangleMesh(verts, triangles) mesh = fslmesh.Mesh(triangles, vertices=verts)
normal = [0, 0, 1] normal = [0, 0, 1]
origin = [0, 0, 0] origin = [0, 0, 0]
...@@ -357,3 +337,14 @@ def test_planeIntersection(): ...@@ -357,3 +337,14 @@ def test_planeIntersection():
assert np.all(np.isclose(lines, expLines)) assert np.all(np.isclose(lines, expLines))
assert np.all(np.isclose(faces, expFaces)) assert np.all(np.isclose(faces, expFaces))
assert np.all(np.isclose(dists, expDists)) assert np.all(np.isclose(dists, expDists))
normal = [0, 0, 1]
origin = [3, 3, 3]
lines, faces, dists = mesh.planeIntersection(normal,
origin,
distances=True)
assert lines.shape == (0, 2, 3)
assert faces.shape == (0, )
assert dists.shape == (0, 2, 3)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment