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
@@ -48,19 +52,22 @@ class H5Geometry(ps.TriangularMesh):
4852 with one or more coordinate sets
4953 """
5054
55+ def __init__ (self , meshes ):
56+ self ._meshes = meshes
57+
5158 @classmethod
5259 def from_filename (klass , pathlike ):
5360 meshes = {}
5461 with h5 .File (pathlike , 'r' ) as h5f :
55- triangles = h5f [ ' topology']
56- for name , coords in h5f ['coordinates' ]. items () :
57- meshes [name ] = (coords , triangles )
62+ triangles = H5ArrayProxy ( pathlike , '/ topology')
63+ for name in h5f ['coordinates' ]:
64+ meshes [name ] = (H5ArrayProxy ( pathlike , f'/coordinates/ { name } ' ) , triangles )
5865 return klass (meshes )
5966
6067 def to_filename (self , pathlike ):
6168 topology = None
6269 coordinates = {}
63- for name , mesh in self .meshes .items ():
70+ for name , mesh in self ._meshes .items ():
6471 coords , faces = mesh
6572 if topology is None :
6673 topology = faces
@@ -69,9 +76,9 @@ def to_filename(self, pathlike):
6976 coordinates [name ] = coords
7077
7178 with h5 .File (pathlike , 'w' ) as h5f :
72- h5f .create_dataset ('/topology' , topology )
79+ h5f .create_dataset ('/topology' , data = topology )
7380 for name , coord in coordinates .items ():
74- h5f .create_dataset (f'/coordinates/{ name } ' , coord )
81+ h5f .create_dataset (f'/coordinates/{ name } ' , data = coord )
7582
7683 def get_coords (self , name = None ):
7784 if name is None :
@@ -139,6 +146,9 @@ def triangles(self):
139146
140147
141148class FreeSurferHemisphere (ps .TriangularMesh ):
149+ def __init__ (self , meshes ):
150+ self ._meshes = meshes
151+
142152 @classmethod
143153 def from_filename (klass , pathlike ):
144154 path = Path (pathlike )
@@ -176,8 +186,26 @@ def get_triangles(self, name=None):
176186
177187 @property
178188 def n_coords (self ):
179- return self .meshes [self ._default ].vnum
189+ return self ._meshes [self ._default ].vnum
180190
181191 @property
182192 def n_triangles (self ):
183- return self .meshes [self ._default ].fnum
193+ return self ._meshes [self ._default ].fnum
194+
195+
196+ def test_FreeSurferHemisphere ():
197+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
198+ assert lh .n_coords == 163842
199+ assert lh .n_triangles == 327680
200+
201+
202+ @skipUnless (has_h5py , reason = 'Test requires h5py' )
203+ def test_make_H5Geometry (tmp_path ):
204+ lh = FreeSurferHemisphere .from_filename (FS_DATA / 'fsaverage/surf/lh.white' )
205+ h5geo = H5Geometry ({name : lh .get_mesh (name ) for name in ('white' , 'pial' )})
206+ h5geo .to_filename (tmp_path / 'geometry.h5' )
207+
208+ rt_h5geo = H5Geometry .from_filename (tmp_path / 'geometry.h5' )
209+ assert set (h5geo ._meshes ) == set (rt_h5geo ._meshes )
210+ assert np .array_equal (lh .get_coords ('white' ), rt_h5geo .get_coords ('white' ))
211+ assert np .array_equal (lh .get_triangles (), rt_h5geo .get_triangles ())
0 commit comments