Commit f9d49cf73f43e2e7a801f09dab738305899a1351

Authored by tatiana
1 parent fc5abcbd

ADD: 3D surface export to file

invesalius/constants.py
1 import os.path 1 import os.path
  2 +
2 import wx 3 import wx
  4 +
3 from project import Project 5 from project import Project
4 6
5 # VTK text 7 # VTK text
@@ -187,3 +189,19 @@ MODE_WW_WL = 4#:"Bright and contrast adjustment"} @@ -187,3 +189,19 @@ MODE_WW_WL = 4#:"Bright and contrast adjustment"}
187 MODE_SLICE_SCROLL = -1 189 MODE_SLICE_SCROLL = -1
188 MODE_SLICE_EDITOR = -2 190 MODE_SLICE_EDITOR = -2
189 191
  192 +############
  193 +
  194 +
  195 +FILETYPE_IV = wx.NewId()
  196 +FILETYPE_RIB = wx.NewId()
  197 +FILETYPE_STL = wx.NewId()
  198 +FILETYPE_VRML = wx.NewId()
  199 +FILETYPE_OBJ = wx.NewId()
  200 +
  201 +FILETYPE_BMP = wx.NewId()
  202 +FILETYPE_JPG = wx.NewId()
  203 +FILETYPE_PNG = wx.NewId()
  204 +FILETYPE_PS = wx.NewId()
  205 +FILETYPE_POV = wx.NewId()
  206 +FILETYPE_OBJ = wx.NewId()
  207 +
invesalius/data/polydata_utils.py
@@ -84,3 +84,17 @@ def CalculateSurfaceArea(polydata): @@ -84,3 +84,17 @@ def CalculateSurfaceArea(polydata):
84 measured_polydata = vtk.vtkMassProperties() 84 measured_polydata = vtk.vtkMassProperties()
85 measured_polydata.SetInput(polydata) 85 measured_polydata.SetInput(polydata)
86 return measured_polydata.GetSurfaceArea() 86 return measured_polydata.GetSurfaceArea()
  87 +
  88 +def Merge(polydata_list):
  89 + append = vtk.vtkAppendPolyData()
  90 +
  91 + for polydata in polydata_list:
  92 + triangle = vtk.TriangleFilter()
  93 + triangle.SetInput(polydata)
  94 + append.AddInput(triangle.GetOutput())
  95 +
  96 + clean = vtk.vtkCleanPolyData()
  97 + clean.SetInput(append.GetOutput())
  98 +
  99 + return append.GetOutput()
  100 +
invesalius/data/surface.py
@@ -3,7 +3,7 @@ import wx.lib.pubsub as ps @@ -3,7 +3,7 @@ import wx.lib.pubsub as ps
3 3
4 import constants as const 4 import constants as const
5 import imagedata_utils as iu 5 import imagedata_utils as iu
6 -from project import Project 6 +import project as prj
7 import vtk_utils as vu 7 import vtk_utils as vu
8 import polydata_utils as pu 8 import polydata_utils as pu
9 from imagedata_utils import BuildEditedImage 9 from imagedata_utils import BuildEditedImage
@@ -49,6 +49,7 @@ class SurfaceManager(): @@ -49,6 +49,7 @@ class SurfaceManager():
49 49
50 ps.Publisher().subscribe(self.OnChangeSurfaceName, 'Change surface name') 50 ps.Publisher().subscribe(self.OnChangeSurfaceName, 'Change surface name')
51 ps.Publisher().subscribe(self.OnShowSurface, 'Show surface') 51 ps.Publisher().subscribe(self.OnShowSurface, 'Show surface')
  52 + ps.Publisher().subscribe(self.OnExportSurface,'Export surface to file')
