Commit 8d9b272f2af829d286c946d1e9cd0a2d5bf25e8c

Authored by Thiago Franco de Moraes
1 parent 071dff96

Created InteractorStyles to handle the interactivity in the viewer_slice

The idea is each interactivity and functionality being implemented as
InteractorStyles. In this branch I created InteractorStyles to handle:
zoom, WW & WL, edition, pan, spin, linear measure and angular measure.

I created a pattern, each InteractorStyle receives as parameter only a
viewer_slice. And a InteractorStyle may create a SetUp and a CleanUp
methods. The SetUp method runs after the creation of the InteractorStyle
and can be used to prepare the ground before the InteractorStyle be
used. The CleanUp method can be used to cleans and unset anything used
during the InteractorStyle use.

This idea can be used in the future to give InVesalius the feature to
run pluggins.

Squashed commit of the following:

commit c48e9290dc91009cf00dc3def692e51c6cebe3e0
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Thu Mar 28 09:18:11 2013 -0300

    Starting with the ww and wl text hidden

commit 5c9a305f4c9821327fb47594a4833f0def899be8
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Wed Mar 27 17:02:37 2013 -0300

    Created a protocol to setup and cleanup when a style is setted

commit b557c29890e70ba1337cd59bf54b29c7f1d2f11e
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Wed Mar 27 15:49:04 2013 -0300

    Cleaning unneeded code from data/styles.py

commit 46f4452a1b5c39e826de86c383345df72eeeb9b1
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Wed Mar 27 15:41:41 2013 -0300

    Cleaning code related to vtk events from viewer_slice

commit 4a7add3a2360df5320a9c7c78d49e533c61997c4
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Wed Mar 27 15:23:19 2013 -0300

    The context menu is working again in the viewer_slice.py

commit 6c0a5b4c281b1d79d5d0fc21728c08868cc71bb2
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Wed Mar 27 15:08:39 2013 -0300

    OnBrushRelease was not binded to 'LeftButtonReleaseEvent'

commit 7c998231f939f0552a99ff41c98d1ac3605ce57d
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Wed Mar 27 15:00:48 2013 -0300

    Added get_coordinate_cursor to CrossInteractorStyle

commit 9cbf791e35f212fdf2b10ddf976636fb6581c7e9
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 16:56:37 2013 -0300

    Created a new interactor style to handle the editor

commit 91ea38bc564f284c3994463530e94847ff2d2bd1
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 14:50:16 2013 -0300

    Added a comment to DefaultInteractorStyle

commit b4a359d6ebbd778f9cf4dcb23edeff9f79884344
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 14:47:56 2013 -0300

    Using DefaultInteractorStyle to const.STATE_DEFAULT

commit ea58ed7c4ac5d7e5c640a49ccce5368e82dea611
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 14:43:20 2013 -0300

    Renamed RightZoomInteractorStyle to DefaultInteractorStyle

commit b7ec9d2e436da10570ecbcf7f25ca32213200872
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 14:19:29 2013 -0300

    Added MouseWheelForwardEvent and MouseWheelBackwardEvent to the RightZoomInteractorStyle

commit 13b7b7ff758a45cf9e89b9ddbcdd190b2de8a8b9
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 14:07:01 2013 -0300

    Passing the viewer to all interactor styles

commit 89d8c6172efeec81359417a1943175968701204a
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 10:25:18 2013 -0300

    Created a new interactor style to change slices with the mouse movement

commit 88fe930f156968916c77b789a5acfded93bd4988
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 09:32:37 2013 -0300

    Cleaning unneeded code related to the zoom

commit 58ec7c3a2b56db90ad6ca5fc06da8df731481634
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 09:26:31 2013 -0300

    Created a new interactor style to handle the Zoom camera by selecting a region

commit 4df1d0612d7041ac2ecc27173483a79dc32b9bec
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Tue Mar 26 09:12:00 2013 -0300

    Created a new interactor style to handle the Zoom camera

commit 2ae6b47162dc63a104edcbd6bb398702642c6d08
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Mon Mar 25 16:32:13 2013 -0300

    Renamed ZoomInteractorStyle to RighZoomInteractorStyle

commit 96dd7511bbbd28c9161dea9c3e2bc466be2646fe
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Mon Mar 25 16:25:55 2013 -0300

    Created a method to reset camera after a span camera

commit 1a85e2a409c9278c6fabae045fbf33a6bc25900f
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Mon Mar 25 16:01:14 2013 -0300

    Created a new interactor style to handle the Spin camera

commit 354f97e80f0f917cc825554b4cf077bbd410a15b
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Mon Mar 25 14:55:46 2013 -0300

    STYLE: Renamed the class LinearMeasure and AngularMeasure

commit 87eacea8d9d7b2a460a8156b45c372fa8d6a32f4
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Fri Mar 22 16:53:16 2013 -0300

    Created a new interactor style to the pan

commit fd6166669bb91315308844a461bd7b8d579f4e79
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Fri Mar 22 16:42:25 2013 -0300

    Removed code which handle angular measurements from viewer_slice

commit 3eeb17e13d68e4b08a88cbff283a3c6e9995d92b
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Fri Mar 22 16:40:16 2013 -0300

    Fix in a comment

commit 3ecbb5f87d2bdd3e343e3db26cc4298285e258fc
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Fri Mar 22 16:38:50 2013 -0300

    Created a new interactor style to handle angular measurements

commit aefd974a410622be9d300330702a99e5b76a51f4
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Fri Mar 22 14:43:05 2013 -0300

    Created a new interactor style to handle Linear measure

commit 13f819f768cfbf96681f14da0f5f253878c12f16
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Fri Mar 22 10:52:45 2013 -0300

    Created a new interactor style to handle Window level & width

commit f7b5fc4d6a0a17b0359510217568644ca344dc5a
Author: Thiago Franco de Moraes <totonixsame@gmail.com>
Date:   Thu Mar 21 15:40:43 2013 -0300

    Created a new interactor style to handle the cross tool
invesalius/data/styles.py
... ... @@ -18,182 +18,601 @@
18 18 #--------------------------------------------------------------------------
19 19  
20 20 import vtk
  21 +import wx
  22 +
  23 +from wx.lib.pubsub import pub as Publisher
