diff --git a/invesalius/data/viewer_volume.py b/invesalius/data/viewer_volume.py index 43e7102..32c05b4 100755 --- a/invesalius/data/viewer_volume.py +++ b/invesalius/data/viewer_volume.py @@ -74,9 +74,51 @@ class Viewer(wx.Panel): self.__bind_events() self.__bind_events_wx() - + self.mouse_pressed = 0 - + + def __bind_events(self): + ps.Publisher().subscribe(self.LoadActor, + 'Load surface actor into viewer') + ps.Publisher().subscribe(self.UpdateRender, + 'Render volume viewer') + ps.Publisher().subscribe(self.ChangeBackgroundColour, + 'Change volume viewer background colour') + # Raycating - related + ps.Publisher().subscribe(self.LoadVolume, + 'Load volume into viewer') + ps.Publisher().subscribe(self.OnSetWindowLevelText, + 'Set volume window and level text') + ps.Publisher().subscribe(self.OnHideRaycasting, + 'Hide raycasting volume') + ps.Publisher().subscribe(self.OnShowRaycasting, + 'Update raycasting preset') + ### + ps.Publisher().subscribe(self.AppendActor,'AppendActor') + ps.Publisher().subscribe(self.SetWidgetInteractor, + 'Set Widget Interactor') + ps.Publisher().subscribe(self.OnSetViewAngle, + 'Set volume view angle') + + ps.Publisher().subscribe(self.SetNewMode, + ('Set interaction mode', const.MODE_WW_WL)) + ps.Publisher().subscribe(self.OnDisableBrightContrast, + ('Set interaction mode', + const.MODE_SLICE_EDITOR)) + + ps.Publisher().subscribe(self.OnExportSurface, 'Export surface to file') + + ps.Publisher().subscribe(self.LoadSlicePlane, 'Load slice plane') + + ps.Publisher().subscribe(self.ResetCamClippingRange, 'Reset cam clipping range') + + ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style') + ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style') + + def __bind_events_wx(self): + #self.Bind(wx.EVT_SIZE, self.OnSize) + pass + def SetInteractorStyle(self, state): action = { const.STATE_PAN: @@ -110,7 +152,7 @@ class Viewer(wx.Panel): { } } - + if (state == const.STATE_ZOOM_SL): style = vtk.vtkInteractorStyleRubberBandZoom() self.interactor.SetInteractorStyle(style) @@ -119,12 +161,41 @@ class Viewer(wx.Panel): style = vtk.vtkInteractorStyleTrackballCamera() self.interactor.SetInteractorStyle(style) self.style = style - + # Check each event available for each mode for event in action[state]: # Bind event style.AddObserver(event,action[state][event]) - + + def SetStyle(self, pubsub_evt): + print "SetStyle" + mode = pubsub_evt.data + + if (mode == const.MODE_ZOOM_SELECTION): + self.SetMode('ZOOMSELECT') + elif(mode == const.MODE_MOVE): + self.SetMode('PAN') + elif(mode == const.MODE_ZOOM): + self.SetMode('ZOOM') + elif(mode == const.MODE_ROTATE): + self.SetMode('SPIN') + elif(mode == const.MODE_WW_WL): + self.SetMode('WINDOWLEVEL') + + def SetNewMode(self, pubsub_evt): + mode = pubsub_evt.topic[1] + + if (mode == const.MODE_ZOOM_SELECTION): + self.SetMode('ZOOMSELECT') + elif(mode == const.MODE_MOVE): + self.SetMode('PAN') + elif(mode == const.MODE_ZOOM): + self.SetMode('ZOOM') + elif(mode == const.MODE_ROTATE): + self.SetMode('SPIN') + elif(mode == const.MODE_WW_WL): + self.SetMode('WINDOWLEVEL') + def OnSpinMove(self, evt, obj): if (self.mouse_pressed): evt.Spin() @@ -133,11 +204,11 @@ class Viewer(wx.Panel): def OnSpinClick(self, evt, obj): self.mouse_pressed = 1 evt.StartSpin() - + def OnReleaseSpinClick(self,evt,obj): self.mouse_pressed = 0 evt.EndSpin() - + def OnZoomMove(self, evt, obj): if (self.mouse_pressed): evt.Dolly() @@ -146,12 +217,11 @@ class Viewer(wx.Panel): def OnZoomClick(self, evt, obj): self.mouse_pressed = 1 evt.StartDolly() - + def OnReleaseZoomClick(self,evt,obj): self.mouse_pressed = 0 evt.EndDolly() - - + def OnPanMove(self, evt, obj): if (self.mouse_pressed): evt.Pan() @@ -160,41 +230,11 @@ class Viewer(wx.Panel): def OnPanClick(self, evt, obj): self.mouse_pressed = 1 evt.StartPan() - + def OnReleasePanClick(self,evt,obj): self.mouse_pressed = 0 evt.EndPan() - - def SetStyle(self, pubsub_evt): - print "SetStyle" - mode = pubsub_evt.data - - if (mode == const.MODE_ZOOM_SELECTION): - self.SetMode('ZOOMSELECT') - elif(mode == const.MODE_MOVE): - self.SetMode('PAN') - elif(mode == const.MODE_ZOOM): - self.SetMode('ZOOM') - elif(mode == const.MODE_ROTATE): - self.SetMode('SPIN') - elif(mode == const.MODE_WW_WL): - self.SetMode('WINDOWLEVEL') - - def SetNewMode(self, pubsub_evt): - mode = pubsub_evt.topic[1] - - if (mode == const.MODE_ZOOM_SELECTION): - self.SetMode('ZOOMSELECT') - elif(mode == const.MODE_MOVE): - self.SetMode('PAN') - elif(mode == const.MODE_ZOOM): - self.SetMode('ZOOM') - elif(mode == const.MODE_ROTATE): - self.SetMode('SPIN') - elif(mode == const.MODE_WW_WL): - self.SetMode('WINDOWLEVEL') - def OnWindowLevelMove(self, obj, evt): if self.onclick and self.raycasting_volume: mouse_x, mouse_y = self.interactor.GetEventPosition() @@ -218,83 +258,6 @@ class Viewer(wx.Panel): if const.RAYCASTING_WWWL_BLUR: self.style.EndZoom() - def ShowOrientationCube(self): - print "ORIENTATION CUBE!" - cube = vtk.vtkAnnotatedCubeActor() - cube.GetXMinusFaceProperty().SetColor(1,0,0) - cube.GetXPlusFaceProperty().SetColor(1,0,0) - cube.GetYMinusFaceProperty().SetColor(0,1,0) - cube.GetYPlusFaceProperty().SetColor(0,1,0) - cube.GetZMinusFaceProperty().SetColor(0,0,1) - cube.GetZPlusFaceProperty().SetColor(0,0,1) - cube.GetTextEdgesProperty().SetColor(0,0,0) - - # anatomic labelling - cube.SetXPlusFaceText ("A") - cube.SetXMinusFaceText("P") - cube.SetYPlusFaceText ("L") - cube.SetYMinusFaceText("R") - cube.SetZPlusFaceText ("S") - cube.SetZMinusFaceText("I") - - axes = vtk.vtkAxesActor() - axes.SetShaftTypeToCylinder() - axes.SetTipTypeToCone() - axes.SetXAxisLabelText("X") - axes.SetYAxisLabelText("Y") - axes.SetZAxisLabelText("Z") - #axes.SetNormalizedLabelPosition(.5, .5, .5) - - orientation_widget = vtk.vtkOrientationMarkerWidget() - orientation_widget.SetOrientationMarker(cube) - orientation_widget.SetViewport(0.85,0.85,1.0,1.0) - #orientation_widget.SetOrientationMarker(axes) - orientation_widget.SetInteractor(self.interactor) - orientation_widget.SetEnabled(1) - orientation_widget.On() - orientation_widget.InteractiveOff() - - - def __bind_events(self): - ps.Publisher().subscribe(self.LoadActor, - 'Load surface actor into viewer') - ps.Publisher().subscribe(self.UpdateRender, - 'Render volume viewer') - ps.Publisher().subscribe(self.ChangeBackgroundColour, - 'Change volume viewer background colour') - # Raycating - related - ps.Publisher().subscribe(self.LoadVolume, - 'Load volume into viewer') - ps.Publisher().subscribe(self.OnSetWindowLevelText, - 'Set volume window and level text') - ps.Publisher().subscribe(self.OnHideRaycasting, - 'Hide raycasting volume') - ps.Publisher().subscribe(self.OnShowRaycasting, - 'Update raycasting preset') - ### - ps.Publisher().subscribe(self.AppendActor,'AppendActor') - ps.Publisher().subscribe(self.SetWidgetInteractor, - 'Set Widget Interactor') - ps.Publisher().subscribe(self.OnSetViewAngle, - 'Set volume view angle') - - ps.Publisher().subscribe(self.SetNewMode, - ('Set interaction mode', const.MODE_WW_WL)) - ps.Publisher().subscribe(self.OnDisableBrightContrast, - ('Set interaction mode', - const.MODE_SLICE_EDITOR)) - - ps.Publisher().subscribe(self.OnExportSurface, 'Export surface to file') - - ps.Publisher().subscribe(self.LoadSlicePlane, 'Load slice plane') - - ps.Publisher().subscribe(self.ResetCamClippingRange, 'Reset cam clipping range') - - - ps.Publisher().subscribe(self.OnEnableStyle, 'Enable style') - ps.Publisher().subscribe(self.OnDisableStyle, 'Disable style') - - def OnEnableStyle(self, pubsub_evt): state = pubsub_evt.data if (state in const.VOLUME_STYLES): @@ -310,11 +273,9 @@ class Viewer(wx.Panel): new_state = self.interaction_style.RemoveState(state) self.SetInteractorStyle(new_state) - def ResetCamClippingRange(self, pubsub_evt): self.ren.ResetCamera() self.ren.ResetCameraClippingRange() - def OnExportSurface(self, pubsub_evt): filename, filetype = pubsub_evt.data @@ -338,32 +299,17 @@ class Viewer(wx.Panel): writer.SetInput(renwin) writer.Write() - - - def __bind_events_wx(self): - #self.Bind(wx.EVT_SIZE, self.OnSize) - pass - def OnEnableBrightContrast(self, pubsub_evt): style = self.style style.AddObserver("MouseMoveEvent", self.OnMove) style.AddObserver("LeftButtonPressEvent", self.OnClick) style.AddObserver("LeftButtonReleaseEvent", self.OnRelease) - def OnDisableBrightContrast(self, pubsub_evt): style = vtk.vtkInteractorStyleTrackballCamera() self.interactor.SetInteractorStyle(style) self.style = style - - def OnSize(self, evt): - self.UpdateRender() - self.Refresh() - self.interactor.UpdateWindowUI() - self.interactor.Update() - evt.Skip() - def OnSetWindowLevelText(self, pubsub_evt): if self.raycasting_volume: ww, wl = pubsub_evt.data @@ -377,30 +323,12 @@ class Viewer(wx.Panel): self.raycasting_volume = False self.text.Hide() - def LoadVolume(self, pubsub_evt): - self.raycasting_volume = True - - volume = pubsub_evt.data[0] - colour = pubsub_evt.data[1] - ww, wl = pubsub_evt.data[2] - - self.light = self.ren.GetLights().GetNextItem() - - self.ren.AddVolume(volume) - self.text.SetValue("WL: %d WW: %d"%(wl, ww)) - self.ren.AddActor(self.text.actor) - self.ren.SetBackground(colour) - - if not (self.view_angle): - self.SetViewAngle(const.VOL_FRONT) - else: - self.ren.ResetCamera() - self.ren.ResetCameraClippingRange() - + def OnSize(self, evt): self.UpdateRender() - - def LoadSlicePlane(self, pubsub_evt): - self.slice_plane = SlicePlane() + self.Refresh() + self.interactor.UpdateWindowUI() + self.interactor.Update() + evt.Skip() def ChangeBackgroundColour(self, pubsub_evt): colour = pubsub_evt.data @@ -409,10 +337,10 @@ class Viewer(wx.Panel): def LoadActor(self, pubsub_evt): actor = pubsub_evt.data - + ren = self.ren ren.AddActor(actor) - + if not (self.view_angle): self.SetViewAngle(const.VOL_FRONT) self.view_angle = 1 @@ -421,40 +349,100 @@ class Viewer(wx.Panel): ren.ResetCameraClippingRange() #self.ShowOrientationCube() - self.interactor.Render() + def LoadSlicePlane(self, pubsub_evt): + self.slice_plane = SlicePlane() + + def LoadVolume(self, pubsub_evt): + self.raycasting_volume = True + + volume = pubsub_evt.data[0] + colour = pubsub_evt.data[1] + ww, wl = pubsub_evt.data[2] + + self.light = self.ren.GetLights().GetNextItem() + + self.ren.AddVolume(volume) + self.text.SetValue("WL: %d WW: %d"%(wl, ww)) + self.ren.AddActor(self.text.actor) + self.ren.SetBackground(colour) + + if not (self.view_angle): + self.SetViewAngle(const.VOL_FRONT) + else: + self.ren.ResetCamera() + self.ren.ResetCameraClippingRange() + + self.UpdateRender() + def OnSetViewAngle(self, evt_pubsub): view = evt_pubsub.data self.SetViewAngle(view) def SetViewAngle(self, view): - cam = self.ren.GetActiveCamera() cam.SetFocalPoint(0,0,0) - + proj = prj.Project() orig_orien = proj.original_orientation - + xv,yv,zv = const.VOLUME_POSITION[orig_orien][0][view] xp,yp,zp = const.VOLUME_POSITION[orig_orien][1][view] - + cam.SetViewUp(xv,yv,zv) cam.SetPosition(xp,yp,zp) - + self.ren.ResetCameraClippingRange() self.ren.ResetCamera() self.interactor.Render() + def ShowOrientationCube(self): + print "ORIENTATION CUBE!" + cube = vtk.vtkAnnotatedCubeActor() + cube.GetXMinusFaceProperty().SetColor(1,0,0) + cube.GetXPlusFaceProperty().SetColor(1,0,0) + cube.GetYMinusFaceProperty().SetColor(0,1,0) + cube.GetYPlusFaceProperty().SetColor(0,1,0) + cube.GetZMinusFaceProperty().SetColor(0,0,1) + cube.GetZPlusFaceProperty().SetColor(0,0,1) + cube.GetTextEdgesProperty().SetColor(0,0,0) + + # anatomic labelling + cube.SetXPlusFaceText ("A") + cube.SetXMinusFaceText("P") + cube.SetYPlusFaceText ("L") + cube.SetYMinusFaceText("R") + cube.SetZPlusFaceText ("S") + cube.SetZMinusFaceText("I") + + axes = vtk.vtkAxesActor() + axes.SetShaftTypeToCylinder() + axes.SetTipTypeToCone() + axes.SetXAxisLabelText("X") + axes.SetYAxisLabelText("Y") + axes.SetZAxisLabelText("Z") + #axes.SetNormalizedLabelPosition(.5, .5, .5) + + orientation_widget = vtk.vtkOrientationMarkerWidget() + orientation_widget.SetOrientationMarker(cube) + orientation_widget.SetViewport(0.85,0.85,1.0,1.0) + #orientation_widget.SetOrientationMarker(axes) + orientation_widget.SetInteractor(self.interactor) + orientation_widget.SetEnabled(1) + orientation_widget.On() + orientation_widget.InteractiveOff() + def UpdateRender(self, evt_pubsub=None): self.interactor.Render() - + def SetWidgetInteractor(self, evt_pubsub=None): evt_pubsub.data.SetInteractor(self.interactor._Iren) def AppendActor(self, evt_pubsub=None): self.ren.AddActor(evt_pubsub.data) + class SlicePlane: def __init__(self): project = prj.Project() @@ -462,22 +450,20 @@ class SlicePlane: self.Create() self.__bind_evt() self.__bind_vtk_evt() - + def __bind_evt(self): ps.Publisher().subscribe(self.Enable, 'Enable plane') ps.Publisher().subscribe(self.Disable, 'Disable plane') ps.Publisher().subscribe(self.ChangeSlice, 'Change slice from slice plane') - + def __bind_vtk_evt(self): self.plane_x.AddObserver("InteractionEvent", self.PlaneEvent) self.plane_y.AddObserver("InteractionEvent", self.PlaneEvent) self.plane_z.AddObserver("InteractionEvent", self.PlaneEvent) - + def PlaneEvent(self, obj, evt): - number = obj.GetSliceIndex() plane_axis = obj.GetPlaneOrientation() - if (self.original_orientation == const.AXIAL): if (plane_axis == 0): orientation = "SAGITAL" @@ -487,7 +473,7 @@ class SlicePlane: number = abs(dimen[0] - (number + 1)) else: orientation = "AXIAL" - + elif(self.original_orientation == const.SAGITAL): if (plane_axis == 0): orientation = "CORONAL" @@ -506,14 +492,12 @@ class SlicePlane: number = abs(dimen[0] - (number + 1)) else: orientation = "CORONAL" - - + if (obj.GetSlicePosition() != 0.0): ps.Publisher().sendMessage(('Set scroll position', \ orientation), number) - - def Create(self): + def Create(self): plane_x = self.plane_x = vtk.vtkImagePlaneWidget() plane_x.DisplayTextOff() ps.Publisher().sendMessage('Input Image in the widget', plane_x) @@ -537,7 +521,7 @@ class SlicePlane: prop1.SetColor(0, 1, 0) cursor_property = plane_y.GetCursorProperty() cursor_property.SetOpacity(0) - + plane_z = self.plane_z = vtk.vtkImagePlaneWidget() plane_z.DisplayTextOff() ps.Publisher().sendMessage('Input Image in the widget', plane_z) @@ -556,40 +540,40 @@ class SlicePlane: prop1 = plane_x.GetPlaneProperty() prop1.SetColor(0, 0, 1) - + prop2 = plane_y.GetPlaneProperty() prop2.SetColor(0, 1, 0) - + elif(self.original_orientation == const.SAGITAL): prop3 = plane_y.GetPlaneProperty() prop3.SetColor(1, 0, 0) prop1 = plane_z.GetPlaneProperty() prop1.SetColor(0, 0, 1) - + prop2 = plane_x.GetPlaneProperty() prop2.SetColor(0, 1, 0) - + else: prop3 = plane_y.GetPlaneProperty() prop3.SetColor(1, 0, 0) prop1 = plane_x.GetPlaneProperty() prop1.SetColor(0, 0, 1) - + prop2 = plane_z.GetPlaneProperty() prop2.SetColor(0, 1, 0) - + ps.Publisher().sendMessage('Set Widget Interactor', plane_x) ps.Publisher().sendMessage('Set Widget Interactor', plane_y) ps.Publisher().sendMessage('Set Widget Interactor', plane_z) - + self.Render() - + def Enable(self, evt_pubsub=None): if (evt_pubsub): label = evt_pubsub.data - + if(self.original_orientation == const.AXIAL): if(label == "Axial"): self.plane_z.On() @@ -602,7 +586,7 @@ class SlicePlane: c = self.plane_x.GetTexture() c.SetRestrictPowerOf2ImageSmaller(1) #print dir(a) - + elif(self.original_orientation == const.SAGITAL): if(label == "Axial"): self.plane_y.On() @@ -617,7 +601,7 @@ class SlicePlane: self.plane_z.On() elif(label == "Sagital"): self.plane_x.On() - + else: self.plane_z.On() self.plane_x.On() @@ -628,7 +612,7 @@ class SlicePlane: def Disable(self, evt_pubsub=None): if (evt_pubsub): label = evt_pubsub.data - + if(self.original_orientation == const.AXIAL): if(label == "Axial"): self.plane_z.Off() @@ -636,7 +620,7 @@ class SlicePlane: self.plane_y.Off() elif(label == "Sagital"): self.plane_x.Off() - + elif(self.original_orientation == const.SAGITAL): if(label == "Axial"): self.plane_y.Off() @@ -658,13 +642,12 @@ class SlicePlane: self.Render() - def Render(self): ps.Publisher().sendMessage('Render volume viewer') - + def ChangeSlice(self, pubsub_evt = None): orientation, number = pubsub_evt.data - + if (self.original_orientation == const.AXIAL): if (orientation == "CORONAL"): self.SetSliceNumber(number, "Y") @@ -672,7 +655,7 @@ class SlicePlane: self.SetSliceNumber(number, "X") else: self.SetSliceNumber(number, "Z") - + elif(self.original_orientation == const.SAGITAL): if (orientation == "CORONAL"): self.SetSliceNumber(number, "X") @@ -680,7 +663,7 @@ class SlicePlane: self.SetSliceNumber(number, "Z") else: self.SetSliceNumber(number, "Y") - + else: if (orientation == "CORONAL"): self.SetSliceNumber(number, "Z") @@ -688,9 +671,9 @@ class SlicePlane: self.SetSliceNumber(number, "X") else: self.SetSliceNumber(number, "Y") - + self.Render() - + def SetSliceNumber(self, number, axis): if (axis == "X"): self.plane_x.SetPlaneOrientationToXAxes() @@ -702,14 +685,12 @@ class SlicePlane: self.plane_z.SetPlaneOrientationToZAxes() self.plane_z.SetSliceIndex(number) - def PointId(self, evt, obj): #TODO: add in the code # picker = vtk.vtkPointPicker() # interactor.SetPicker(picker) # interactor.AddObserver("left...", self.PointId) - x,y = evt.GetLastEventPosition() self.picker.Pick(x, y, 0, self.ren1) point_id = self.picker.GetPointId() - + -- libgit2 0.21.2