Commit 5caf20b9d7ac4ed1b953a8c21f040d4ec8dee527

Authored by tatiana
1 parent 2b5c9c39

FIX: Normals in STL and OBJ

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
... ...