21 24  
22 25 import constants as const
23 26  
24   -class ViewerStyle:
25   - def __init__(self):
26   - self.interactor = None
27   - self.style = None
28   - self.render = None
29   -
30   - def SetInteractor(self, interactor):
31   -
32   - # Setting style already defined in VTK
33   - if (self.style is None):
34   - self.style = vtk.vtkInteractorStyle()
35   - #self.style.SetInteractor(interactor)
36   - self.SetStyleConfig()
37   - interactor.SetInteractorStyle(style)
38   -
39   - # Saving data into attributes
40   - self.render = interactor.GetRenderWindow().GetRenderer()
41   - self.interactor = interactor
42   -
43   - # Call events
44   - self.__init_evt()
45   -
46   - def SetStyleConfig(self):
47   - print "calling parent"
48   - pass
49   -
50   - def __init_evt(self):
51   - style = self.style
52   - style.AddObserver("LeftButtonPressEvent", self.OnLeftButtonDown)
53   - style.AddObserver("LeftButtonReleaseEvent", self.OnLeftButtonUp)
54   - style.AddObserver("MiddleButtonPressEvent", self.OnMiddleButtonDown)
55   - style.AddObserver("MiddleButtonReleaseEvent", self.OnMiddleButtonUp)
56   - style.AddObserver("RightButtonPressEvent", self.OnRightButtonDown)
57   - style.AddObserver("RightButtonReleaseEvent", self.OnRightButtonUp)
58   - style.AddObserver("MouseWheelForwardEvent", self.OnScroll)
59   - style.AddObserver("MouseWheelBackwardEvent", self.OnScroll)
60   -
61   - style.AddObserver("MouseMoveEvent",self.OnMouseMove)
62   -
63   - def OnScroll(self, evt, str_evt):
64   - pass
65   -
66   - def OnLeftButtonDown(self, evt, str_evt):
67   - pass
68   -
69   - def OnLeftButtonUp(self, evt, str_evt):
70   - pass
71   -
72   - def OnMiddleButtonDown(self, evt, str_evt):
73   - pass
74   -
75   - def OnMiddleButtonUp(self, evt, str_evt):
76   - pass
77   -
78   - def OnRightButtonDown(self, evt, str_evt):
79   - pass
80   -
81   - def OnRightButtonUp(self, evt, str_evt):
82   - pass
83   -
84   - def OnMouseMove(self, evt, str_evt):
85   - pass
86   -
87   -class ViewerStyleSlice(ViewerStyle):
88   - def __init__(self):
89   - ViewerStyle.__init__(self)
90   - self.orientation = 'AXIAL'
91   -
92   - self.style = vtk.vtkInteractorStyleImage()
93   - self.style.AutoAdjustCameraClippingRangeOn()
94   -
95   - def SetOrientation(self, orientation='AXIAL'):
96   - self.orientation = orientation
97   -
98   - def OnScroll(self, evt, evt_string):
99   - if evt_string == "MouseWheelForwardEvent":
100   - value = 1
101   - else: # elif evt_string =="MouseWheelBackwardEvent":
102   - value = -1
103   - ps.Publisher().sendMessage(('Set scroll position', self.orientation), value)
104   -
105   -class ViewerStyleSliceEditor(ViewerStyleSlice):
  27 +ORIENTATIONS = {
  28 + "AXIAL": const.AXIAL,
  29 + "CORONAL": const.CORONAL,
  30 + "SAGITAL": const.SAGITAL,
  31 + }
106 32  
107   - def __init__(self):
108   - # FIXME: the idea is not using Slice from here...!
109   - #self.slice_ = slc.Slice()
110   -
111   - self.picker = vtk.vtkCellPicker() # define position where user clicked
112   -
113   - self.mouse_pressed = 0 # define if operation will executed run or not
114   -
115   - self.style = const.OP_ADD # define brush operation .OP_DEL, .OP_THRESH
  33 +class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage):
  34 + def __init__(self, viewer):
  35 + self.right_pressed = False
  36 + self.left_pressed = False
116 37  
117   -
118   - def SetData(self, actor_bounds, imagedata_dimensions):
119   - self.pos_converter = ViewerToImagedataPosConverter(actor_bounds,
120   - imagedata_dimensions,
121   - self.renderer)
  38 + self.AddObserver("LeftButtonPressEvent", self.OnPressLeftButton)
  39 + self.AddObserver("LeftButtonReleaseEvent", self.OnReleaseLeftButton)
122 40  
123   - def SetStyleConfig(self):
124   - print "calling son"
125   -
126   - def SetOrientation(self, orient):
127   - pass
  41 + self.AddObserver("RightButtonPressEvent",self.OnPressRightButton)
  42 + self.AddObserver("RightButtonReleaseEvent", self.OnReleaseRightButton)
  43 +
  44 + def OnPressLeftButton(self, evt, obj):
  45 + self.left_pressed = True
  46 +
  47 + def OnReleaseLeftButton(self, evt, obj):
  48 + self.left_pressed = False
  49 +
  50 + def OnPressRightButton(self, evt, obj):
  51 + self.right_pressed = True
  52 + self.viewer.last_position_mouse_move = \
  53 + self.viewer.interactor.GetLastEventPosition()
  54 +
  55 + def OnReleaseRightButton(self, evt, obj):
  56 + self.right_pressed = False
  57 +
  58 +
  59 +class DefaultInteractorStyle(BaseImageInteractorStyle):
  60 + """
  61 + Interactor style responsible for Default functionalities:
  62 + * Zoom moving mouse with right button pressed;
  63 + * Change the slices with the scroll.
  64 + """
  65 + def __init__(self, viewer):
  66 + BaseImageInteractorStyle.__init__(self, viewer)
  67 +
  68 + self.viewer = viewer
  69 +
  70 + # Zoom using right button
  71 + self.AddObserver("RightButtonPressEvent",self.OnZoomRightClick)
  72 + self.AddObserver("MouseMoveEvent", self.OnZoomRightMove)
  73 +
  74 + self.AddObserver("MouseWheelForwardEvent",self.OnScrollForward)
  75 + self.AddObserver("MouseWheelBackwardEvent", self.OnScrollBackward)
  76 +
  77 + def OnZoomRightMove(self, evt, obj):
  78 + if (self.right_pressed):
  79 + evt.Dolly()
  80 + evt.OnRightButtonDown()
  81 +
  82 + def OnZoomRightClick(self, evt, obj):
  83 + evt.StartDolly()
  84 +
  85 + def OnScrollForward(self, evt, obj):
  86 + self.viewer.OnScrollForward()
  87 +
  88 + def OnScrollBackward(self, evt, obj):
  89 + self.viewer.OnScrollBackward()
  90 +
  91 +
  92 +class CrossInteractorStyle(DefaultInteractorStyle):
  93 + """
  94 + Interactor style responsible for the Cross.
  95 + """
  96 + def __init__(self, viewer):
  97 + DefaultInteractorStyle.__init__(self, viewer)
  98 +
  99 + self.viewer = viewer
  100 + self.orientation = viewer.orientation
  101 + self.slice_actor = viewer.slice_data.actor
  102 + self.slice_data = viewer.slice_data
  103 +
  104 + self.picker = vtk.vtkWorldPointPicker()
  105 +
  106 + self.AddObserver("MouseMoveEvent", self.OnCrossMove)
  107 + self.AddObserver("LeftButtonPressEvent", self.OnCrossMouseClick)
  108 + self.AddObserver("LeftButtonReleaseEvent", self.OnReleaseLeftButton)
  109 +
  110 + def SetUp(self):
  111 + self.viewer._set_cross_visibility(1)
  112 +
  113 + def CleanUp(self):
  114 + self.viewer._set_cross_visibility(0)
  115 +
  116 + def OnCrossMouseClick(self, obj, evt):
  117 + iren = obj.GetInteractor()
  118 + self.ChangeCrossPosition(iren)
  119 +
  120 + def OnCrossMove(self, obj, evt):
  121 + # The user moved the mouse with left button pressed
  122 + if self.left_pressed:
  123 + print "OnCrossMove interactor style"
  124 + iren = obj.GetInteractor()
  125 + self.ChangeCrossPosition(iren)
  126 +
  127 + def ChangeCrossPosition(self, iren):
  128 + mouse_x, mouse_y = iren.GetEventPosition()
  129 + ren = iren.GetRenderWindow().GetRenderers().GetFirstRenderer()
  130 + self.picker.Pick(mouse_x, mouse_y, 0, ren)
  131 +
  132 + # Get in what slice data the click occurred
  133 + # pick to get click position in the 3d world
  134 + coord_cross = self.get_coordinate_cursor()
  135 + position = self.slice_actor.GetInput().FindPoint(coord_cross)
  136 + # Forcing focal point to be setted in the center of the pixel.
  137 + coord_cross = self.slice_actor.GetInput().GetPoint(position)
  138 +
  139 + coord = self.calcultate_scroll_position(position)
  140 + self.ScrollSlice(coord)
  141 +
  142 + Publisher.sendMessage('Update cross position', coord_cross)
  143 + Publisher.sendMessage('Set ball reference position based on bound',
  144 + coord_cross)
  145 + Publisher.sendMessage('Set camera in volume', coord_cross)
  146 + Publisher.sendMessage('Render volume viewer')
