11from pathlib import Path
2+ from unittest import skipUnless
23
34import numpy as np
45
56from nibabel import pointset as ps
67from nibabel .arrayproxy import ArrayProxy
78from nibabel .optpkg import optional_package
9+ from nibabel .tests .nibabel_data import get_nibabel_data
810
911h5 , has_h5py , _ = optional_package ('h5py' )
1012
13+ FS_DATA = Path (get_nibabel_data ()) / 'nitest-freesurfer'
14+
1115
1216class H5ArrayProxy :
1317 def __init__ (self , file_like , dataset_name ):
@@ -38,7 +42,7 @@ def __array__(self, dtype=None):
3842 with h5 .File (self .file_like , "r" ) as h5f :
3943 return np .asanyarray (h5f [self .dataset_name ], dtype )
4044
41- def __slicer__ (self , slicer ):
45+ def __getitem__ (self , slicer ):
4246 with h5 .File (self .file_like , "r" ) as h5f :
4347 return h5f [self .dataset_name ][slicer ]
4448
@@ -47,19 +51,22 @@ class H5Geometry(ps.TriangularMesh):
4751 """Simple Geometry file structure that combines a single topology
4852 with one or more coordinate sets
4953 """
54+ def __init__ (self , meshes ):
55+ self ._meshes = meshes
56+
5057 @classmethod
5158 def from_filename (klass , pathlike ):
5259 meshes = {}
5360 with h5 .File (pathlike , "r" ) as h5f :
54- triangles = h5f [ ' topology']
55- for name , coords in h5f ['coordinates' ]. items () :
56- meshes [name ] = (coords , triangles )
61+ triangles = H5ArrayProxy ( pathlike , '/ topology')
62+ for name in h5f ['coordinates' ]:
63+ meshes [name ] = (H5ArrayProxy ( pathlike , f'/coordinates/ { name } ' ) , triangles )
5764 return klass (meshes )
5865
5966 def to_filename (self , pathlike ):
6067 topology = None
6168 coordinates = {}
62- for name , mesh in self .meshes .items ():
69+ for name , mesh in self ._meshes .items ():
6370 coords , faces = mesh
6471 if topology is None :
6572 topology = faces
@@ -68,9 +75,9 @@ def to_filename(self, pathlike):
6875 coordinates [name ] = coords
6976
7077 with h5 .File (pathlike , "w" ) as h5f :
71- h5f .create_dataset ("/topology" , topology )
78+ h5f .create_dataset ("/topology" , data = topology )
7279 for name , coord in coordinates .items ():
73- h5f .create_dataset (f"/coordinates/{ name } " , coord )
80+ h5f .create_dataset (f"/coordinates/{ name } " , data = coord )
7481
7582 def get_coords (self , name = None ):
7683 if name is None :
@@ -137,6 +144,9 @@ def triangles(self):
137144
138145
139146class FreeSurferHemisphere (ps .TriangularMesh ):
147+ def __init__ (self , meshes ):
148+ self ._meshes = meshes
149+
140150 @classmethod
141151 def from_filename (klass , pathlike ):
142152 path = Path (pathlike )
@@ -167,8 +177,26 @@ def get_triangles(self, name=None):
167177
168178 @property
169179 def n_coords (self ):
170- return self .meshes [self ._default ].vnum
180+ return self ._meshes [self ._default ].vnum
171181
172182 @property
173183 def n_triangles (self ):
174- return self .meshes [self ._default ].fnum
184+ return self ._meshes [self ._default ].fnum
185+
186+
187+ def test_FreeSurferHemisphere ():
188+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
189+ assert lh .n_coords == 163842
190+ assert lh .n_triangles == 327680
191+
192+
193+ @skipUnless (has_h5py , reason = "Test requires h5py" )
194+ def test_make_H5Geometry (tmp_path ):
195+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
196+ h5geo = H5Geometry ({name : lh .get_mesh (name ) for name in ('white' , 'pial' )})
197+ h5geo .to_filename (tmp_path / "geometry.h5" )
198+
199+ rt_h5geo = H5Geometry .from_filename (tmp_path / "geometry.h5" )
200+ assert set (h5geo ._meshes ) == set (rt_h5geo ._meshes )
201+ assert np .array_equal (lh .get_coords ('white' ), rt_h5geo .get_coords ('white' ))
202+ assert np .array_equal (lh .get_triangles (), rt_h5geo .get_triangles ())
0 commit comments