Commit f7b5fc4d6a0a17b0359510217568644ca344dc5a

Authored by Thiago Franco de Moraes
1 parent 071dff96
Exists in interactor_style

Created a new interactor style to handle the cross tool

invesalius/data/styles.py
... ... @@ -19,8 +19,145 @@
19 19  
20 20 import vtk
21 21  
  22 +from wx.lib.pubsub import pub as Publisher
  23 +
22 24 import constants as const
23 25  
  26 +class ZoomInteractorStyle(vtk.vtkInteractorStyleImage):
  27 + """
  28 + Interactor style responsible for zoom the camera.
  29 + """
  30 + def __init__(self):
  31 + self.right_pressed = False
  32 +
  33 + # Zoom using right button
  34 + self.AddObserver("RightButtonPressEvent",self.OnZoomRightClick)
  35 + self.AddObserver("MouseMoveEvent", self.OnZoomRightMove)
  36 + self.AddObserver("RightButtonReleaseEvent", self.OnZoomRightRelease)
  37 +
  38 + def OnZoomRightMove(self, evt, obj):
  39 + if (self.right_pressed):
  40 + evt.Dolly()
  41 + evt.OnRightButtonDown()
  42 +
  43 + def OnZoomRightClick(self, evt, obj):
  44 + self.right_pressed = 1
  45 + evt.StartDolly()
  46 +
  47 + def OnZoomRightRelease(self, evt, obj):
  48 + self.right_pressed = False
  49 +
  50 +class CrossInteractorStyle(ZoomInteractorStyle):
  51 + """
  52 + Interactor style responsible for the Cross.
  53 + """
  54 + def __init__(self, orientation, slice_data):
  55 + ZoomInteractorStyle.__init__(self)
  56 +
  57 + self.orientation = orientation
  58 + self.slice_actor = slice_data.actor
  59 + self.slice_data = slice_data
  60 +
  61 + self.left_pressed = False
  62 + self.picker = vtk.vtkWorldPointPicker()
  63 +
  64 + self.AddObserver("MouseMoveEvent", self.OnCrossMove)
  65 + self.AddObserver("LeftButtonPressEvent", self.OnCrossMouseClick)
  66 + self.AddObserver("LeftButtonReleaseEvent", self.OnReleaseLeftButton)
  67 +
  68 + def OnCrossMouseClick(self, obj, evt):
  69 + self.left_pressed = True
  70 + iren = obj.GetInteractor()
  71 + self.ChangeCrossPosition(iren)
  72 +
  73 + def OnCrossMove(self, obj, evt):
  74 + # The user moved the mouse with left button pressed
  75 + if self.left_pressed:
  76 + print "OnCrossMove interactor style"
  77 + iren = obj.GetInteractor()
  78 + self.ChangeCrossPosition(iren)
  79 +
  80 + def OnReleaseLeftButton(self, obj, evt):
  81 + self.left_pressed = False
  82 +
  83 + def ChangeCrossPosition(self, iren):
  84 + mouse_x, mouse_y = iren.GetEventPosition()
  85 + ren = iren.GetRenderWindow().GetRenderers().GetFirstRenderer()
  86 + self.picker.Pick(mouse_x, mouse_y, 0, ren)
  87 +
  88 + # Get in what slice data the click occurred
  89 + # pick to get click position in the 3d world
  90 + coord_cross = self.get_coordinate_cursor()
  91 + position = self.slice_actor.GetInput().FindPoint(coord_cross)
  92 + # Forcing focal point to be setted in the center of the pixel.
  93 + coord_cross = self.slice_actor.GetInput().GetPoint(position)
  94 +
  95 + coord = self.calcultate_scroll_position(position)
  96 + self.ScrollSlice(coord)
  97 +
  98 + Publisher.sendMessage('Update cross position', coord_cross)
  99 + Publisher.sendMessage('Set ball reference position based on bound',
  100 + coord_cross)
  101 + Publisher.sendMessage('Set camera in volume', coord_cross)
  102 + Publisher.sendMessage('Render volume viewer')
  103 +
  104 + iren.Render()
  105 +
  106 + def get_coordinate_cursor(self):
  107 + # Find position
  108 + x, y, z = self.picker.GetPickPosition()
  109 + bounds = self.slice_actor.GetBounds()
  110 + if bounds[0] == bounds[1]:
  111 + x = bounds[0]
  112 + elif bounds[2] == bounds[3]:
  113 + y = bounds[2]
  114 + elif bounds[4] == bounds[5]:
  115 + z = bounds[4]
  116 + return x, y, z
  117 +
  118 + def calcultate_scroll_position(self, position):
  119 + # Based in the given coord (x, y, z), returns a list with the scroll positions for each
  120 + # orientation, being the first position the sagital, second the coronal
  121 + # and the last, axial.
  122 +
  123 + if self.orientation == 'AXIAL':
  124 + image_width = self.slice_actor.GetInput().GetDimensions()[0]
  125 + axial = self.slice_data.number
  126 + coronal = position / image_width
  127 + sagital = position % image_width
  128 +
  129 + elif self.orientation == 'CORONAL':
  130 + image_width = self.slice_actor.GetInput().GetDimensions()[0]
  131 + axial = position / image_width
  132 + coronal = self.slice_data.number
  133 + sagital = position % image_width
  134 +
  135 + elif self.orientation == 'SAGITAL':
  136 + image_width = self.slice_actor.GetInput().GetDimensions()[1]
  137 + axial = position / image_width
  138 + coronal = position % image_width
  139 + sagital = self.slice_data.number
  140 +
  141 + return sagital, coronal, axial
  142 +
  143 + def ScrollSlice(self, coord):
  144 + if self.orientation == "AXIAL":
  145 + Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
  146 + coord[0])
  147 + Publisher.sendMessage(('Set scroll position', 'CORONAL'),
  148 + coord[1])
  149 + elif self.orientation == "SAGITAL":
  150 + Publisher.sendMessage(('Set scroll position', 'AXIAL'),
  151 + coord[2])
  152 + Publisher.sendMessage(('Set scroll position', 'CORONAL'),
  153 + coord[1])
  154 + elif self.orientation == "CORONAL":
  155 + Publisher.sendMessage(('Set scroll position', 'AXIAL'),
  156 + coord[2])
  157 + Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
  158 + coord[0])
  159 +
  160 +
