def __init__(self, rwi, renderer): # nnsmit-edit self.overlay_active = 0; # end edit self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) self.ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.ipws[0].GetLookupTable() for ipw in self.ipws: ipw.SetInteractor(rwi) ipw.SetLookupTable(lut) # nnsmit-edit self.overlay_ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut2 = self.overlay_ipws[0].GetLookupTable() lut2.SetNumberOfTableValues(3) lut2.SetTableValue(0,0,0,0,0) lut2.SetTableValue(1,0.5,0,1,1) lut2.SetTableValue(2,1,0,0,1) lut2.Build() for ipw_overlay in self.overlay_ipws: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # now actually connect the sync_overlay observer for i,ipw in enumerate(self.ipws): ipw.AddObserver('InteractionEvent',lambda vtk_o, vtk_e, i=i: self.observer_sync_overlay(self.ipws,i)) # end edit # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipws[0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0)
def __init__(self, rwi, renderer): self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) self.ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.ipws[0].GetLookupTable() for ipw in self.ipws: ipw.SetInteractor(rwi) ipw.SetLookupTable(lut) # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipws[0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0)
def __init__(self, rwi, renderer): self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) #This is a collection of 1- or 3-component image plane widgets. Each entry corresponds to a single overlay. self.ipw_triads = {} self.add_overlay( 0, [0, 0, 0, 0.1] ) #Almost-transparent black - for showing the pickable plane stored at id = 0. # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipw_triads[0][0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0, 0, 0) self.current_index_pos = (0, 0, 0)
def __init__(self, rwi, renderer): self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) #This is a collection of 1- or 3-component image plane widgets. Each entry corresponds to a single overlay. self.ipw_triads = {} self.add_overlay(0, [0, 0, 0, 0.1]) #Almost-transparent black - for showing the pickable plane stored at id = 0. # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipw_triads[0][0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0)
class CMSliceViewer: """Simple class for enabling 1 or 3 ortho slices in a 3D scene. """ def __init__(self, rwi, renderer): # nnsmit-edit self.overlay_active = 0; # end edit self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) self.ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.ipws[0].GetLookupTable() for ipw in self.ipws: ipw.SetInteractor(rwi) ipw.SetLookupTable(lut) # nnsmit-edit self.overlay_ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut2 = self.overlay_ipws[0].GetLookupTable() lut2.SetNumberOfTableValues(3) lut2.SetTableValue(0,0,0,0,0) lut2.SetTableValue(1,0.5,0,1,1) lut2.SetTableValue(2,1,0,0,1) lut2.Build() for ipw_overlay in self.overlay_ipws: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # now actually connect the sync_overlay observer for i,ipw in enumerate(self.ipws): ipw.AddObserver('InteractionEvent',lambda vtk_o, vtk_e, i=i: self.observer_sync_overlay(self.ipws,i)) # end edit # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipws[0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0) # nnsmit-edit def observer_sync_overlay(self,ipws,ipw_idx): # get the primary IPW pipw = ipws[ipw_idx] # get the overlay IPW oipw = self.overlay_ipws[ipw_idx] # get plane geometry from primary o,p1,p2 = pipw.GetOrigin(),pipw.GetPoint1(),pipw.GetPoint2() # and apply to the overlay oipw.SetOrigin(o) oipw.SetPoint1(p1) oipw.SetPoint2(p2) oipw.UpdatePlacement() # end edit def close(self): self.set_input(None) self.dv_orientation_widget.close() self.set_overlay_input(None) def activate_slice(self, idx): if idx in [1,2]: self.ipws[idx].SetEnabled(1) self.ipws[idx].SetPicker(self.picker) def deactivate_slice(self, idx): if idx in [1,2]: self.ipws[idx].SetEnabled(0) self.ipws[idx].SetPicker(None) def get_input(self): return self.ipws[0].GetInput() def get_world_pos(self, image_pos): """Given image coordinates, return the corresponding world position. """ idata = self.get_input() if not idata: return None ispacing = idata.GetSpacing() iorigin = idata.GetOrigin() # calculate real coords world = map(operator.add, iorigin, map(operator.mul, ispacing, image_pos[0:3])) def set_perspective(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOff() def set_parallel(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOn() # nnsmit edit def set_opacity(self,opacity): lut = self.ipws[0].GetLookupTable() lut.SetAlphaRange(opacity, opacity) lut.Build() self.ipws[0].SetLookupTable(lut) # end edit def _handler_mousewheel(self, event): # event.GetWheelRotation() is + or - 120 depending on # direction of turning. if event.ControlDown(): delta = 10 elif event.ShiftDown(): delta = 1 else: # if user is NOT doing shift / control, we pass on to the # default handling which will give control to the VTK # mousewheel handlers. self.rwi.OnMouseWheel(event) return if event.GetWheelRotation() > 0: self._ipw1_delta_slice(+delta) else: self._ipw1_delta_slice(-delta) self.render() self.ipws[0].InvokeEvent('InteractionEvent') def _ipw1_delta_slice(self, delta): """Move to the delta slices fw/bw, IF the IPW is currently aligned with one of the axes. """ ipw = self.ipws[0] if ipw.GetPlaneOrientation() < 3: ci = ipw.GetSliceIndex() ipw.SetSliceIndex(ci + delta) def render(self): self.rwi.GetRenderWindow().Render() # nnsmit edit # synch those overlays: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) # end edit def reset_camera(self): self.renderer.ResetCamera() cam = self.renderer.GetActiveCamera() cam.SetViewUp(0,-1,0) def reset_to_default_view(self, view_index): """ @param view_index 2 for XY """ if view_index == 2: cam = self.renderer.GetActiveCamera() # then make sure it's up is the right way cam.SetViewUp(0,-1,0) # just set the X,Y of the camera equal to the X,Y of the # focal point. fp = cam.GetFocalPoint() cp = cam.GetPosition() if cp[2] < fp[2]: z = fp[2] + (fp[2] - cp[2]) else: z = cp[2] cam.SetPosition(fp[0], fp[1], z) # first reset the camera self.renderer.ResetCamera() # nnsmit edit # synch overlays as well: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): ipw_overlay.SetSliceIndex(0) for i, ipw in enumerate(self.ipws): ipw.SetWindowLevel(500,-800,0) self.render() # end edit def set_input(self, input): ipw = self.ipws[0] ipw.DisplayTextOn() if input == ipw.GetInput(): return if input is None: # remove outline actor, else this will cause errors when # we disable the IPWs (they call a render!) self.renderer.RemoveViewProp(self.outline_actor) self.outline_source.SetInput(None) self.dv_orientation_widget.set_input(None) for ipw in self.ipws: # argh, this disable causes a render ipw.SetEnabled(0) ipw.SetInput(None) else: self.outline_source.SetInput(input) self.renderer.AddViewProp(self.outline_actor) orientations = [2, 0, 1] active = [1, 0, 0] for i, ipw in enumerate(self.ipws): ipw.SetInput(input) ipw.SetWindowLevel(500,-800,0) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.dv_orientation_widget.set_input(input) # nnsmit-edit # FIXME: Create pretty fix for this codeclone. def set_overlay_input(self, input): self.overlay_active = 1 ipw = self.overlay_ipws[0] if input == ipw.GetInput(): return if input is None: self.overlay_active = 0; for ipw_overlay in self.overlay_ipws: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render()
def __init__(self, rwi, renderer): # nnsmit-edit self.overlay_active = 0; self.overlay_active_voxels = 0; self.overlay_active_100band1 = 0; self.overlay_active_100band2 = 0; self.overlay_active_100band3 = 0; self.overlay_active_50band1 = 0; self.overlay_active_50band2 = 0; self.overlay_active_50band3 = 0; # end edit self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) self.ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.ipws[0].GetLookupTable() for ipw in self.ipws: ipw.SetInteractor(rwi) ipw.SetLookupTable(lut) # IPWS for overlay self.overlay_ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.overlay_ipws[0].GetLookupTable() lut.SetNumberOfTableValues(3) lut.SetTableValue(0,0,0,0,0) lut.SetTableValue(1,0.5,0,1,1) lut.SetTableValue(2,1,0,0,1) lut.Build() for ipw_overlay in self.overlay_ipws: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for voxels selected in scatterplot self.overlay_ipws_voxels = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.overlay_ipws_voxels[0].GetLookupTable() lut.SetNumberOfTableValues(3) lut.SetTableValue(0,0,0,0,0) lut.SetTableValue(1,0.5,0,1,1) lut.SetTableValue(2,1,0,0,1) lut.Build() for ipw_overlay in self.overlay_ipws_voxels: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in first row self.overlay_ipws_100band1 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut1 = self.overlay_ipws_100band1[0].GetLookupTable() lut1.SetNumberOfTableValues(3) lut1.SetTableValue(0,0,0,0,0) lut1.SetTableValue(1, 1, 1, 0, 1) lut1.SetTableValue(2, 1,1,0, 1) lut1.Modified() lut1.Build() for ipw_overlay in self.overlay_ipws_100band1: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut1) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 50%band in first row self.overlay_ipws_50band1 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut1 = self.overlay_ipws_50band1[0].GetLookupTable() lut1.SetNumberOfTableValues(3) lut1.SetTableValue(0,0,0,0,0) lut1.SetTableValue(1, 1, 1, 0, 1) lut1.SetTableValue(2, 1,1,0, 1) lut1.Modified() lut1.Build() for ipw_overlay in self.overlay_ipws_50band1: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut1) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in second row self.overlay_ipws_100band2 = [vtk.vtkImagePlaneWidget() for _ in range(3)] #lut2 = self.overlay_ipws_100band2[0].GetLookupTable() #lut2.SetNumberOfTableValues(3) #lut2.SetTableValue(0,0,0,0,0) #lut2.SetTableValue(1, 0.98,0,0, 0.37) #lut2.SetTableValue(2, 0.98,0,0, 0.37) #lut2.Modified() #lut2.Build() for ipw_overlay in self.overlay_ipws_100band2: ipw_overlay.SetInteractor(rwi) #ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in second row self.overlay_ipws_50band2 = [vtk.vtkImagePlaneWidget() for _ in range(3)] #lut2 = self.overlay_ipws_100band2[0].GetLookupTable() #lut2.SetNumberOfTableValues(3) #lut2.SetTableValue(0,0,0,0,0) #lut2.SetTableValue(1, 0.98,0,0, 0.37) #lut2.SetTableValue(2, 0.98,0,0, 0.37) #lut2.Modified() #lut2.Build() for ipw_overlay in self.overlay_ipws_50band2: ipw_overlay.SetInteractor(rwi) #ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in third row self.overlay_ipws_100band3 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut3 = self.overlay_ipws_100band3[0].GetLookupTable() lut3.SetNumberOfTableValues(3) lut3.SetTableValue(0,0,0,0,0) lut3.SetTableValue(1,0,0.643,0.941, 0.5) lut3.SetTableValue(2,0,0.643,0.941, 0.5) lut3.Modified() lut3.Build() for ipw_overlay in self.overlay_ipws_100band3: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut3) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 50%band in third row self.overlay_ipws_50band3 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut3 = self.overlay_ipws_50band3[0].GetLookupTable() lut3.SetNumberOfTableValues(3) lut3.SetTableValue(0,0,0,0,0) lut3.SetTableValue(1,0,0.643,0.941, 0.5) lut3.SetTableValue(2,0,0.643,0.941, 0.5) lut3.Modified() lut3.Build() for ipw_overlay in self.overlay_ipws_50band3: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut3) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # now actually connect the sync_overlay observer for i,ipw in enumerate(self.ipws): ipw.AddObserver('InteractionEvent',lambda vtk_o, vtk_e, i=i: self.observer_sync_overlay(self.ipws,i)) # end edit # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipws[0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0)
class CMSliceViewer: """Simple class for enabling 1 or 3 ortho slices in a 3D scene. """ def __init__(self, rwi, renderer): # nnsmit-edit self.overlay_active = 0; self.overlay_active_voxels = 0; self.overlay_active_100band1 = 0; self.overlay_active_100band2 = 0; self.overlay_active_100band3 = 0; self.overlay_active_50band1 = 0; self.overlay_active_50band2 = 0; self.overlay_active_50band3 = 0; # end edit self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) self.ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.ipws[0].GetLookupTable() for ipw in self.ipws: ipw.SetInteractor(rwi) ipw.SetLookupTable(lut) # IPWS for overlay self.overlay_ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.overlay_ipws[0].GetLookupTable() lut.SetNumberOfTableValues(3) lut.SetTableValue(0,0,0,0,0) lut.SetTableValue(1,0.5,0,1,1) lut.SetTableValue(2,1,0,0,1) lut.Build() for ipw_overlay in self.overlay_ipws: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for voxels selected in scatterplot self.overlay_ipws_voxels = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.overlay_ipws_voxels[0].GetLookupTable() lut.SetNumberOfTableValues(3) lut.SetTableValue(0,0,0,0,0) lut.SetTableValue(1,0.5,0,1,1) lut.SetTableValue(2,1,0,0,1) lut.Build() for ipw_overlay in self.overlay_ipws_voxels: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in first row self.overlay_ipws_100band1 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut1 = self.overlay_ipws_100band1[0].GetLookupTable() lut1.SetNumberOfTableValues(3) lut1.SetTableValue(0,0,0,0,0) lut1.SetTableValue(1, 1, 1, 0, 1) lut1.SetTableValue(2, 1,1,0, 1) lut1.Modified() lut1.Build() for ipw_overlay in self.overlay_ipws_100band1: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut1) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 50%band in first row self.overlay_ipws_50band1 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut1 = self.overlay_ipws_50band1[0].GetLookupTable() lut1.SetNumberOfTableValues(3) lut1.SetTableValue(0,0,0,0,0) lut1.SetTableValue(1, 1, 1, 0, 1) lut1.SetTableValue(2, 1,1,0, 1) lut1.Modified() lut1.Build() for ipw_overlay in self.overlay_ipws_50band1: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut1) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in second row self.overlay_ipws_100band2 = [vtk.vtkImagePlaneWidget() for _ in range(3)] #lut2 = self.overlay_ipws_100band2[0].GetLookupTable() #lut2.SetNumberOfTableValues(3) #lut2.SetTableValue(0,0,0,0,0) #lut2.SetTableValue(1, 0.98,0,0, 0.37) #lut2.SetTableValue(2, 0.98,0,0, 0.37) #lut2.Modified() #lut2.Build() for ipw_overlay in self.overlay_ipws_100band2: ipw_overlay.SetInteractor(rwi) #ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in second row self.overlay_ipws_50band2 = [vtk.vtkImagePlaneWidget() for _ in range(3)] #lut2 = self.overlay_ipws_100band2[0].GetLookupTable() #lut2.SetNumberOfTableValues(3) #lut2.SetTableValue(0,0,0,0,0) #lut2.SetTableValue(1, 0.98,0,0, 0.37) #lut2.SetTableValue(2, 0.98,0,0, 0.37) #lut2.Modified() #lut2.Build() for ipw_overlay in self.overlay_ipws_50band2: ipw_overlay.SetInteractor(rwi) #ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 100%band in third row self.overlay_ipws_100band3 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut3 = self.overlay_ipws_100band3[0].GetLookupTable() lut3.SetNumberOfTableValues(3) lut3.SetTableValue(0,0,0,0,0) lut3.SetTableValue(1,0,0.643,0.941, 0.5) lut3.SetTableValue(2,0,0.643,0.941, 0.5) lut3.Modified() lut3.Build() for ipw_overlay in self.overlay_ipws_100band3: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut3) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # IPWS for overlay of 50%band in third row self.overlay_ipws_50band3 = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut3 = self.overlay_ipws_50band3[0].GetLookupTable() lut3.SetNumberOfTableValues(3) lut3.SetTableValue(0,0,0,0,0) lut3.SetTableValue(1,0,0.643,0.941, 0.5) lut3.SetTableValue(2,0,0.643,0.941, 0.5) lut3.Modified() lut3.Build() for ipw_overlay in self.overlay_ipws_50band3: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut3) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # now actually connect the sync_overlay observer for i,ipw in enumerate(self.ipws): ipw.AddObserver('InteractionEvent',lambda vtk_o, vtk_e, i=i: self.observer_sync_overlay(self.ipws,i)) # end edit # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipws[0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0) # nnsmit-edit def observer_sync_overlay(self,ipws,ipw_idx): # get the primary IPW pipw = ipws[ipw_idx] # get the overlay IPW oipw = self.overlay_ipws[ipw_idx] #get the voxels overlay IPW oipwvoxels = self.overlay_ipws_voxels[ipw_idx] #get the overlay IPW for 100%band in first row oipw100r1 = self.overlay_ipws_100band1[ipw_idx] #get the overlay IPW for 50%band in first row oipw50r1 = self.overlay_ipws_50band1[ipw_idx] #get the overlay IPW for 100%band in second row oipw100r2 = self.overlay_ipws_100band2[ipw_idx] #get the overlay IPW for 100%band in second row oipw50r2 = self.overlay_ipws_50band2[ipw_idx] #get the overlay IPW for 100%band in third row oipw100r3 = self.overlay_ipws_100band3[ipw_idx] #get the overlay IPW for 50%band in third row oipw50r3 = self.overlay_ipws_50band3[ipw_idx] # get plane geometry from primary o,p1,p2 = pipw.GetOrigin(),pipw.GetPoint1(),pipw.GetPoint2() # and apply to the overlay oipw.SetOrigin(o) oipw.SetPoint1(p1) oipw.SetPoint2(p2) oipw.UpdatePlacement() oipwvoxels.SetOrigin(o) oipwvoxels.SetPoint1(p1) oipwvoxels.SetPoint2(p2) oipwvoxels.UpdatePlacement() oipw100r1.SetOrigin(o) oipw100r1.SetPoint1(p1) oipw100r1.SetPoint2(p2) oipw100r1.UpdatePlacement() oipw50r1.SetOrigin(o) oipw50r1.SetPoint1(p1) oipw50r1.SetPoint2(p2) oipw50r1.UpdatePlacement() oipw100r2.SetOrigin(o) oipw100r2.SetPoint1(p1) oipw100r2.SetPoint2(p2) oipw100r2.UpdatePlacement() oipw50r2.SetOrigin(o) oipw50r2.SetPoint1(p1) oipw50r2.SetPoint2(p2) oipw50r2.UpdatePlacement() oipw100r3.SetOrigin(o) oipw100r3.SetPoint1(p1) oipw100r3.SetPoint2(p2) oipw100r3.UpdatePlacement() oipw50r3.SetOrigin(o) oipw50r3.SetPoint1(p1) oipw50r3.SetPoint2(p2) oipw50r3.UpdatePlacement() # end edit def close(self): self.set_input(None) self.dv_orientation_widget.close() self.set_overlay_input(None) self.set_overlay_input_voxels(None) self.set_overlay_input_axial_100band1(None) self.set_overlay_input_sagittal_100band1(None) self.set_overlay_input_coronal_100band1(None) self.set_overlay_input_axial_100band2(None) self.set_overlay_input_sagittal_100band2(None) self.set_overlay_input_coronal_100band2(None) self.set_overlay_input_axial_100band3(None) self.set_overlay_input_sagittal_100band3(None) self.set_overlay_input_coronal_100band3(None) self.set_overlay_input_axial_50band1(None) self.set_overlay_input_sagittal_50band1(None) self.set_overlay_input_coronal_50band1(None) self.set_overlay_input_axial_50band2(None) self.set_overlay_input_sagittal_50band2(None) self.set_overlay_input_coronal_50band2(None) self.set_overlay_input_axial_50band3(None) self.set_overlay_input_sagittal_50band3(None) self.set_overlay_input_coronal_50band3(None) def activate_slice(self, idx): if idx in [1,2]: self.ipws[idx].SetEnabled(1) self.ipws[idx].SetPicker(self.picker) def deactivate_slice(self, idx): if idx in [1,2]: self.ipws[idx].SetEnabled(0) self.ipws[idx].SetPicker(None) def get_input(self): return self.ipws[0].GetInput() def get_world_pos(self, image_pos): """Given image coordinates, return the corresponding world position. """ idata = self.get_input() if not idata: return None ispacing = idata.GetSpacing() iorigin = idata.GetOrigin() # calculate real coords world = map(operator.add, iorigin, map(operator.mul, ispacing, image_pos[0:3])) def set_perspective(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOff() def set_parallel(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOn() # nnsmit edit def set_opacity(self,opacity): lut = self.ipws[0].GetLookupTable() lut.SetAlphaRange(opacity, opacity) lut.Build() self.ipws[0].SetLookupTable(lut) # end edit def _handler_mousewheel(self, event): # event.GetWheelRotation() is + or - 120 depending on # direction of turning. if event.ControlDown(): delta = 10 elif event.ShiftDown(): delta = 1 else: # if user is NOT doing shift / control, we pass on to the # default handling which will give control to the VTK # mousewheel handlers. self.rwi.OnMouseWheel(event) return if event.GetWheelRotation() > 0: self._ipw1_delta_slice(+delta) else: self._ipw1_delta_slice(-delta) self.render() self.ipws[0].InvokeEvent('InteractionEvent') def _ipw1_delta_slice(self, delta): """Move to the delta slices fw/bw, IF the IPW is currently aligned with one of the axes. """ ipw = self.ipws[0] if ipw.GetPlaneOrientation() < 3: ci = ipw.GetSliceIndex() ipw.SetSliceIndex(ci + delta) def render(self): self.rwi.GetRenderWindow().Render() # nnsmit edit # synch those overlays: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_voxels == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_voxels): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_100band1 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_100band1): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_100band2 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_100band2): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_100band3 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_100band3): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_50band1 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_50band1): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_50band2 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_50band2): self.observer_sync_overlay(self.ipws, i) if self.overlay_active_50band3 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_50band3): self.observer_sync_overlay(self.ipws, i) # end edit def reset_camera(self): self.renderer.ResetCamera() cam = self.renderer.GetActiveCamera() cam.SetViewUp(0,-1,0) def reset_to_default_view(self, view_index): """ @param view_index 2 for XY """ if view_index == 2: cam = self.renderer.GetActiveCamera() # then make sure it's up is the right way cam.SetViewUp(0,-1,0) # just set the X,Y of the camera equal to the X,Y of the # focal point. fp = cam.GetFocalPoint() cp = cam.GetPosition() if cp[2] < fp[2]: z = fp[2] + (fp[2] - cp[2]) else: z = cp[2] cam.SetPosition(fp[0], fp[1], z) # first reset the camera self.renderer.ResetCamera() # nnsmit edit # synch overlays as well: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): ipw_overlay.SetSliceIndex(0) if self.overlay_active_voxels == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_voxels): ipw_overlay.SetSliceIndex(0) if self.overlay_active_100band1 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_100band1): ipw_overlay.SetSliceIndex(0) if self.overlay_active_100band2 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_100band2): ipw_overlay.SetSliceIndex(0) if self.overlay_active_100band3 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_100band3): ipw_overlay.SetSliceIndex(0) if self.overlay_active_50band1 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_50band1): ipw_overlay.SetSliceIndex(0) if self.overlay_active_50band2 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_50band2): ipw_overlay.SetSliceIndex(0) if self.overlay_active_50band3 == 1: for i, ipw_overlay in enumerate(self.overlay_ipws_50band3): ipw_overlay.SetSliceIndex(0) for i, ipw in enumerate(self.ipws): ipw.SetWindowLevel(500,-800,0) self.render() # end edit def set_input(self, input): ipw = self.ipws[0] ipw.DisplayTextOn() if input == ipw.GetInput(): return if input is None: # remove outline actor, else this will cause errors when # we disable the IPWs (they call a render!) self.renderer.RemoveViewProp(self.outline_actor) self.outline_source.SetInput(None) self.dv_orientation_widget.set_input(None) for ipw in self.ipws: # argh, this disable causes a render ipw.SetEnabled(0) ipw.SetInput(None) else: self.outline_source.SetInput(input) self.renderer.AddViewProp(self.outline_actor) orientations = [2, 0, 1] active = [1, 0, 0] for i, ipw in enumerate(self.ipws): ipw.SetInput(input) ipw.SetWindowLevel(500,-800,0) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.dv_orientation_widget.set_input(input) # nnsmit-edit #-------------------------- Set the overlays for the average dose plan color mapping ---------------------------- def set_overlay_input(self, input): self.overlay_active = 1 ipw = self.overlay_ipws[0] if input == ipw.GetInput(): return if input is None: self.overlay_active = 0; for ipw_overlay in self.overlay_ipws: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_inputS(self, input): self.overlay_active = 1 ipw = self.overlay_ipws[1] if input == ipw.GetInput(): return if input is None: self.overlay_active = 0; for ipw_overlay in self.overlay_ipws: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_inputC(self, input): self.overlay_active = 1 ipw = self.overlay_ipws[2] if input == ipw.GetInput(): return if input is None: self.overlay_active = 0; for ipw_overlay in self.overlay_ipws: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_voxels(self, input): self.overlay_active_voxels = 1 ipw = self.overlay_ipws_voxels[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_voxels = 0; for ipw_overlay in self.overlay_ipws_voxels: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_voxels): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() #-------------------------- Set the overlays for the contour bands ---------------------------- ''' An image plan widget has 3 axes: axial, sagittal and coronal. The set_overlay methods use the ipws. Because the 50%band and the 100%band are different files, and also because there are 3 rows with changeable isovalues, it's necessary to create an ipws for every band in every row. This is an hack / Hard coded feature, create specifically for Ensemble Viewer. The nomenclature is: set_overlay_input_axial_100band1 ---------------------------> Set overlay for 100% band in row 1, in axial plane ------------| set_overlay_input_sagittal_100band1 ------------------------> Set overlay for 100% band in row 1, in sagittal plane | overlay_ipws_100band1, overlay_active_100band1 set_overlay_input_coronal_100band1 ------------------------> Set overlay for 100% band in row 1, in coronal plane-----------| set_overlay_input_axial_50band1 ---------------------------> Set overlay for 50% band in row 1, in axial plane ------------| set_overlay_input_sagittal_50band1 ------------------------> Set overlay for 50% band in row 1, in sagittal plane | overlay_ipws_50band1, overlay_active_50band1 set_overlay_input_coronal_50band1 ------------------------> Set overlay for 50% band in row 1, in coronal plane-----------| -------------------------------------------------------------------------------------------------------------------------------------------------------------- set_overlay_input_axial_100band2 ---------------------------> Set overlay for 100% band in row 2, in axial plane ------------| set_overlay_input_sagittal_100band2 ------------------------> Set overlay for 100% band in row 2, in sagittal plane | overlay_ipws_100band2, overlay_active_100band2 set_overlay_input_coronal_100band2 ------------------------> Set overlay for 100% band in row 2, in coronal plane-----------| set_overlay_input_axial_50band2 ---------------------------> Set overlay for 50% band in row 2, in axial plane ------------| set_overlay_input_sagittal_50band2 ------------------------> Set overlay for 50% band in row 2, in sagittal plane | overlay_ipws_50band2, overlay_active_50band2 set_overlay_input_coronal_50band2 ------------------------> Set overlay for 50% band in row 2, in coronal plane-----------| --------------------------------------------------------------------------------------------------------------------------------------------------------------- set_overlay_input_axial_100band3 ---------------------------> Set overlay for 100% band in row 3, in axial plane ------------| set_overlay_input_sagittal_100band3 ------------------------> Set overlay for 100% band in row 3, in sagittal plane | overlay_ipws_100band3, overlay_active_100band3 set_overlay_input_coronal_100band3 ------------------------> Set overlay for 100% band in row 3, in coronal plane-----------| set_overlay_input_axial_50band3 ---------------------------> Set overlay for 50% band in row 3, in axial plane ------------| set_overlay_input_sagittal_50band3 ------------------------> Set overlay for 50% band in row 3, in sagittal plane | overlay_ipws_100band3, overlay_active_100band3 set_overlay_input_coronal_50band3 ------------------------> Set overlay for 50% band in row 3, in coronal plane-----------| ''' ###------------------------FIRST ROW---------------------------### def set_overlay_input_axial_100band1(self, input): self.overlay_active_100band1 = 1 ipw = self.overlay_ipws_100band1[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band1 = 0; for ipw_overlay in self.overlay_ipws_100band1: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band1): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_sagittal_100band1(self, input): self.overlay_active_100band1 = 1 ipw = self.overlay_ipws_100band1[1] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band1 = 0; for ipw_overlay in self.overlay_ipws_100band1: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band1): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_coronal_100band1(self, input): self.overlay_active_100band1 = 1 ipw = self.overlay_ipws_100band1[2] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band1 = 0; for ipw_overlay in self.overlay_ipws_100band1: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band1): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_axial_50band1(self, input): self.overlay_active_50band1 = 1 ipw = self.overlay_ipws_50band1[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band1 = 0; for ipw_overlay in self.overlay_ipws_50band1: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band1): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_sagittal_50band1(self, input): self.overlay_active_50band1 = 1 ipw = self.overlay_ipws_50band1[1] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band1 = 0; for ipw_overlay in self.overlay_ipws_50band1: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band1): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_coronal_50band1(self, input): self.overlay_active_50band1 = 1 ipw = self.overlay_ipws_50band1[2] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band1 = 0; for ipw_overlay in self.overlay_ipws_50band1: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band1): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render() ###------------------------SECOND ROW---------------------------### def set_overlay_input_axial_100band2(self, input): self.overlay_active_100band2 = 1 ipw = self.overlay_ipws_100band2[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band2 = 0; for ipw_overlay in self.overlay_ipws_100band2: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band2): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_sagittal_100band2(self, input): self.overlay_active_100band2 = 1 ipw = self.overlay_ipws_100band2[1] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band2 = 0; for ipw_overlay in self.overlay_ipws_100band2: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band2): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_coronal_100band2(self, input): self.overlay_active_100band2 = 1 ipw = self.overlay_ipws_100band2[2] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band2 = 0; for ipw_overlay in self.overlay_ipws_100band2: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band2): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_axial_50band2(self, input): self.overlay_active_50band2 = 1 ipw = self.overlay_ipws_50band2[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band2 = 0; for ipw_overlay in self.overlay_ipws_50band2: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band2): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_sagittal_50band2(self, input): self.overlay_active_50band2 = 1 ipw = self.overlay_ipws_50band2[1] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band2 = 0; for ipw_overlay in self.overlay_ipws_50band2: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band2): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_coronal_50band2(self, input): self.overlay_active_50band2 = 1 ipw = self.overlay_ipws_50band2[2] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band2 = 0; for ipw_overlay in self.overlay_ipws_50band2: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band2): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render() ###-------------------------THIRD ROW---------------------------### def set_overlay_input_axial_100band3(self, input): self.overlay_active_100band3 = 1 ipw = self.overlay_ipws_100band3[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band3 = 0; for ipw_overlay in self.overlay_ipws_100band3: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band3): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_sagittal_100band3(self, input): self.overlay_active_100band3 = 1 ipw = self.overlay_ipws_100band3[1] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band3 = 0; for ipw_overlay in self.overlay_ipws_100band3: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band3): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_coronal_100band3(self, input): self.overlay_active_100band3 = 1 ipw = self.overlay_ipws_100band3[2] if input == ipw.GetInput(): return if input is None: self.overlay_active_100band3 = 0; for ipw_overlay in self.overlay_ipws_100band3: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_100band3): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_axial_50band3(self, input): self.overlay_active_50band3 = 1 ipw = self.overlay_ipws_50band3[0] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band3 = 0; for ipw_overlay in self.overlay_ipws_50band3: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band3): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_sagittal_50band3(self, input): self.overlay_active_50band3 = 1 ipw = self.overlay_ipws_50band3[1] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band1 = 0; for ipw_overlay in self.overlay_ipws_50band3: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 1, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band3): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # sagittal ipw_overlay.SetEnabled(active[i]) self.render() def set_overlay_input_coronal_50band3(self, input): self.overlay_active_50band3 = 1 ipw = self.overlay_ipws_50band3[2] if input == ipw.GetInput(): return if input is None: self.overlay_active_50band3 = 0; for ipw_overlay in self.overlay_ipws_50band3: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [0, 0, 1] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws_50band3): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # coronal ipw_overlay.SetEnabled(active[i]) self.render()
class CMSliceViewer: """Simple class for enabling 1 or 3 ortho slices in a 3D scene. """ def __init__(self, rwi, renderer): # nnsmit-edit self.overlay_active = 0 # end edit self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) self.ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = self.ipws[0].GetLookupTable() for ipw in self.ipws: ipw.SetInteractor(rwi) ipw.SetLookupTable(lut) # nnsmit-edit self.overlay_ipws = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut2 = self.overlay_ipws[0].GetLookupTable() lut2.SetNumberOfTableValues(3) lut2.SetTableValue(0, 0, 0, 0, 0) lut2.SetTableValue(1, 0.5, 0, 1, 1) lut2.SetTableValue(2, 1, 0, 0, 1) lut2.Build() for ipw_overlay in self.overlay_ipws: ipw_overlay.SetInteractor(rwi) ipw_overlay.SetLookupTable(lut2) ipw_overlay.AddObserver('InteractionEvent', wx.EVT_MOUSEWHEEL) # now actually connect the sync_overlay observer for i, ipw in enumerate(self.ipws): ipw.AddObserver('InteractionEvent', lambda vtk_o, vtk_e, i=i: self. observer_sync_overlay(self.ipws, i)) # end edit # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipws[0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0, 0, 0) self.current_index_pos = (0, 0, 0) # nnsmit-edit def observer_sync_overlay(self, ipws, ipw_idx): # get the primary IPW pipw = ipws[ipw_idx] # get the overlay IPW oipw = self.overlay_ipws[ipw_idx] # get plane geometry from primary o, p1, p2 = pipw.GetOrigin(), pipw.GetPoint1(), pipw.GetPoint2() # and apply to the overlay oipw.SetOrigin(o) oipw.SetPoint1(p1) oipw.SetPoint2(p2) oipw.UpdatePlacement() # end edit def close(self): self.set_input(None) self.dv_orientation_widget.close() self.set_overlay_input(None) def activate_slice(self, idx): if idx in [1, 2]: self.ipws[idx].SetEnabled(1) self.ipws[idx].SetPicker(self.picker) def deactivate_slice(self, idx): if idx in [1, 2]: self.ipws[idx].SetEnabled(0) self.ipws[idx].SetPicker(None) def get_input(self): return self.ipws[0].GetInput() def get_world_pos(self, image_pos): """Given image coordinates, return the corresponding world position. """ idata = self.get_input() if not idata: return None ispacing = idata.GetSpacing() iorigin = idata.GetOrigin() # calculate real coords world = map(operator.add, iorigin, map(operator.mul, ispacing, image_pos[0:3])) def set_perspective(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOff() def set_parallel(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOn() # nnsmit edit def set_opacity(self, opacity): lut = self.ipws[0].GetLookupTable() lut.SetAlphaRange(opacity, opacity) lut.Build() self.ipws[0].SetLookupTable(lut) # end edit def _handler_mousewheel(self, event): # event.GetWheelRotation() is + or - 120 depending on # direction of turning. if event.ControlDown(): delta = 10 elif event.ShiftDown(): delta = 1 else: # if user is NOT doing shift / control, we pass on to the # default handling which will give control to the VTK # mousewheel handlers. self.rwi.OnMouseWheel(event) return if event.GetWheelRotation() > 0: self._ipw1_delta_slice(+delta) else: self._ipw1_delta_slice(-delta) self.render() self.ipws[0].InvokeEvent('InteractionEvent') def _ipw1_delta_slice(self, delta): """Move to the delta slices fw/bw, IF the IPW is currently aligned with one of the axes. """ ipw = self.ipws[0] if ipw.GetPlaneOrientation() < 3: ci = ipw.GetSliceIndex() ipw.SetSliceIndex(ci + delta) def render(self): self.rwi.GetRenderWindow().Render() # nnsmit edit # synch those overlays: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) # end edit def reset_camera(self): self.renderer.ResetCamera() cam = self.renderer.GetActiveCamera() cam.SetViewUp(0, -1, 0) def reset_to_default_view(self, view_index): """ @param view_index 2 for XY """ if view_index == 2: cam = self.renderer.GetActiveCamera() # then make sure it's up is the right way cam.SetViewUp(0, -1, 0) # just set the X,Y of the camera equal to the X,Y of the # focal point. fp = cam.GetFocalPoint() cp = cam.GetPosition() if cp[2] < fp[2]: z = fp[2] + (fp[2] - cp[2]) else: z = cp[2] cam.SetPosition(fp[0], fp[1], z) # first reset the camera self.renderer.ResetCamera() # nnsmit edit # synch overlays as well: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): ipw_overlay.SetSliceIndex(0) for i, ipw in enumerate(self.ipws): ipw.SetWindowLevel(500, -800, 0) self.render() # end edit def set_input(self, input): ipw = self.ipws[0] ipw.DisplayTextOn() if input == ipw.GetInput(): return if input is None: # remove outline actor, else this will cause errors when # we disable the IPWs (they call a render!) self.renderer.RemoveViewProp(self.outline_actor) self.outline_source.SetInput(None) self.dv_orientation_widget.set_input(None) for ipw in self.ipws: # argh, this disable causes a render ipw.SetEnabled(0) ipw.SetInput(None) else: self.outline_source.SetInput(input) self.renderer.AddViewProp(self.outline_actor) orientations = [2, 0, 1] active = [1, 0, 0] for i, ipw in enumerate(self.ipws): ipw.SetInput(input) ipw.SetWindowLevel(500, -800, 0) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.dv_orientation_widget.set_input(input) # nnsmit-edit # FIXME: Create pretty fix for this codeclone. def set_overlay_input(self, input): self.overlay_active = 1 ipw = self.overlay_ipws[0] if input == ipw.GetInput(): return if input is None: self.overlay_active = 0 for ipw_overlay in self.overlay_ipws: ipw_overlay.SetEnabled(0) ipw_overlay.SetInput(None) else: active = [1, 0, 0] orientations = [2, 0, 1] for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipws, i) ipw_overlay.SetInput(input) ipw_overlay.SetPlaneOrientation(orientations[i]) # axial ipw_overlay.SetEnabled(active[i]) self.render()
class OverlaySliceViewer: """Class for viewing 3D binary masks in a slice-view. Supports arbitrary number of overlays in user-definable colours. """ has_active_slices = False def __init__(self, rwi, renderer): self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) #This is a collection of 1- or 3-component image plane widgets. Each entry corresponds to a single overlay. self.ipw_triads = {} self.add_overlay(0, [0, 0, 0, 0.1]) #Almost-transparent black - for showing the pickable plane stored at id = 0. # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipw_triads[0][0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0,0,0) self.current_index_pos = (0,0,0) def add_overlay(self, id, rgba_colour): """Creates and ads a new (set of) image plane widgets corresponding to a new overlay. id : the string id which will be used to identify this overlay for future lookups. rgba_colour : a length 4 vector giving the red,green,blue,opacity value for this overlay. Range = [0,1] """ if self.ipw_triads.has_key(id): raise ValueError('The overlay id = "%s" is already in use! Cannot this id - aborting.' % id) else: new_ipw_triad = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = new_ipw_triad[0].GetLookupTable() lut.SetNumberOfTableValues(2) if len(self.ipw_triads) == 0: lut.SetTableValue(0,0,0,0,0.1) #Almost-transparent black - for showing the pickable plane else: lut.SetTableValue(0,0,0,0,0) #Transparent: for non-interfering overlay on existing layers lut.SetTableValue(1,rgba_colour[0],rgba_colour[1],rgba_colour[2],rgba_colour[3]) #Specified RGBA for binary "true" lut.Build() for ipw in new_ipw_triad: ipw.SetInteractor(self.rwi) ipw.SetLookupTable(lut) self.ipw_triads[id] = new_ipw_triad base_ipw_triad = self.ipw_triads[0] # now actually connect the sync_overlay observer for i,ipw in enumerate(base_ipw_triad): ipw.AddObserver('InteractionEvent',lambda vtk_o, vtk_e, i=i: self.observer_sync_overlay(base_ipw_triad, new_ipw_triad, i)) #fmalan-edit based on nnsmit-edit def observer_sync_overlay(self, master_ipw_triad, slave_ipw_triad, ipw_idx): # get the primary IPW master_ipw = master_ipw_triad[ipw_idx] # get the overlay IPW slave_ipw = slave_ipw_triad[ipw_idx] # get plane geometry from primary o,p1,p2 = master_ipw.GetOrigin(),master_ipw.GetPoint1(),master_ipw.GetPoint2() # and apply to the overlay slave_ipw.SetOrigin(o) slave_ipw.SetPoint1(p1) slave_ipw.SetPoint2(p2) slave_ipw.UpdatePlacement() # end edit def close(self): for id in self.ipw_triads.keys(): self.set_input(id, None) self.dv_orientation_widget.close() def activate_slice(self, id, idx): if idx in [1,2]: self.ipw_triads[id][idx].SetEnabled(1) self.ipw_triads[id][idx].SetPicker(self.picker) def deactivate_slice(self, id, idx): if idx in [1,2]: self.ipw_triads[id][idx].SetEnabled(0) self.ipw_triads[id][idx].SetPicker(None) def _get_input(self, id): return self.ipw_triads[id].GetInput() def get_world_pos(self, image_pos): """Given image coordinates, return the corresponding world position. """ idata = self._get_input(0) if not idata: return None ispacing = idata.GetSpacing() iorigin = idata.GetOrigin() # calculate real coords world = map(operator.add, iorigin, map(operator.mul, ispacing, image_pos[0:3])) return world def set_perspective(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOff() def set_parallel(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOn() def _handler_mousewheel(self, event): # event.GetWheelRotation() is + or - 120 depending on # direction of turning. if event.ControlDown(): delta = 10 elif event.ShiftDown(): delta = 1 else: # if user is NOT doing shift / control, we pass on to the # default handling which will give control to the VTK # mousewheel handlers. self.rwi.OnMouseWheel(event) return if event.GetWheelRotation() > 0: self._ipw1_delta_slice(+delta) else: self._ipw1_delta_slice(-delta) self.render() for id in self.ipw_triads.keys(): self.ipw_triads[id][0].InvokeEvent('InteractionEvent') def _ipw1_delta_slice(self, delta): """Move to the delta slices fw/bw, IF the IPW is currently aligned with one of the axes. """ ipw = self.ipw_triads[0][0] if ipw.GetPlaneOrientation() < 3: ci = ipw.GetSliceIndex() ipw.SetSliceIndex(ci + delta) def render(self): self.rwi.GetRenderWindow().Render() #TODO: Check this code # nnsmit edit # synch those overlays: ''' if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipw_triads, i, 0) self.observer_sync_overlay(self.ipw_triads, i, 1) self.observer_sync_overlay(self.ipw_triads, i, 2) ''' # end edit def reset_camera(self): self.renderer.ResetCamera() def reset_to_default_view(self, view_index): """ @param view_index 2 for XY """ if view_index == 2: cam = self.renderer.GetActiveCamera() # then make sure it's up is the right way cam.SetViewUp(0,1,0) # just set the X,Y of the camera equal to the X,Y of the # focal point. fp = cam.GetFocalPoint() cp = cam.GetPosition() if cp[2] < fp[2]: z = fp[2] + (fp[2] - cp[2]) else: z = cp[2] cam.SetPosition(fp[0], fp[1], z) # first reset the camera self.renderer.ResetCamera() ''' # nnsmit edit # synch overlays as well: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): ipw_overlay.SetSliceIndex(0) ''' self.render() def set_input(self, id, input): if self.ipw_triads.has_key(id): selected_ipw_triad = self.ipw_triads[id] if input == selected_ipw_triad[0].GetInput(): return if input is None: ipw_triad = self.ipw_triads[id] for ipw in ipw_triad: # argh, this disable causes a render ipw.SetEnabled(0) ipw.SetInput(None) remaining_active_slices = False if self.has_active_slices: for key in self.ipw_triads: if key != 0: ipw_triad = self.ipw_triads[key] for ipw in ipw_triad: if ipw.GetEnabled(): remaining_active_slices = True break if remaining_active_slices: break if not remaining_active_slices: self.has_active_slices = False self.outline_source.SetInput(None) self.renderer.RemoveViewProp(self.outline_actor) self.dv_orientation_widget.set_input(None) base_ipw_triad = self.ipw_triads[0] for i, ipw in enumerate(base_ipw_triad): ipw.SetInput(None) ipw.SetEnabled(0) else: orientations = [2, 0, 1] active = [1, 0, 0] if not self.has_active_slices: self.outline_source.SetInput(input) self.renderer.AddViewProp(self.outline_actor) self.dv_orientation_widget.set_input(input) base_ipw_triad = self.ipw_triads[0] for i, ipw in enumerate(base_ipw_triad): ipw.SetInput(input) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.has_active_slices = True base_ipw_triad = self.ipw_triads[0] for i, ipw in enumerate(selected_ipw_triad): ipw.SetInput(input) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.observer_sync_overlay(base_ipw_triad, selected_ipw_triad, i) #sync to the current position of the base (pickable) triad else: raise ValueError('The overlay with id = "%s" was not found!' % id)
class OverlaySliceViewer: """Class for viewing 3D binary masks in a slice-view. Supports arbitrary number of overlays in user-definable colours. """ has_active_slices = False def __init__(self, rwi, renderer): self.rwi = rwi self.renderer = renderer istyle = vtk.vtkInteractorStyleTrackballCamera() rwi.SetInteractorStyle(istyle) # we unbind the existing mousewheel handler so it doesn't # interfere rwi.Unbind(wx.EVT_MOUSEWHEEL) rwi.Bind(wx.EVT_MOUSEWHEEL, self._handler_mousewheel) #This is a collection of 1- or 3-component image plane widgets. Each entry corresponds to a single overlay. self.ipw_triads = {} self.add_overlay( 0, [0, 0, 0, 0.1] ) #Almost-transparent black - for showing the pickable plane stored at id = 0. # we only set the picker on the visible IPW, else the # invisible IPWs block picking! self.picker = vtk.vtkCellPicker() self.picker.SetTolerance(0.005) self.ipw_triads[0][0].SetPicker(self.picker) self.outline_source = vtk.vtkOutlineCornerFilter() m = vtk.vtkPolyDataMapper() m.SetInput(self.outline_source.GetOutput()) a = vtk.vtkActor() a.SetMapper(m) a.PickableOff() self.outline_actor = a self.dv_orientation_widget = DVOrientationWidget(rwi) # this can be used by clients to store the current world # position self.current_world_pos = (0, 0, 0) self.current_index_pos = (0, 0, 0) def add_overlay(self, id, rgba_colour): """Creates and ads a new (set of) image plane widgets corresponding to a new overlay. id : the string id which will be used to identify this overlay for future lookups. rgba_colour : a length 4 vector giving the red,green,blue,opacity value for this overlay. Range = [0,1] """ if self.ipw_triads.has_key(id): raise ValueError( 'The overlay id = "%s" is already in use! Cannot this id - aborting.' % id) else: new_ipw_triad = [vtk.vtkImagePlaneWidget() for _ in range(3)] lut = new_ipw_triad[0].GetLookupTable() lut.SetNumberOfTableValues(2) if len(self.ipw_triads) == 0: lut.SetTableValue( 0, 0, 0, 0, 0.1 ) #Almost-transparent black - for showing the pickable plane else: lut.SetTableValue( 0, 0, 0, 0, 0 ) #Transparent: for non-interfering overlay on existing layers lut.SetTableValue( 1, rgba_colour[0], rgba_colour[1], rgba_colour[2], rgba_colour[3]) #Specified RGBA for binary "true" lut.Build() for ipw in new_ipw_triad: ipw.SetInteractor(self.rwi) ipw.SetLookupTable(lut) self.ipw_triads[id] = new_ipw_triad base_ipw_triad = self.ipw_triads[0] # now actually connect the sync_overlay observer for i, ipw in enumerate(base_ipw_triad): ipw.AddObserver( 'InteractionEvent', lambda vtk_o, vtk_e, i=i: self.observer_sync_overlay( base_ipw_triad, new_ipw_triad, i)) #fmalan-edit based on nnsmit-edit def observer_sync_overlay(self, master_ipw_triad, slave_ipw_triad, ipw_idx): # get the primary IPW master_ipw = master_ipw_triad[ipw_idx] # get the overlay IPW slave_ipw = slave_ipw_triad[ipw_idx] # get plane geometry from primary o, p1, p2 = master_ipw.GetOrigin(), master_ipw.GetPoint1( ), master_ipw.GetPoint2() # and apply to the overlay slave_ipw.SetOrigin(o) slave_ipw.SetPoint1(p1) slave_ipw.SetPoint2(p2) slave_ipw.UpdatePlacement() # end edit def close(self): for id in self.ipw_triads.keys(): self.set_input(id, None) self.dv_orientation_widget.close() def activate_slice(self, id, idx): if idx in [1, 2]: self.ipw_triads[id][idx].SetEnabled(1) self.ipw_triads[id][idx].SetPicker(self.picker) def deactivate_slice(self, id, idx): if idx in [1, 2]: self.ipw_triads[id][idx].SetEnabled(0) self.ipw_triads[id][idx].SetPicker(None) def _get_input(self, id): return self.ipw_triads[id].GetInput() def get_world_pos(self, image_pos): """Given image coordinates, return the corresponding world position. """ idata = self._get_input(0) if not idata: return None ispacing = idata.GetSpacing() iorigin = idata.GetOrigin() # calculate real coords world = map(operator.add, iorigin, map(operator.mul, ispacing, image_pos[0:3])) return world def set_perspective(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOff() def set_parallel(self): cam = self.renderer.GetActiveCamera() cam.ParallelProjectionOn() def _handler_mousewheel(self, event): # event.GetWheelRotation() is + or - 120 depending on # direction of turning. if event.ControlDown(): delta = 10 elif event.ShiftDown(): delta = 1 else: # if user is NOT doing shift / control, we pass on to the # default handling which will give control to the VTK # mousewheel handlers. self.rwi.OnMouseWheel(event) return if event.GetWheelRotation() > 0: self._ipw1_delta_slice(+delta) else: self._ipw1_delta_slice(-delta) self.render() for id in self.ipw_triads.keys(): self.ipw_triads[id][0].InvokeEvent('InteractionEvent') def _ipw1_delta_slice(self, delta): """Move to the delta slices fw/bw, IF the IPW is currently aligned with one of the axes. """ ipw = self.ipw_triads[0][0] if ipw.GetPlaneOrientation() < 3: ci = ipw.GetSliceIndex() ipw.SetSliceIndex(ci + delta) def render(self): self.rwi.GetRenderWindow().Render() #TODO: Check this code # nnsmit edit # synch those overlays: ''' if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): self.observer_sync_overlay(self.ipw_triads, i, 0) self.observer_sync_overlay(self.ipw_triads, i, 1) self.observer_sync_overlay(self.ipw_triads, i, 2) ''' # end edit def reset_camera(self): self.renderer.ResetCamera() def reset_to_default_view(self, view_index): """ @param view_index 2 for XY """ if view_index == 2: cam = self.renderer.GetActiveCamera() # then make sure it's up is the right way cam.SetViewUp(0, 1, 0) # just set the X,Y of the camera equal to the X,Y of the # focal point. fp = cam.GetFocalPoint() cp = cam.GetPosition() if cp[2] < fp[2]: z = fp[2] + (fp[2] - cp[2]) else: z = cp[2] cam.SetPosition(fp[0], fp[1], z) # first reset the camera self.renderer.ResetCamera() ''' # nnsmit edit # synch overlays as well: if self.overlay_active == 1: for i, ipw_overlay in enumerate(self.overlay_ipws): ipw_overlay.SetSliceIndex(0) ''' self.render() def set_input(self, id, input): if self.ipw_triads.has_key(id): selected_ipw_triad = self.ipw_triads[id] if input == selected_ipw_triad[0].GetInput(): return if input is None: ipw_triad = self.ipw_triads[id] for ipw in ipw_triad: # argh, this disable causes a render ipw.SetEnabled(0) ipw.SetInput(None) remaining_active_slices = False if self.has_active_slices: for key in self.ipw_triads: if key != 0: ipw_triad = self.ipw_triads[key] for ipw in ipw_triad: if ipw.GetEnabled(): remaining_active_slices = True break if remaining_active_slices: break if not remaining_active_slices: self.has_active_slices = False self.outline_source.SetInput(None) self.renderer.RemoveViewProp(self.outline_actor) self.dv_orientation_widget.set_input(None) base_ipw_triad = self.ipw_triads[0] for i, ipw in enumerate(base_ipw_triad): ipw.SetInput(None) ipw.SetEnabled(0) else: orientations = [2, 0, 1] active = [1, 0, 0] if not self.has_active_slices: self.outline_source.SetInput(input) self.renderer.AddViewProp(self.outline_actor) self.dv_orientation_widget.set_input(input) base_ipw_triad = self.ipw_triads[0] for i, ipw in enumerate(base_ipw_triad): ipw.SetInput(input) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.has_active_slices = True base_ipw_triad = self.ipw_triads[0] for i, ipw in enumerate(selected_ipw_triad): ipw.SetInput(input) ipw.SetPlaneOrientation(orientations[i]) # axial ipw.SetSliceIndex(0) ipw.SetEnabled(active[i]) self.observer_sync_overlay( base_ipw_triad, selected_ipw_triad, i ) #sync to the current position of the base (pickable) triad else: raise ValueError('The overlay with id = "%s" was not found!' % id)