Commit 5caf20b9d7ac4ed1b953a8c21f040d4ec8dee527
1 parent
2b5c9c39
Exists in
master
and in
6 other branches
FIX: Normals in STL and OBJ
Showing
2 changed files
with
37 additions
and
29 deletions
Show diff stats
invesalius/data/surface.py
... | ... | @@ -35,12 +35,12 @@ import wx.lib.pubsub as ps |
35 | 35 | #------------------------------------------------------------------ |
36 | 36 | class SurfaceProcess(multiprocessing.Process): |
37 | 37 | |
38 | - def __init__(self, conn, filename, mode, min_value, max_value, | |
38 | + def __init__(self, pipe, filename, mode, min_value, max_value, | |
39 | 39 | decimate_reduction, smooth_relaxation_factor, |
40 | 40 | smooth_iterations): |
41 | 41 | |
42 | 42 | multiprocessing.Process.__init__(self) |
43 | - self.conn = conn | |
43 | + self.pipe = pipe | |
44 | 44 | self.filename = filename |
45 | 45 | self.mode = mode |
46 | 46 | self.min_value = min_value |
... | ... | @@ -54,7 +54,7 @@ class SurfaceProcess(multiprocessing.Process): |
54 | 54 | |
55 | 55 | def SendProgress(self, obj, msg): |
56 | 56 | prog = obj.GetProgress() |
57 | - self.conn.send([prog, msg]) | |
57 | + self.pipe.send([prog, msg]) | |
58 | 58 | |
59 | 59 | def CreateSurface(self): |
60 | 60 | |
... | ... | @@ -97,7 +97,7 @@ class SurfaceProcess(multiprocessing.Process): |
97 | 97 | decimation.SetTargetReduction(self.decimate_reduction) |
98 | 98 | decimation.GetOutput().ReleaseDataFlagOn() |
99 | 99 | decimation.AddObserver("ProgressEvent", lambda obj,evt: |
100 | - self.SendProgress(obj, "Reducing number of triangles...")) | |
100 | + self.SendProgress(obj, "Generating 3D surface...")) | |
101 | 101 | polydata = decimation.GetOutput() |
102 | 102 | |
103 | 103 | if self.smooth_iterations and self.smooth_relaxation_factor: |
... | ... | @@ -110,7 +110,7 @@ class SurfaceProcess(multiprocessing.Process): |
110 | 110 | smoother.BoundarySmoothingOn() |
111 | 111 | smoother.GetOutput().ReleaseDataFlagOn() |
112 | 112 | smoother.AddObserver("ProgressEvent", lambda obj,evt: |
113 | - self.SendProgress(obj, "Smoothing surface...")) | |
113 | + self.SendProgress(obj, "Generating 3D surface...")) | |
114 | 114 | polydata = smoother.GetOutput() |
115 | 115 | |
116 | 116 | # Filter used to detect and fill holes. Only fill boundary edges holes. |
... | ... | @@ -120,19 +120,9 @@ class SurfaceProcess(multiprocessing.Process): |
120 | 120 | filled_polydata.SetInput(polydata) |
121 | 121 | filled_polydata.SetHoleSize(500) |
122 | 122 | filled_polydata.AddObserver("ProgressEvent", lambda obj,evt: |
123 | - self.SendProgress(obj, "Filling surface...")) | |
123 | + self.SendProgress(obj, "Generating 3D surface...")) | |
124 | 124 | polydata = filled_polydata.GetOutput() |
125 | - # Orient normals from inside to outside | |
126 | 125 | |
127 | - normals = vtk.vtkPolyDataNormals() | |
128 | - normals.SetInput(polydata) | |
129 | - normals.SetFeatureAngle(80) | |
130 | - normals.AutoOrientNormalsOn() | |
131 | - normals.GetOutput().ReleaseDataFlagOn() | |
132 | - normals.AddObserver("ProgressEvent", lambda obj,evt: | |
133 | - self.SendProgress(obj, "Orienting normals...")) | |
134 | - normals.UpdateInformation() | |
135 | - polydata = normals.GetOutput() | |
136 | 126 | |
137 | 127 | filename = tempfile.mktemp() |
138 | 128 | writer = vtk.vtkXMLPolyDataWriter() |
... | ... | @@ -140,8 +130,8 @@ class SurfaceProcess(multiprocessing.Process): |
140 | 130 | writer.SetFileName(filename) |
141 | 131 | writer.Write() |
142 | 132 | |
143 | - self.conn.send(None) | |
144 | - self.conn.send(filename) | |
133 | + self.pipe.send(None) | |
134 | + self.pipe.send(filename) | |
145 | 135 | |
146 | 136 | #---------------------------------------------------------------------------------------------- |
147 | 137 | class Surface(): |
... | ... | @@ -307,19 +297,19 @@ class SurfaceManager(): |
307 | 297 | pipeline_size = 5 |
308 | 298 | UpdateProgress = vu.ShowProgress(pipeline_size) |
309 | 299 | |
310 | - conn_in, conn_out = multiprocessing.Pipe() | |
311 | - sp = SurfaceProcess(conn_in, filename_img, mode, min_value, max_value, | |
300 | + pipe_in, pipe_out = multiprocessing.Pipe() | |
301 | + sp = SurfaceProcess(pipe_in, filename_img, mode, min_value, max_value, | |
312 | 302 | decimate_reduction, smooth_relaxation_factor, |
313 | 303 | smooth_iterations) |
314 | 304 | sp.start() |
315 | 305 | |
316 | 306 | while 1: |
317 | - msg = conn_out.recv() | |
307 | + msg = pipe_out.recv() | |
318 | 308 | if(msg is None): |
319 | 309 | break |
320 | 310 | UpdateProgress(msg[0],msg[1]) |
321 | 311 | |
322 | - filename_polydata = conn_out.recv() | |
312 | + filename_polydata = pipe_out.recv() | |
323 | 313 | |
324 | 314 | reader = vtk.vtkXMLPolyDataReader() |
325 | 315 | reader.SetFileName(filename_polydata) |
... | ... | @@ -447,16 +437,19 @@ class SurfaceManager(): |
447 | 437 | def OnExportSurface(self, pubsub_evt): |
448 | 438 | filename, filetype = pubsub_evt.data |
449 | 439 | if (filetype == const.FILETYPE_STL) or\ |
450 | - (filetype == const.FILETYPE_VTP): | |
440 | + (filetype == const.FILETYPE_VTP) or\ | |
441 | + (filetype == const.FILETYPE_PLY) : | |
451 | 442 | |
452 | 443 | # First we identify all surfaces that are selected |
453 | 444 | # (if any) |
454 | 445 | proj = prj.Project() |
455 | 446 | polydata_list = [] |
447 | + | |
456 | 448 | for index in proj.surface_dict: |
457 | 449 | surface = proj.surface_dict[index] |
458 | 450 | if surface.is_shown: |
459 | 451 | polydata_list.append(surface.polydata) |
452 | + | |
460 | 453 | if len(polydata_list) == 0: |
461 | 454 | print "oops - no polydata" |
462 | 455 | return |
... | ... | @@ -473,8 +466,8 @@ class SurfaceManager(): |
473 | 466 | writer.SetFileTypeToBinary() |
474 | 467 | elif filetype == const.FILETYPE_VTP: |
475 | 468 | writer = vtk.vtkXMLPolyDataWriter() |
476 | - elif filetype == const.FILETYPE_IV: | |
477 | - writer = vtk.vtkIVWriter() | |
469 | + #elif filetype == const.FILETYPE_IV: | |
470 | + # writer = vtk.vtkIVWriter() | |
478 | 471 | elif filetype == const.FILETYPE_PLY: |
479 | 472 | writer = vtk.vtkPLYWriter() |
480 | 473 | writer.SetFileTypeToBinary() |
... | ... | @@ -482,6 +475,16 @@ class SurfaceManager(): |
482 | 475 | #writer.SetColorModeToUniformCellColor() |
483 | 476 | #writer.SetColor(255, 0, 0) |
484 | 477 | |
478 | + if filetype == const.FILETYPE_STL: | |
479 | + # Invert normals | |
480 | + normals = vtk.vtkPolyDataNormals() | |
481 | + normals.SetInput(polydata) | |
482 | + normals.SetFeatureAngle(80) | |
483 | + normals.AutoOrientNormalsOn() | |
484 | + normals.GetOutput().ReleaseDataFlagOn() | |
485 | + normals.UpdateInformation() | |
486 | + polydata = normals.GetOutput() | |
487 | + | |
485 | 488 | writer.SetFileName(filename) |
486 | 489 | writer.SetInput(polydata) |
487 | 490 | writer.Write() | ... | ... |
invesalius/data/viewer_volume.py
... | ... | @@ -279,25 +279,30 @@ class Viewer(wx.Panel): |
279 | 279 | |
280 | 280 | def OnExportSurface(self, pubsub_evt): |
281 | 281 | filename, filetype = pubsub_evt.data |
282 | + fileprefix = filename.split(".")[-2] | |
282 | 283 | renwin = self.interactor.GetRenderWindow() |
283 | 284 | |
284 | 285 | if filetype == const.FILETYPE_RIB: |
285 | 286 | writer = vtk.vtkRIBExporter() |
286 | - writer.SetFileName(filename) | |
287 | + writer.SetFilePrefix(fileprefix) | |
288 | + writer.SetTexturePrefix(fileprefix) | |
287 | 289 | writer.SetInput(renwin) |
290 | + writer.Write() | |
288 | 291 | elif filetype == const.FILETYPE_VRML: |
289 | 292 | writer = vtk.vtkVRMLExporter() |
290 | 293 | writer.SetFileName(filename) |
291 | 294 | writer.SetInput(renwin) |
295 | + writer.Write() | |
292 | 296 | elif filetype == const.FILETYPE_OBJ: |
293 | 297 | writer = vtk.vtkOBJExporter() |
294 | - writer.SetFilePrefix(filename.split(".")[-2]) | |
298 | + writer.SetFilePrefix(fileprefix) | |
295 | 299 | writer.SetInput(renwin) |
296 | - else: # const.FILETYPE_IV: | |
300 | + writer.Write() | |
301 | + elif filetype == const.FILETYPE_IV: | |
297 | 302 | writer = vtk.vtkIVExporter() |
298 | 303 | writer.SetFileName(filename) |
299 | 304 | writer.SetInput(renwin) |
300 | - writer.Write() | |
305 | + writer.Write() | |
301 | 306 | |
302 | 307 | def OnEnableBrightContrast(self, pubsub_evt): |
303 | 308 | style = self.style | ... | ... |