24 161 class ViewerStyle:
25 162 def __init__(self):
26 163 self.interactor = None
... ...
invesalius/data/viewer_slice.py
... ... @@ -27,6 +27,8 @@ import numpy
27 27 import vtk
28 28 from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor
29 29  
  30 +import styles
  31 +
30 32 import wx
31 33 from wx.lib.pubsub import pub as Publisher
32 34  
... ... @@ -173,127 +175,142 @@ class Viewer(wx.Panel):
173 175 interactor.SetInteractorStyle(style)
174 176  
175 177 def SetInteractorStyle(self, state):
176   - self.state = state
177   - action = {const.SLICE_STATE_CROSS:
178   - {
179   - "MouseMoveEvent": self.OnCrossMove,
180   - "LeftButtonPressEvent": self.OnCrossMouseClick,
181   - },
182   - const.SLICE_STATE_EDITOR:
183   - {
184   - "MouseMoveEvent": self.OnBrushMove,
185   - "LeftButtonPressEvent": self.OnBrushClick,
186   - "LeftButtonReleaseEvent": self.OnBrushRelease,
187   - "EnterEvent": self.OnEnterInteractor,
188   - "LeaveEvent": self.OnLeaveInteractor
189   - },
190   - const.STATE_PAN:
191   - {
192   - "MouseMoveEvent": self.OnPanMove,
193   - "LeftButtonPressEvent": self.OnPanClick,
194   - "LeftButtonReleaseEvent": self.OnVtkRightRelease
195   - },
196   - const.STATE_SPIN:
197   - {
198   - "MouseMoveEvent": self.OnSpinMove,
199   - "LeftButtonPressEvent": self.OnSpinClick,
200   - "LeftButtonReleaseEvent": self.OnVtkRightRelease
201   - },
202   - const.STATE_ZOOM:
203   - {
204   - "MouseMoveEvent": self.OnZoomMoveLeft,
205   - "LeftButtonPressEvent": self.OnZoomLeftClick,
206   - "LeftButtonReleaseEvent": self.OnVtkRightRelease
207   - },
208   - const.SLICE_STATE_SCROLL:
209   - {
210   - "MouseMoveEvent": self.OnChangeSliceMove,
211   - "LeftButtonPressEvent": self.OnChangeSliceClick,
212   - },
213   - const.STATE_WL:
214   - {
215   - "MouseMoveEvent": self.OnWindowLevelMove,
216   - "LeftButtonPressEvent": self.OnWindowLevelClick,
217   - },
218   - const.STATE_DEFAULT:
219   - {
220   - },
221   - const.STATE_MEASURE_DISTANCE:
222   - {
223   - "LeftButtonPressEvent": self.OnInsertLinearMeasurePoint
224   - },
225   - const.STATE_MEASURE_ANGLE:
226   - {
227   - "LeftButtonPressEvent": self.OnInsertAngularMeasurePoint
228   - },
229   - }
  178 + if state == const.SLICE_STATE_CROSS:
  179 + style = styles.CrossInteractorStyle(self.orientation,
  180 + self.slice_data)
  181 + self.style = style
  182 + self.interactor.SetInteractorStyle(style)
  183 + self.interactor.Render()
