From a91e32e77db9fbc961c0daa125fcde8a5bcc0857 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Tue, 19 Jan 2016 15:04:28 +0000 Subject: [PATCH] Slice spacing/zrange values are hopefully set to sensible things when Z axis/display space change. --- fsl/fsleyes/gl/lightboxcanvas.py | 112 ++++++++++++++++++----------- fsl/fsleyes/views/lightboxpanel.py | 30 ++++---- 2 files changed, 88 insertions(+), 54 deletions(-) diff --git a/fsl/fsleyes/gl/lightboxcanvas.py b/fsl/fsleyes/gl/lightboxcanvas.py index 5a9e7f1b4..27a296dd9 100644 --- a/fsl/fsleyes/gl/lightboxcanvas.py +++ b/fsl/fsleyes/gl/lightboxcanvas.py @@ -21,6 +21,7 @@ import fsl.fsleyes.gl.slicecanvas as slicecanvas import fsl.fsleyes.gl.resources as glresources import fsl.fsleyes.gl.routines as glroutines import fsl.fsleyes.gl.textures as textures +import fsl.data.image as fslimage log = logging.getLogger(__name__) @@ -71,6 +72,7 @@ class LightBoxCanvas(slicecanvas.SliceCanvas): canvasToWorld worldToCanvas getTotalRows + calcSliceSpacing """ @@ -232,6 +234,54 @@ class LightBoxCanvas(slicecanvas.SliceCanvas): """Returns the total number of rows that may be displayed. """ return self._totalRows + + def calcSliceSpacing(self, overlay): + """Calculates and returns a Z-axis slice spacing value suitable + for the given overlay. + """ + displayCtx = self.displayCtx + opts = displayCtx.getOpts(overlay) + overlay = displayCtx.getReferenceImage(overlay) + zmin, zmax = opts.bounds.getLimits(self.zax) + + # If the overlay does not have a + # reference NIFTI1 image, choose + # an arbitrary slice spacing. + if overlay is None: return (zmax - zmin) / 50.0 + + # Otherwise return a spacing + # appropriate for the current + # display space + if opts.transform == 'id': return 1 + elif opts.transform == 'pixdim': return overlay.pixdim[self.zax] + elif opts.transform == 'affine': return min(overlay.pixdim[:3]) + + # This overlay is being displayed with a + # custrom transformation matrix - check + # to see what display space we're in + displaySpace = displayCtx.displaySpace + + if isinstance(displaySpace, fslimage.Nifti1): + return self.calcSliceSpacing(displaySpace) + else: + return min(overlay.pixdim[:3]) + + + def _zAxisChanged(self, *a): + """Overrides :meth:`.SliceCanvas._zAxisChanged`. Calls that + method, and then resets the :attr:`sliceSpacing` and :attr:`zrange` + properties to sensible values. + """ + slicecanvas.SliceCanvas._zAxisChanged(self, *a) + + overlay = self.displayCtx.getSelectedOverlay() + + if overlay is None: + return + + self.sliceSpacing = self.calcSliceSpacing(overlay) + self.zrange.x = self.displayCtx.bounds.getRange(self.zax) + def _topRowChanged(self, *a): """Called when the :attr:`topRow` property changes. Adjusts display @@ -346,7 +396,7 @@ class LightBoxCanvas(slicecanvas.SliceCanvas): height == 0: return - self._nslices = int(np.floor(zlen / self.sliceSpacing)) + self._nslices = int(np.ceil(zlen / self.sliceSpacing)) self._totalRows = int(np.ceil(self._nslices / float(self.ncols))) if self._nslices == 0 or self._totalRows == 0: @@ -418,47 +468,29 @@ class LightBoxCanvas(slicecanvas.SliceCanvas): self.setConstraint('zrange', 'minDistance', 0) self.zrange.x = (0, 0) self.sliceSpacing = 0 - else: + return - # Get the new Z range from the - # display context bounding box. - # - # And calculate the minimum possible - # slice spacing - the smallest pixdim - # across all overlays in the list. - newZRange = self.displayCtx.bounds.getRange(self.zax) - newZGap = sys.float_info.max - - for overlay in self.overlayList: + # Get the new Z range from the + # display context bounding box. + # + # And calculate the minimum possible + # slice spacing - the smallest pixdim + # across all overlays in the list. + newZRange = self.displayCtx.bounds.getRange(self.zax) + newZGap = sys.float_info.max - overlay = self.displayCtx.getReferenceImage(overlay) - - if overlay is None: - continue - - opts = self.displayCtx.getOpts(overlay) - - if opts.transform == 'id': - zgap = 1 - elif opts.transform == 'pixdim': - zgap = overlay.pixdim[self.zax] - else: - zgap = min(overlay.pixdim[:3]) - - if zgap < newZGap: - newZGap = zgap - - # If there were no volumetric overlays - # in the overlay list, choose an arbitrary - # default slice spacing - if newZGap == sys.float_info.max: - newZGap = (newZRange[1] - newZRange[0]) / 50.0 - - # Update the zrange and slice - # spacing constraints - self.zrange.setLimits(0, *newZRange) - self.setConstraint('zrange', 'minDistance', newZGap) - self.setConstraint('sliceSpacing', 'minval', newZGap) + for overlay in self.overlayList: + + zgap = self.calcSliceSpacing(overlay) + + if zgap < newZGap: + newZGap = zgap + + # Update the zrange and slice + # spacing constraints + self.zrange.setLimits(0, *newZRange) + self.setConstraint('zrange', 'minDistance', newZGap) + self.setConstraint('sliceSpacing', 'minval', newZGap) def _overlayBoundsChanged(self, *a): diff --git a/fsl/fsleyes/views/lightboxpanel.py b/fsl/fsleyes/views/lightboxpanel.py index 89ff0095e..375a86d55 100644 --- a/fsl/fsleyes/views/lightboxpanel.py +++ b/fsl/fsleyes/views/lightboxpanel.py @@ -261,11 +261,16 @@ class LightBoxPanel(canvaspanel.CanvasPanel): self._name, self.__transformChanged) - # If the current zrange is [0, 0] we'll - # assume that it needs to be initialised. - sceneOpts = self.getSceneOptions() - if sceneOpts.zrange == [0.0, 0.0]: - sceneOpts.zrange = self._displayCtx.bounds.getRange(sceneOpts.zax) + # If the current zrange is [0, 0] + # we'll assume that the spacing/ + # zrange need to be initialised. + lbCanvas = self.__lbCanvas + opts = self.getSceneOptions() + + if opts.zrange == [0.0, 0.0]: + + opts.sliceSpacing = lbCanvas.calcSliceSpacing(selectedOverlay) + opts.zrange = self._displayCtx.bounds.getRange(opts.zax) def __transformChanged(self, *a): @@ -288,15 +293,12 @@ class LightBoxPanel(canvaspanel.CanvasPanel): loBounds = opts.bounds.getLo() hiBounds = opts.bounds.getHi() - if opts.transform == 'id': - sceneOpts.sliceSpacing = 1 - elif opts.transform == 'pixdim': - sceneOpts.sliceSpacing = overlay.pixdim[sceneOpts.zax] - else: - sceneOpts.sliceSpacing = min(overlay.pixdim[sceneOpts.zax]) - - sceneOpts.zrange.x = (loBounds[sceneOpts.zax], - hiBounds[sceneOpts.zax]) + # Reset the spacing/zrange. Not + # sure if this is the best idea, + # but it's here for the time being. + sceneOpts.sliceSpacing = self.__lbCanvas.calcSliceSpacing(overlay) + sceneOpts.zrange.x = (loBounds[sceneOpts.zax], + hiBounds[sceneOpts.zax]) self.__onResize() -- GitLab