Skip to content

Commit 5ded851

Browse files
committed
RF: Drop triangular meshes for now
1 parent c3ba28d commit 5ded851

File tree

2 files changed

+0
-210
lines changed

2 files changed

+0
-210
lines changed

nibabel/pointset.py

-58
Original file line numberDiff line numberDiff line change
@@ -144,64 +144,6 @@ def get_coords(self, *, as_homogeneous: bool = False):
144144
return coords
145145

146146

147-
class TriangularMesh(Pointset):
148-
def __init__(self, mesh):
149-
if isinstance(mesh, tuple) and len(mesh) == 2:
150-
coords, self._triangles = mesh
151-
elif hasattr(mesh, 'coords') and hasattr(mesh, 'triangles'):
152-
coords = mesh.coords
153-
self._triangles = mesh.triangles
154-
elif hasattr(mesh, 'get_mesh'):
155-
coords, self._triangles = mesh.get_mesh()
156-
else:
157-
raise ValueError('Cannot interpret input as triangular mesh')
158-
super().__init__(coords)
159-
160-
@property
161-
def n_triangles(self):
162-
"""Number of faces
163-
164-
Subclasses should override with more efficient implementations.
165-
"""
166-
return self._triangles.shape[0]
167-
168-
def get_triangles(self):
169-
"""Mx3 array of indices into coordinate table"""
170-
return self._triangles
171-
172-
def get_mesh(self, name=None):
173-
return self.get_coords(name=name), self.get_triangles()
174-
175-
def get_names(self):
176-
"""List of surface names that can be passed to
177-
``get_{coords,triangles,mesh}``
178-
"""
179-
raise NotImplementedError
180-
181-
182-
class TriMeshFamily(TriangularMesh):
183-
def __init__(self, mapping, default=None):
184-
self._triangles = None
185-
self._coords = {}
186-
for name, mesh in dict(mapping).items():
187-
coords, triangles = TriangularMesh(mesh).get_mesh()
188-
if self._triangles is None:
189-
self._triangles = triangles
190-
self._coords[name] = coords
191-
192-
if default is None:
193-
default = next(iter(self._coords))
194-
self._default = default
195-
196-
def get_names(self):
197-
return list(self._coords)
198-
199-
def get_coords(self, name=None):
200-
if name is None:
201-
name = self._default
202-
return self._coords[name]
203-
204-
205147
class Grid(Pointset):
206148
r"""A regularly-spaced collection of coordinates
207149

nibabel/tests/test_pointset.py

-152
Original file line numberDiff line numberDiff line change
@@ -182,155 +182,3 @@ def test_to_mask(self):
182182
],
183183
)
184184
assert np.array_equal(mask_img.affine, np.eye(4))
185-
186-
187-
class H5ArrayProxy:
188-
def __init__(self, file_like, dataset_name):
189-
self.file_like = file_like
190-
self.dataset_name = dataset_name
191-
with h5.File(file_like, 'r') as h5f:
192-
arr = h5f[dataset_name]
193-
self._shape = arr.shape
194-
self._dtype = arr.dtype
195-
196-
@property
197-
def is_proxy(self):
198-
return True
199-
200-
@property
201-
def shape(self):
202-
return self._shape
203-
204-
@property
205-
def ndim(self):
206-
return len(self.shape)
207-
208-
@property
209-
def dtype(self):
210-
return self._dtype
211-
212-
def __array__(self, dtype=None):
213-
with h5.File(self.file_like, 'r') as h5f:
214-
return np.asanyarray(h5f[self.dataset_name], dtype)
215-
216-
def __getitem__(self, slicer):
217-
with h5.File(self.file_like, 'r') as h5f:
218-
return h5f[self.dataset_name][slicer]
219-
220-
221-
class H5Geometry(ps.TriMeshFamily):
222-
"""Simple Geometry file structure that combines a single topology
223-
with one or more coordinate sets
224-
"""
225-
226-
@classmethod
227-
def from_filename(klass, pathlike):
228-
meshes = {}
229-
with h5.File(pathlike, 'r') as h5f:
230-
triangles = H5ArrayProxy(pathlike, '/topology')
231-
for name in h5f['coordinates']:
232-
meshes[name] = (H5ArrayProxy(pathlike, f'/coordinates/{name}'), triangles)
233-
return klass(meshes)
234-
235-
def to_filename(self, pathlike):
236-
with h5.File(pathlike, 'w') as h5f:
237-
h5f.create_dataset('/topology', data=self.get_triangles())
238-
for name, coord in self._coords.items():
239-
h5f.create_dataset(f'/coordinates/{name}', data=coord)
240-
241-
242-
class FSGeometryProxy:
243-
def __init__(self, pathlike):
244-
self._file_like = str(Path(pathlike))
245-
self._offset = None
246-
self._vnum = None
247-
self._fnum = None
248-
249-
def _peek(self):
250-
from nibabel.freesurfer.io import _fread3
251-
252-
with open(self._file_like, 'rb') as fobj:
253-
magic = _fread3(fobj)
254-
if magic != 16777214:
255-
raise NotImplementedError('Triangle files only!')
256-
fobj.readline()
257-
fobj.readline()
258-
self._vnum = np.fromfile(fobj, '>i4', 1)[0]
259-
self._fnum = np.fromfile(fobj, '>i4', 1)[0]
260-
self._offset = fobj.tell()
261-
262-
@property
263-
def vnum(self):
264-
if self._vnum is None:
265-
self._peek()
266-
return self._vnum
267-
268-
@property
269-
def fnum(self):
270-
if self._fnum is None:
271-
self._peek()
272-
return self._fnum
273-
274-
@property
275-
def offset(self):
276-
if self._offset is None:
277-
self._peek()
278-
return self._offset
279-
280-
@auto_attr
281-
def coords(self):
282-
ap = ArrayProxy(self._file_like, ((self.vnum, 3), '>f4', self.offset))
283-
ap.order = 'C'
284-
return ap
285-
286-
@auto_attr
287-
def triangles(self):
288-
offset = self.offset + 12 * self.vnum
289-
ap = ArrayProxy(self._file_like, ((self.fnum, 3), '>i4', offset))
290-
ap.order = 'C'
291-
return ap
292-
293-
294-
class FreeSurferHemisphere(ps.TriMeshFamily):
295-
@classmethod
296-
def from_filename(klass, pathlike):
297-
path = Path(pathlike)
298-
hemi, default = path.name.split('.')
299-
mesh_names = (
300-
'orig',
301-
'white',
302-
'smoothwm',
303-
'pial',
304-
'inflated',
305-
'sphere',
306-
'midthickness',
307-
'graymid',
308-
) # Often created
309-
if default not in mesh_names:
310-
mesh_names.append(default)
311-
meshes = {}
312-
for mesh in mesh_names:
313-
fpath = path.parent / f'{hemi}.{mesh}'
314-
if fpath.exists():
315-
meshes[mesh] = FSGeometryProxy(fpath)
316-
hemi = klass(meshes)
317-
hemi._default = default
318-
return hemi
319-
320-
321-
def test_FreeSurferHemisphere():
322-
lh = FreeSurferHemisphere.from_filename(FS_DATA / 'fsaverage/surf/lh.white')
323-
assert lh.n_coords == 163842
324-
assert lh.n_triangles == 327680
325-
326-
327-
@skipUnless(has_h5py, reason='Test requires h5py')
328-
def test_make_H5Geometry(tmp_path):
329-
lh = FreeSurferHemisphere.from_filename(FS_DATA / 'fsaverage/surf/lh.white')
330-
h5geo = H5Geometry({name: lh.get_mesh(name) for name in ('white', 'pial')})
331-
h5geo.to_filename(tmp_path / 'geometry.h5')
332-
333-
rt_h5geo = H5Geometry.from_filename(tmp_path / 'geometry.h5')
334-
assert set(h5geo._coords) == set(rt_h5geo._coords)
335-
assert np.array_equal(lh.get_coords('white'), rt_h5geo.get_coords('white'))
336-
assert np.array_equal(lh.get_triangles(), rt_h5geo.get_triangles())

0 commit comments

Comments
 (0)