230 184  
  185 + ## Zoom using right button
  186 + #style.AddObserver("RightButtonPressEvent",self.OnZoomRightClick)
  187 + #style.AddObserver("MouseMoveEvent", self.OnZoomMoveRight)
  188 + #style.AddObserver("RightButtonReleaseEvent", self.OnVtkRightRelease)
  189 +
  190 + #Scroll change slice
  191 + style.AddObserver("MouseWheelForwardEvent",self.OnScrollForward)
  192 + style.AddObserver("MouseWheelBackwardEvent", self.OnScrollBackward)
231 193  
232   - if state == const.SLICE_STATE_CROSS:
233 194 self.__set_cross_visibility(1)
234 195 Publisher.sendMessage('Activate ball reference')
235 196 else:
236   - self.__set_cross_visibility(0)
237   - Publisher.sendMessage('Deactivate ball reference')
  197 + self.state = state
  198 + action = {
  199 + const.SLICE_STATE_EDITOR:
  200 + {
  201 + "MouseMoveEvent": self.OnBrushMove,
  202 + "LeftButtonPressEvent": self.OnBrushClick,
  203 + "LeftButtonReleaseEvent": self.OnBrushRelease,
  204 + "EnterEvent": self.OnEnterInteractor,
  205 + "LeaveEvent": self.OnLeaveInteractor
  206 + },
  207 + const.STATE_PAN:
  208 + {
  209 + "MouseMoveEvent": self.OnPanMove,
  210 + "LeftButtonPressEvent": self.OnPanClick,
  211 + "LeftButtonReleaseEvent": self.OnVtkRightRelease
  212 + },
  213 + const.STATE_SPIN:
  214 + {
  215 + "MouseMoveEvent": self.OnSpinMove,
  216 + "LeftButtonPressEvent": self.OnSpinClick,
  217 + "LeftButtonReleaseEvent": self.OnVtkRightRelease
  218 + },
  219 + const.STATE_ZOOM:
  220 + {
  221 + "MouseMoveEvent": self.OnZoomMoveLeft,
  222 + "LeftButtonPressEvent": self.OnZoomLeftClick,
  223 + "LeftButtonReleaseEvent": self.OnVtkRightRelease
  224 + },
  225 + const.SLICE_STATE_SCROLL:
  226 + {
  227 + "MouseMoveEvent": self.OnChangeSliceMove,
  228 + "LeftButtonPressEvent": self.OnChangeSliceClick,
  229 + },
  230 + const.STATE_WL:
  231 + {
  232 + "MouseMoveEvent": self.OnWindowLevelMove,
  233 + "LeftButtonPressEvent": self.OnWindowLevelClick,
  234 + },
  235 + const.STATE_DEFAULT:
  236 + {
  237 + },
  238 + const.STATE_MEASURE_DISTANCE:
  239 + {
  240 + "LeftButtonPressEvent": self.OnInsertLinearMeasurePoint
  241 + },
  242 + const.STATE_MEASURE_ANGLE:
  243 + {
  244 + "LeftButtonPressEvent": self.OnInsertAngularMeasurePoint
  245 + },
  246 + }
  247 +
  248 +
  249 + if state == const.SLICE_STATE_CROSS:
  250 + self.__set_cross_visibility(1)
  251 + Publisher.sendMessage('Activate ball reference')
  252 + else:
  253 + self.__set_cross_visibility(0)
  254 + Publisher.sendMessage('Deactivate ball reference')