128 147  
129   - def OnLeftButtonDown(self, evt, str_evt):
130   - self.mouse_pressed = 1
131   -
132   - def OnLeftButtonUp(self, evt, str_evt):
133   - self.mouse_pressed = 0
134   -
135   - def OnMouseMove(self, evt, str_evt):
136   - pos = self.interactor.GetEventPosition()
137   - wx = pos[0]
138   - wy = pos[1]
  148 + iren.Render()
  149 +
  150 +
  151 + def calcultate_scroll_position(self, position):
  152 + # Based in the given coord (x, y, z), returns a list with the scroll positions for each
  153 + # orientation, being the first position the sagital, second the coronal
  154 + # and the last, axial.
139 155  
140   - self.pick.Pick(wx, wy, 0, self.render)
  156 + if self.orientation == 'AXIAL':
  157 + image_width = self.slice_actor.GetInput().GetDimensions()[0]
  158 + axial = self.slice_data.number
  159 + coronal = position / image_width
  160 + sagital = position % image_width
  161 +
  162 + elif self.orientation == 'CORONAL':
  163 + image_width = self.slice_actor.GetInput().GetDimensions()[0]
  164 + axial = position / image_width
  165 + coronal = self.slice_data.number
  166 + sagital = position % image_width
  167 +
  168 + elif self.orientation == 'SAGITAL':
  169 + image_width = self.slice_actor.GetInput().GetDimensions()[1]
  170 + axial = position / image_width
  171 + coronal = position % image_width
  172 + sagital = self.slice_data.number
  173 +
  174 + return sagital, coronal, axial
  175 +
  176 + def ScrollSlice(self, coord):
  177 + if self.orientation == "AXIAL":
  178 + Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
  179 + coord[0])
  180 + Publisher.sendMessage(('Set scroll position', 'CORONAL'),
  181 + coord[1])
  182 + elif self.orientation == "SAGITAL":
  183 + Publisher.sendMessage(('Set scroll position', 'AXIAL'),
  184 + coord[2])
  185 + Publisher.sendMessage(('Set scroll position', 'CORONAL'),
  186 + coord[1])
  187 + elif self.orientation == "CORONAL":
  188 + Publisher.sendMessage(('Set scroll position', 'AXIAL'),
  189 + coord[2])
  190 + Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
  191 + coord[0])
  192 +
  193 + def get_coordinate_cursor(self):
  194 + # Find position
141 195 x, y, z = self.picker.GetPickPosition()
  196 + bounds = self.viewer.slice_data.actor.GetBounds()
  197 + if bounds[0] == bounds[1]:
  198 + x = bounds[0]
  199 + elif bounds[2] == bounds[3]:
  200 + y = bounds[2]
  201 + elif bounds[4] == bounds[5]:
  202 + z = bounds[4]
  203 + return x, y, z
  204 +
  205 +
  206 +class WWWLInteractorStyle(DefaultInteractorStyle):
  207 + """
  208 + Interactor style responsible for Window Level & Width functionality.
  209 + """
  210 + def __init__(self, viewer):
  211 + DefaultInteractorStyle.__init__(self, viewer)
  212 +
  213 + self.viewer = viewer
  214 +
  215 + self.last_x = 0
  216 + self.last_y = 0
  217 +
  218 + self.acum_achange_window = viewer.slice_.window_width
  219 + self.acum_achange_level = viewer.slice_.window_level
  220 +
  221 + self.AddObserver("MouseMoveEvent", self.OnWindowLevelMove)
  222 + self.AddObserver("LeftButtonPressEvent", self.OnWindowLevelClick)
  223 +
  224 + def SetUp(self):
  225 + self.viewer.on_wl = True
  226 + self.viewer.wl_text.Show()
  227 +
  228 + def CleanUp(self):
  229 + self.viewer.on_wl = False
  230 + self.viewer.wl_text.Hide()
  231 +
  232 + def OnWindowLevelMove(self, obj, evt):
  233 + if (self.left_pressed):
  234 + iren = obj.GetInteractor()
  235 + mouse_x, mouse_y = iren.GetEventPosition()
  236 + self.acum_achange_window += mouse_x - self.last_x
  237 + self.acum_achange_level += mouse_y - self.last_y
  238 + self.last_x, self.last_y = mouse_x, mouse_y
  239 +
  240 + Publisher.sendMessage('Bright and contrast adjustment image',
  241 + (self.acum_achange_window, self.acum_achange_level))
  242 +
  243 + #self.SetWLText(self.acum_achange_level,
  244 + # self.acum_achange_window)
  245 +
  246 + const.WINDOW_LEVEL['Manual'] = (self.acum_achange_window,\
  247 + self.acum_achange_level)
  248 + Publisher.sendMessage('Check window and level other')
  249 + Publisher.sendMessage('Update window level value',(self.acum_achange_window,
  250 + self.acum_achange_level))
  251 + #Necessary update the slice plane in the volume case exists
  252 + Publisher.sendMessage('Update slice viewer')
  253 + Publisher.sendMessage('Render volume viewer')
  254 +
  255 + def OnWindowLevelClick(self, obj, evt):
  256 + iren = obj.GetInteractor()
  257 + self.last_x, self.last_y = iren.GetLastEventPosition()
  258 +
  259 + self.acum_achange_window = viewer.slice_.window_width
  260 + self.acum_achange_level = viewer.slice_.window_level
  261 +
  262 +
  263 +class LinearMeasureInteractorStyle(DefaultInteractorStyle):
  264 + """
  265 + Interactor style responsible for insert linear measurements.
  266 + """
  267 + def __init__(self, viewer):
  268 + DefaultInteractorStyle.__init__(self, viewer)
  269 +
  270 + self.viewer = viewer
  271 + self.orientation = viewer.orientation
  272 + self.slice_data = viewer.slice_data
  273 +
  274 + self.picker = vtk.vtkCellPicker()