52 53
53 def AddNewActor(self, pubsub_evt): 54 def AddNewActor(self, pubsub_evt):
54 """ 55 """
@@ -170,13 +171,6 @@ class SurfaceManager(): @@ -170,13 +171,6 @@ class SurfaceManager():
170 UpdateProgress(normals, "Orienting normals...")) 171 UpdateProgress(normals, "Orienting normals..."))
171 polydata = normals.GetOutput() 172 polydata = normals.GetOutput()
172 173
173 - #======= Temporary Code =======  
174 - stl = vtk.vtkSTLWriter()  
175 - stl.SetFileTypeToBinary()  
176 - stl.SetInputConnection(normals.GetOutputPort())  
177 - stl.SetFileName("surface.stl")  
178 - stl.Write()  
179 - #==============================  
180 174
181 # TODO (Paulo): Why do we need this filter? 175 # TODO (Paulo): Why do we need this filter?
182 # without this the volume does not appear 176 # without this the volume does not appear
@@ -207,7 +201,7 @@ class SurfaceManager(): @@ -207,7 +201,7 @@ class SurfaceManager():
207 actor.GetProperty().SetOpacity(1-surface.transparency) 201 actor.GetProperty().SetOpacity(1-surface.transparency)
208 202
209 # Append surface into Project.surface_dict 203 # Append surface into Project.surface_dict
210 - proj = Project() 204 + proj = prj.Project()
211 proj.surface_dict[surface.index] = surface 205 proj.surface_dict[surface.index] = surface
212 206
213 # Save actor for future management tasks 207 # Save actor for future management tasks
@@ -241,13 +235,13 @@ class SurfaceManager(): @@ -241,13 +235,13 @@ class SurfaceManager():
241 ps.Publisher().sendMessage('Remove surface actor from viewer', (index)) 235 ps.Publisher().sendMessage('Remove surface actor from viewer', (index))
242 self.actors_dict.pop(index) 236 self.actors_dict.pop(index)
243 # Remove surface from project's surface_dict 237 # Remove surface from project's surface_dict
244 - proj = Project() 238 + proj = prj.Project()
245 proj.surface_dict.pop(index) 239 proj.surface_dict.pop(index)
246 240
247 241
248 def OnChangeSurfaceName(self, pubsub_evt): 242 def OnChangeSurfaceName(self, pubsub_evt):
249 index, name = pubsub_evt.data 243 index, name = pubsub_evt.data
250 - proj = Project() 244 + proj = prj.Project()
251 proj.surface_dict[index].name = name 245 proj.surface_dict[index].name = name
252 246
253 def OnShowSurface(self, pubsub_evt): 247 def OnShowSurface(self, pubsub_evt):
@@ -261,7 +255,7 @@ class SurfaceManager(): @@ -261,7 +255,7 @@ class SurfaceManager():
261 """ 255 """
262 self.actors_dict[index].SetVisibility(value) 256 self.actors_dict[index].SetVisibility(value)
263 # Update value in project's surface_dict 257 # Update value in project's surface_dict
264 - proj = Project() 258 + proj = prj.Project()
265 proj.surface_dict[index].is_shown = value 259 proj.surface_dict[index].is_shown = value
266 ps.Publisher().sendMessage('Render volume viewer') 260 ps.Publisher().sendMessage('Render volume viewer')
267 261
@@ -273,7 +267,7 @@ class SurfaceManager(): @@ -273,7 +267,7 @@ class SurfaceManager():
273 index, value = pubsub_evt.data 267 index, value = pubsub_evt.data
274 self.actors_dict[index].GetProperty().SetOpacity(1-value) 268 self.actors_dict[index].GetProperty().SetOpacity(1-value)
275 # Update value in project's surface_dict 269 # Update value in project's surface_dict
276 - proj = Project() 270 + proj = prj.Project()
277 proj.surface_dict[index].transparency = value 271 proj.surface_dict[index].transparency = value
278 ps.Publisher().sendMessage('Render volume viewer') 272 ps.Publisher().sendMessage('Render volume viewer')
279 273
@@ -283,6 +277,32 @@ class SurfaceManager(): @@ -283,6 +277,32 @@ class SurfaceManager():
283 index, colour = pubsub_evt.data 277 index, colour = pubsub_evt.data
284 self.actors_dict[index].GetProperty().SetColor(colour) 278 self.actors_dict[index].GetProperty().SetColor(colour)
285 # Update value in project's surface_dict 279 # Update value in project's surface_dict
286 - proj = Project() 280 + proj = prj.Project()
287 proj.surface_dict[index].colour = colour 281 proj.surface_dict[index].colour = colour
288 ps.Publisher().sendMessage('Render volume viewer') 282 ps.Publisher().sendMessage('Render volume viewer')
  283 +
  284 +
  285 + def OnExportSurface(self, pubsub_evt):
  286 + filename, filetype = pubsub_evt.data
  287 +
  288 + if filetype == const.FILETYPE_STL:
  289 + proj = prj.Project()
  290 + polydata_list = []
  291 + for index in proj.surface_dict:
  292 + surface = proj.surface_dict[index]
  293 + if surface.is_shown:
  294 + polydata_list.append(surface.polydata)
  295 + if len(polydata_list) < 0:
  296 + print "oops - no polydata"
  297 + return
  298 + elif len(polydata_list) == 1:
  299 + polydata = polydata_list[0]
  300 + else:
  301 + polydata = pu.Merge(polydata_list)
  302 + writer = vtk.vtkSTLWriter()
  303 + writer.SetFileTypeToBinary()
  304 + writer.SetFileName(filename)
  305 + writer.SetInput(polydata)
  306 + writer.Write()
  307 +
  308 +
