Commit 8d9b272f2af829d286c946d1e9cd0a2d5bf25e8c
1 parent
071dff96
Exists in
master
and in
3 other branches
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
Showing
2 changed files
with
601 additions
and
606 deletions
Show diff stats
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) | ... | ... |