238 255  
239   - if state == const.STATE_WL:
240   - self.on_wl = True
241   - self.wl_text.Show()
242   - else:
243   - self.on_wl = False
244   - self.wl_text.Hide()
  256 + if state == const.STATE_WL:
  257 + self.on_wl = True
  258 + self.wl_text.Show()
  259 + else:
  260 + self.on_wl = False
  261 + self.wl_text.Hide()
245 262  
246   - self.__set_editor_cursor_visibility(0)
247   -
248   - # Bind method according to current mode
249   - if(state == const.STATE_ZOOM_SL):
250   - style = vtk.vtkInteractorStyleRubberBandZoom()
  263 + self.__set_editor_cursor_visibility(0)
  264 +
  265 + # Bind method according to current mode
  266 + if(state == const.STATE_ZOOM_SL):
  267 + style = vtk.vtkInteractorStyleRubberBandZoom()
251 268  
252   - style.AddObserver("RightButtonPressEvent", self.QuitRubberBandZoom)
253   - #style.AddObserver("RightButtonPressEvent", self.EnterRubberBandZoom)
  269 + style.AddObserver("RightButtonPressEvent", self.QuitRubberBandZoom)
  270 + #style.AddObserver("RightButtonPressEvent", self.EnterRubberBandZoom)
254 271  
255   - else:
256   - style = vtk.vtkInteractorStyleImage()
257   -
258   - # Check each event available for each state
259   - for event in action[state]:
260   - # Bind event
261   - style.AddObserver(event,
262   - action[state][event])
263   -
264   - # Common to all styles
265   - # Mouse Buttons' presses / releases
266   - style.AddObserver("LeftButtonPressEvent", self.OnLeftClick)
267   - style.AddObserver("LeftButtonReleaseEvent", self.OnReleaseLeftButton)
268   - style.AddObserver("RightButtonPressEvent", self.OnRightClick)
269   - style.AddObserver("RightButtonReleaseEvent", self.OnReleaseRightButton)
270   -
271   - # Zoom using right button
272   - style.AddObserver("RightButtonPressEvent",self.OnZoomRightClick)
273   - style.AddObserver("MouseMoveEvent", self.OnZoomMoveRight)
274   - style.AddObserver("RightButtonReleaseEvent", self.OnVtkRightRelease)
275   -
276   - #Scroll change slice
277   - style.AddObserver("MouseWheelForwardEvent",self.OnScrollForward)
278   - style.AddObserver("MouseWheelBackwardEvent", self.OnScrollBackward)
279   -
280   - if ((state == const.STATE_ZOOM) or (state == const.STATE_ZOOM_SL)):
281   - self.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnZoom)
282   - else:
283   - self.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnSpinPan)
  272 + else:
  273 + style = vtk.vtkInteractorStyleImage()
  274 +
  275 + # Check each event available for each state
  276 + for event in action[state]:
  277 + # Bind event
  278 + style.AddObserver(event,
  279 + action[state][event])
  280 +
  281 + # Common to all styles
  282 + # Mouse Buttons' presses / releases
  283 + style.AddObserver("LeftButtonPressEvent", self.OnLeftClick)
  284 + style.AddObserver("LeftButtonReleaseEvent", self.OnReleaseLeftButton)
  285 + style.AddObserver("RightButtonPressEvent", self.OnRightClick)
  286 + style.AddObserver("RightButtonReleaseEvent", self.OnReleaseRightButton)
  287 +
  288 + # Zoom using right button
  289 + style.AddObserver("RightButtonPressEvent",self.OnZoomRightClick)
  290 + style.AddObserver("MouseMoveEvent", self.OnZoomMoveRight)
  291 + style.AddObserver("RightButtonReleaseEvent", self.OnVtkRightRelease)
  292 +
  293 + #Scroll change slice
  294 + style.AddObserver("MouseWheelForwardEvent",self.OnScrollForward)
  295 + style.AddObserver("MouseWheelBackwardEvent", self.OnScrollBackward)
  296 +
  297 + if ((state == const.STATE_ZOOM) or (state == const.STATE_ZOOM_SL)):
  298 + self.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnZoom)
  299 + else:
  300 + self.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnSpinPan)
