Skip to content
Snippets Groups Projects
Commit 28df70c4 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Xax/yax are passed to all GLObject constructors, so SliceCanvas does not

need to call setAxes after GLObject creation (as this can cause issues
due to asynchronous ImageTexture initialisation). Also, related bugfix
to GLLabel - ready() checks to make sure that shader object has been created
parent c701ee65
No related branches found
No related tags found
No related merge requests found
......@@ -95,21 +95,27 @@ class Annotations(object):
def line(self, *args, **kwargs):
"""Queues a line for drawing - see the :class:`Line` class. """
hold = kwargs.pop('hold', False)
return self.obj(Line(*args, **kwargs), hold)
obj = Line(self.__xax, self.__yax, *args, **kwargs)
return self.obj(obj, hold)
def rect(self, *args, **kwargs):
"""Queues a rectangle for drawing - see the :class:`Rectangle` class.
"""
hold = kwargs.pop('hold', False)
return self.obj(Rect(*args, **kwargs), hold)
obj = Rect(self.__xax, self.__yax, *args, **kwargs)
return self.obj(obj, hold)
def grid(self, *args, **kwargs):
"""Queues a voxel grid for drawing - see the :class:`VoxelGrid` class.
"""
hold = kwargs.pop('hold', False)
return self.obj(VoxelGrid(*args, **kwargs), hold)
obj = VoxelGrid(self.__xax, self.__yax, *args, **kwargs)
return self.obj(obj, hold)
def selection(self, *args, **kwargs):
......@@ -117,7 +123,9 @@ class Annotations(object):
class.
"""
hold = kwargs.pop('hold', False)
return self.obj(VoxelSelection(*args, **kwargs), hold)
obj = VoxelSelection(self.__xax, self.__yax, *args, **kwargs)
return self.obj(obj, hold)
def obj(self, obj, hold=False):
......@@ -236,9 +244,13 @@ class AnnotationObject(globject.GLSimpleObject):
:meth:`globject.GLObject.draw` method.
"""
def __init__(self, xform=None, colour=None, width=None):
def __init__(self, xax, yax, xform=None, colour=None, width=None):
"""Create an ``AnnotationObject``.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
:arg xform: Transformation matrix which will be applied to all
vertex coordinates.
......@@ -246,7 +258,7 @@ class AnnotationObject(globject.GLSimpleObject):
:arg width: Line width to use for the annotation.
"""
globject.GLSimpleObject.__init__(self)
globject.GLSimpleObject.__init__(self, xax, yax)
self.colour = colour
self.width = width
......@@ -269,13 +281,17 @@ class Line(AnnotationObject):
2D line.
"""
def __init__(self, xy1, xy2, *args, **kwargs):
def __init__(self, xax, yax, xy1, xy2, *args, **kwargs):
"""Create a ``Line`` annotation.
The ``xy1`` and ``xy2`` coordinate tuples should be in relation to the
axes which map to the horizontal/vertical screen axes on the target
canvas.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
:arg xy1: Tuple containing the (x, y) coordinates of one endpoint.
:arg xy2: Tuple containing the (x, y) coordinates of the second
......@@ -284,7 +300,7 @@ class Line(AnnotationObject):
All other arguments are passed through to
:meth:`AnnotationObject.__init__`.
"""
AnnotationObject.__init__(self, *args, **kwargs)
AnnotationObject.__init__(self, xax, yax, *args, **kwargs)
self.xy1 = xy1
self.xy2 = xy2
......@@ -310,18 +326,22 @@ class Rect(AnnotationObject):
2D rectangle.
"""
def __init__(self, xy, w, h, *args, **kwargs):
def __init__(self, xax, yax, xy, w, h, *args, **kwargs):
"""Create a :class:`Rect` annotation.
:arg xy: Tuple specifying bottom left of the rectangle, in the display
coordinate system.
:arg w: Rectangle width.
:arg h: Rectangle height.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
:arg xy: Tuple specifying bottom left of the rectangle, in the display
coordinate system.
:arg w: Rectangle width.
:arg h: Rectangle height.
All other arguments are passed through to
:meth:`AnnotationObject.__init__`.
"""
AnnotationObject.__init__(self, *args, **kwargs)
AnnotationObject.__init__(self, xax, yax, *args, **kwargs)
self.xy = xy
self.w = w
self.h = h
......@@ -371,6 +391,8 @@ class VoxelGrid(AnnotationObject):
def __init__(self,
xax,
yax,
selectMask,
displayToVoxMat,
voxToDisplayMat,
......@@ -379,6 +401,10 @@ class VoxelGrid(AnnotationObject):
**kwargs):
"""Create a ``VoxelGrid`` annotation.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
:arg selectMask: A 3D numpy array, the same shape as the image
being annotated (or a sub-space of the image -
see the ``offsets`` argument), which is
......@@ -403,7 +429,7 @@ class VoxelGrid(AnnotationObject):
"""
kwargs['xform'] = voxToDisplayMat
AnnotationObject.__init__(self, *args, **kwargs)
AnnotationObject.__init__(self, xax, yax, *args, **kwargs)
if offsets is None:
offsets = [0, 0, 0]
......@@ -453,6 +479,8 @@ class VoxelSelection(AnnotationObject):
def __init__(self,
xax,
yax,
selection,
displayToVoxMat,
voxToDisplayMat,
......@@ -461,6 +489,10 @@ class VoxelSelection(AnnotationObject):
**kwargs):
"""Create a ``VoxelSelection`` annotation.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
:arg selection: A :class:`.Selection` instance which defines
the voxels to be highlighted.
......@@ -484,7 +516,7 @@ class VoxelSelection(AnnotationObject):
:meth:`AnnotationObject.__init__` method.
"""
AnnotationObject.__init__(self, *args, **kwargs)
AnnotationObject.__init__(self, xax, yax, *args, **kwargs)
if offsets is None:
offsets = [0, 0, 0]
......
......@@ -43,20 +43,25 @@ class GLLabel(globject.GLImageObject):
"""
def __init__(self, image, display):
def __init__(self, image, display, xax, yax):
"""Create a ``GLLabel``.
:arg image: The :class:`.Image` instance.
:arg display: The associated :class:`.Display` instance.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
globject.GLImageObject.__init__(self, image, display)
lutTexName = '{}_lut'.format(self.name)
globject.GLImageObject.__init__(self, image, display, xax, yax)
lutTexName = '{}_lut'.format(self.name)
self.lutTexture = textures.LookupTableTexture(lutTexName)
self.imageTexture = None
# The shader attribute will be created
# by the gllabel_funcs module
self.shader = None
self.addListeners()
self.refreshLutTexture()
......@@ -86,7 +91,9 @@ class GLLabel(globject.GLImageObject):
"""Returns ``True`` if this ``GLLabel`` is ready to be drawn, ``False``
otherwise.
"""
return self.imageTexture is not None and self.imageTexture.ready()
return self.shader is not None and \
self.imageTexture is not None and \
self.imageTexture.ready()
def addListeners(self):
......
......@@ -53,12 +53,13 @@ class GLLineVector(glvector.GLVector):
"""
def __init__(self, image, display):
def __init__(self, image, display, xax, yax):
"""Create a ``GLLineVector`` instance.
:arg image: An :class:`.Image` or :class:`.TensorImage` instance.
:arg display: The associated :class:`.Display` instance.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
# If the overlay is a TensorImage, use the
......@@ -70,6 +71,8 @@ class GLLineVector(glvector.GLVector):
glvector.GLVector.__init__(self,
image,
display,
xax,
yax,
vectorImage=vecImage,
init=lambda: fslgl.gllinevector_funcs.init(
self))
......
......@@ -65,16 +65,20 @@ class GLModel(globject.GLObject):
"""
def __init__(self, overlay, display):
def __init__(self, overlay, display, xax, yax):
"""Create a ``GLModel``.
:arg overlay: A :class:`.Model` overlay.
:arg display: A :class:`.Display` instance defining how the
``overlay`` is to be displayed.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
globject.GLObject.__init__(self)
globject.GLObject.__init__(self, xax, yax)
self.shader = None
self.overlay = overlay
......
......@@ -50,7 +50,7 @@ def getGLObjectType(overlayType):
return typeMap.get(overlayType, None)
def createGLObject(overlay, display):
def createGLObject(overlay, display, xax, yax):
"""Create :class:`GLObject` instance for the given overlay, as specified
by the :attr:`.Display.overlayType` property.
......@@ -58,10 +58,14 @@ def createGLObject(overlay, display):
:arg display: A :class:`.Display` instance describing how the overlay
should be displayed.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
ctr = getGLObjectType(display.overlayType)
if ctr is not None: return ctr(overlay, display)
if ctr is not None: return ctr(overlay, display, xax, yax)
else: return None
......@@ -104,7 +108,11 @@ class GLObject(notifier.Notifier):
Sub-class implementations must do the following:
- Call :meth:`__init__`.
- Call :meth:`__init__`. A ``GLObject.__init__`` sub-class method must
have the following signature::
def __init__(self, overlay, display, xax, yax)
- Call :meth:`notify` whenever its OpenGL representation changes.
......@@ -132,23 +140,26 @@ class GLObject(notifier.Notifier):
"""
def __init__(self):
"""Create a :class:`GLObject`. The constructor adds one attribute
def __init__(self, xax, yax):
"""Create a :class:`GLObject`. The constructor adds one attribute
to this instance, ``name``, which is simply a unique name for this
instance, and gives default values to the ``xax``, ``yax``, and
``zax`` attributes.
instance, and gives values to the ``xax``, ``yax``, and ``zax``
attributes.
Subclass implementations must call this method, and should also
perform any necessary OpenGL initialisation, such as creating
textures.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
# Give this instance a name, and set
# initial values for the display axes
self.name = '{}_{}'.format(type(self).__name__, id(self))
self.xax = 0
self.yax = 1
self.zax = 2
self.xax = xax
self.yax = yax
self.zax = 3 - xax - yax
log.memory('{}.init ({})'.format(type(self).__name__, id(self)))
......@@ -285,9 +296,9 @@ class GLSimpleObject(GLObject):
be called.
"""
def __init__(self):
def __init__(self, xax, yax):
"""Create a ``GLSimpleObject``. """
GLObject.__init__(self)
GLObject.__init__(self, xax, yax)
def ready(self):
......@@ -315,7 +326,7 @@ class GLImageObject(GLObject):
of :class:`.Nifti1` instances.
"""
def __init__(self, image, display):
def __init__(self, image, display, xax, yax):
"""Create a ``GLImageObject``.
This constructor adds the following attributes to this instance:
......@@ -333,9 +344,13 @@ class GLImageObject(GLObject):
:arg image: The :class:`.Nifti1` instance
:arg display: An associated :class:`.Display` instance.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
GLObject.__init__(self)
GLObject.__init__(self, xax, yax)
self.image = image
self.display = display
self.displayOpts = display.getDisplayOpts()
......
......@@ -59,11 +59,13 @@ class GLRGBVector(glvector.GLVector):
"""
def __init__(self, image, display):
def __init__(self, image, display, xax, yax):
"""Create a ``GLRGBVector``.
:arg image: An :class:`.Image` or :class:`.TensorImage` instance.
:arg display: The associated :class:`.Display` instance.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
# If the overlay is a TensorImage, use the
......@@ -75,6 +77,8 @@ class GLRGBVector(glvector.GLVector):
glvector.GLVector.__init__(self,
image,
display,
xax,
yax,
prefilter=np.abs,
vectorImage=vecImage,
init=lambda: fslgl.glrgbvector_funcs.init(
......
......@@ -28,7 +28,7 @@ class GLTensor(glvector.GLVector):
"""
def __init__(self, image, display):
def __init__(self, image, display, xax, yax):
"""Create a ``GLTensor``. Calls the :func:`.gl21.gltensor_funcs.init`
function.
......@@ -36,10 +36,16 @@ class GLTensor(glvector.GLVector):
:arg display: The :class:`.Display` instance associated with the
``image``.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
glvector.GLVector.__init__(self,
image,
display,
xax,
yax,
prefilter=np.abs,
vectorImage=image.V1(),
init=lambda: fslgl.gltensor_funcs.init(
......
......@@ -96,6 +96,8 @@ class GLVector(globject.GLImageObject):
def __init__(self,
image,
display,
xax,
yax,
prefilter=None,
vectorImage=None,
init=None):
......@@ -116,6 +118,10 @@ class GLVector(globject.GLImageObject):
:arg display: A :class:`.Display` object which describes how the
image is to be displayed.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
:arg prefilter: An optional function which filters the data before it
is stored as a 3D texture. See
:class:`.ImageTexture`. Whether or not this function
......@@ -145,7 +151,7 @@ class GLVector(globject.GLImageObject):
raise ValueError('Image must be 4 dimensional, with 3 volumes '
'representing the XYZ vector angles')
globject.GLImageObject.__init__(self, image, display)
globject.GLImageObject.__init__(self, image, display, xax, yax)
name = self.name
......
......@@ -142,16 +142,20 @@ class GLVolume(globject.GLImageObject):
"""
def __init__(self, image, display):
def __init__(self, image, display, xax, yax):
"""Create a ``GLVolume`` object.
:arg image: An :class:`.Image` object.
:arg display: A :class:`.Display` object which describes how the image
is to be displayed.
:arg xax: Initial display X axis
:arg yax: Initial display Y axis
"""
globject.GLImageObject.__init__(self, image, display)
globject.GLImageObject.__init__(self, image, display, xax, yax)
# Add listeners to this image so the view can be
# updated when its display properties are changed
......
......@@ -802,10 +802,12 @@ class SliceCanvas(props.HasProperties):
self._glObjects.pop(overlay)
return
globj = globject.createGLObject(overlay, display)
globj = globject.createGLObject(overlay,
display,
self.xax,
self.yax)
if globj is not None:
globj.setAxes(self.xax, self.yax)
globj.register(self.name, self._refresh)
self._glObjects[overlay] = globj
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment