Commit 2fade61abc95553bd4a1b9f00981ee64e1c9c734

Authored by Santiago Castro
Committed by Thiago Franco de Moraes
1 parent 78173f1e
Exists in master

Add command line options for saving and exporting (#85)

* Create option in app.py to import and then save the project

* Add command to import and export in STL to all available presets

* Create option to open InVesalius without gui

* Add option --export

* No-gui doing less work when creating surface

* Print on debug

* Fix missing session assignment in non-gui mode

* Add option to import every group of DICOM images

* Checking surface index exists in actors_dict before removing it
.dockerignore 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +.git*
  2 +.python-version
  3 +Dockerfile
... ...
Dockerfile 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +FROM ubuntu:16.04
  2 +
  3 +RUN apt-get update
  4 +RUN apt-get install -y \
  5 + cython \
  6 + locales \
  7 + python-concurrent.futures \
  8 + python-gdcm \
  9 + python-matplotlib \
  10 + python-nibabel \
  11 + python-numpy \
  12 + python-pil \
  13 + python-psutil \
  14 + python-scipy \
  15 + python-serial \
  16 + python-skimage \
  17 + python-vtk6 \
  18 + python-vtkgdcm \
  19 + python-wxgtk3.0
  20 +
  21 +RUN locale-gen en_US.UTF-8
  22 +ENV LANG en_US.UTF-8
  23 +ENV LANGUAGE en_US:en
  24 +ENV LC_ALL en_US.UTF-8
  25 +
  26 +WORKDIR /usr/local/app
  27 +
  28 +COPY . .
  29 +
  30 +RUN python setup.py build_ext --inplace
... ...
app.py
... ... @@ -24,6 +24,9 @@ import optparse as op
24 24 import os
25 25 import sys
26 26 import shutil
  27 +import traceback
  28 +
  29 +import re
27 30  
28 31 if sys.platform == 'win32':
29 32 import _winreg
... ... @@ -218,7 +221,8 @@ class SplashScreen(wx.SplashScreen):
218 221 self.control = Controller(self.main)
219 222  
220 223 self.fc = wx.FutureCall(1, self.ShowMain)
221   - wx.FutureCall(1, parse_comand_line)
  224 + options, args = parse_comand_line()
  225 + wx.FutureCall(1, use_cmd_optargs, options, args)
222 226  
223 227 # Check for updates
224 228 from threading import Thread
... ... @@ -244,6 +248,24 @@ class SplashScreen(wx.SplashScreen):
244 248 if self.fc.IsRunning():
245 249 self.Raise()
246 250  
  251 +
  252 +def non_gui_startup(options, args):
  253 + lang = 'en'
  254 + _ = i18n.InstallLanguage(lang)
  255 +
  256 + from invesalius.control import Controller
  257 + from invesalius.project import Project
  258 +
  259 + session = ses.Session()
  260 + if not session.ReadSession():
  261 + session.CreateItens()
  262 + session.SetLanguage(lang)
  263 + session.WriteSessionFile()
  264 +
  265 + control = Controller(None)
  266 +
  267 + use_cmd_optargs(options, args)
  268 +
247 269 # ------------------------------------------------------------------
248 270  
249 271  
... ... @@ -262,39 +284,138 @@ def parse_comand_line():
262 284 action="store_true",
263 285 dest="debug")
264 286  
  287 + parser.add_option('--no-gui',
  288 + action='store_true',
  289 + dest='no_gui')
  290 +
265 291 # -i or --import: import DICOM directory
266 292 # chooses largest series
267 293 parser.add_option("-i", "--import",
268 294 action="store",
269 295 dest="dicom_dir")
  296 +
  297 + parser.add_option("--import-all",
  298 + action="store")
  299 +
  300 + parser.add_option("-s", "--save",
  301 + help="Save the project after an import.")
  302 +
  303 + parser.add_option("-t", "--threshold",
  304 + help="Define the threshold for the export (e.g. 100-780).")
  305 +
  306 + parser.add_option("-e", "--export",
  307 + help="Export to STL.")
  308 +
  309 + parser.add_option("-a", "--export-to-all",
  310 + help="Export to STL for all mask presets.")
  311 +
270 312 options, args = parser.parse_args()
  313 + return options, args
  314 +
271 315  
  316 +def use_cmd_optargs(options, args):
272 317 # If debug argument...
273 318 if options.debug:
274 319 Publisher.subscribe(print_events, Publisher.ALL_TOPICS)
  320 + session = ses.Session()
275 321 session.debug = 1
276 322  
277 323 # If import DICOM argument...
278 324 if options.dicom_dir:
279 325 import_dir = options.dicom_dir
280   - Publisher.sendMessage('Import directory', import_dir)
  326 + Publisher.sendMessage('Import directory', {'directory': import_dir, 'gui': not options.no_gui})
  327 +
  328 + if options.save:
  329 + Publisher.sendMessage('Save project', os.path.abspath(options.save))
  330 + exit(0)
  331 +
  332 + check_for_export(options)
  333 +
  334 + return True
  335 + elif options.import_all:
  336 + import invesalius.reader.dicom_reader as dcm
  337 + for patient in dcm.GetDicomGroups(options.import_all):
  338 + for group in patient.GetGroups():
  339 + Publisher.sendMessage('Import group', {'group': group, 'gui': not options.no_gui})
  340 + check_for_export(options, suffix=group.title, remove_surfaces=False)
  341 + Publisher.sendMessage('Remove masks', [0])
281 342 return True
282 343  
283 344 # Check if there is a file path somewhere in what the user wrote
284 345 # In case there is, try opening as it was a inv3
285 346 else:
286   - i = len(args)
287   - while i:
288   - i -= 1
289   - file = args[i].decode(sys.stdin.encoding)
290   - if os.path.isfile(file):
291   - path = os.path.abspath(file)
292   - Publisher.sendMessage('Open project', path)
293   - i = 0
  347 + for arg in reversed(args):
  348 + if os.path.isfile(arg):
  349 + path_ = os.path.abspath(arg.decode(sys.stdin.encoding))
  350 + Publisher.sendMessage('Open project', path_)
  351 +
  352 + check_for_export(options)
294 353 return True
295 354 return False
296 355  
297 356  
  357 +def sanitize(text):
  358 + text = str(text).strip().replace(' ', '_')
  359 + return re.sub(r'(?u)[^-\w.]', '', text)
  360 +
  361 +
  362 +def check_for_export(options, suffix='', remove_surfaces=False):
  363 + suffix = sanitize(suffix)
  364 +
  365 + if options.export:
  366 + if not options.threshold:
  367 + print("Need option --threshold when using --export.")
  368 + exit(1)
  369 + threshold_range = tuple([int(n) for n in options.threshold.split(',')])
  370 +
  371 + if suffix:
  372 + if options.export.endswith('.stl'):
  373 + path_ = '{}-{}.stl'.format(options.export[:-4], suffix)
  374 + else:
  375 + path_ = '{}-{}.stl'.format(options.export, suffix)
  376 + else:
  377 + path_ = options.export
  378 +
  379 + export(path_, threshold_range, remove_surface=remove_surfaces)
  380 + elif options.export_to_all:
  381 + # noinspection PyBroadException
  382 + try:
  383 + from invesalius.project import Project
  384 +
  385 + for threshold_name, threshold_range in Project().presets.thresh_ct.iteritems():
  386 + if isinstance(threshold_range[0], int):
  387 + path_ = u'{}-{}-{}.stl'.format(options.export_to_all, suffix, threshold_name)
  388 + export(path_, threshold_range, remove_surface=True)
  389 + except:
  390 + traceback.print_exc()
  391 + finally:
  392 + exit(0)
  393 +
  394 +
  395 +def export(path_, threshold_range, remove_surface=False):
  396 + import invesalius.constants as const
  397 +
  398 + Publisher.sendMessage('Set threshold values', threshold_range)
  399 +
  400 + surface_options = {
  401 + 'method': {
  402 + 'algorithm': 'Default',
  403 + 'options': {},
  404 + }, 'options': {
  405 + 'index': 0,
  406 + 'name': '',
  407 + 'quality': _('Optimal *'),
  408 + 'fill': False,
  409 + 'keep_largest': False,
  410 + 'overwrite': False,
  411 + }
  412 + }
  413 + Publisher.sendMessage('Create surface from index', surface_options)
  414 + Publisher.sendMessage('Export surface to file', (path_, const.FILETYPE_STL))
  415 + if remove_surface:
  416 + Publisher.sendMessage('Remove surfaces', [0])
  417 +
  418 +
298 419 def print_events(data):
299 420 """
300 421 Print pubsub messages
... ... @@ -305,8 +426,13 @@ def main():
305 426 """
306 427 Initialize InVesalius GUI
307 428 """
308   - application = InVesalius(0)
309   - application.MainLoop()
  429 + options, args = parse_comand_line()
  430 +
  431 + if options.no_gui:
  432 + non_gui_startup(options, args)
  433 + else:
  434 + application = InVesalius(0)
  435 + application.MainLoop()
310 436  
311 437 if __name__ == '__main__':
312 438 #Is needed because of pyinstaller
... ...
invesalius/constants.py
... ... @@ -694,19 +694,19 @@ BTNS_IMG_MKS = {IR1: {0: 'LEI'},
694 694 IR2: {1: 'REI'},
695 695 IR3: {2: 'NAI'}}
696 696  
697   -TIPS_IMG = [wx.ToolTip(_("Select left ear in image")),
698   - wx.ToolTip(_("Select right ear in image")),
699   - wx.ToolTip(_("Select nasion in image"))]
  697 +TIPS_IMG = [_("Select left ear in image"),
  698 + _("Select right ear in image"),
  699 + _("Select nasion in image")]
700 700  
701 701 BTNS_TRK = {TR1: {3: _('LET')},
702 702 TR2: {4: _('RET')},
703 703 TR3: {5: _('NAT')},
704 704 SET: {6: _('SET')}}
705 705  
706   -TIPS_TRK = [wx.ToolTip(_("Select left ear with spatial tracker")),
707   - wx.ToolTip(_("Select right ear with spatial tracker")),
708   - wx.ToolTip(_("Select nasion with spatial tracker")),
709   - wx.ToolTip(_("Show set coordinates in image"))]
  706 +TIPS_TRK = [_("Select left ear with spatial tracker"),
  707 + _("Select right ear with spatial tracker"),
  708 + _("Select nasion with spatial tracker"),
  709 + _("Show set coordinates in image")]
710 710  
711 711 CAL_DIR = os.path.abspath(os.path.join(FILE_PATH, '..', 'navigation', 'mtc_files', 'CalibrationFiles'))
712 712 MAR_DIR = os.path.abspath(os.path.join(FILE_PATH, '..', 'navigation', 'mtc_files', 'Markers'))
... ...
invesalius/control.py
... ... @@ -68,6 +68,7 @@ class Controller():
68 68  
69 69 def __bind_events(self):
70 70 Publisher.subscribe(self.OnImportMedicalImages, 'Import directory')
  71 + Publisher.subscribe(self.OnImportGroup, 'Import group')
71 72 Publisher.subscribe(self.OnShowDialogImportDirectory,
72 73 'Show import directory dialog')
73 74 Publisher.subscribe(self.OnShowDialogImportOtherFiles,
... ... @@ -105,6 +106,8 @@ class Controller():
105 106  
106 107 Publisher.subscribe(self.SetBitmapSpacing, 'Set bitmap spacing')
107 108  
  109 + Publisher.subscribe(self.OnSaveProject, 'Save project')
  110 +
108 111 def SetBitmapSpacing(self, pubsub_evt):
109 112 proj = prj.Project()
110 113 proj.spacing = pubsub_evt.data
... ... @@ -329,6 +332,10 @@ class Controller():
329 332 session.OpenProject(filepath)
330 333 Publisher.sendMessage("Enable state project", True)
331 334  
  335 + def OnSaveProject(self, pubsub_evt):
  336 + path = pubsub_evt.data
  337 + self.SaveProject(path)
  338 +
332 339 def SaveProject(self, path=None):
333 340 Publisher.sendMessage('Begin busy cursor')
334 341 session = ses.Session()
... ... @@ -442,10 +449,11 @@ class Controller():
442 449 #----------- to import by command line ---------------------------------------------------
443 450  
444 451 def OnImportMedicalImages(self, pubsub_evt):
445   - directory = pubsub_evt.data
446   - self.ImportMedicalImages(directory)
  452 + directory = pubsub_evt.data['directory']
  453 + gui = pubsub_evt.data['gui']
  454 + self.ImportMedicalImages(directory, gui)
447 455  
448   - def ImportMedicalImages(self, directory):
  456 + def ImportMedicalImages(self, directory, gui=True):
449 457 patients_groups = dcm.GetDicomGroups(directory)
450 458 name = directory.rpartition('\\')[-1].split('.')
451 459 print "patients: ", patients_groups
... ... @@ -453,7 +461,7 @@ class Controller():
453 461 if len(patients_groups):
454 462 # OPTION 1: DICOM
455 463 group = dcm.SelectLargerDicomGroup(patients_groups)
456   - matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0, 0], gui=True)
  464 + matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0, 0], gui=gui)
457 465 self.CreateDicomProject(dicom, matrix, matrix_filename)
458 466 else:
459 467 # OPTION 2: NIfTI, Analyze or PAR/REC
... ... @@ -476,6 +484,18 @@ class Controller():
476 484 self.LoadProject()
477 485 Publisher.sendMessage("Enable state project", True)
478 486  
  487 + def OnImportGroup(self, pubsub_evt):
  488 + group = pubsub_evt.data['group']
  489 + gui = pubsub_evt.data['gui']
  490 + self.ImportGroup(group, gui)
  491 +
  492 + def ImportGroup(self, group, gui=True):
  493 + matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0, 0], gui=gui)
  494 + self.CreateDicomProject(dicom, matrix, matrix_filename)
  495 +
  496 + self.LoadProject()
  497 + Publisher.sendMessage("Enable state project", True)
  498 +
479 499 #-------------------------------------------------------------------------------------
480 500  
481 501 def LoadProject(self):
... ... @@ -785,7 +805,7 @@ class Controller():
785 805 n_slices = len(filelist)
786 806 resolution_percentage = utils.calculate_resizing_tofitmemory(int(sx), int(sy), n_slices, bits/8)
787 807  
788   - if resolution_percentage < 1.0:
  808 + if resolution_percentage < 1.0 and gui:
789 809 re_dialog = dialog.ResizeImageDialog()
790 810 re_dialog.SetValue(int(resolution_percentage*100))
791 811 re_dialog_value = re_dialog.ShowModal()
... ...
invesalius/data/slice_.py
... ... @@ -359,19 +359,22 @@ class Slice(object):
359 359  
360 360 # TODO: merge this code with apply_slice_buffer_to_mask
361 361 b_mask = self.buffer_slices["AXIAL"].mask
362   - n = self.buffer_slices["AXIAL"].index + 1
363   - self.current_mask.matrix[n, 1:, 1:] = b_mask
364   - self.current_mask.matrix[n, 0, 0] = 1
  362 + if b_mask is not None:
  363 + n = self.buffer_slices["AXIAL"].index + 1
  364 + self.current_mask.matrix[n, 1:, 1:] = b_mask
  365 + self.current_mask.matrix[n, 0, 0] = 1
365 366  
366 367 b_mask = self.buffer_slices["CORONAL"].mask
367   - n = self.buffer_slices["CORONAL"].index + 1
368   - self.current_mask.matrix[1:, n, 1:] = b_mask
369   - self.current_mask.matrix[0, n, 0] = 1
  368 + if b_mask is not None:
  369 + n = self.buffer_slices["CORONAL"].index + 1
  370 + self.current_mask.matrix[1:, n, 1:] = b_mask
  371 + self.current_mask.matrix[0, n, 0] = 1
370 372  
371 373 b_mask = self.buffer_slices["SAGITAL"].mask
372   - n = self.buffer_slices["SAGITAL"].index + 1
373   - self.current_mask.matrix[1:, 1:, n] = b_mask
374   - self.current_mask.matrix[0, 0, n] = 1
  374 + if b_mask is not None:
  375 + n = self.buffer_slices["SAGITAL"].index + 1
  376 + self.current_mask.matrix[1:, 1:, n] = b_mask
  377 + self.current_mask.matrix[0, 0, n] = 1
375 378  
376 379 if to_reload:
377 380 Publisher.sendMessage('Reload actual slice')
... ... @@ -888,7 +891,8 @@ class Slice(object):
888 891 self.current_mask.matrix[n+1, 1:, 1:] = m
889 892 else:
890 893 slice_ = self.buffer_slices[orientation].image
891   - self.buffer_slices[orientation].mask = (255 * ((slice_ >= thresh_min) & (slice_ <= thresh_max))).astype('uint8')
  894 + if slice_ is not None:
  895 + self.buffer_slices[orientation].mask = (255 * ((slice_ >= thresh_min) & (slice_ <= thresh_max))).astype('uint8')
892 896  
893 897 # Update viewer
894 898 #Publisher.sendMessage('Update slice viewer')
... ...
invesalius/data/surface.py
... ... @@ -191,14 +191,15 @@ class SurfaceManager():
191 191 if selected_items:
192 192 for index in selected_items:
193 193 proj.RemoveSurface(index)
194   - actor = old_dict[index]
195   - for i in old_dict:
196   - if i < index:
197   - new_dict[i] = old_dict[i]
198   - if i > index:
199   - new_dict[i-1] = old_dict[i]
200   - old_dict = new_dict
201   - Publisher.sendMessage('Remove surface actor from viewer', actor)
  194 + if index in old_dict:
  195 + actor = old_dict[index]
  196 + for i in old_dict:
  197 + if i < index:
  198 + new_dict[i] = old_dict[i]
  199 + if i > index:
  200 + new_dict[i-1] = old_dict[i]
  201 + old_dict = new_dict
  202 + Publisher.sendMessage('Remove surface actor from viewer', actor)
202 203 self.actors_dict = new_dict
203 204  
204 205 if self.last_surface_index in selected_items:
... ... @@ -674,7 +675,6 @@ class SurfaceManager():
674 675 # polydata.SetSource(None)
675 676 del decimation
676 677  
677   - to_measure = polydata
678 678 #to_measure.Register(None)
679 679 # to_measure.SetSource(None)
680 680  
... ... @@ -713,115 +713,133 @@ class SurfaceManager():
713 713 # polydata.DebugOn()
714 714 del filled_polydata
715 715  
716   - normals = vtk.vtkPolyDataNormals()
717   - # normals.ReleaseDataFlagOn()
718   - normals_ref = weakref.ref(normals)
719   - normals_ref().AddObserver("ProgressEvent", lambda obj,evt:
720   - UpdateProgress(normals_ref(), _("Creating 3D surface...")))
721   - normals.SetInputData(polydata)
722   - normals.SetFeatureAngle(80)
723   - normals.AutoOrientNormalsOn()
724   - # normals.GetOutput().ReleaseDataFlagOn()
725   - normals.Update()
726   - del polydata
727   - polydata = normals.GetOutput()
728   - #polydata.Register(None)
729   - # polydata.SetSource(None)
730   - del normals
731   -
732   - # Improve performance
733   - stripper = vtk.vtkStripper()
734   - # stripper.ReleaseDataFlagOn()
735   - stripper_ref = weakref.ref(stripper)
736   - stripper_ref().AddObserver("ProgressEvent", lambda obj,evt:
737   - UpdateProgress(stripper_ref(), _("Creating 3D surface...")))
738   - stripper.SetInputData(polydata)
739   - stripper.PassThroughCellIdsOn()
740   - stripper.PassThroughPointIdsOn()
741   - # stripper.GetOutput().ReleaseDataFlagOn()
742   - stripper.Update()
743   - del polydata
744   - polydata = stripper.GetOutput()
745   - #polydata.Register(None)
746   - # polydata.SetSource(None)
747   - del stripper
  716 + to_measure = polydata
748 717  
749   - # Map polygonal data (vtkPolyData) to graphics primitives.
750   - mapper = vtk.vtkPolyDataMapper()
751   - mapper.SetInputData(polydata)
752   - mapper.ScalarVisibilityOff()
753   - # mapper.ReleaseDataFlagOn()
754   - mapper.ImmediateModeRenderingOn() # improve performance
  718 + # If InVesalius is running without GUI
  719 + if wx.GetApp() is None:
  720 + proj = prj.Project()
  721 + #Create Surface instance
  722 + if overwrite:
  723 + surface = Surface(index = self.last_surface_index)
  724 + proj.ChangeSurface(surface)
  725 + else:
  726 + surface = Surface(name=surface_name)
  727 + index = proj.AddSurface(surface)
  728 + surface.index = index
  729 + self.last_surface_index = index
  730 + surface.colour = colour
  731 + surface.polydata = polydata
755 732  
756   - # Represent an object (geometry & properties) in the rendered scene
757   - actor = vtk.vtkActor()
758   - actor.SetMapper(mapper)
759   - del mapper
760   - #Create Surface instance
761   - if overwrite:
762   - surface = Surface(index = self.last_surface_index)
  733 + # With GUI
763 734 else:
764   - surface = Surface(name=surface_name)
765   - surface.colour = colour
766   - surface.polydata = polydata
767   - del polydata
  735 + normals = vtk.vtkPolyDataNormals()
  736 + # normals.ReleaseDataFlagOn()
  737 + normals_ref = weakref.ref(normals)
  738 + normals_ref().AddObserver("ProgressEvent", lambda obj,evt:
  739 + UpdateProgress(normals_ref(), _("Creating 3D surface...")))
  740 + normals.SetInputData(polydata)
  741 + normals.SetFeatureAngle(80)
  742 + normals.AutoOrientNormalsOn()
  743 + # normals.GetOutput().ReleaseDataFlagOn()
  744 + normals.Update()
  745 + del polydata
  746 + polydata = normals.GetOutput()
  747 + #polydata.Register(None)
  748 + # polydata.SetSource(None)
  749 + del normals
768 750  
769   - # Set actor colour and transparency
770   - actor.GetProperty().SetColor(colour)
771   - actor.GetProperty().SetOpacity(1-surface.transparency)
  751 + # Improve performance
  752 + stripper = vtk.vtkStripper()
  753 + # stripper.ReleaseDataFlagOn()
  754 + stripper_ref = weakref.ref(stripper)
  755 + stripper_ref().AddObserver("ProgressEvent", lambda obj,evt:
  756 + UpdateProgress(stripper_ref(), _("Creating 3D surface...")))
  757 + stripper.SetInputData(polydata)
  758 + stripper.PassThroughCellIdsOn()
  759 + stripper.PassThroughPointIdsOn()
  760 + # stripper.GetOutput().ReleaseDataFlagOn()
  761 + stripper.Update()
  762 + del polydata
  763 + polydata = stripper.GetOutput()
  764 + #polydata.Register(None)
  765 + # polydata.SetSource(None)
  766 + del stripper
772 767  
773   - prop = actor.GetProperty()
  768 + # Map polygonal data (vtkPolyData) to graphics primitives.
  769 + mapper = vtk.vtkPolyDataMapper()
  770 + mapper.SetInputData(polydata)
  771 + mapper.ScalarVisibilityOff()
  772 + # mapper.ReleaseDataFlagOn()
  773 + mapper.ImmediateModeRenderingOn() # improve performance
774 774  
775   - interpolation = int(ses.Session().surface_interpolation)
  775 + # Represent an object (geometry & properties) in the rendered scene
  776 + actor = vtk.vtkActor()
  777 + actor.SetMapper(mapper)
  778 + del mapper
  779 + #Create Surface instance
  780 + if overwrite:
  781 + surface = Surface(index = self.last_surface_index)
  782 + else:
  783 + surface = Surface(name=surface_name)
  784 + surface.colour = colour
  785 + surface.polydata = polydata
  786 + del polydata
776 787  
777   - prop.SetInterpolation(interpolation)
  788 + # Set actor colour and transparency
  789 + actor.GetProperty().SetColor(colour)
  790 + actor.GetProperty().SetOpacity(1-surface.transparency)
778 791  
779   - proj = prj.Project()
780   - if overwrite:
781   - proj.ChangeSurface(surface)
782   - else:
783   - index = proj.AddSurface(surface)
784   - surface.index = index
785   - self.last_surface_index = index
  792 + prop = actor.GetProperty()
786 793  
787   - session = ses.Session()
788   - session.ChangeProject()
  794 + interpolation = int(ses.Session().surface_interpolation)
789 795  
790   - # The following lines have to be here, otherwise all volumes disappear
791   - measured_polydata = vtk.vtkMassProperties()
792   - # measured_polydata.ReleaseDataFlagOn()
793   - measured_polydata.SetInputData(to_measure)
794   - volume = float(measured_polydata.GetVolume())
795   - area = float(measured_polydata.GetSurfaceArea())
796   - surface.volume = volume
797   - surface.area = area
798   - self.last_surface_index = surface.index
799   - del measured_polydata
800   - del to_measure
  796 + prop.SetInterpolation(interpolation)
801 797  
802   - Publisher.sendMessage('Load surface actor into viewer', actor)
  798 + proj = prj.Project()
  799 + if overwrite:
  800 + proj.ChangeSurface(surface)
  801 + else:
  802 + index = proj.AddSurface(surface)
  803 + surface.index = index
  804 + self.last_surface_index = index
803 805  
804   - # Send actor by pubsub to viewer's render
805   - if overwrite and self.actors_dict.keys():
806   - old_actor = self.actors_dict[self.last_surface_index]
807   - Publisher.sendMessage('Remove surface actor from viewer', old_actor)
  806 + session = ses.Session()
  807 + session.ChangeProject()
808 808  
809   - # Save actor for future management tasks
810   - self.actors_dict[surface.index] = actor
  809 + measured_polydata = vtk.vtkMassProperties()
  810 + # measured_polydata.ReleaseDataFlagOn()
  811 + measured_polydata.SetInputData(to_measure)
  812 + volume = float(measured_polydata.GetVolume())
  813 + area = float(measured_polydata.GetSurfaceArea())
  814 + surface.volume = volume
  815 + surface.area = area
  816 + self.last_surface_index = surface.index
  817 + del measured_polydata
  818 + del to_measure
811 819  
812   - Publisher.sendMessage('Update surface info in GUI',
813   - (surface.index, surface.name,
814   - surface.colour, surface.volume,
815   - surface.area,
816   - surface.transparency))
817   -
818   - #When you finalize the progress. The bar is cleaned.
819   - UpdateProgress = vu.ShowProgress(1)
820   - UpdateProgress(0, _("Ready"))
821   - Publisher.sendMessage('Update status text in GUI', _("Ready"))
822   -
823   - Publisher.sendMessage('End busy cursor')
824   - del actor
  820 + Publisher.sendMessage('Load surface actor into viewer', actor)
  821 +
  822 + # Send actor by pubsub to viewer's render
  823 + if overwrite and self.actors_dict.keys():
  824 + old_actor = self.actors_dict[self.last_surface_index]
  825 + Publisher.sendMessage('Remove surface actor from viewer', old_actor)
  826 +
  827 + # Save actor for future management tasks
  828 + self.actors_dict[surface.index] = actor
  829 +
  830 + Publisher.sendMessage('Update surface info in GUI',
  831 + (surface.index, surface.name,
  832 + surface.colour, surface.volume,
  833 + surface.area,
  834 + surface.transparency))
  835 +
  836 + #When you finalize the progress. The bar is cleaned.
  837 + UpdateProgress = vu.ShowProgress(1)
  838 + UpdateProgress(0, _("Ready"))
  839 + Publisher.sendMessage('Update status text in GUI', _("Ready"))
  840 +
  841 + Publisher.sendMessage('End busy cursor')
  842 + del actor
825 843  
826 844 def UpdateSurfaceInterpolation(self, pub_evt):
827 845 interpolation = int(ses.Session().surface_interpolation)
... ...
invesalius/data/vtk_utils.py
... ... @@ -44,7 +44,10 @@ def ShowProgress(number_of_filters = 1,
44 44 progress = [0]
45 45 last_obj_progress = [0]
46 46 if (dialog_type == "ProgressDialog"):
47   - dlg = ProgressDialog(100)
  47 + try:
  48 + dlg = ProgressDialog(100)
  49 + except wx._core.PyNoAppError:
  50 + return lambda obj, label: 0
48 51  
49 52  
50 53 # when the pipeline is larger than 1, we have to consider this object
... ...
invesalius/gui/task_navigator.py
... ... @@ -247,7 +247,7 @@ class NeuronavigationPanel(wx.Panel):
247 247 n = btns_img[k].keys()[0]
248 248 lab = btns_img[k].values()[0]
249 249 self.btns_coord[n] = wx.ToggleButton(self, k, label=lab, size=wx.Size(45, 23))
250   - self.btns_coord[n].SetToolTip(tips_img[n])
  250 + self.btns_coord[n].SetToolTip(wx.ToolTip(tips_img[n]))
251 251 self.btns_coord[n].Bind(wx.EVT_TOGGLEBUTTON, self.OnImageFiducials)
252 252  
253 253 # Push buttons for tracker fiducials
... ... @@ -258,7 +258,7 @@ class NeuronavigationPanel(wx.Panel):
258 258 n = btns_trk[k].keys()[0]
259 259 lab = btns_trk[k].values()[0]
260 260 self.btns_coord[n] = wx.Button(self, k, label=lab, size=wx.Size(45, 23))
261   - self.btns_coord[n].SetToolTip(tips_trk[n-3])
  261 + self.btns_coord[n].SetToolTip(wx.ToolTip(tips_trk[n-3]))
262 262 # Excepetion for event of button that set image coordinates
263 263 if n == 6:
264 264 self.btns_coord[n].Bind(wx.EVT_BUTTON, self.OnSetImageCoordinates)
... ...
invesalius/utils.py
... ... @@ -76,6 +76,7 @@ def debug(error_str):
76 76 from invesalius.session import Session
77 77 session = Session()
78 78 #if session.debug:
  79 + print(error_str)
79 80  
80 81 def next_copy_name(original_name, names_list):
81 82 """
... ...