142 275  
143   - if self.mouse_pressed:
144   - #wx, wy = self.From3dToImagePixel(pos, (x, y, z))
145   - wx, wy = self.pos_converter.GetImagedataCoordinates(x, y, z)
146   - #self.CircleOperation(wx, wy, self.slice_) # TODO!
147   - ps.Publisher().sendMessage('Update edited imagedata', self.image)
148   - ps.Publisher().sendMessage('Update slice viewer', None)
149   -
150   - # update cursor
151   - self.cursor.SetPosition(x, y, z)
152   - self.cursor.Update()
153   -
154   - obj.OnMouseMove()
155   -
156   - self.interactor.Render()
157   -
158   -class ViewerToImagedataPosConverter():
159   - def __init__(self, actor_bounds, imagedata_dimensions, renderer):
160   - self.actor_bounds = actor_bounds
161   - self.imagedata_dimensions = imagedata_dimensions
162   - self.renderer = renderer
  276 + self.AddObserver("LeftButtonPressEvent", self.OnInsertLinearMeasurePoint)
  277 +
  278 + def OnInsertLinearMeasurePoint(self, obj, evt):
  279 + iren = obj.GetInteractor()
  280 + x,y = iren.GetEventPosition()
  281 + render = iren.FindPokedRenderer(x, y)
  282 + slice_number = self.slice_data.number
  283 + self.picker.Pick(x, y, 0, render)
  284 + x, y, z = self.picker.GetPickPosition()
  285 + if self.picker.GetViewProp():
  286 + Publisher.sendMessage("Add measurement point",
  287 + ((x, y,z), const.LINEAR,
  288 + ORIENTATIONS[self.orientation],
  289 + slice_number))
  290 + self.viewer.interactor.Render()
  291 +
  292 +
  293 +class AngularMeasureInteractorStyle(DefaultInteractorStyle):
  294 + """
  295 + Interactor style responsible for insert angular measurements.
  296 + """
  297 + def __init__(self, viewer):
  298 + DefaultInteractorStyle.__init__(self, viewer)
  299 +
  300 + self.viewer = viewer
  301 + self.orientation = viewer.orientation
  302 + self.slice_data = viewer.slice_data
  303 +
  304 + self.picker = vtk.vtkCellPicker()
  305 +
  306 + self.AddObserver("LeftButtonPressEvent", self.OnInsertAngularMeasurePoint)
  307 +
  308 + def OnInsertAngularMeasurePoint(self, obj, evt):
  309 + iren = obj.GetInteractor()
  310 + x,y = iren.GetEventPosition()
  311 + render = iren.FindPokedRenderer(x, y)
  312 + slice_number = self.slice_data.number
  313 + self.picker.Pick(x, y, 0, render)
  314 + x, y, z = self.picker.GetPickPosition()
  315 + if self.picker.GetViewProp():
  316 + Publisher.sendMessage("Add measurement point",
  317 + ((x, y,z), const.ANGULAR,
  318 + ORIENTATIONS[self.orientation],
  319 + slice_number))
  320 + self.viewer.interactor.Render()
  321 +
  322 +
  323 +class PanMoveInteractorStyle(DefaultInteractorStyle):
  324 + """
  325 + Interactor style responsible for translate the camera.
  326 + """
  327 + def __init__(self, viewer):
  328 + DefaultInteractorStyle.__init__(self, viewer)
  329 +
  330 + self.viewer = viewer
  331 +
  332 + self.AddObserver("MouseMoveEvent", self.OnPanMove)
  333 + self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnspan)
  334 +
  335 + def OnPanMove(self, obj, evt):
  336 + if self.left_pressed:
  337 + obj.Pan()
  338 + obj.OnRightButtonDown()
  339 +
  340 + def OnUnspan(self, evt):
  341 + iren = self.viewer.interactor
  342 + mouse_x, mouse_y = iren.GetLastEventPosition()
  343 + ren = iren.FindPokedRenderer(mouse_x, mouse_y)
  344 + ren.ResetCamera()
  345 + iren.Render()
  346 +
  347 +
  348 +class SpinInteractorStyle(DefaultInteractorStyle):
  349 + """
  350 + Interactor style responsible for spin the camera.
  351 + """
  352 + def __init__(self, viewer):
  353 + DefaultInteractorStyle.__init__(self, viewer)
  354 +
  355 + self.viewer = viewer
  356 +
  357 + self.AddObserver("MouseMoveEvent", self.OnSpinMove)
  358 + self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnspin)
  359 +
  360 + def OnSpinMove(self, obj, evt):
  361 + iren = obj.GetInteractor()
  362 + mouse_x, mouse_y = iren.GetLastEventPosition()
  363 + ren = iren.FindPokedRenderer(mouse_x, mouse_y)
  364 + cam = ren.GetActiveCamera()
  365 + if (self.left_pressed):
  366 + self.viewer.UpdateTextDirection(cam)
  367 + self.spined_image = True
  368 + obj.Spin()
  369 + obj.OnRightButtonDown()
  370 +
  371 + def OnUnspin(self, evt):
  372 + orig_orien = 1
  373 + iren = self.viewer.interactor
  374 + mouse_x, mouse_y = iren.GetLastEventPosition()
  375 + ren = iren.FindPokedRenderer(mouse_x, mouse_y)
  376 + cam = ren.GetActiveCamera()
  377 + cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.viewer.orientation])
  378 + self.viewer.ResetTextDirection(cam)
  379 + iren.Render()
  380 +
  381 +
  382 +class ZoomInteractorStyle(DefaultInteractorStyle):
  383 + """
  384 + Interactor style responsible for zoom with movement of the mouse and the
  385 + left mouse button clicked.
  386 + """
  387 + def __init__(self, viewer):
  388 + DefaultInteractorStyle.__init__(self, viewer)
  389 +
  390 + self.viewer = viewer
  391 +
  392 + self.AddObserver("MouseMoveEvent", self.OnZoomMoveLeft)
  393 + self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnZoom)
  394 +
  395 + def OnZoomMoveLeft(self, obj, evt):
  396 + if self.left_pressed:
  397 + obj.Dolly()
  398 + obj.OnRightButtonDown()
  399 +
  400 + def OnUnZoom(self, evt):
  401 + mouse_x, mouse_y = self.viewer.interactor.GetLastEventPosition()
  402 + ren = self.viewer.interactor.FindPokedRenderer(mouse_x, mouse_y)
  403 + #slice_data = self.get_slice_data(ren)
  404 + ren.ResetCamera()
  405 + ren.ResetCameraClippingRange()
  406 + #self.Reposition(slice_data)
  407 + self.viewer.interactor.Render()
  408 +
  409 +
  410 +class ZoomSLInteractorStyle(vtk.vtkInteractorStyleRubberBandZoom):
  411 + """
  412 + Interactor style responsible for zoom by selecting a region.
  413 + """
  414 + def __init__(self, viewer):
  415 + self.viewer = viewer
  416 + self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnUnZoom)
  417 +
  418 + def OnUnZoom(self, evt):
  419 + mouse_x, mouse_y = self.viewer.interactor.GetLastEventPosition()
  420 + ren = self.viewer.interactor.FindPokedRenderer(mouse_x, mouse_y)
  421 + #slice_data = self.get_slice_data(ren)
  422 + ren.ResetCamera()
  423 + ren.ResetCameraClippingRange()
  424 + #self.Reposition(slice_data)
  425 + self.viewer.interactor.Render()
  426 +
  427 +
  428 +class ChangeSliceInteractorStyle(DefaultInteractorStyle):
  429 + """
  430 + Interactor style responsible for change slice moving the mouse.
  431 + """
  432 + def __init__(self, viewer):
  433 + DefaultInteractorStyle.__init__(self, viewer)
  434 +
  435 + self.viewer = viewer
  436 +
  437 + self.AddObserver("MouseMoveEvent", self.OnChangeSliceMove)
  438 + self.AddObserver("LeftButtonPressEvent", self.OnChangeSliceClick)
  439 +
  440 + def OnChangeSliceMove(self, evt, obj):
  441 + if self.left_pressed:
  442 + min = 0
  443 + max = self.viewer.slice_.GetMaxSliceNumber(self.viewer.orientation)
  444 +
  445 + position = self.viewer.interactor.GetLastEventPosition()
  446 + scroll_position = self.viewer.scroll.GetThumbPosition()
  447 +
  448 + if (position[1] > self.last_position) and\
  449 + (self.acum_achange_slice > min):
  450 + self.acum_achange_slice -= 1
  451 + elif(position[1] < self.last_position) and\
  452 + (self.acum_achange_slice < max):
  453 + self.acum_achange_slice += 1
  454 + self.last_position = position[1]
  455 +
  456 + self.viewer.scroll.SetThumbPosition(self.acum_achange_slice)
  457 + self.viewer.OnScrollBar()
  458 +
  459 + def OnChangeSliceClick(self, evt, obj):
  460 + position = self.viewer.interactor.GetLastEventPosition()
  461 + self.acum_achange_slice = self.viewer.scroll.GetThumbPosition()
  462 + self.last_position = position[1]
  463 +
  464 +
  465 +class EditorInteractorStyle(DefaultInteractorStyle):
  466 + def __init__(self, viewer):
  467 + DefaultInteractorStyle.__init__(self, viewer)
  468 +
  469 + self.viewer = viewer
  470 + self.orientation = self.viewer.orientation
  471 +
  472 + self.picker = vtk.vtkWorldPointPicker()
  473 +
  474 + self.AddObserver("EnterEvent", self.OnEnterInteractor)
  475 + self.AddObserver("LeaveEvent", self.OnLeaveInteractor)
  476 +
  477 + self.AddObserver("LeftButtonPressEvent", self.OnBrushClick)
  478 + self.AddObserver("LeftButtonReleaseEvent", self.OnBrushRelease)
  479 + self.AddObserver("MouseMoveEvent", self.OnBrushMove)
  480 +
  481 + def OnEnterInteractor(self, obj, evt):
  482 + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
  483 + return
  484 + self.viewer.slice_data.cursor.Show()
  485 + self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
  486 + self.viewer.interactor.Render()
