Commit 32a72e8b400238d37779453dcf05084a5402256d

Authored by Paulo Henrique Junqueira Amorim
1 parent 7853c073

ENH: Cursor actor is being shown over slice. Not working when cursor is moved.

Showing 1 changed file with 75 additions and 60 deletions   Show diff stats
invesalius/data/viewer_slice.py
@@ -29,34 +29,34 @@ import project @@ -29,34 +29,34 @@ import project
29 import cursor_actors as ca 29 import cursor_actors as ca
30 30
31 class Viewer(wx.Panel): 31 class Viewer(wx.Panel):
32 - 32 +
33 def __init__(self, prnt, orientation='AXIAL'): 33 def __init__(self, prnt, orientation='AXIAL'):
34 wx.Panel.__init__(self, prnt, size=wx.Size(320, 300)) 34 wx.Panel.__init__(self, prnt, size=wx.Size(320, 300))
35 - 35 +
36 colour = [255*c for c in const.ORIENTATION_COLOUR[orientation]] 36 colour = [255*c for c in const.ORIENTATION_COLOUR[orientation]]
37 self.SetBackgroundColour(colour) 37 self.SetBackgroundColour(colour)
38 - 38 +
39 # Interactor aditional style 39 # Interactor aditional style
40 self.modes = ['DEFAULT'] 40 self.modes = ['DEFAULT']
41 self.mouse_pressed = 0 41 self.mouse_pressed = 0
42 - 42 +
43 self.__init_gui() 43 self.__init_gui()
44 44
45 self.orientation = orientation 45 self.orientation = orientation
46 self.slice_number = 0 46 self.slice_number = 0
47 - 47 +
48 self._brush_cursor_op = 'Draw' 48 self._brush_cursor_op = 'Draw'
49 self.brush_cursor_size = 30 49 self.brush_cursor_size = 30
50 - 50 + self.cursor = None
51 # VTK pipeline and actors 51 # VTK pipeline and actors
52 self.__config_interactor() 52 self.__config_interactor()
53 self.pick = vtk.vtkCellPicker() 53 self.pick = vtk.vtkCellPicker()
54 - 54 +
55 self.__bind_events() 55 self.__bind_events()
56 self.__bind_events_wx() 56 self.__bind_events_wx()
57 57
58 def __init_gui(self): 58 def __init_gui(self):
59 - 59 +
60 interactor = wxVTKRenderWindowInteractor(self, -1, size=self.GetSize()) 60 interactor = wxVTKRenderWindowInteractor(self, -1, size=self.GetSize())
61 61
62 scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL) 62 scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL)
@@ -78,7 +78,7 @@ class Viewer(wx.Panel): @@ -78,7 +78,7 @@ class Viewer(wx.Panel):
78 self.interactor = interactor 78 self.interactor = interactor
79 79
80 def __config_interactor(self): 80 def __config_interactor(self):
81 - 81 +
82 ren = vtk.vtkRenderer() 82 ren = vtk.vtkRenderer()
83 83
84 interactor = self.interactor 84 interactor = self.interactor
@@ -86,14 +86,13 @@ class Viewer(wx.Panel): @@ -86,14 +86,13 @@ class Viewer(wx.Panel):
86 86
87 self.cam = ren.GetActiveCamera() 87 self.cam = ren.GetActiveCamera()
88 self.ren = ren 88 self.ren = ren
89 -  
90 - self.AppendMode('EDITOR')  
91 - 89 +
  90 +
