From 9788dc49ef277833e33bdb0aeb477e7b049b502a Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Mon, 13 Jul 2015 15:12:16 +0100
Subject: [PATCH] New option on GLVolume instances to invert the clipping
 range. Used by ClusterPanel when display z stats. Not implemented in GL14
 yet. New random lut that should have been in previous commit.

---
 fsl/data/strings.py                      |  11 +--
 fsl/fslview/controls/clusterpanel.py     |  12 ++-
 fsl/fslview/displaycontext/volumeopts.py |  10 ++-
 fsl/fslview/gl/gl21/glvolume_frag.glsl   |   9 +-
 fsl/fslview/gl/gl21/glvolume_funcs.py    |   9 +-
 fsl/fslview/gl/glvolume.py               |  50 ++++++------
 fsl/fslview/layouts.py                   |   1 +
 fsl/fslview/luts/random.lut              | 100 +++++++++++++++++++++++
 8 files changed, 165 insertions(+), 37 deletions(-)
 create mode 100644 fsl/fslview/luts/random.lut

diff --git a/fsl/data/strings.py b/fsl/data/strings.py
index 321b1d6e5..15faf8bee 100644
--- a/fsl/data/strings.py
+++ b/fsl/data/strings.py
@@ -349,11 +349,12 @@ properties = TypeDict({
     'ImageOpts.transform'  : 'Image transform',
     'ImageOpts.volume'     : 'Volume',
     
-    'VolumeOpts.displayRange'  : 'Display range',
-    'VolumeOpts.clippingRange' : 'Clipping range',
-    'VolumeOpts.cmap'          : 'Colour map',
-    'VolumeOpts.invert'        : 'Invert colour map',
-    'VolumeOpts.interpolation' : 'Interpolation',
+    'VolumeOpts.displayRange'   : 'Display range',
+    'VolumeOpts.clippingRange'  : 'Clipping range',
+    'VolumeOpts.cmap'           : 'Colour map',
+    'VolumeOpts.invert'         : 'Invert colour map',
+    'VolumeOpts.invertClipping' : 'Invert clipping range',
+    'VolumeOpts.interpolation'  : 'Interpolation',
 
     'MaskOpts.colour'         : 'Colour',
     'MaskOpts.invert'         : 'Invert',
diff --git a/fsl/fslview/controls/clusterpanel.py b/fsl/fslview/controls/clusterpanel.py
index 3b99b1988..20ba3e1a2 100644
--- a/fsl/fslview/controls/clusterpanel.py
+++ b/fsl/fslview/controls/clusterpanel.py
@@ -106,12 +106,18 @@ class ClusterPanel(fslpanel.FSLViewPanel):
         log.debug('Adding Z-statistic {} to overlay list'.format(zstats.name))
         self._overlayList.append(zstats)
 
-        opts   = self._overlayList.getOpts(zstats)
-        zthres = overlay.thresholds()['z']
+        opts   = self._displayCtx.getOpts(zstats)
+        zthres = float(overlay.thresholds()['z'])
         
         if zthres is not None:
+
+            absmax = max(map(abs, (opts.dataMin, opts.dataMax)))
+            
             # Set clipping range
-            pass
+            opts.cmap            = 'Render3'
+            opts.invertClipping  = True 
+            opts.displayRange.x  = -absmax, absmax
+            opts.clippingRange.x = -zthres, zthres
 
     
     def __addClusterMaskClick(self, ev):
diff --git a/fsl/fslview/displaycontext/volumeopts.py b/fsl/fslview/displaycontext/volumeopts.py
index 42c6a6966..e20d3c525 100644
--- a/fsl/fslview/displaycontext/volumeopts.py
+++ b/fsl/fslview/displaycontext/volumeopts.py
@@ -221,7 +221,15 @@ class VolumeOpts(ImageOpts):
     clippingRange = props.Bounds(
         ndims=1,
         labels=[strings.choices['VolumeOpts.displayRange.min'],
-                strings.choices['VolumeOpts.displayRange.max']]) 
+                strings.choices['VolumeOpts.displayRange.max']])
+    """Values outside of this range are not shown."""
+
+    
+    invertClipping = props.Boolean(default=False)
+    """If ``True``, the behaviour of ``clippingRange`` is inverted, i.e.
+    values inside the clipping range are clipped, instead of those outside
+    the clipping range.
+    """
 
     
     cmap = props.ColourMap(default=fslcm.getColourMaps()[0],
diff --git a/fsl/fslview/gl/gl21/glvolume_frag.glsl b/fsl/fslview/gl/gl21/glvolume_frag.glsl
index d24efa14d..98e952ca9 100644
--- a/fsl/fslview/gl/gl21/glvolume_frag.glsl
+++ b/fsl/fslview/gl/gl21/glvolume_frag.glsl
@@ -46,6 +46,12 @@ uniform float clipLow;
  */
 uniform float clipHigh;
 
+/*
+ * Invert clipping behaviour - clip voxels
+ * that are inside the clipLow/High bounds.
+ */
+uniform bool invertClip;
+
 /*
  * Image voxel coordinates.
  */
@@ -85,8 +91,9 @@ void main(void) {
     /*
      * Clip out of range voxel values
      */
-    if (voxValue < clipLow || voxValue > clipHigh) {
       
+    if ((!invertClip && (voxValue <  clipLow || voxValue >  clipHigh)) ||
+        (invertClip  && (voxValue >= clipLow && voxValue <= clipHigh))) {
       gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
       return;
     }
diff --git a/fsl/fslview/gl/gl21/glvolume_funcs.py b/fsl/fslview/gl/gl21/glvolume_funcs.py
index 47884edcb..502f2e6f7 100644
--- a/fsl/fslview/gl/gl21/glvolume_funcs.py
+++ b/fsl/fslview/gl/gl21/glvolume_funcs.py
@@ -81,7 +81,9 @@ def compileShaders(self):
     self.clipLowPos         = gl.glGetUniformLocation(self.shaders,
                                                       'clipLow')
     self.clipHighPos        = gl.glGetUniformLocation(self.shaders,
-                                                      'clipHigh') 
+                                                      'clipHigh')
+    self.invertClipPos      = gl.glGetUniformLocation(self.shaders,
+                                                      'invertClip')
 
 
 def init(self):
@@ -130,8 +132,9 @@ def updateShaderState(self):
         self.imageTexture.invVoxValXform[0, 0] + \
         self.imageTexture.invVoxValXform[3, 0] 
 
-    gl.glUniform1f(self.clipLowPos,  clipLow)
-    gl.glUniform1f(self.clipHighPos, clipHigh)
+    gl.glUniform1f(self.clipLowPos,    clipLow)
+    gl.glUniform1f(self.clipHighPos,   clipHigh)
+    gl.glUniform1f(self.invertClipPos, opts.invertClipping)
 
     # Bind transformation matrices to transform
     # display coordinates to voxel coordinates,
diff --git a/fsl/fslview/gl/glvolume.py b/fsl/fslview/gl/glvolume.py
index 183c44eae..b0ba1d940 100644
--- a/fsl/fslview/gl/glvolume.py
+++ b/fsl/fslview/gl/glvolume.py
@@ -215,18 +215,19 @@ class GLVolume(globject.GLImageObject):
             fslgl.glvolume_funcs.updateShaderState(self)
             self.onUpdate()
 
-        display.addListener(          'softwareMode',  lName, shaderCompile)
-        display.addListener(          'alpha',         lName, colourUpdate)
-        opts   .addListener(          'displayRange',  lName, colourUpdate)
-        opts   .addListener(          'clippingRange', lName, shaderUpdate)
-        opts   .addListener(          'cmap',          lName, colourUpdate)
-        opts   .addListener(          'invert',        lName, colourUpdate)
-        opts   .addListener(          'volume',        lName, imageUpdate)
-        opts   .addListener(          'resolution',    lName, imageUpdate)
-        opts   .addListener(          'interpolation', lName, imageUpdate)
-        opts   .addSyncChangeListener('volume',        lName, imageRefresh)
-        opts   .addSyncChangeListener('resolution',    lName, imageRefresh)
-        opts   .addSyncChangeListener('interpolation', lName, imageRefresh)
+        display.addListener(          'softwareMode',   lName, shaderCompile)
+        display.addListener(          'alpha',          lName, colourUpdate)
+        opts   .addListener(          'displayRange',   lName, colourUpdate)
+        opts   .addListener(          'clippingRange',  lName, shaderUpdate)
+        opts   .addListener(          'invertClipping', lName, shaderUpdate)
+        opts   .addListener(          'cmap',           lName, colourUpdate)
+        opts   .addListener(          'invert',         lName, colourUpdate)
+        opts   .addListener(          'volume',         lName, imageUpdate)
+        opts   .addListener(          'resolution',     lName, imageUpdate)
+        opts   .addListener(          'interpolation',  lName, imageUpdate)
+        opts   .addSyncChangeListener('volume',         lName, imageRefresh)
+        opts   .addSyncChangeListener('resolution',     lName, imageRefresh)
+        opts   .addSyncChangeListener('interpolation',  lName, imageRefresh)
 
 
     def removeDisplayListeners(self):
@@ -239,18 +240,19 @@ class GLVolume(globject.GLImageObject):
 
         lName = self.name
         
-        display.removeListener(          'softwareMode',  lName)
-        display.removeListener(          'alpha',         lName)
-        opts   .removeListener(          'displayRange',  lName)
-        opts   .removeListener(          'clippingRange', lName)
-        opts   .removeListener(          'cmap',          lName)
-        opts   .removeListener(          'invert',        lName)
-        opts   .removeListener(          'volume',        lName)
-        opts   .removeListener(          'resolution',    lName)
-        opts   .removeListener(          'interpolation', lName)
-        opts   .removeSyncChangeListener('volume',        lName)
-        opts   .removeSyncChangeListener('resolution',    lName)
-        opts   .removeSyncChangeListener('interpolation', lName)
+        display.removeListener(          'softwareMode',   lName)
+        display.removeListener(          'alpha',          lName)
+        opts   .removeListener(          'displayRange',   lName)
+        opts   .removeListener(          'clippingRange',  lName)
+        opts   .removeListener(          'invertClipping', lName)
+        opts   .removeListener(          'cmap',           lName)
+        opts   .removeListener(          'invert',         lName)
+        opts   .removeListener(          'volume',         lName)
+        opts   .removeListener(          'resolution',     lName)
+        opts   .removeListener(          'interpolation',  lName)
+        opts   .removeSyncChangeListener('volume',         lName)
+        opts   .removeSyncChangeListener('resolution',     lName)
+        opts   .removeSyncChangeListener('interpolation',  lName)
 
         
     def preDraw(self):
diff --git a/fsl/fslview/layouts.py b/fsl/fslview/layouts.py
index d29316164..d718aa608 100644
--- a/fsl/fslview/layouts.py
+++ b/fsl/fslview/layouts.py
@@ -198,6 +198,7 @@ VolumeOptsLayout = props.VGroup(
      widget(VolumeOpts, 'interpolation'),
      widget(VolumeOpts, 'cmap'),
      widget(VolumeOpts, 'invert'),
+     widget(VolumeOpts, 'invertClipping'),
      widget(VolumeOpts, 'displayRange',  showLimits=False, slider=True),
      widget(VolumeOpts, 'clippingRange', showLimits=False, slider=True)))
 
diff --git a/fsl/fslview/luts/random.lut b/fsl/fslview/luts/random.lut
new file mode 100644
index 000000000..ec8eb804a
--- /dev/null
+++ b/fsl/fslview/luts/random.lut
@@ -0,0 +1,100 @@
+1    0.753957  0.867576  0.271705  1
+2    0.175670  0.556856  0.853074  2
+3    0.616579  0.428308  0.915121  3
+4    0.110243  0.436278  0.131227  4
+5    0.465684  0.976166  0.635108  5
+6    0.825495  0.771942  0.013743  6
+7    0.628049  0.636244  0.519229  7
+8    0.101028  0.565114  0.029126  8
+9    0.418215  0.220175  0.966078  9
+10   0.816653  0.373931  0.401798  10
+11   0.637509  0.120339  0.753382  11
+12   0.585776  0.032367  0.375861  12
+13   0.015209  0.335977  0.181752  13
+14   0.195217  0.360584  0.037638  14
+15   0.540792  0.393421  0.872021  15
+16   0.100611  0.922189  0.970646  16
+17   0.441413  0.720121  0.114097  17
+18   0.054189  0.802448  0.396482  18
+19   0.843831  0.212114  0.126534  19
+20   0.013238  0.661898  0.627306  20
+21   0.520004  0.060818  0.654433  21
+22   0.961100  0.857134  0.091915  22
+23   0.142877  0.869319  0.327252  23
+24   0.973514  0.177186  0.000637  24
+25   0.193389  0.669488  0.079120  25
+26   0.403754  0.632487  0.672783  26
+27   0.294108  0.238623  0.510592  27
+28   0.024675  0.966545  0.173122  28
+29   0.702642  0.120403  0.836783  29
+30   0.843735  0.511668  0.122329  30
+31   0.247394  0.487522  0.760667  31
+32   0.855482  0.534199  0.062248  32
+33   0.950164  0.137868  0.161542  33
+34   0.878682  0.145550  0.423443  34
+35   0.170771  0.538220  0.479534  35
+36   0.163487  0.638112  0.088006  36
+37   0.309358  0.472614  0.939749  37
+38   0.251450  0.852559  0.238243  38
+39   0.322004  0.339350  0.723849  39
+40   0.073325  0.336263  0.243346  40
+41   0.142180  0.275155  0.774014  41
+42   0.418987  0.583517  0.318479  42
+43   0.995191  0.990123  0.965973  43
+44   0.642541  0.758896  0.143941  44
+45   0.834454  0.761811  0.138111  45
+46   0.501360  0.738872  0.998445  46
+47   0.520952  0.734247  0.817867  47
+48   0.108258  0.250040  0.155309  48
+49   0.325019  0.944486  0.010224  49
+50   0.424140  0.102665  0.490829  50
+51   0.370078  0.800670  0.486968  51
+52   0.065647  0.370630  0.369046  52
+53   0.673859  0.336860  0.451118  53
+54   0.896240  0.208660  0.311405  54
+55   0.032992  0.388272  0.141788  55
+56   0.597351  0.525615  0.506587  56
+57   0.956410  0.771918  0.753641  57
+58   0.120402  0.858108  0.991605  58
+59   0.877427  0.082101  0.234755  59
+60   0.477014  0.491835  0.259360  60
+61   0.542788  0.672746  0.682472  61
+62   0.318897  0.978855  0.982079  62
+63   0.086253  0.190322  0.972290  63
+64   0.312732  0.646115  0.808268  64
+65   0.014660  0.166523  0.833427  65
+66   0.606085  0.568510  0.155079  66
+67   0.012467  0.244901  0.116065  67
+68   0.318608  0.668963  0.480013  68
+69   0.306045  0.464696  0.394668  69
+70   0.379937  0.371335  0.764122  70
+71   0.745970  0.730465  0.745599  71
+72   0.904569  0.522597  0.279317  72
+73   0.217184  0.694758  0.909990  73
+74   0.750476  0.633568  0.058840  74
+75   0.844020  0.863140  0.462612  75
+76   0.281654  0.832169  0.510462  76
+77   0.425268  0.686997  0.222606  77
+78   0.326425  0.540490  0.280333  78
+79   0.590842  0.528112  0.636941  79
+80   0.681903  0.369310  0.461865  80
+81   0.860682  0.849561  0.089141  81
+82   0.619122  0.775355  0.780499  82
+83   0.038706  0.201079  0.453245  83
+84   0.094238  0.713224  0.259966  84
+85   0.179885  0.400481  0.529972  85
+86   0.252183  0.183222  0.057824  86
+87   0.983813  0.054503  0.859952  87
+88   0.762208  0.630860  0.404059  88
+89   0.698418  0.577782  0.759200  89
+90   0.543927  0.277553  0.912846  90
+91   0.716609  0.380220  0.050177  91
+92   0.098866  0.533259  0.482783  92
+93   0.509431  0.652996  0.522129  93
+94   0.703915  0.764983  0.865093  94
+95   0.481741  0.000886  0.392668  95
+96   0.345841  0.333430  0.202012  96
+97   0.950121  0.987155  0.160110  97
+98   0.884708  0.861041  0.278094  98
+99   0.653307  0.993621  0.772908  99
+100  0.670894  0.057756  0.683406  100
\ No newline at end of file
-- 
GitLab