163 487  
164   - def GetImagedataCoordinates(self, picker_position):
165   - x, y, z = picker_position
  488 + def OnLeaveInteractor(self, obj, evt):
  489 + self.viewer.slice_data.cursor.Show(0)
  490 + self.viewer.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
  491 + self.viewer.interactor.Render()
  492 +
  493 + def OnBrushClick(self, obj, evt):
  494 + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
  495 + return
166 496  
167   - c = vtk.vtkCoordinate()
168   - c.SetCoordinateSystemToWorld()
169   - c.SetValue(bounds[::2])
170   - xi, yi = c.GetComputedViewportValue(self.render)
  497 + viewer = self.viewer
  498 + iren = viewer.interactor
171 499  
172   - c.SetValue(bounds[1::2])
173   - xf, yf = c.GetComputedViewportValue(self.render)
  500 + viewer._set_editor_cursor_visibility(1)
  501 +
  502 + mouse_x, mouse_y = iren.GetEventPosition()
  503 + render = iren.FindPokedRenderer(mouse_x, mouse_y)
  504 + slice_data = viewer.get_slice_data(render)
  505 +
  506 + # TODO: Improve!
  507 + #for i in self.slice_data_list:
  508 + #i.cursor.Show(0)
  509 + slice_data.cursor.Show()
  510 +
  511 + self.picker.Pick(mouse_x, mouse_y, 0, render)
174 512  
175   - c.SetValue(x, y, z)
176   - wx, wy = c.GetComputedViewportValue(self.render)
  513 + coord = self.get_coordinate_cursor()
  514 + position = slice_data.actor.GetInput().FindPoint(coord)
177 515  
178   - wx = wx - xi
179   - wy = wy - yi
  516 + if position != -1:
  517 + coord = slice_data.actor.GetInput().GetPoint(position)
  518 +
  519 + slice_data.cursor.SetPosition(coord)
  520 + cursor = slice_data.cursor
  521 + radius = cursor.radius
  522 +
  523 + if position < 0:
  524 + position = viewer.calculate_matrix_position(coord)
  525 +
  526 + viewer.slice_.edit_mask_pixel(viewer._brush_cursor_op, cursor.GetPixels(),
  527 + position, radius, viewer.orientation)
  528 + viewer._flush_buffer = True
  529 +
  530 + # TODO: To create a new function to reload images to viewer.
  531 + viewer.OnScrollBar()
  532 +
  533 + def OnBrushMove(self, obj, evt):
  534 + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
  535 + return
  536 +
  537 + viewer = self.viewer
  538 + iren = viewer.interactor
  539 +
  540 + viewer._set_editor_cursor_visibility(1)
  541 +
  542 + mouse_x, mouse_y = iren.GetEventPosition()
  543 + render = iren.FindPokedRenderer(mouse_x, mouse_y)
  544 + slice_data = viewer.get_slice_data(render)
  545 +
  546 + # TODO: Improve!
  547 + #for i in self.slice_data_list:
  548 + #i.cursor.Show(0)
  549 +
  550 + self.picker.Pick(mouse_x, mouse_y, 0, render)
180 551  
181   - xf = xf - xi
182   - yf = yf - yi
  552 + #if (self.pick.GetViewProp()):
  553 + #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
  554 + #else:
  555 + #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
  556 +
  557 + coord = self.get_coordinate_cursor()
  558 + position = viewer.slice_data.actor.GetInput().FindPoint(coord)