92 def AppendMode(self, mode): 91 def AppendMode(self, mode):
93 - 92 +
94 # Retrieve currently set modes 93 # Retrieve currently set modes
95 self.modes.append(mode) 94 self.modes.append(mode)
96 - 95 +
97 # All modes and bindings 96 # All modes and bindings
98 action = {'DEFAULT': { 97 action = {'DEFAULT': {
99 "MouseMoveEvent": self.OnCrossMove, 98 "MouseMoveEvent": self.OnCrossMove,
@@ -111,7 +110,7 @@ class Viewer(wx.Panel): @@ -111,7 +110,7 @@ class Viewer(wx.Panel):
111 style = vtk.vtkInteractorStyleImage() 110 style = vtk.vtkInteractorStyleImage()
112 self.style = style 111 self.style = style
113 self.interactor.SetInteractorStyle(style) 112 self.interactor.SetInteractorStyle(style)
114 - 113 +
115 # Check all modes set by user 114 # Check all modes set by user
116 for mode in self.modes: 115 for mode in self.modes:
117 # Check each event available for each mode 116 # Check each event available for each mode
@@ -120,17 +119,7 @@ class Viewer(wx.Panel): @@ -120,17 +119,7 @@ class Viewer(wx.Panel):
120 style.AddObserver(event, 119 style.AddObserver(event,
121 action[mode][event]) 120 action[mode][event])
122 121
123 - # Insert cursor  
124 - cursor = ca.CursorCircle()  
125 - cursor.SetOrientation(self.orientation)  
126 - coordinates = {"SAGITAL": [self.slice_number, 0, 0],  
127 - "CORONAL": [0, self.slice_number, 0],  
128 - "AXIAL": [0, 0, self.slice_number]}  
129 - cursor.SetPosition(coordinates[self.orientation])  
130 - self.ren.AddActor(cursor.actor)  
131 - self.ren.Render()  
132 -  
133 - self.cursor = cursor 122 +
134 123
135 def ChangeBrushSize(self, pubsub_evt): 124 def ChangeBrushSize(self, pubsub_evt):
136 size = pubsub_evt.data 125 size = pubsub_evt.data
@@ -140,23 +129,24 @@ class Viewer(wx.Panel): @@ -140,23 +129,24 @@ class Viewer(wx.Panel):
140 self.interactor.Render() 129 self.interactor.Render()
141 130
142 def ChangeBrushColour(self, pubsub_evt): 131 def ChangeBrushColour(self, pubsub_evt):
143 - vtk_colour = pubsub_evt.data[3]  
144 - self.cursor.SetColour(vtk_colour)  
145 - self._brush_cursor_colour = vtk_colour  
146 - self.ren.Render()  
147 - self.interactor.Render()  
148 - 132 + if (self.cursor):
  133 + vtk_colour = pubsub_evt.data[3]
  134 + self.cursor.SetColour(vtk_colour)
  135 + self._brush_cursor_colour = vtk_colour
  136 + self.ren.Render()
  137 + self.interactor.Render()
  138 +
149 139
150 def ChangeBrushActor(self, pubsub_evt): 140 def ChangeBrushActor(self, pubsub_evt):
151 brush_type = pubsub_evt.data 141 brush_type = pubsub_evt.data
152 self.ren.RemoveActor(self.cursor.actor) 142 self.ren.RemoveActor(self.cursor.actor)
153 - 143 +
154 if brush_type == 'square': 144 if brush_type == 'square':
155 cursor = ca.CursorRectangle() 145 cursor = ca.CursorRectangle()
156 elif brush_type == 'circle': 146 elif brush_type == 'circle':
157 cursor = ca.CursorCircle() 147 cursor = ca.CursorCircle()
158 self.cursor = cursor 148 self.cursor = cursor
159 - 149 +
160 cursor.SetOrientation(self.orientation) 150 cursor.SetOrientation(self.orientation)
161 coordinates = {"SAGITAL": [self.slice_number, 0, 0], 151 coordinates = {"SAGITAL": [self.slice_number, 0, 0],
162 "CORONAL": [0, self.slice_number, 0], 152 "CORONAL": [0, self.slice_number, 0],
@@ -187,21 +177,21 @@ class Viewer(wx.Panel): @@ -187,21 +177,21 @@ class Viewer(wx.Panel):
187 self.cursor.SetPosition(coord) 177 self.cursor.SetPosition(coord)
188 self.cursor.SetEditionPosition(self.GetCoordinateCursorEdition()) 178 self.cursor.SetEditionPosition(self.GetCoordinateCursorEdition())
189 self.ren.Render() 179 self.ren.Render()
190 - 180 +
191 if self._brush_cursor_op == 'Erase': 181 if self._brush_cursor_op == 'Erase':
192 evt_msg = 'Erase mask pixel' 182 evt_msg = 'Erase mask pixel'
193 elif self._brush_cursor_op == 'Draw': 183 elif self._brush_cursor_op == 'Draw':
194 evt_msg = 'Add mask pixel' 184 evt_msg = 'Add mask pixel'
195 elif self._brush_cursor_op == 'Threshold': 185 elif self._brush_cursor_op == 'Threshold':
196 evt_msg = 'Edit mask pixel' 186 evt_msg = 'Edit mask pixel'
197 - 187 +
198 if self.mouse_pressed: 188 if self.mouse_pressed:
199 print "Edit pixel region based on origin:", coord 189 print "Edit pixel region based on origin:", coord
200 pixels = self.cursor.GetPixels() 190 pixels = self.cursor.GetPixels()
201 for coord in pixels: 191 for coord in pixels:
202 ps.Publisher().sendMessage(evt_msg, coord) 192 ps.Publisher().sendMessage(evt_msg, coord)
203 self.interactor.Render() 193 self.interactor.Render()
204 - 194 +
205 def OnCrossMove(self, obj, evt_vtk): 195 def OnCrossMove(self, obj, evt_vtk):
206 coord = self.GetCoordinate() 196 coord = self.GetCoordinate()
207 # Update position in other slices 197 # Update position in other slices
@@ -214,34 +204,34 @@ class Viewer(wx.Panel): @@ -214,34 +204,34 @@ class Viewer(wx.Panel):
214 coord[1]) 204 coord[1])
215 ps.Publisher().sendMessage(('Set scroll position', 'AXIAL'), 205 ps.Publisher().sendMessage(('Set scroll position', 'AXIAL'),
216 coord[2]) 206 coord[2])
217 -  
218 - 207 +
  208 +
219 def GetCoordinate(self): 209 def GetCoordinate(self):
220 - 210 +
221 # Find position 211 # Find position
222 mouse_x, mouse_y = self.interactor.GetEventPosition() 212 mouse_x, mouse_y = self.interactor.GetEventPosition()
223 self.pick.Pick(mouse_x, mouse_y, 0, self.ren) 213 self.pick.Pick(mouse_x, mouse_y, 0, self.ren)
224 x, y, z = self.pick.GetPickPosition() 214 x, y, z = self.pick.GetPickPosition()
225 - 215 +
226 # First we fix the position origin, based on vtkActor bounds 216 # First we fix the position origin, based on vtkActor bounds
227 bounds = self.actor.GetBounds() 217 bounds = self.actor.GetBounds()
228 bound_xi, bound_xf, bound_yi, bound_yf, bound_zi, bound_zf = bounds 218 bound_xi, bound_xf, bound_yi, bound_yf, bound_zi, bound_zf = bounds
229 x = float(x - bound_xi) 219 x = float(x - bound_xi)
230 y = float(y - bound_yi) 220 y = float(y - bound_yi)
231 z = float(z - bound_zi) 221 z = float(z - bound_zi)
232 - 222 +
233 # Then we fix the porpotion, based on vtkImageData spacing 223 # Then we fix the porpotion, based on vtkImageData spacing
234 spacing_x, spacing_y, spacing_z = self.imagedata.GetSpacing() 224 spacing_x, spacing_y, spacing_z = self.imagedata.GetSpacing()
235 x = x/spacing_x 225 x = x/spacing_x
236 y = y/spacing_y 226 y = y/spacing_y
237 z = z/spacing_z 227 z = z/spacing_z
238 - 228 +
239 # Based on the current orientation, we define 3D position 229 # Based on the current orientation, we define 3D position
240 coordinates = {"SAGITAL": [self.slice_number, y, z], 230 coordinates = {"SAGITAL": [self.slice_number, y, z],
241 "CORONAL": [x, self.slice_number, z], 231 "CORONAL": [x, self.slice_number, z],
242 "AXIAL": [x, y, self.slice_number]} 232 "AXIAL": [x, y, self.slice_number]}
243 coord = [int(coord) for coord in coordinates[self.orientation]] 233 coord = [int(coord) for coord in coordinates[self.orientation]]
244 - 234 +
245 # According to vtkImageData extent, we limit min and max value 235 # According to vtkImageData extent, we limit min and max value
246 # If this is not done, a VTK Error occurs when mouse is pressed outside 236 # If this is not done, a VTK Error occurs when mouse is pressed outside
247 # vtkImageData extent 237 # vtkImageData extent
@@ -254,24 +244,24 @@ class Viewer(wx.Panel): @@ -254,24 +244,24 @@ class Viewer(wx.Panel):
254 elif coord[index] < extent_min[index]: 244 elif coord[index] < extent_min[index]:
255 coord[index] = extent_min[index] 245 coord[index] = extent_min[index]
256 #print "New coordinate: ", coord 246 #print "New coordinate: ", coord
257 - 247 +
258 return coord 248 return coord
259 - 249 +
260 def GetCoordinateCursor(self): 250 def GetCoordinateCursor(self):
261 - 251 +
262 # Find position 252 # Find position
263 mouse_x, mouse_y = self.interactor.GetEventPosition() 253 mouse_x, mouse_y = self.interactor.GetEventPosition()
264 self.pick.Pick(mouse_x, mouse_y, 0, self.ren) 254 self.pick.Pick(mouse_x, mouse_y, 0, self.ren)
265 x, y, z = self.pick.GetPickPosition() 255 x, y, z = self.pick.GetPickPosition()
266 return x, y, z 256 return x, y, z
267 - 257 +
268 def GetCoordinateCursorEdition(self): 258 def GetCoordinateCursorEdition(self):
269 - 259 +
270 # Find position 260 # Find position
271 mouse_x, mouse_y = self.interactor.GetEventPosition() 261 mouse_x, mouse_y = self.interactor.GetEventPosition()
272 self.pick.Pick(mouse_x, mouse_y, 0, self.ren) 262 self.pick.Pick(mouse_x, mouse_y, 0, self.ren)
273 x, y, z = self.pick.GetPickPosition() 263 x, y, z = self.pick.GetPickPosition()
274 - 264 +
275 # First we fix the position origin, based on vtkActor bounds 265 # First we fix the position origin, based on vtkActor bounds
276 bounds = self.actor.GetBounds() 266 bounds = self.actor.GetBounds()
277 bound_xi, bound_xf, bound_yi, bound_yf, bound_zi, bound_zf = bounds 267 bound_xi, bound_xf, bound_yi, bound_yf, bound_zi, bound_zf = bounds
@@ -299,21 +289,21 @@ class Viewer(wx.Panel): @@ -299,21 +289,21 @@ class Viewer(wx.Panel):
299 z = self.slice_number 289 z = self.slice_number
300 290
301 return x,y,z 291 return x,y,z
302 - 292 +
303 def __bind_events(self): 293 def __bind_events(self):
304 ps.Publisher().subscribe(self.LoadImagedata, 'Load slice to viewer') 294 ps.Publisher().subscribe(self.LoadImagedata, 'Load slice to viewer')
305 ps.Publisher().subscribe(self.SetColour, 'Change mask colour') 295 ps.Publisher().subscribe(self.SetColour, 'Change mask colour')
306 ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer') 296 ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer')
307 - ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position', 297 + ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position',
308 self.orientation)) 298 self.orientation))
309 - 299 +
310 ### 300 ###
311 ps.Publisher().subscribe(self.ChangeBrushSize,'Set edition brush size') 301 ps.Publisher().subscribe(self.ChangeBrushSize,'Set edition brush size')
312 ps.Publisher().subscribe(self.ChangeBrushColour, 'Add mask') 302 ps.Publisher().subscribe(self.ChangeBrushColour, 'Add mask')
313 ps.Publisher().subscribe(self.ChangeBrushActor, 'Set brush format') 303 ps.Publisher().subscribe(self.ChangeBrushActor, 'Set brush format')
314 ps.Publisher().subscribe(self.ChangeBrushOperation, 'Set edition operation') 304 ps.Publisher().subscribe(self.ChangeBrushOperation, 'Set edition operation')
315 -  
316 - 305 +
  306 +
