diff --git a/invesalius/constants.py b/invesalius/constants.py index 6f68d9b..cda6735 100644 --- a/invesalius/constants.py +++ b/invesalius/constants.py @@ -2,6 +2,11 @@ import os.path import wx from project import Project +# VTK text +TEXT_SIZE = 12 +TEXT_COLOUR = (1,1,1) +TEXT_POSITION = (0.03, 0.97) + # Slice orientation AXIAL = 0 CORONAL = 1 diff --git a/invesalius/data/viewer_volume.py b/invesalius/data/viewer_volume.py index a4fad6c..56ff8c8 100755 --- a/invesalius/data/viewer_volume.py +++ b/invesalius/data/viewer_volume.py @@ -23,8 +23,10 @@ import wx import vtk from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor import wx.lib.pubsub as ps + import constants as const import project as prj +import data.vtk_utils as vtku class Viewer(wx.Panel): def __init__(self, parent): @@ -32,36 +34,57 @@ class Viewer(wx.Panel): self.SetBackgroundColour(wx.Colour(0, 0, 0)) style = vtk.vtkInteractorStyleTrackballCamera() + self.style = style - iren = wxVTKRenderWindowInteractor(self, -1, size = self.GetSize()) - iren.SetInteractorStyle(style) + interactor = wxVTKRenderWindowInteractor(self, -1, size = self.GetSize()) + interactor.SetInteractorStyle(style) sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(iren, 1, wx.EXPAND) + sizer.Add(interactor, 1, wx.EXPAND) self.SetSizer(sizer) self.Layout() - # It would be more correct (API-wise) to call iren.Initialize() and - # iren.Start() here, but Initialize() calls RenderWindow.Render(). + # It would be more correct (API-wise) to call interactor.Initialize() and + # interactor.Start() here, but Initialize() calls RenderWindow.Render(). # That Render() call will get through before we can setup the # RenderWindow() to render via the wxWidgets-created context; this # causes flashing on some platforms and downright breaks things on # other platforms. Instead, we call widget.Enable(). This means # that the RWI::Initialized ivar is not set, but in THIS SPECIFIC CASE, # that doesn't matter. - iren.Enable(1) + interactor.Enable(1) ren = vtk.vtkRenderer() - iren.GetRenderWindow().AddRenderer(ren) + interactor.GetRenderWindow().AddRenderer(ren) - self.iren = iren + self.interactor = interactor self.ren = ren + self.onclick = False + self.__bind_events() self.__bind_events_wx() self.view_angle = None + def OnMove(self, obj, evt): + if self.onclick: + mouse_x, mouse_y = self.interactor.GetEventPosition() + diff_x = mouse_x - self.last_x + diff_y = mouse_y - self.last_y + self.last_x, self.last_y = mouse_x, mouse_y + ps.Publisher().sendMessage('Set raycasting relative window and level', + (diff_x, diff_y)) + self.interactor.Render() + + def OnClick(self, obj, evt): + self.onclick = True + mouse_x, mouse_y = self.interactor.GetEventPosition() + self.last_x, self.last_y = mouse_x, mouse_y + + def OnRelease(self, obj, evt): + self.onclick = False + def __bind_events(self): ps.Publisher().subscribe(self.LoadActor, 'Load surface actor into viewer') ps.Publisher().subscribe(self.UpdateRender, 'Render volume viewer') @@ -73,25 +96,52 @@ class Viewer(wx.Panel): 'Set Widget Interactor') ps.Publisher().subscribe(self.OnSetViewAngle, 'Set volume view angle') - + ps.Publisher().subscribe(self.OnSetWindowLevelText, + 'Set volume window and level text') + ps.Publisher().subscribe(self.OnEnableBrightContrast, + 'Bright and contrast adjustment') + ps.Publisher().subscribe(self.OnDisableBrightContrast, + 'Set Editor Mode') 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): - print "viewer_volume :: OnSize" self.UpdateRender() self.Refresh() - print dir(self.iren) - self.iren.UpdateWindowUI() - self.iren.Update() + self.interactor.UpdateWindowUI() + self.interactor.Update() evt.Skip() + def OnSetWindowLevelText(self, pubsub_evt): + ww, wl = pubsub_evt.data + self.text.SetValue("WL: %d WW: %d"%(wl, ww)) + def LoadVolume(self, pubsub_evt): - volume, colour = pubsub_evt.data + volume = pubsub_evt.data[0] self.light = self.ren.GetLights().GetNextItem() + + text = vtku.Text() + self.text = text + self.ren.AddVolume(volume) + self.ren.AddActor(text.actor) + if not (self.view_angle): self.SetViewAngle(const.VOL_FRONT) else: @@ -117,7 +167,7 @@ class Viewer(wx.Panel): ren.ResetCamera() ren.ResetCameraClippingRange() - self.iren.Render() + self.interactor.Render() def OnSetViewAngle(self, evt_pubsub): view = evt_pubsub.data @@ -139,21 +189,21 @@ class Viewer(wx.Panel): self.ren.ResetCameraClippingRange() self.ren.ResetCamera() - self.iren.Render() + self.interactor.Render() def UpdateRender(self, evt_pubsub=None): - self.iren.Render() + self.interactor.Render() def CreatePlanes(self): imagedata = self.imagedata ren = self.ren - iren = self.iren + interactor = self.interactor import ivVolumeWidgets as vw axial_plane = vw.Plane() axial_plane.SetRender(ren) - axial_plane.SetInteractor(iren) + axial_plane.SetInteractor(interactor) axial_plane.SetOrientation(vw.AXIAL) axial_plane.SetInput(imagedata) axial_plane.Show() @@ -161,7 +211,7 @@ class Viewer(wx.Panel): coronal_plane = vw.Plane() coronal_plane.SetRender(ren) - coronal_plane.SetInteractor(iren) + coronal_plane.SetInteractor(interactor) coronal_plane.SetOrientation(vw.CORONAL) coronal_plane.SetInput(imagedata) coronal_plane.Show() @@ -169,14 +219,14 @@ class Viewer(wx.Panel): sagital_plane = vw.Plane() sagital_plane.SetRender(ren) - sagital_plane.SetInteractor(iren) + sagital_plane.SetInteractor(interactor) sagital_plane.SetOrientation(vw.SAGITAL) sagital_plane.SetInput(imagedata) sagital_plane.Show() sagital_plane.Update() def SetWidgetInteractor(self, evt_pubsub=None): - evt_pubsub.data.SetInteractor(self.iren._Iren) + evt_pubsub.data.SetInteractor(self.interactor._Iren) def AppendActor(self, evt_pubsub=None): self.ren.AddActor(evt_pubsub.data) diff --git a/invesalius/data/volume.py b/invesalius/data/volume.py index 7ffff9e..93a7517 100755 --- a/invesalius/data/volume.py +++ b/invesalius/data/volume.py @@ -72,6 +72,9 @@ class Volume(): self.exist = None self.color_transfer = None self.opacity_transfer_func = None + self.ww = None + self.wl = None + self.n = 0 self.__bind_events() @@ -83,10 +86,12 @@ class Volume(): 'Hide raycasting volume') ps.Publisher().subscribe(self.SetRaycastPreset, 'Set raycasting preset') - ps.Publisher().subscribe(self.SetWWWL, + ps.Publisher().subscribe(self.OnSetWindowLevel, 'Set raycasting wwwl') ps.Publisher().subscribe(self.Refresh, 'Set raycasting refresh') + ps.Publisher().subscribe(self.OnSetRelativeWindowLevel, + 'Set raycasting relative window and level') def OnLoadVolume(self, pubsub_evt): label = pubsub_evt.data @@ -95,7 +100,6 @@ class Volume(): def LoadConfig(self): self.config = Project().raycasting_preset - #print path def OnHideVolume(self, pubsub_evt): self.volume.SetVisibility(0) @@ -126,11 +130,24 @@ class Volume(): self.Create8bColorTable(self.scale) self.Create8bOpacityTable(self.scale) - def SetWWWL(self, pubsub_evt): + def OnSetRelativeWindowLevel(self, pubsub_evt): + diff_ww, diff_wl = pubsub_evt.data + ww = self.ww + diff_ww + wl = self.wl + diff_wl + ps.Publisher().sendMessage('Set volume window and level text', + (ww, wl)) + self.SetWWWL(ww, wl) + self.ww = ww + self.wl = wl + + def OnSetWindowLevel(self, pubsub_evt): ww, wl, n = pubsub_evt.data - print "Setting ww, wl", ww, wl + self.SetWWWL(ww,wl,n) + + def SetWWWL(self, ww, wl): + if self.config['advancedCLUT']: - curve = self.config['16bitClutCurves'][n] + curve = self.config['16bitClutCurves'][self.n] p1 = curve[0] p2 = curve[-1] @@ -155,7 +172,7 @@ class Volume(): self.config['ww'] = ww self.__config_preset() - ps.Publisher().sendMessage('Render volume viewer', None) + #ps.Publisher().sendMessage('Render volume viewer', None) def Refresh(self, pubsub_evt): self.__config_preset() @@ -167,7 +184,6 @@ class Volume(): else: color_transfer = vtk.vtkColorTransferFunction() color_transfer.RemoveAllPoints() - print self.config curve_table = self.config['16bitClutCurves'] color_table = self.config['16bitClutColors'] colors = [] @@ -191,12 +207,10 @@ class Volume(): color_transfer = vtk.vtkColorTransferFunction() color_transfer.RemoveAllPoints() color_preset = self.config['CLUT'] - print ">>>", color_preset if color_preset != "No CLUT": p = plistlib.readPlist( os.path.join(const.RAYCASTING_PRESETS_DIRECTORY, 'color_list', color_preset + '.plist')) - print "nome clut", p r = p['Red'] g = p['Green'] b = p['Blue'] @@ -205,7 +219,6 @@ class Volume(): wl = self.TranslateScale(scale, self.config['wl']) inc = ww / 254.0 for i,rgb in enumerate(colors): - print i,inc, ww, wl - ww/2 + i * inc, rgb color_transfer.AddRGBPoint((wl - ww/2) + (i * inc), *[i/255.0 for i in rgb]) self.color_transfer = color_transfer return color_transfer @@ -221,6 +234,8 @@ class Volume(): ww = self.config['ww'] wl = self.config['wl'] + self.ww = ww + self.wl = wl l1 = wl - ww/2.0 l2 = wl + ww/2.0 @@ -255,16 +270,12 @@ class Volume(): ww = self.config['ww'] wl = self.TranslateScale(scale, self.config['wl']) - print ww, wl - l1 = wl - ww/2.0 l2 = wl + ww/2.0 opacity_transfer_func.RemoveAllPoints() opacity_transfer_func.AddSegment(0, 0, 2**16-1, 0) - print "l1, l2", l1, l2 - k1 = 0.0 k2 = 1.0 diff --git a/invesalius/data/vtk_utils.py b/invesalius/data/vtk_utils.py index e8f143d..43ce97a 100644 --- a/invesalius/data/vtk_utils.py +++ b/invesalius/data/vtk_utils.py @@ -1,4 +1,7 @@ import wx.lib.pubsub as ps +import vtk + +import constants as const # If you are frightened by the code bellow, or think it must have been result of # an identation error, lookup at: @@ -47,4 +50,41 @@ def ShowProgress(number_of_filters = 1): (progress[0], label)) return progress[0] - return UpdateProgress \ No newline at end of file + return UpdateProgress + +class Text(object): + def __init__(self): + + property = vtk.vtkTextProperty() + property.SetFontSize(const.TEXT_SIZE) + property.SetFontFamilyToArial() + property.BoldOff() + property.ItalicOff() + property.ShadowOn() + property.SetJustificationToLeft() + property.SetVerticalJustificationToTop() + property.SetColor(const.TEXT_COLOUR) + self.property = property + + mapper = vtk.vtkTextMapper() + mapper.SetTextProperty(property) + self.mapper = mapper + + x, y = const.TEXT_POSITION + actor = vtk.vtkActor2D() + actor.SetMapper(mapper) + actor.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() + actor.GetPositionCoordinate().SetValue(x,y) + self.actor = actor + + def SetValue(self, value): + self.mapper.SetInput(str(value)) + + def SetPosition(self, position): + self.actor.SetPositionCoordinate().SetValue(position) + + def Show(self, value=1): + if value: + self.actor.VisibilityOn() + else: + self.actor.VisibilityOff() -- libgit2 0.21.2