183 559  
184   - wx = (wx * self.imagedata_dimensions[0]) / xf
185   - wy = (wy * self.imagedata_dimensions[1]) / yf
  560 + # when position == -1 the cursos is not over the image, so is not
  561 + # necessary to set the cursor position to world coordinate center of
  562 + # pixel from slice image.
  563 + if position != -1:
  564 + coord = slice_data.actor.GetInput().GetPoint(position)
  565 + slice_data.cursor.SetPosition(coord)
  566 + #self.__update_cursor_position(slice_data, coord)
186 567  
187   - return wx, wy
  568 + if (self.left_pressed):
  569 + cursor = slice_data.cursor
  570 + position = slice_data.actor.GetInput().FindPoint(coord)
  571 + radius = cursor.radius
188 572  
189   -################################################################################
  573 + if position < 0:
  574 + position = viewer.calculate_matrix_position(coord)
  575 +
  576 + viewer.slice_.edit_mask_pixel(viewer._brush_cursor_op, cursor.GetPixels(),
  577 + position, radius, self.orientation)
  578 + # TODO: To create a new function to reload images to viewer.
  579 + viewer.OnScrollBar(update3D=False)
190 580  
191   -# style = vtk.vtkInteractorStyleImage()
192   -# style.SetInteractor(interactor)
  581 + else:
  582 + viewer.interactor.Render()
193 583  
194   -# interactor.SetInteractorStyle(style)
195   -# self.style = style
  584 + def OnBrushRelease(self, evt, obj):
  585 + if (self.viewer.slice_.buffer_slices[self.orientation].mask is None):
  586 + return
  587 +
  588 + self.viewer.slice_.apply_slice_buffer_to_mask(self.orientation)
  589 + self.viewer._flush_buffer = False
  590 +
  591 + def get_coordinate_cursor(self):
  592 + # Find position
  593 + x, y, z = self.picker.GetPickPosition()
  594 + bounds = self.viewer.slice_data.actor.GetBounds()
  595 + if bounds[0] == bounds[1]:
  596 + x = bounds[0]
  597 + elif bounds[2] == bounds[3]:
  598 + y = bounds[2]
  599 + elif bounds[4] == bounds[5]:
  600 + z = bounds[4]
  601 + return x, y, z
196 602  
197   -#self.interactor.SetCursor(cursors.ZOOM_IN_CURSOR)
198 603  
199   -################################################################################
  604 +def get_style(style):
  605 + STYLES = {
  606 + const.STATE_DEFAULT: DefaultInteractorStyle,
  607 + const.SLICE_STATE_CROSS: CrossInteractorStyle,
  608 + const.STATE_WL: WWWLInteractorStyle,
  609 + const.STATE_MEASURE_DISTANCE: LinearMeasureInteractorStyle,
  610 + const.STATE_MEASURE_ANGLE: AngularMeasureInteractorStyle,
  611 + const.STATE_PAN: PanMoveInteractorStyle,
  612 + const.STATE_SPIN: SpinInteractorStyle,
  613 + const.STATE_ZOOM: ZoomInteractorStyle,
  614 + const.STATE_ZOOM_SL: ZoomSLInteractorStyle,
  615 + const.SLICE_STATE_SCROLL: ChangeSliceInteractorStyle,
  616 + const.SLICE_STATE_EDITOR: EditorInteractorStyle,
  617 + }
  618 + return STYLES[style]
... ...
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  
... ... @@ -65,6 +67,7 @@ class Viewer(wx.Panel):
65 67 self.spined_image = False #Use to control to spin
66 68 self.paned_image = False
67 69  
  70 + self.style = None
68 71 self.last_position_mouse_move = ()
69 72 self.state = const.STATE_DEFAULT
70 73  
... ... @@ -173,194 +176,21 @@ class Viewer(wx.Panel):
173 176 interactor.SetInteractorStyle(style)
174 177  
175 178 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   - }
230   -
231   -
232   - if state == const.SLICE_STATE_CROSS:
233   - self.__set_cross_visibility(1)
234   - Publisher.sendMessage('Activate ball reference')
235   - else:
236   - self.__set_cross_visibility(0)
237   - Publisher.sendMessage('Deactivate ball reference')
238   -
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()
245   -
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()
  179 + cleanup = getattr(self.style, 'CleanUp', None)
  180 + if cleanup:
  181 + self.style.CleanUp()
251 182  
252   - style.AddObserver("RightButtonPressEvent", self.QuitRubberBandZoom)
253   - #style.AddObserver("RightButtonPressEvent", self.EnterRubberBandZoom)
254   -
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)
  183 + style = styles.get_style(state)(self)
284 184  
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)
  185 + setup = getattr(style, 'SetUp', None)
  186 + if setup:
  187 + style.SetUp()
293 188  
294 189 self.style = style
295 190 self.interactor.SetInteractorStyle(style)
296 191 self.interactor.Render()
297   -
298   - def QuitRubberBandZoom(self, evt, obj):
299   - style = vtk.vtkInteractorStyleImage()
300   - self.interactor.SetInteractorStyle(style)
301   - self.style = style
302   -
303   - style.AddObserver("LeftButtonPressEvent", self.EnterRubberBandZoom)
304 192  
305   - # Zoom using right button
306   - style.AddObserver("RightButtonPressEvent", self.OnRightClick)
307   - style.AddObserver("RightButtonReleaseEvent", self.OnReleaseRightButton)
308   - style.AddObserver("RightButtonPressEvent",self.OnZoomRightClick)
309   - style.AddObserver("MouseMoveEvent", self.OnZoomMoveRight)
310   - style.AddObserver("RightButtonReleaseEvent", self.OnReleaseRightButton)
311   -
312   - def EnterRubberBandZoom(self, evt, obj):
313   - style = vtk.vtkInteractorStyleRubberBandZoom()
314   - self.interactor.SetInteractorStyle(style)
315   - self.style = style
316   -
317   - style.AddObserver("RightButtonPressEvent", self.QuitRubberBandZoom)
318   -
319   - def OnRightClick(self, evt, obj):
320   - self.last_position_mouse_move = \
321   - self.interactor.GetLastEventPosition()
322   -
323   - self.right_pressed = 1
324   -
325   - def OnReleaseRightButton(self, evt, obj):
326   - self.right_pressed = 0
327   - Publisher.sendMessage('Update slice viewer')
328   -
329   - def OnLeftClick(self, evt, obj):
330   - self.left_pressed = 1
331   -
332   - def OnZoomLeftClick(self, evt, obj):
333   - evt.StartDolly()
334   -
335   - def OnReleaseLeftButton(self, evt, obj):
336   - self.left_pressed = 0
337   - Publisher.sendMessage('Update slice viewer')
338   -
339   - def OnWindowLevelMove(self, evt, obj):
340   - if (self.left_pressed):
341   - position = self.interactor.GetLastEventPosition()
342   - mouse_x, mouse_y = self.interactor.GetEventPosition()
343   - self.acum_achange_window += mouse_x - self.last_x
344   - self.acum_achange_level += mouse_y - self.last_y
345   - self.last_x, self.last_y = mouse_x, mouse_y
346   -
347   - Publisher.sendMessage('Bright and contrast adjustment image',
348   - (self.acum_achange_window, self.acum_achange_level))
349   -
350   - #self.SetWLText(self.acum_achange_level,
351   - # self.acum_achange_window)
352   -
353   - const.WINDOW_LEVEL['Manual'] = (self.acum_achange_window,\
354   - self.acum_achange_level)
355   - Publisher.sendMessage('Check window and level other')
356   - Publisher.sendMessage('Update window level value',(self.acum_achange_window,
357   - self.acum_achange_level))
358   - #Necessary update the slice plane in the volume case exists
359   - Publisher.sendMessage('Update slice viewer')
360   - Publisher.sendMessage('Render volume viewer')
361   -
362   - def OnWindowLevelClick(self, evt, obj):
363   - self.last_x, self.last_y = self.interactor.GetLastEventPosition()
  193 + self.state = state