317 def ChangeBrushOperation(self, pubsub_evt): 307 def ChangeBrushOperation(self, pubsub_evt):
318 print pubsub_evt.data 308 print pubsub_evt.data
319 self._brush_cursor_op = pubsub_evt.data 309 self._brush_cursor_op = pubsub_evt.data
@@ -339,6 +329,7 @@ class Viewer(wx.Panel): @@ -339,6 +329,7 @@ class Viewer(wx.Panel):
339 329
340 actor = vtk.vtkImageActor() 330 actor = vtk.vtkImageActor()
341 actor.SetInput(slice_.GetOutput()) 331 actor.SetInput(slice_.GetOutput())
  332 + actor_bound = actor.GetBounds()
342 self.actor = actor 333 self.actor = actor
343 334
344 colour = const.ORIENTATION_COLOUR[self.orientation] 335 colour = const.ORIENTATION_COLOUR[self.orientation]
@@ -363,7 +354,30 @@ class Viewer(wx.Panel): @@ -363,7 +354,30 @@ class Viewer(wx.Panel):
363 self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number, 354 self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number,
364 max_slice_number) 355 max_slice_number)
365 self.SetScrollPosition(0) 356 self.SetScrollPosition(0)
366 - self.cursor.SetSpacing(imagedata.GetSpacing()) 357 +
  358 + actor_bound = actor.GetBounds()
  359 +
  360 + # Insert cursor
  361 + cursor = ca.CursorCircle()
  362 + cursor.SetOrientation(self.orientation)
  363 + self.__update_cursor_position()
  364 + cursor.SetSpacing(imagedata.GetSpacing())
  365 + self.ren.AddActor(cursor.actor)
  366 + self.ren.Render()
  367 +
  368 + self.cursor = cursor
  369 +
  370 + self.AppendMode('EDITOR')
  371 +
  372 + def __update_cursor_position(self, position = None):
  373 +
  374 + if (self.cursor):
  375 + slice_number = self.slice_number
  376 + actor_bound = self.actor.GetBounds()
  377 + coordinates = {"SAGITAL": [actor_bound[1] + 1 + slice_number, actor_bound[3], actor_bound[5]],
  378 + "CORONAL": [actor_bound[1], actor_bound[3] + 1 + slice_number, actor_bound[5]],
  379 + "AXIAL": [actor_bound[1], actor_bound[3], actor_bound[5] + 1 + slice_number]}
  380 + self.cursor.SetPosition(coordinates[self.orientation])