284 301  
285   - # Measures are using vtkPropPicker because they need to get which actor
286   - # was picked.
287   - if state in (const.STATE_MEASURE_DISTANCE, const.STATE_MEASURE_ANGLE):
288   - self.pick = vtk.vtkPropPicker()
289   - self.interactor.SetPicker(self.pick)
290   - else:
291   - self.pick = vtk.vtkWorldPointPicker()
292   - self.interactor.SetPicker(self.pick)
  302 + # Measures are using vtkPropPicker because they need to get which actor
  303 + # was picked.
  304 + if state in (const.STATE_MEASURE_DISTANCE, const.STATE_MEASURE_ANGLE):
  305 + self.pick = vtk.vtkPropPicker()
  306 + self.interactor.SetPicker(self.pick)
  307 + else:
  308 + self.pick = vtk.vtkWorldPointPicker()
  309 + self.interactor.SetPicker(self.pick)
293 310  
294   - self.style = style
295   - self.interactor.SetInteractorStyle(style)
296   - self.interactor.Render()
  311 + self.style = style
  312 + self.interactor.SetInteractorStyle(style)
  313 + self.interactor.Render()
297 314  
298 315 def QuitRubberBandZoom(self, evt, obj):
299 316 style = vtk.vtkInteractorStyleImage()
... ... @@ -808,37 +825,6 @@ class Viewer(wx.Panel):
808 825 self.slice_.apply_slice_buffer_to_mask(self.orientation)
809 826 self._flush_buffer = False
810 827  
811   - def OnCrossMouseClick(self, evt, obj):
812   - self.ChangeCrossPosition()
813   -
814   - def OnCrossMove(self, evt, obj):
815   - # The user moved the mouse with left button pressed
816   - if self.left_pressed:
817   - self.ChangeCrossPosition()
818   -
819   - def ChangeCrossPosition(self):
820   - mouse_x, mouse_y = self.interactor.GetEventPosition()
821   - renderer = self.slice_data.renderer
822   - self.pick.Pick(mouse_x, mouse_y, 0, renderer)
823   -
824   - # Get in what slice data the click occurred
825   - # pick to get click position in the 3d world
826   - coord_cross = self.get_coordinate_cursor()
827   - position = self.slice_data.actor.GetInput().FindPoint(coord_cross)
828   - # Forcing focal point to be setted in the center of the pixel.
829   - coord_cross = self.slice_data.actor.GetInput().GetPoint(position)
830   -
831   - coord = self.calcultate_scroll_position(position)
832   - self.ScrollSlice(coord)
833   -
834   - Publisher.sendMessage('Update cross position', coord_cross)
835   - Publisher.sendMessage('Set ball reference position based on bound',
836   - coord_cross)
837   - Publisher.sendMessage('Set camera in volume', coord_cross)
838   - Publisher.sendMessage('Render volume viewer')
839   -
840   - self.interactor.Render()
841   -
842 828 def Navigation(self, pubsub_evt):
843 829 # Get point from base change
844 830 x, y, z = pubsub_evt.data
... ...