Slicer  4.11
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
AbstractScriptedSegmentEditorEffect.py
Go to the documentation of this file.
1 import os
2 import vtk, qt, ctk, slicer, logging
3 
4 #
5 # Abstract class of python scripted segment editor effects
6 #
7 
9  """ Abstract scripted segment editor effects for effects implemented in python
10 
11  USAGE:
12  1. Instantiation and registration
13  Instantiate segment editor effect adaptor class from
14  module (e.g. from setup function), and set python source:
15  > import qSlicerSegmentationsEditorEffectsPythonQt as effects
16  > scriptedEffect = effects.qSlicerSegmentEditorScriptedEffect(None)
17  > scriptedEffect.setPythonSource(MyEffect.filePath)
18  > scriptedEffect.self().register()
19  If effect name is added to slicer.modules.segmenteditorscriptedeffectnames
20  list then the above instantiation and registration steps are not necessary,
21  as the SegmentEditor module do all these.
22 
23  2. Call host C++ implementation using
24  > self.scriptedEffect.functionName()
25 
26  2.a. Most frequently used such methods are:
27  Parameter get/set: parameter, integerParameter, doubleParameter, setParameter
28  Add options widget: addOptionsWidget
29  Coordinate transforms: rasToXy, xyzToRas, xyToRas, xyzToIjk, xyToIjk
30  Convenience getters: renderWindow, renderer, viewNode
31 
32  2.b. Always call API functions (the ones that are defined in the adaptor
33  class qSlicerSegmentEditorScriptedEffect) using the adaptor accessor:
34  > self.scriptedEffect.updateGUIFromMRML()
35 
36  3. To prevent deactivation of an effect by clicking place fiducial toolbar button,
37  override interactionNodeModified(self, interactionNode)
38 
39  An example for a generic effect is the ThresholdEffect
40 
41  """
42 
43  def __init__(self, scriptedEffect):
44  self.scriptedEffect = scriptedEffect
45 
46  def register(self):
47  import qSlicerSegmentationsEditorEffectsPythonQt
48  #TODO: For some reason the instance() function cannot be called as a class function although it's static
49  factory = qSlicerSegmentationsEditorEffectsPythonQt.qSlicerSegmentEditorEffectFactory()
50  effectFactorySingleton = factory.instance()
51  effectFactorySingleton.registerEffect(self.scriptedEffect)
52 
53  #
54  # Utility functions for convenient coordinate transformations
55  #
56  def rasToXy(self, ras, viewWidget):
57  rasVector = qt.QVector3D(ras[0], ras[1], ras[2])
58  xyPoint = self.scriptedEffect.rasToXy(rasVector, viewWidget)
59  return [xyPoint.x(), xyPoint.y()]
60 
61  def xyzToRas(self, xyz, viewWidget):
62  xyzVector = qt.QVector3D(xyz[0], xyz[1], xyz[2])
63  rasVector = self.scriptedEffect.xyzToRas(xyzVector, viewWidget)
64  return [rasVector.x(), rasVector.y(), rasVector.z()]
65 
66  def xyToRas(self, xy, viewWidget):
67  xyPoint = qt.QPoint(xy[0], xy[1])
68  rasVector = self.scriptedEffect.xyToRas(xyPoint, viewWidget)
69  return [rasVector.x(), rasVector.y(), rasVector.z()]
70 
71  def xyzToIjk(self, xyz, viewWidget, image, parentTransformNode=None):
72  import vtkSegmentationCorePython as vtkSegmentationCore
73  xyzVector = qt.QVector3D(xyz[0], xyz[1], xyz[2])
74  ijkVector = self.scriptedEffect.xyzToIjk(xyzVector, viewWidget, image, parentTransformNode)
75  return [int(ijkVector.x()), int(ijkVector.y()), int(ijkVector.z())]
76 
77  def xyToIjk(self, xy, viewWidget, image, parentTransformNode=None):
78  import vtkSegmentationCorePython as vtkSegmentationCore
79  xyPoint = qt.QPoint(xy[0], xy[1])
80  ijkVector = self.scriptedEffect.xyToIjk(xyPoint, viewWidget, image, parentTransformNode)
81  return [int(ijkVector.x()), int(ijkVector.y()), int(ijkVector.z())]
82 
83  def setWidgetMinMaxStepFromImageSpacing(self, spinbox, imageData):
84  # Set spinbox minimum, maximum, and step size from vtkImageData spacing:
85  # Set widget minimum spacing and step size to be 1/10th or less than minimum spacing
86  # Set widget minimum spacing to be 100x or more than minimum spacing
87  if not imageData:
88  return
89  import math
90  spinbox.unitAwareProperties &= ~(slicer.qMRMLSpinBox.MinimumValue | slicer.qMRMLSpinBox.MaximumValue | slicer.qMRMLSpinBox.Precision)
91  stepSize = 10**(math.floor(math.log10(min(imageData.GetSpacing())/10.0)))
92  spinbox.minimum = stepSize
93  spinbox.maximum = 10**(math.ceil(math.log10(max(imageData.GetSpacing())*100.0)))
94  spinbox.singleStep = stepSize
95  # number of decimals is set to be able to show the step size (e.g., stepSize = 0.01 => decimals = 2)
96  spinbox.decimals = max(int(-math.floor(math.log10(stepSize))),0)