364 194  
365 195 def UpdateWindowLevelValue(self, pubsub_evt):
366 196 window, level = pubsub_evt.data
... ... @@ -368,112 +198,6 @@ class Viewer(wx.Panel):
368 198 self.SetWLText(window, level)
369 199 Publisher.sendMessage('Update all slice')
370 200  
371   -
372   - def OnChangeSliceMove(self, evt, obj):
373   - if (self.left_pressed):
374   - min = 0
375   - max = self.slice_.GetMaxSliceNumber(self.orientation)
376   -
377   - if (self.left_pressed):
378   - position = self.interactor.GetLastEventPosition()
379   - scroll_position = self.scroll.GetThumbPosition()
380   -
381   - if (position[1] > self.last_position) and\
382   - (self.acum_achange_slice > min):
383   - self.acum_achange_slice -= 1
384   - elif(position[1] < self.last_position) and\
385   - (self.acum_achange_slice < max):
386   - self.acum_achange_slice += 1
387   - self.last_position = position[1]
388   -
389   - self.scroll.SetThumbPosition(self.acum_achange_slice)
390   - self.OnScrollBar()
391   -
392   - def OnChangeSliceClick(self, evt, obj):
393   - position = list(self.interactor.GetLastEventPosition())
394   - self.acum_achange_slice = self.scroll.GetThumbPosition()
395   - self.last_position = position[1]
396   -
397   - def OnPanMove(self, evt, obj):
398   - mouse_x, mouse_y = self.interactor.GetLastEventPosition()
399   - ren = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
400   - cam = ren.GetActiveCamera()
401   -
402   - if (self.left_pressed):
403   - evt.Pan()
404   - evt.OnRightButtonDown()
405   - self.paned_image = True
406   -
407   - def OnPanClick(self, evt, obj):
408   - evt.StartPan()
409   -
410   - def OnZoomMoveLeft(self, evt, obj):
411   - if self.left_pressed:
412   - evt.Dolly()
413   - evt.OnRightButtonDown()
414   -
415   - def OnVtkRightRelease(self, evt, obj):
416   - evt.OnRightButtonUp()
417   -
418   - def OnUnZoom(self, evt, obj = None):
419   - mouse_x, mouse_y = self.interactor.GetLastEventPosition()
420   - ren = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
421   - slice_data = self.get_slice_data(ren)
422   - ren.ResetCamera()
423   - ren.ResetCameraClippingRange()
424   - #self.Reposition(slice_data)
425   - self.interactor.Render()
426   -
427   - def OnUnSpinPan(self, evt):
428   - orientation = self.orientation
429   - proj = project.Project()
430   - orig_orien = 1
431   - mouse_x, mouse_y = self.interactor.GetLastEventPosition()
432   - ren = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
433   -
434   - if((self.state == const.STATE_SPIN) and (self.spined_image)):
435   - self.cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.orientation])
436   - # Values are on ccw order, starting from the top:
437   - if self.orientation == 'AXIAL':
438   - values = [_("A"), _("R"), _("P"), _("L")]
439   - elif self.orientation == 'CORONAL':
440   - values = [_("T"), _("R"), _("B"), _("L")]
441   - else: # 'SAGITAL':
442   - values = [_("T"), _("P"), _("B"), _("A")]
443   -
444   - self.RenderTextDirection(values)
445   - self.interactor.Render()
446   - self.spined_image = False
447   - elif((self.state == const.STATE_PAN) and (self.paned_image)):
448   - ren.ResetCamera()
449   - self.interactor.Render()
450   - self.paned_image = False
451   -
452   - def OnSpinMove(self, evt, obj):
453   - mouse_x, mouse_y = self.interactor.GetLastEventPosition()
454   - ren = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
455   - cam = ren.GetActiveCamera()
456   - if (self.left_pressed):
457   - self.UpdateTextDirection(cam)
458   - self.spined_image = True
459   - evt.Spin()
460   - evt.OnRightButtonDown()
461   -
462   -
463   - def OnSpinClick(self, evt, obj):
464   - evt.StartSpin()
465   -
466   - def OnEnterInteractor(self, evt, obj):
467   - if (self.slice_.buffer_slices[self.orientation].mask is None):
468   - return
469   - self.slice_data.cursor.Show()
470   - self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
471   -
472   - def OnLeaveInteractor(self, evt, obj):
473   - self.slice_data.cursor.Show(0)
474   - self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
475   - self.interactor.Render()
476   -
477 201 def SetWLText(self, window_width, window_level):
478 202 value = STR_WL%(window_level, window_width)
479 203 if (self.wl_text):
... ... @@ -544,6 +268,17 @@ class Viewer(wx.Panel):
544 268 self.right_text.SetValue(directions[3])
545 269 self.interactor.Render()
546 270  
  271 + def ResetTextDirection(self, cam):
  272 + # Values are on ccw order, starting from the top:
  273 + if self.orientation == 'AXIAL':
  274 + values = [_("A"), _("R"), _("P"), _("L")]
  275 + elif self.orientation == 'CORONAL':
  276 + values = [_("T"), _("R"), _("B"), _("L")]
  277 + else: # 'SAGITAL':
  278 + values = [_("T"), _("P"), _("B"), _("A")]
  279 +
  280 + self.RenderTextDirection(values)
  281 + self.interactor.Render()