invesalius/data/viewer_volume.py
@@ -158,6 +158,32 @@ class Viewer(wx.Panel): @@ -158,6 +158,32 @@ class Viewer(wx.Panel):
158 ('Set interaction mode', 158 ('Set interaction mode',
159 const.MODE_SLICE_EDITOR)) 159 const.MODE_SLICE_EDITOR))
160 160
  161 + ps.Publisher().subscribe(self.OnExportSurface, 'Export surface to file')
  162 +
  163 + def OnExportSurface(self, pubsub_evt):
  164 + filename, filetype = pubsub_evt.data
  165 + renwin = self.interactor.GetRenderWindow()
  166 +
  167 + if filetype == const.FILETYPE_RIB:
  168 + writer = vtk.vtkIVExporter()
  169 + writer.SetFileName(filename)
  170 + writer.SetInput(renwin)
  171 + elif filetype == const.FILETYPE_VRML:
  172 + writer = vtk.vtkVRMLExporter()
  173 + writer.SetFileName(filename)
  174 + writer.SetInput(renwin)
  175 + elif filetype == const.FILETYPE_OBJ:
  176 + writer = vtk.vtkOBJExporter()
  177 + writer.SetFilePrefix(filename.split(".")[-2])
  178 + writer.SetInput(renwin)
  179 + else: # const.FILETYPE_IV:
  180 + writer = vtk.vtkIVExporter()
  181 + writer.SetFileName(filename)
  182 + writer.SetInput(renwin)
  183 + writer.Write()
  184 +
  185 +
  186 +
161 def __bind_events_wx(self): 187 def __bind_events_wx(self):
162 #self.Bind(wx.EVT_SIZE, self.OnSize) 188 #self.Bind(wx.EVT_SIZE, self.OnSize)
163 pass 189 pass
@@ -216,7 +242,6 @@ class Viewer(wx.Panel): @@ -216,7 +242,6 @@ class Viewer(wx.Panel):
216 self.ren.ResetCamera() 242 self.ren.ResetCamera()
217 self.ren.ResetCameraClippingRange() 243 self.ren.ResetCameraClippingRange()
218 244
219 - #self.ShowOrientationCube()  
220 245
221 self.UpdateRender() 246 self.UpdateRender()
222 247
@@ -239,7 +264,7 @@ class Viewer(wx.Panel): @@ -239,7 +264,7 @@ class Viewer(wx.Panel):
239 ren.ResetCameraClippingRange() 264 ren.ResetCameraClippingRange()
240 265
241 266
242 - self.ShowOrientationCube() 267 + #self.ShowOrientationCube()
243 268
244 self.interactor.Render() 269 self.interactor.Render()
245 270