diff --git a/invesalius/constants.py b/invesalius/constants.py index 4071e7b..fa237a4 100644 --- a/invesalius/constants.py +++ b/invesalius/constants.py @@ -1,5 +1,7 @@ import os.path + import wx + from project import Project # VTK text @@ -187,3 +189,19 @@ MODE_WW_WL = 4#:"Bright and contrast adjustment"} MODE_SLICE_SCROLL = -1 MODE_SLICE_EDITOR = -2 +############ + + +FILETYPE_IV = wx.NewId() +FILETYPE_RIB = wx.NewId() +FILETYPE_STL = wx.NewId() +FILETYPE_VRML = wx.NewId() +FILETYPE_OBJ = wx.NewId() + +FILETYPE_BMP = wx.NewId() +FILETYPE_JPG = wx.NewId() +FILETYPE_PNG = wx.NewId() +FILETYPE_PS = wx.NewId() +FILETYPE_POV = wx.NewId() +FILETYPE_OBJ = wx.NewId() + diff --git a/invesalius/data/polydata_utils.py b/invesalius/data/polydata_utils.py index cb4029f..78618f0 100644 --- a/invesalius/data/polydata_utils.py +++ b/invesalius/data/polydata_utils.py @@ -84,3 +84,17 @@ def CalculateSurfaceArea(polydata): measured_polydata = vtk.vtkMassProperties() measured_polydata.SetInput(polydata) return measured_polydata.GetSurfaceArea() + +def Merge(polydata_list): + append = vtk.vtkAppendPolyData() + + for polydata in polydata_list: + triangle = vtk.TriangleFilter() + triangle.SetInput(polydata) + append.AddInput(triangle.GetOutput()) + + clean = vtk.vtkCleanPolyData() + clean.SetInput(append.GetOutput()) + + return append.GetOutput() + diff --git a/invesalius/data/surface.py b/invesalius/data/surface.py index 10665e8..2fbae65 100644 --- a/invesalius/data/surface.py +++ b/invesalius/data/surface.py @@ -3,7 +3,7 @@ import wx.lib.pubsub as ps import constants as const import imagedata_utils as iu -from project import Project +import project as prj import vtk_utils as vu import polydata_utils as pu from imagedata_utils import BuildEditedImage @@ -49,6 +49,7 @@ class SurfaceManager(): ps.Publisher().subscribe(self.OnChangeSurfaceName, 'Change surface name') ps.Publisher().subscribe(self.OnShowSurface, 'Show surface') + ps.Publisher().subscribe(self.OnExportSurface,'Export surface to file') def AddNewActor(self, pubsub_evt): """ @@ -170,13 +171,6 @@ class SurfaceManager(): UpdateProgress(normals, "Orienting normals...")) polydata = normals.GetOutput() - #======= Temporary Code ======= - stl = vtk.vtkSTLWriter() - stl.SetFileTypeToBinary() - stl.SetInputConnection(normals.GetOutputPort()) - stl.SetFileName("surface.stl") - stl.Write() - #============================== # TODO (Paulo): Why do we need this filter? # without this the volume does not appear @@ -207,7 +201,7 @@ class SurfaceManager(): actor.GetProperty().SetOpacity(1-surface.transparency) # Append surface into Project.surface_dict - proj = Project() + proj = prj.Project() proj.surface_dict[surface.index] = surface # Save actor for future management tasks @@ -241,13 +235,13 @@ class SurfaceManager(): ps.Publisher().sendMessage('Remove surface actor from viewer', (index)) self.actors_dict.pop(index) # Remove surface from project's surface_dict - proj = Project() + proj = prj.Project() proj.surface_dict.pop(index) def OnChangeSurfaceName(self, pubsub_evt): index, name = pubsub_evt.data - proj = Project() + proj = prj.Project() proj.surface_dict[index].name = name def OnShowSurface(self, pubsub_evt): @@ -261,7 +255,7 @@ class SurfaceManager(): """ self.actors_dict[index].SetVisibility(value) # Update value in project's surface_dict - proj = Project() + proj = prj.Project() proj.surface_dict[index].is_shown = value ps.Publisher().sendMessage('Render volume viewer') @@ -273,7 +267,7 @@ class SurfaceManager(): index, value = pubsub_evt.data self.actors_dict[index].GetProperty().SetOpacity(1-value) # Update value in project's surface_dict - proj = Project() + proj = prj.Project() proj.surface_dict[index].transparency = value ps.Publisher().sendMessage('Render volume viewer') @@ -283,6 +277,32 @@ class SurfaceManager(): index, colour = pubsub_evt.data self.actors_dict[index].GetProperty().SetColor(colour) # Update value in project's surface_dict - proj = Project() + proj = prj.Project() proj.surface_dict[index].colour = colour ps.Publisher().sendMessage('Render volume viewer') + + + def OnExportSurface(self, pubsub_evt): + filename, filetype = pubsub_evt.data + + if filetype == const.FILETYPE_STL: + proj = prj.Project() + polydata_list = [] + for index in proj.surface_dict: + surface = proj.surface_dict[index] + if surface.is_shown: + polydata_list.append(surface.polydata) + if len(polydata_list) < 0: + print "oops - no polydata" + return + elif len(polydata_list) == 1: + polydata = polydata_list[0] + else: + polydata = pu.Merge(polydata_list) + writer = vtk.vtkSTLWriter() + writer.SetFileTypeToBinary() + writer.SetFileName(filename) + writer.SetInput(polydata) + writer.Write() + + diff --git a/invesalius/data/viewer_volume.py b/invesalius/data/viewer_volume.py index 0a1cf85..d0fe41a 100755 --- a/invesalius/data/viewer_volume.py +++ b/invesalius/data/viewer_volume.py @@ -158,6 +158,32 @@ class Viewer(wx.Panel): ('Set interaction mode', const.MODE_SLICE_EDITOR)) + ps.Publisher().subscribe(self.OnExportSurface, 'Export surface to file') + + def OnExportSurface(self, pubsub_evt): + filename, filetype = pubsub_evt.data + renwin = self.interactor.GetRenderWindow() + + if filetype == const.FILETYPE_RIB: + writer = vtk.vtkIVExporter() + writer.SetFileName(filename) + writer.SetInput(renwin) + elif filetype == const.FILETYPE_VRML: + writer = vtk.vtkVRMLExporter() + writer.SetFileName(filename) + writer.SetInput(renwin) + elif filetype == const.FILETYPE_OBJ: + writer = vtk.vtkOBJExporter() + writer.SetFilePrefix(filename.split(".")[-2]) + writer.SetInput(renwin) + else: # const.FILETYPE_IV: + writer = vtk.vtkIVExporter() + writer.SetFileName(filename) + writer.SetInput(renwin) + writer.Write() + + + def __bind_events_wx(self): #self.Bind(wx.EVT_SIZE, self.OnSize) pass @@ -216,7 +242,6 @@ class Viewer(wx.Panel): self.ren.ResetCamera() self.ren.ResetCameraClippingRange() - #self.ShowOrientationCube() self.UpdateRender() @@ -239,7 +264,7 @@ class Viewer(wx.Panel): ren.ResetCameraClippingRange() - self.ShowOrientationCube() + #self.ShowOrientationCube() self.interactor.Render() -- libgit2 0.21.2