Commit f9d49cf73f43e2e7a801f09dab738305899a1351
1 parent
fc5abcbd
Exists in
master
and in
68 other branches
ADD: 3D surface export to file
Showing
4 changed files
with
93 additions
and
16 deletions
Show diff stats
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 |