Skip to content

Commit

Permalink
adds a horizontal slider to slice the volume
Browse files Browse the repository at this point in the history
requires #235 to be fixed to successfully reset on new image loaded
  • Loading branch information
paskino committed Sep 8, 2023
1 parent e34f054 commit f4f24ff
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 1 deletion.
37 changes: 36 additions & 1 deletion Wrappers/Python/ccpi/viewer/CILViewer2D.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from ccpi.viewer.CILViewerBase import CILViewerBase
from ccpi.viewer.utils import Converter

from ccpi.viewer.widgets import cilviewerBoxWidget
from ccpi.viewer.widgets import cilviewerBoxWidget, SliderProperties, SliderCallback


class CILInteractorStyle(vtk.vtkInteractorStyle):
Expand Down Expand Up @@ -1140,6 +1140,10 @@ def __init__(self, dimx=600, dimy=600, ren=None, renWin=None, iren=None, debug=T
self.imageTracer.AutoCloseOn()
self.imageTracer.AddObserver(vtk.vtkWidgetEvent.Select, self.style.OnTracerModifiedEvent, 1.0)

# Slider widget
self.sliderProperty = SliderProperties()
self.sliderWidget = None

self.__vis_mode = CILViewer2D.IMAGE_WITH_OVERLAY
self.setVisualisationToImageWithOverlay()

Expand Down Expand Up @@ -1311,6 +1315,7 @@ def installPipeline(self):
elif self.vis_mode == CILViewer2D.RECTILINEAR_WIPE:
self.installRectilinearWipePipeline()

self.installSliderWidget()
self.ren.ResetCamera()
self.ren.Render()

Expand Down Expand Up @@ -1461,6 +1466,36 @@ def installRectilinearWipePipeline(self):

self.AddActor(wipeSlice, WIPE_ACTOR)

def installSliderWidget(self):
if self.sliderWidget is not None:
self.sliderProperty.value_minimum = 0
self.sliderProperty.value_maximum = self.img3D.GetDimensions()[2] - 1

self.sliderProperty.value_initial = self.getActiveSlice()
return
self.sliderProperty.value_minimum = 0
self.sliderProperty.value_maximum = self.img3D.GetDimensions()[2] - 1

self.sliderProperty.value_initial = self.getActiveSlice()

sw = self.sliderProperty.make_slider_widget()
sw.SetInteractor(self.getInteractor())
sw.SetAnimationModeToAnimate()
sw.EnabledOn()

cb = SliderCallback(self, sw)

# Add interaction observers
sw.AddObserver(vtk.vtkCommand.InteractionEvent, cb)

self.style.AddObserver("MouseWheelForwardEvent", cb.update_from_viewer, 0.9 )
self.style.AddObserver("MouseWheelBackwardEvent", cb.update_from_viewer, 0.9 )
self.style.AddObserver("KeyPressEvent", cb.update_orientation, 0.9 )

# save references
self.sliderWidget = sw
self.sliderCallback = cb

def AdjustCamera(self, resetcamera=False):
self.ren.ResetCameraClippingRange()

Expand Down
1 change: 1 addition & 0 deletions Wrappers/Python/ccpi/viewer/widgets/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .box_widgets import cilviewerBoxWidget, cilviewerLineWidget
from .slider import SliderCallback, SliderProperties
126 changes: 126 additions & 0 deletions Wrappers/Python/ccpi/viewer/widgets/slider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import vtk

class SliderProperties:
tube_width = 0.004
slider_length = 0.025
slider_width = 0.015
end_cap_length = 0.008
end_cap_width = 0.02
title_height = 0.02
label_height = 0.02

value_minimum = 0.0
value_maximum = 1.0
value_initial = 1.0

p1 = [0.12, end_cap_width * 1.1]
p2 = [0.88, end_cap_width * 1.1]

title = None

title_color = 'Black'
label_color = 'White'
value_color = 'White'
value_background_color = 'Black'
slider_color = 'Lime'
selected_color = 'Lime'
bar_color = 'Gray'
bar_ends_color = 'Yellow'


def make_slider_widget(properties):
"""
Make the slider widget based on the properties of this class.
Returns
-------
A configured vtkSliderWidget with its vtkSliderRepresentation2D.
"""
slider = vtk.vtkSliderRepresentation2D()

slider.SetMinimumValue(properties.value_minimum)
slider.SetMaximumValue(properties.value_maximum)
slider.SetValue(properties.value_initial)
slider.SetTitleText(properties.title)

slider.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay()
slider.GetPoint1Coordinate().SetValue(properties.p1[0], properties.p1[1])
slider.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay()
slider.GetPoint2Coordinate().SetValue(properties.p2[0], properties.p2[1])

slider.SetTubeWidth(properties.tube_width)
slider.SetSliderLength(properties.slider_length)
slider.SetSliderWidth(properties.slider_width)
slider.SetEndCapLength(properties.end_cap_length)
slider.SetEndCapWidth(properties.end_cap_width)
slider.SetTitleHeight(properties.title_height)
slider.SetLabelHeight(properties.label_height)

colors = vtk.vtkNamedColors()
# Set the colors of the slider components.
# Change the color of the bar.
slider.GetTubeProperty().SetColor(colors.GetColor3d(properties.bar_color))
# Change the color of the ends of the bar.
slider.GetCapProperty().SetColor(colors.GetColor3d(properties.bar_ends_color))
# Change the color of the knob that slides.
slider.GetSliderProperty().SetColor(colors.GetColor3d(properties.slider_color))
# Change the color of the knob when the mouse is held on it.
slider.GetSelectedProperty().SetColor(colors.GetColor3d(properties.selected_color))
# Change the color of the text displaying the value.
slider.GetLabelProperty().SetColor(colors.GetColor3d(properties.value_color))
slider.GetLabelProperty().SetBackgroundColor(colors.GetColor3d(properties.value_background_color))
slider.GetLabelProperty().ShadowOff()
# Use the one color for the labels.
# slider.GetTitleProperty().SetColor(colors.GetColor3d(properties.label_color))
# Change the color of the text indicating what the slider controls

slider.GetTitleProperty().SetColor(1,1,1)
slider.GetTitleProperty().ShadowOff()

slider_widget = vtk.vtkSliderWidget()
slider_widget.SetRepresentation(slider)

return slider_widget

class SliderCallback:
'''
Class to propagate the effects of interaction between the slider widget and the viewer
the slider is embedded into.
Parameters:
-----------
- viewer, CILViewer2D the slider is embedded into
- slider_widget, the vtkSliderWidget that is embedded in the viewer
'''
def __init__(self, viewer, slider_widget):
self.viewer = viewer
self.slider_widget = slider_widget

def __call__(self, caller, ev):
slider_widget = caller
value = slider_widget.GetRepresentation().GetValue()
self.viewer.displaySlice(int(value))
self.update_label(slider_widget, value)

def update_label(self, slider_widget, value):
rep = slider_widget.GetRepresentation()
maxval = rep.GetMaximumValue()
txt = "Slice {}/{}".format(int(value), int(maxval))
rep.SetLabelFormat(txt)

def update_from_viewer(self, caller, ev):
# The caller is the interactor style
value = caller.GetActiveSlice()
self.slider_widget.GetRepresentation().SetValue(value)
self.update_label(self.slider_widget, value)
caller.GetRenderWindow().Render()

def update_orientation(self, caller, ev):
value = caller.GetActiveSlice()
dims = caller._viewer.img3D.GetDimensions()
maxslice = dims[caller.GetSliceOrientation()] -1
self.slider_widget.GetRepresentation().SetMaximumValue(maxslice)
self.update_from_viewer(caller, ev)

0 comments on commit f4f24ff

Please sign in to comment.