547 282  
548 283 def UpdateTextDirection(self, cam):
549 284 croll = cam.GetRoll()
... ... @@ -716,129 +451,6 @@ class Viewer(wx.Panel):
716 451 slice_data.SetCursor(cursor)
717 452 self.interactor.Render()
718 453  
719   - def OnBrushClick(self, evt, obj):
720   - if (self.slice_.buffer_slices[self.orientation].mask is None):
721   - return
722   -
723   - self.__set_editor_cursor_visibility(1)
724   -
725   - mouse_x, mouse_y = self.interactor.GetEventPosition()
726   - render = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
727   - slice_data = self.get_slice_data(render)
728   -
729   - # TODO: Improve!
730   - #for i in self.slice_data_list:
731   - #i.cursor.Show(0)
732   - self.slice_data.cursor.Show()
733   -
734   - self.pick.Pick(mouse_x, mouse_y, 0, render)
735   -
736   - coord = self.get_coordinate_cursor()
737   - position = self.slice_data.actor.GetInput().FindPoint(coord)
738   -
739   - if position != -1:
740   - coord = self.slice_data.actor.GetInput().GetPoint(position)
741   -
742   - slice_data.cursor.SetPosition(coord)
743   - cursor = self.slice_data.cursor
744   - radius = cursor.radius
745   -
746   - if position < 0:
747   - position = self.calculate_matrix_position(coord)
748   -
749   - self.slice_.edit_mask_pixel(self._brush_cursor_op, cursor.GetPixels(),
750   - position, radius, self.orientation)
751   - self._flush_buffer = True
752   -
753   - # TODO: To create a new function to reload images to viewer.
754   - self.OnScrollBar()
755   -
756   - def OnBrushMove(self, evt, obj):
757   - if (self.slice_.buffer_slices[self.orientation].mask is None):
758   - return
759   -
760   - self.__set_editor_cursor_visibility(1)
761   -
762   - mouse_x, mouse_y = self.interactor.GetEventPosition()
763   - render = self.interactor.FindPokedRenderer(mouse_x, mouse_y)
764   - slice_data = self.get_slice_data(render)
765   -
766   - # TODO: Improve!
767   - #for i in self.slice_data_list:
768   - #i.cursor.Show(0)
769   -
770   - self.pick.Pick(mouse_x, mouse_y, 0, render)
771   -
772   - #if (self.pick.GetViewProp()):
773   - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_BLANK))
774   - #else:
775   - #self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
776   -
777   - coord = self.get_coordinate_cursor()
778   - position = self.slice_data.actor.GetInput().FindPoint(coord)
779   -
780   - # when position == -1 the cursos is not over the image, so is not
781   - # necessary to set the cursor position to world coordinate center of
782   - # pixel from slice image.
783   - if position != -1:
784   - coord = self.slice_data.actor.GetInput().GetPoint(position)
785   - slice_data.cursor.SetPosition(coord)
786   - #self.__update_cursor_position(slice_data, coord)
787   -
788   - if (self.left_pressed):
789   - cursor = self.slice_data.cursor
790   - position = self.slice_data.actor.GetInput().FindPoint(coord)
791   - radius = cursor.radius
792   -
793   - if position < 0:
794   - position = self.calculate_matrix_position(coord)
795   -
796   - self.slice_.edit_mask_pixel(self._brush_cursor_op, cursor.GetPixels(),
797   - position, radius, self.orientation)
798   - # TODO: To create a new function to reload images to viewer.
799   - self.OnScrollBar(update3D=False)
800   -
801   - else:
802   - self.interactor.Render()
803   -
804   - def OnBrushRelease(self, evt, obj):
805   - if (self.slice_.buffer_slices[self.orientation].mask is None):
806   - return
807   -
808   - self.slice_.apply_slice_buffer_to_mask(self.orientation)
809   - self._flush_buffer = False
810   -
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 454 def Navigation(self, pubsub_evt):
843 455 # Get point from base change
844 456 x, y, z = pubsub_evt.data
... ... @@ -868,14 +480,6 @@ class Viewer(wx.Panel):
868 480 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),
869 481 coord[0])
870 482  
871   - def OnZoomMoveRight(self, evt, obj):
872   - if (self.right_pressed):
873   - evt.Dolly()
874   - evt.OnRightButtonDown()
875   -
876   - def OnZoomRightClick(self, evt, obj):
877   - evt.StartDolly()
878   -
879 483 def get_slice_data(self, render):
880 484 #for slice_data in self.slice_data_list:
881 485 #if slice_data.renderer is render:
... ... @@ -993,7 +597,7 @@ class Viewer(wx.Panel):
993 597 Publisher.subscribe(self.UpdateWindowLevelValue,\
994 598 'Update window level value')
995 599  
996   - #Publisher.subscribe(self.__set_cross_visibility,\
  600 + #Publisher.subscribe(self._set_cross_visibility,\
997 601 # 'Set cross visibility')
998 602 ###
999 603 Publisher.subscribe(self.__set_layout,
... ... @@ -1225,6 +829,7 @@ class Viewer(wx.Panel):
1225 829 self.interactor.Render()
1226 830  
1227 831 self.EnableText()
  832 + self.wl_text.Hide()
1228 833 ## Insert cursor
1229 834 self.SetInteractorStyle(const.STATE_DEFAULT)
1230 835  
... ... @@ -1260,10 +865,10 @@ class Viewer(wx.Panel):
1260 865 pos = pubsub_evt.data
1261 866 self.cross.SetFocalPoint(pos)
1262 867  
1263   - def __set_cross_visibility(self, visibility):
  868 + def _set_cross_visibility(self, visibility):
1264 869 self.cross_actor.SetVisibility(visibility)
1265 870  
1266   - def __set_editor_cursor_visibility(self, visibility):
  871 + def _set_editor_cursor_visibility(self, visibility):
1267 872 for slice_data in self.slice_data_list:
1268 873 slice_data.cursor.actor.SetVisibility(visibility)
1269 874  
... ... @@ -1484,35 +1089,6 @@ class Viewer(wx.Panel):
1484 1089 coord[index] = extent_min[index]
1485 1090 return coord
1486 1091  
1487   - def OnInsertLinearMeasurePoint(self, obj, evt):
1488   - x,y = self.interactor.GetEventPosition()
1489   - render = self.interactor.FindPokedRenderer(x, y)
1490   - slice_data = self.get_slice_data(render)
1491   - slice_number = slice_data.number
1492   - self.pick.Pick(x, y, 0, render)
1493   - x, y, z = self.pick.GetPickPosition()
1494   - print x, y, z
1495   - if self.pick.GetViewProp():
1496   - self.render_to_add = slice_data.renderer
1497   - Publisher.sendMessage("Add measurement point",
1498   - ((x, y,z), const.LINEAR, ORIENTATIONS[self.orientation],
1499   - slice_number))
1500   - self.interactor.Render()
1501   -
1502   - def OnInsertAngularMeasurePoint(self, obj, evt):
1503   - x,y = self.interactor.GetEventPosition()
1504   - render = self.interactor.FindPokedRenderer(x, y)
1505   - slice_data = self.get_slice_data(render)
1506   - slice_number = slice_data.number
1507   - self.pick.Pick(x, y, 0, render)
1508   - x, y, z = self.pick.GetPickPosition()
1509   - if self.pick.GetViewProp():
1510   - self.render_to_add = slice_data.renderer
1511   - Publisher.sendMessage("Add measurement point",
1512   - ((x, y,z), const.ANGULAR, ORIENTATIONS[self.orientation],
1513   - slice_number))
1514   - self.interactor.Render()
1515   -
1516 1092 def ReloadActualSlice(self, pubsub_evt):
1517 1093 pos = self.scroll.GetThumbPosition()
1518 1094 self.set_slice_number(pos)
... ...