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 | 1 | import os.path |
2 | + | |
2 | 3 | import wx |
4 | + | |
3 | 5 | from project import Project |
4 | 6 | |
5 | 7 | # VTK text |
... | ... | @@ -187,3 +189,19 @@ MODE_WW_WL = 4#:"Bright and contrast adjustment"} |
187 | 189 | MODE_SLICE_SCROLL = -1 |
188 | 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 | 84 | measured_polydata = vtk.vtkMassProperties() |
85 | 85 | measured_polydata.SetInput(polydata) |
86 | 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 | 3 | |
4 | 4 | import constants as const |
5 | 5 | import imagedata_utils as iu |
6 | -from project import Project | |
6 | +import project as prj | |
7 | 7 | import vtk_utils as vu |
8 | 8 | import polydata_utils as pu |
9 | 9 | from imagedata_utils import BuildEditedImage |
... | ... | @@ -49,6 +49,7 @@ class SurfaceManager(): |
49 | 49 | |
50 | 50 | ps.Publisher().subscribe(self.OnChangeSurfaceName, 'Change surface name') |
51 | 51 | ps.Publisher().subscribe(self.OnShowSurface, 'Show surface') |
52 | + ps.Publisher().subscribe(self.OnExportSurface,'Export surface to file') | |
52 | 53 | |
53 | 54 | def AddNewActor(self, pubsub_evt): |
54 | 55 | """ |
... | ... | @@ -170,13 +171,6 @@ class SurfaceManager(): |
170 | 171 | UpdateProgress(normals, "Orienting normals...")) |
171 | 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 | 175 | # TODO (Paulo): Why do we need this filter? |
182 | 176 | # without this the volume does not appear |
... | ... | @@ -207,7 +201,7 @@ class SurfaceManager(): |
207 | 201 | actor.GetProperty().SetOpacity(1-surface.transparency) |
208 | 202 | |
209 | 203 | # Append surface into Project.surface_dict |
210 | - proj = Project() | |
204 | + proj = prj.Project() | |
211 | 205 | proj.surface_dict[surface.index] = surface |
212 | 206 | |
213 | 207 | # Save actor for future management tasks |
... | ... | @@ -241,13 +235,13 @@ class SurfaceManager(): |
241 | 235 | ps.Publisher().sendMessage('Remove surface actor from viewer', (index)) |
242 | 236 | self.actors_dict.pop(index) |
243 | 237 | # Remove surface from project's surface_dict |
244 | - proj = Project() | |
238 | + proj = prj.Project() | |
245 | 239 | proj.surface_dict.pop(index) |
246 | 240 | |
247 | 241 | |
248 | 242 | def OnChangeSurfaceName(self, pubsub_evt): |
249 | 243 | index, name = pubsub_evt.data |
250 | - proj = Project() | |
244 | + proj = prj.Project() | |
251 | 245 | proj.surface_dict[index].name = name |
252 | 246 | |
253 | 247 | def OnShowSurface(self, pubsub_evt): |
... | ... | @@ -261,7 +255,7 @@ class SurfaceManager(): |
261 | 255 | """ |
262 | 256 | self.actors_dict[index].SetVisibility(value) |
263 | 257 | # Update value in project's surface_dict |
264 | - proj = Project() | |
258 | + proj = prj.Project() | |
265 | 259 | proj.surface_dict[index].is_shown = value |
266 | 260 | ps.Publisher().sendMessage('Render volume viewer') |
267 | 261 | |
... | ... | @@ -273,7 +267,7 @@ class SurfaceManager(): |
273 | 267 | index, value = pubsub_evt.data |
274 | 268 | self.actors_dict[index].GetProperty().SetOpacity(1-value) |
275 | 269 | # Update value in project's surface_dict |
276 | - proj = Project() | |
270 | + proj = prj.Project() | |
277 | 271 | proj.surface_dict[index].transparency = value |
278 | 272 | ps.Publisher().sendMessage('Render volume viewer') |
279 | 273 | |
... | ... | @@ -283,6 +277,32 @@ class SurfaceManager(): |
283 | 277 | index, colour = pubsub_evt.data |
284 | 278 | self.actors_dict[index].GetProperty().SetColor(colour) |
285 | 279 | # Update value in project's surface_dict |
286 | - proj = Project() | |
280 | + proj = prj.Project() | |
287 | 281 | proj.surface_dict[index].colour = colour |
288 | 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 | 158 | ('Set interaction mode', |
159 | 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 | 187 | def __bind_events_wx(self): |
162 | 188 | #self.Bind(wx.EVT_SIZE, self.OnSize) |
163 | 189 | pass |
... | ... | @@ -216,7 +242,6 @@ class Viewer(wx.Panel): |
216 | 242 | self.ren.ResetCamera() |
217 | 243 | self.ren.ResetCameraClippingRange() |
218 | 244 | |
219 | - #self.ShowOrientationCube() | |
220 | 245 | |
221 | 246 | self.UpdateRender() |
222 | 247 | |
... | ... | @@ -239,7 +264,7 @@ class Viewer(wx.Panel): |
239 | 264 | ren.ResetCameraClippingRange() |
240 | 265 | |
241 | 266 | |
242 | - self.ShowOrientationCube() | |
267 | + #self.ShowOrientationCube() | |
243 | 268 | |
244 | 269 | self.interactor.Render() |
245 | 270 | ... | ... |