From 0467986e2c2047a48cf65613b39da8e91d6186a7 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauldmccarthy@gmail.com> Date: Tue, 23 Jan 2018 08:44:48 +0000 Subject: [PATCH] New Mesh.loadVertices method. Mesh.vertices only raises a notification if the vertex set changes. --- fsl/data/freesurfer.py | 26 ++++++++++++++++++++++++++ fsl/data/gifti.py | 32 +++++++++++++++++++++++++++++--- fsl/data/mesh.py | 42 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 5 deletions(-) diff --git a/fsl/data/freesurfer.py b/fsl/data/freesurfer.py index 029274eab..23622047b 100644 --- a/fsl/data/freesurfer.py +++ b/fsl/data/freesurfer.py @@ -104,6 +104,32 @@ class FreesurferMesh(fslmesh.Mesh): self.addVertices(verts, f, select=False) + def loadVertices(self, infile, key=None, **kwargs): + """Overrides :meth:`.Mesh.loadVertices`. If the given ``infile`` + looks like a Freesurfer file, it is loaded via + ``nibabel.freesurfer.load_geometry``. Otherwise, it is passed to + :meth:`.Mesh.loadVertices`. + """ + if not fslpath.hasExt(infile, GEOMETRY_EXTENSIONS): + return fslmesh.Mesh.loadVertices( + self, infile, key, **kwargs) + + infile = op.abspath(infile) + if key is None: + key = infile + + # TODO merge metadata + vertices, indices, meta, comment = nibfs.read_geometry( + infile, + read_metadata=True, + read_stamp=True) + + vertices = vertices.reshape(self.vertices.shape) + self.addVertices(vertices, key, **kwargs) + + return vertices + + def loadVertexData(self, infile, key=None): """Overrides :meth:`.Mesh.loadVertexData`. If the given ``infile`` looks like a Freesurfer file, it is loaded via the diff --git a/fsl/data/gifti.py b/fsl/data/gifti.py index c8ddd0685..d83d9b430 100644 --- a/fsl/data/gifti.py +++ b/fsl/data/gifti.py @@ -104,12 +104,38 @@ class GiftiMesh(fslmesh.Mesh): self.setMeta( sfile, surfimg) + def loadVertices(self, infile, key=None, *args, **kwargs): + """Overrides the :meth:`.Mesh.loadVertices` method. + + Attempts to load vertices for this ``GiftiMesh`` from the given + ``infile``, which may be a GIFTI file or a plain text file containing + vertices. + """ + + if not infile.endswith('.gii'): + return fslmesh.Mesh.loadVertices( + self, infile, key, *args, **kwargs) + + infile = op.abspath(infile) + + if key is None: + key = infile + + surfimg, vertices, _ = loadGiftiMesh(infile) + vertices = vertices.reshape(self.vertices.shape[0], 3) + + self.addVertices(vertices, key, *args, **kwargs) + self.setMeta( infile, surfimg) + + return vertices + + def loadVertexData(self, infile, key=None): - """Overrides the :meth:`.TriangleMesh.loadVertexData` method. + """Overrides the :meth:`.Mesh.loadVertexData` method. Attempts to load data associated with each vertex of this - ``GiftiMesh`` from the given ``dataSource``, which may be - a GIFTI file or a plain text file which contains vertex data. + ``GiftiMesh`` from the given ``infile``, which may be a GIFTI file or + a plain text file which contains vertex data. """ infile = op.abspath(infile) diff --git a/fsl/data/mesh.py b/fsl/data/mesh.py index 3abf6f695..01b6cf40d 100644 --- a/fsl/data/mesh.py +++ b/fsl/data/mesh.py @@ -91,6 +91,7 @@ class Mesh(notifier.Notifier, meta.Meta): .. autosummary:: :nosignatures: + loadVertices addVertices selectedVertices vertexSets @@ -253,14 +254,19 @@ class Mesh(notifier.Notifier, meta.Meta): def vertices(self, key): """Select the current vertex set - a ``KeyError`` is raised if no vertex set with the specified ``key`` has been added. + + When the current vertex set is changed, a notification is emitted + through the :class:`.Notifier` interface, with the topic + ``'vertices'``. """ # Force a key error if # the key is invalid self.__vertices[key] - self.__selected = key - self.notify(topic='vertices') + if self.__selected != key: + self.__selected = key + self.notify(topic='vertices') @property @@ -320,6 +326,36 @@ class Mesh(notifier.Notifier, meta.Meta): return lo, hi + def loadVertices(self, infile, key=None, **kwargs): + """Loads vertex data from the given ``infile``, and adds it as a vertex + set with the given ``key``. This implementation supports loading vertex + data from white-space delimited text files via ``numpy.loadtxt``, but + sub-classes may override this method to support additional file types. + + + :arg infile: File to load data from. + + :arg key: Key to pass to :meth:`addVertices`. If not provided, + set to ``infile`` (converted to an absolute path) + + All of the other arguments are passed through to :meth:`addVertices`. + + :returns: The loaded vertices. + """ + + infile = op.abspath(infile) + + if key is None: + key = infile + + vertices = np.loadtxt(infile) + vertices = vertices.reshape(self.vertices.shape) + + self.addVertices(vertices, key, **kwargs) + + return vertices + + def addVertices(self, vertices, key=None, select=True, fixWinding=False): """Adds a set of vertices to this ``Mesh``. @@ -387,6 +423,8 @@ class Mesh(notifier.Notifier, meta.Meta): :arg key: Key to pass to :meth:`addVertexData`. If not provided, set to ``infile`` (converted to an absolute path) + + :returns: The loaded vertex data. """ infile = op.abspath(infile) -- GitLab