367 381
368 def SetOrientation(self, orientation): 382 def SetOrientation(self, orientation):
369 self.orientation = orientation 383 self.orientation = orientation
@@ -378,10 +392,10 @@ class Viewer(wx.Panel): @@ -378,10 +392,10 @@ class Viewer(wx.Panel):
378 cam.SetViewUp(const.CAM_VIEW_UP[self.orientation]) 392 cam.SetViewUp(const.CAM_VIEW_UP[self.orientation])
379 cam.ComputeViewPlaneNormal() 393 cam.ComputeViewPlaneNormal()
380 cam.OrthogonalizeViewUp() 394 cam.OrthogonalizeViewUp()
381 - cam.ParallelProjectionOn() 395 + cam.ParallelProjectionOn()
382 396
383 self.__update_display_extent() 397 self.__update_display_extent()
384 - 398 +
385 self.ren.ResetCamera() 399 self.ren.ResetCamera()
386 self.ren.Render() 400 self.ren.Render()
387 401
@@ -389,11 +403,11 @@ class Viewer(wx.Panel): @@ -389,11 +403,11 @@ class Viewer(wx.Panel):
389 403
390 pos = self.slice_number 404 pos = self.slice_number
391 e = self.imagedata.GetWholeExtent() 405 e = self.imagedata.GetWholeExtent()
392 - 406 +
393 new_extent = {"SAGITAL": (pos, pos, e[2], e[3], e[4], e[5]), 407 new_extent = {"SAGITAL": (pos, pos, e[2], e[3], e[4], e[5]),
394 "CORONAL": (e[0], e[1], pos, pos, e[4], e[5]), 408 "CORONAL": (e[0], e[1], pos, pos, e[4], e[5]),
395 "AXIAL": (e[0], e[1], e[2], e[3], pos, pos)} 409 "AXIAL": (e[0], e[1], e[2], e[3], pos, pos)}
396 - 410 +
397 self.actor.SetDisplayExtent(new_extent[self.orientation]) 411 self.actor.SetDisplayExtent(new_extent[self.orientation])
398 self.ren.ResetCameraClippingRange() 412 self.ren.ResetCameraClippingRange()
399 self.ren.Render() 413 self.ren.Render()
@@ -416,6 +430,7 @@ class Viewer(wx.Panel): @@ -416,6 +430,7 @@ class Viewer(wx.Panel):
416 self.text_actor.SetInput(str(index)) 430 self.text_actor.SetInput(str(index))
417 self.slice_number = index 431 self.slice_number = index
418 self.__update_display_extent() 432 self.__update_display_extent()
  433 + self.__update_cursor_position()
419 434
420 def ChangeSliceNumber(self, pubsub_evt): 435 def ChangeSliceNumber(self, pubsub_evt):
421 index = pubsub_evt.data 436 index = pubsub_evt.data