Commit 7c2fdb4bbe8bb56d5fbc8e15f04f26f0168f8712

Authored by tfmoraes
1 parent 4191a837

Merge branch 'surface_creation'

invesalius/data/slice_.py
... ... @@ -596,10 +596,11 @@ class Slice(object):
596 596 #---------------------------------------------------------------------------
597 597  
598 598 def CreateSurfaceFromIndex(self, pubsub_evt):
599   - mask_index, overwrite_surface, algorithm, options = pubsub_evt.data
  599 + print pubsub_evt.data
  600 + surface_parameters = pubsub_evt.data
600 601  
601 602 proj = Project()
602   - mask = proj.mask_dict[mask_index]
  603 + mask = proj.mask_dict[surface_parameters['options']['index']]
603 604  
604 605 # This is very important. Do not use masks' imagedata. It would mess up
605 606 # surface quality event when using contour
... ... @@ -611,12 +612,8 @@ class Slice(object):
611 612  
612 613 mask.matrix.flush()
613 614  
614   - Publisher.sendMessage('Create surface', (algorithm, options,
615   - self.matrix,
616   - self.matrix_filename,
617   - mask, self.spacing,
618   - overwrite_surface))
619   -
  615 + Publisher.sendMessage('Create surface', (self, mask,
  616 + surface_parameters))
620 617 def GetOutput(self):
621 618 return self.blend_filter.GetOutput()
622 619  
... ...
invesalius/data/surface.py
... ... @@ -369,31 +369,29 @@ class SurfaceManager():
369 369 """
370 370 Create surface actor, save into project and send it to viewer.
371 371 """
372   - algorithm, options, matrix, filename_img, mask, spacing, overwrite = pubsub_evt.data
373   - min_value, max_value = mask.threshold_range
374   - fill_holes = False
375   -
376   - mask.matrix.flush()
377   -
378   - #if len(surface_data) == 5:
379   - #imagedata, colour, [min_value, max_value], \
380   - #edited_points, overwrite = pubsub_evt.data
381   - #quality=_('Optimal *')
382   - #surface_name = ""
383   - #fill_holes = True
384   - #keep_largest = False
385   - #else:
386   - #imagedata, colour, [min_value, max_value],\
387   - #edited_points, overwrite, surface_name,\
388   - #quality, fill_holes, keep_largest =\
389   - #pubsub_evt.data
  372 + slice_, mask, surface_parameters = pubsub_evt.data
  373 + matrix = slice_.matrix
  374 + filename_img = slice_.matrix_filename
  375 + spacing = slice_.spacing
  376 +
  377 + algorithm = surface_parameters['method']['algorithm']
  378 + options = surface_parameters['method']['options']
  379 +
  380 + surface_name = surface_parameters['options']['name']
  381 + quality = surface_parameters['options']['quality']
  382 + fill_holes = surface_parameters['options']['fill']
  383 + keep_largest = surface_parameters['options']['keep_largest']
390 384  
391 385 mode = 'CONTOUR' # 'GRAYSCALE'
392   - quality=_('Optimal *')
393   - keep_largest = False
394   - surface_name = ""
  386 + min_value, max_value = mask.threshold_range
395 387 colour = mask.colour
396 388  
  389 + try:
  390 + overwrite = surface_parameters['options']['overwrite']
  391 + except KeyError:
  392 + overwrite = False
  393 + mask.matrix.flush()
  394 +
397 395 if quality in const.SURFACE_QUALITY.keys():
398 396 imagedata_resolution = const.SURFACE_QUALITY[quality][0]
399 397 smooth_iterations = const.SURFACE_QUALITY[quality][1]
... ... @@ -448,8 +446,9 @@ class SurfaceManager():
448 446 smooth_relaxation_factor,
449 447 smooth_iterations, language,
450 448 flip_image, q_in, q_out,
451   - mask.was_edited and algorithm != u'InVesalius 3.b2',
452   - algorithm)
  449 + algorithm != 'Default',
  450 + algorithm,
  451 + imagedata_resolution)
453 452 p.append(sp)
454 453 sp.start()
455 454  
... ... @@ -501,7 +500,7 @@ class SurfaceManager():
501 500 polydata.SetSource(None)
502 501 del polydata_append
503 502  
504   - if algorithm == u'Context aware smoothing':
  503 + if algorithm == 'ca_smoothing':
505 504 normals = vtk.vtkPolyDataNormals()
506 505 normals_ref = weakref.ref(normals)
507 506 normals_ref().AddObserver("ProgressEvent", lambda obj,evt:
... ... @@ -542,21 +541,23 @@ class SurfaceManager():
542 541 polydata.DebugOn()
543 542  
544 543 else:
545   - smoother = vtk.vtkWindowedSincPolyDataFilter()
  544 + #smoother = vtk.vtkWindowedSincPolyDataFilter()
  545 + smoother = vtk.vtkSmoothPolyDataFilter()
546 546 smoother_ref = weakref.ref(smoother)
547 547 smoother_ref().AddObserver("ProgressEvent", lambda obj,evt:
548 548 UpdateProgress(smoother_ref(), _("Generating 3D surface...")))
549 549 smoother.SetInput(polydata)
550 550 smoother.SetNumberOfIterations(smooth_iterations)
551   - smoother.SetFeatureAngle(120)
552   - smoother.SetEdgeAngle(90.0)
  551 + smoother.SetRelaxationFactor(smooth_relaxation_factor)
  552 + smoother.SetFeatureAngle(80)
  553 + #smoother.SetEdgeAngle(90.0)
  554 + #smoother.SetPassBand(0.1)
553 555 smoother.BoundarySmoothingOn()
554   - smoother.SetPassBand(0.1)
  556 + smoother.FeatureEdgeSmoothingOn()
  557 + #smoother.NormalizeCoordinatesOn()
  558 + #smoother.NonManifoldSmoothingOn()
555 559 smoother.ReleaseDataFlagOn()
556 560 smoother.GetOutput().ReleaseDataFlagOn()
557   - #smoother.FeatureEdgeSmoothingOn()
558   - #smoother.NonManifoldSmoothingOn()
559   - #smoother.NormalizeCoordinatesOn()
560 561 smoother.Update()
561 562 del polydata
562 563 polydata = smoother.GetOutput()
... ...
invesalius/data/surface_process.py
... ... @@ -7,6 +7,8 @@ import vtk
7 7  
8 8 import i18n
9 9 import converters
  10 +import imagedata_utils as iu
  11 +
10 12 from scipy import ndimage
11 13  
12 14 class SurfaceProcess(multiprocessing.Process):
... ... @@ -15,7 +17,7 @@ class SurfaceProcess(multiprocessing.Process):
15 17 mask_shape, mask_dtype, spacing, mode, min_value, max_value,
16 18 decimate_reduction, smooth_relaxation_factor,
17 19 smooth_iterations, language, flip_image, q_in, q_out,
18   - from_binary, algorithm):
  20 + from_binary, algorithm, imagedata_resolution):
19 21  
20 22 multiprocessing.Process.__init__(self)
21 23 self.pipe = pipe
... ... @@ -35,6 +37,7 @@ class SurfaceProcess(multiprocessing.Process):
35 37 self.shape = shape
36 38 self.from_binary = from_binary
37 39 self.algorithm = algorithm
  40 + self.imagedata_resolution = imagedata_resolution
38 41  
39 42 self.mask_filename = mask_filename
40 43 self.mask_shape = mask_shape
... ... @@ -96,6 +99,9 @@ class SurfaceProcess(multiprocessing.Process):
96 99 "AXIAL")
97 100 del a_image
98 101  
  102 + if self.imagedata_resolution:
  103 + image = iu.ResampleImage3D(image, self.imagedata_resolution)
  104 +
99 105 flip = vtk.vtkImageFlip()
100 106 flip.SetInput(image)
101 107 flip.SetFilteredAxis(1)
... ...
invesalius/gui/data_notebook.py
... ... @@ -29,6 +29,7 @@ import wx.lib.platebtn as pbtn
29 29 from wx.lib.pubsub import pub as Publisher
30 30  
31 31 import constants as const
  32 +import data.slice_ as slice_
32 33 import gui.dialogs as dlg
33 34 import gui.widgets.listctrl as listmix
34 35 import utils as ul
... ... @@ -615,9 +616,10 @@ class SurfaceButtonControlPanel(wx.Panel):
615 616 self.OnDuplicate()
616 617  
617 618 def OnNew(self):
618   - import project as prj
619   -
620   - dialog = dlg.NewSurfaceDialog()
  619 + sl = slice_.Slice()
  620 + dialog = dlg.SurfaceCreationDialog(self, -1,
  621 + _('InVesalius 3 - New surface'),
  622 + mask_edited=sl.current_mask.was_edited)
621 623 try:
622 624 if dialog.ShowModal() == wx.ID_OK:
623 625 ok = 1
... ... @@ -627,25 +629,10 @@ class SurfaceButtonControlPanel(wx.Panel):
627 629 ok = 1
628 630  
629 631 if ok:
630   - (mask_index, surface_name, surface_quality, fill_holes,\
631   - keep_largest) = dialog.GetValue()
632   -
633   - # Retrieve information from mask
634   - proj = prj.Project()
635   - mask = proj.mask_dict[mask_index]
636   -
637   - # Send all information so surface can be created
638   - surface_data = [proj.imagedata,
639   - mask.colour,
640   - mask.threshold_range,
641   - mask.edited_points,
642   - False, # overwrite
643   - surface_name,
644   - surface_quality,
645   - fill_holes,
646   - keep_largest]
647   -
648   - Publisher.sendMessage('Create surface', surface_data)
  632 + surface_options = dialog.GetValue()
  633 +
  634 + Publisher.sendMessage('Create surface from index', surface_options)
  635 + dialog.Destroy()
649 636  
650 637 def OnRemove(self):
651 638 self.parent.listctrl.RemoveSurfaces()
... ...
invesalius/gui/default_tasks.py
... ... @@ -260,7 +260,7 @@ class UpperTaskPanel(wx.Panel):
260 260 Publisher.subscribe(self.OnFoldExport, 'Fold export task')
261 261  
262 262 def OnOverwrite(self, pubsub_evt):
263   - self.overwrite = pubsub_evt.data[1]
  263 + self.overwrite = pubsub_evt.data['options']['overwrite']
264 264  
265 265 def OnFoldSurface(self, pubsub_evt):
266 266 if not self.overwrite:
... ...
invesalius/gui/dialogs.py
... ... @@ -34,6 +34,14 @@ import project as proj
34 34 import session as ses
35 35 import utils
36 36  
  37 +class MaskEvent(wx.PyCommandEvent):
  38 + def __init__(self , evtType, id, mask_index):
  39 + wx.PyCommandEvent.__init__(self, evtType, id,)
  40 + self.mask_index = mask_index
  41 +
  42 +myEVT_MASK_SET = wx.NewEventType()
  43 +EVT_MASK_SET = wx.PyEventBinder(myEVT_MASK_SET, 1)
  44 +
37 45 class NumberDialog(wx.Dialog):
38 46 def __init__(self, message, value=0):
39 47 pre = wx.PreDialog()
... ... @@ -964,7 +972,6 @@ class SurfaceDialog(wx.Dialog):
964 972 def __init__(self):
965 973 wx.Dialog.__init__(self, None, -1, u'Surface generation options')
966 974 self._build_widgets()
967   - self._bind_wx()
968 975 self.CenterOnScreen()
969 976  
970 977 def _build_widgets(self):
... ... @@ -975,12 +982,266 @@ class SurfaceDialog(wx.Dialog):
975 982 btn_sizer.AddButton(btn_cancel)
976 983 btn_sizer.Realize()
977 984  
978   - self.alg_types = {0: u'Context aware smoothing', 1: u'Binary'}#,2: u'InVesalius 3.b2'}
979   - self.cb_types = wx.ComboBox(self, -1, self.alg_types[0],
980   - choices=[self.alg_types[i] for i in sorted(self.alg_types)],
981   - style=wx.CB_READONLY)
  985 + self.ca = SurfaceMethodPanel(self, -1, True)
  986 +
  987 + self.main_sizer = wx.BoxSizer(wx.VERTICAL)
  988 + self.main_sizer.Add(self.ca, 0, wx.EXPAND|wx.ALL, 5)
  989 + self.main_sizer.Add(btn_sizer, 0, wx.EXPAND | wx.ALL, 5)
  990 +
  991 + self.SetSizer(self.main_sizer)
  992 + self.Fit()
  993 +
  994 + def GetOptions(self):
  995 + return self.ca.GetOptions()
  996 +
  997 + def GetAlgorithmSelected(self):
  998 + return self.ca.GetAlgorithmSelected()
  999 +
  1000 +
  1001 +####################### New surface creation dialog ###########################
  1002 +class SurfaceCreationDialog(wx.Dialog):
  1003 + def __init__(self, parent=None, ID=-1, title=_(u"Surface creation"),
  1004 + size=wx.DefaultSize, pos=wx.DefaultPosition,
  1005 + style=wx.DEFAULT_DIALOG_STYLE, useMetal=False,
  1006 + mask_edited=False):
  1007 +
  1008 + # Instead of calling wx.Dialog.__init__ we precreate the dialog
  1009 + # so we can set an extra style that must be set before
  1010 + # creation, and then we create the GUI object using the Create
  1011 + # method.
  1012 + pre = wx.PreDialog()
  1013 + pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
  1014 + pre.Create(parent, ID, title, pos, (50,30), style)
  1015 +
  1016 + # This extra style can be set after the UI object has been created.
  1017 + if 'wxMac' in wx.PlatformInfo and useMetal:
  1018 + self.SetExtraStyle(wx.DIALOG_EX_METAL)
  1019 +
  1020 + # This next step is the most important, it turns this Python
  1021 + # object into the real wrapper of the dialog (instead of pre)
  1022 + # as far as the wxPython extension is concerned.
  1023 + self.PostCreate(pre)
  1024 +
  1025 + self.CenterOnScreen()
  1026 +
  1027 + self.nsd = SurfaceCreationOptionsPanel(self, -1)
  1028 + self.nsd.Bind(EVT_MASK_SET, self.OnSetMask)
  1029 + surface_options_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1,
  1030 + _('Surface creation options')), wx.VERTICAL)
  1031 + surface_options_sizer.Add(self.nsd, 0, wx.EXPAND|wx.ALL, 5)
  1032 +
  1033 + self.ca = SurfaceMethodPanel(self, -1, mask_edited)
  1034 + surface_method_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1,
  1035 + _('Surface creation method')), wx.VERTICAL)
  1036 + surface_method_sizer.Add(self.ca, 0, wx.EXPAND|wx.ALL, 5)
  1037 +
  1038 + btn_ok = wx.Button(self, wx.ID_OK)
  1039 + btn_ok.SetDefault()
  1040 + btn_cancel = wx.Button(self, wx.ID_CANCEL)
  1041 +
  1042 + btnsizer = wx.StdDialogButtonSizer()
  1043 + btnsizer.AddButton(btn_ok)
  1044 + btnsizer.AddButton(btn_cancel)
  1045 + btnsizer.Realize()
  1046 +
  1047 + sizer_panels = wx.BoxSizer(wx.HORIZONTAL)
  1048 + sizer_panels.Add(surface_method_sizer, 0, wx.EXPAND|wx.ALL, 5)
  1049 + sizer_panels.Add(surface_options_sizer, 0, wx.EXPAND|wx.ALL, 5)
  1050 +
  1051 + sizer = wx.BoxSizer(wx.VERTICAL)
  1052 + sizer.Add(sizer_panels, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
  1053 + sizer.Add(btnsizer, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
  1054 +
  1055 + self.SetSizer(sizer)
  1056 + sizer.Fit(self)
  1057 +
  1058 + self.Show()
  1059 +
  1060 + def OnSetMask(self, evt):
  1061 + mask = proj.Project().mask_dict[evt.mask_index]
  1062 + self.ca.mask_edited = mask.was_edited
  1063 + self.ca.ReloadMethodsOptions()
  1064 +
  1065 +
  1066 +
  1067 + def GetValue(self):
  1068 + return {"method": self.ca.GetValue(),
  1069 + "options": self.nsd.GetValue()}
  1070 +
  1071 +
  1072 +class SurfaceCreationOptionsPanel(wx.Panel):
  1073 + def __init__(self, parent, ID=-1):
  1074 + import constants as const
  1075 + import data.surface as surface
  1076 + import project as prj
  1077 +
  1078 + wx.Panel.__init__(self, parent, ID)
  1079 +
  1080 + # LINE 1: Surface name
  1081 + label_surface = wx.StaticText(self, -1, _("New surface name:"))
  1082 +
  1083 + default_name = const.SURFACE_NAME_PATTERN %(surface.Surface.general_index+2)
  1084 + text = wx.TextCtrl(self, -1, "", size=(80,-1))
  1085 + text.SetHelpText(_("Name the surface to be created"))
  1086 + text.SetValue(default_name)
  1087 + self.text = text
  1088 +
  1089 + # LINE 2: Mask of reference
  1090 +
  1091 + # Informative label
  1092 + label_mask = wx.StaticText(self, -1, _("Mask of reference:"))
  1093 +
  1094 + #Retrieve existing masks
  1095 + project = prj.Project()
  1096 + index_list = project.mask_dict.keys()
  1097 + index_list.sort()
  1098 + self.mask_list = [project.mask_dict[index].name for index in index_list]
  1099 +
  1100 + # Mask selection combo
  1101 + combo_mask = wx.ComboBox(self, -1, "", choices= self.mask_list,
  1102 + style=wx.CB_DROPDOWN|wx.CB_READONLY)
  1103 + combo_mask.SetSelection(len(self.mask_list)-1)
  1104 + combo_mask.Bind(wx.EVT_COMBOBOX, self.OnSetMask)
  1105 + if sys.platform != 'win32':
  1106 + combo_mask.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
  1107 + self.combo_mask = combo_mask
  1108 +
  1109 + # LINE 3: Surface quality
  1110 + label_quality = wx.StaticText(self, -1, _("Surface quality:"))
  1111 +
  1112 + choices = const.SURFACE_QUALITY_LIST
  1113 + style = wx.CB_DROPDOWN|wx.CB_READONLY
  1114 + combo_quality = wx.ComboBox(self, -1, "",
  1115 + choices= choices,
  1116 + style=style)
  1117 + combo_quality.SetSelection(3)
  1118 + if sys.platform != 'win32':
  1119 + combo_quality.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
  1120 + self.combo_quality = combo_quality
  1121 +
  1122 + # OVERVIEW
  1123 + # Sizer that joins content above
  1124 + flag_link = wx.EXPAND|wx.GROW|wx.ALL
  1125 + flag_button = wx.ALL | wx.EXPAND| wx.GROW
  1126 +
  1127 + fixed_sizer = wx.FlexGridSizer(rows=2, cols=2, hgap=10, vgap=5)
  1128 + fixed_sizer.AddGrowableCol(0, 1)
  1129 + fixed_sizer.AddMany([ (label_surface, 1, flag_link, 0),
  1130 + (text, 1, flag_button, 0),
  1131 + (label_mask, 1, flag_link, 0),
  1132 + (combo_mask, 0, flag_button, 0),
  1133 + (label_quality, 1, flag_link, 0),
  1134 + (combo_quality, 0, flag_button, 0)])
  1135 +
  1136 +
  1137 + # LINES 4 and 5: Checkboxes
  1138 + check_box_holes = wx.CheckBox(self, -1, _("Fill holes"))
  1139 + check_box_holes.SetValue(True)
  1140 + self.check_box_holes = check_box_holes
  1141 + check_box_largest = wx.CheckBox(self, -1, _("Keep largest region"))
  1142 + self.check_box_largest = check_box_largest
  1143 +
  1144 + # OVERVIEW
  1145 + # Merge all sizers and checkboxes
  1146 + sizer = wx.BoxSizer(wx.VERTICAL)
  1147 + sizer.Add(fixed_sizer, 0, wx.TOP|wx.RIGHT|wx.LEFT|wx.GROW|wx.EXPAND, 5)
  1148 + sizer.Add(check_box_holes, 0, wx.RIGHT|wx.LEFT, 5)
  1149 + sizer.Add(check_box_largest, 0, wx.RIGHT|wx.LEFT, 5)
  1150 +
  1151 + self.SetSizer(sizer)
  1152 + sizer.Fit(self)
  1153 +
  1154 + def OnSetMask(self, evt):
  1155 + new_evt = MaskEvent(myEVT_MASK_SET, -1, self.combo_mask.GetSelection())
  1156 + self.GetEventHandler().ProcessEvent(new_evt)
  1157 +
  1158 + def GetValue(self):
  1159 + mask_index = self.combo_mask.GetSelection()
  1160 + surface_name = self.text.GetValue()
  1161 + quality = const.SURFACE_QUALITY_LIST[self.combo_quality.GetSelection()]
  1162 + fill_holes = self.check_box_holes.GetValue()
  1163 + keep_largest = self.check_box_largest.GetValue()
  1164 + return {"index": mask_index,
  1165 + "name": surface_name,
  1166 + "quality": quality,
  1167 + "fill": fill_holes,
  1168 + "keep_largest": keep_largest,
  1169 + "overwrite": False}
  1170 +
  1171 +
  1172 +class CAOptions(wx.Panel):
  1173 + '''
  1174 + Options related to Context aware algorithm:
  1175 + Angle: The min angle to a vertex to be considered a staircase vertex;
  1176 + Max distance: The max distance a normal vertex must be to calculate its
  1177 + weighting;
  1178 + Min Weighting: The min weight a vertex must have;
  1179 + Steps: The number of iterations the smoothing algorithm have to do.
  1180 + '''
  1181 + def __init__(self, parent):
  1182 + wx.Panel.__init__(self, parent, -1)
  1183 + self._build_widgets()
  1184 +
  1185 + def _build_widgets(self):
  1186 + self.angle = floatspin.FloatSpin(self, -1, value=0.7, min_val=0.0,
  1187 + max_val=1.0, increment=0.1,
  1188 + digits=1)
  1189 +
  1190 + self.max_distance = floatspin.FloatSpin(self, -1, value=3.0, min_val=0.0,
  1191 + max_val=100.0, increment=0.1,
  1192 + digits=2)
  1193 +
  1194 + self.min_weight = floatspin.FloatSpin(self, -1, value=0.2, min_val=0.0,
  1195 + max_val=1.0, increment=0.1,
  1196 + digits=1)
  1197 +
  1198 + self.steps = wx.SpinCtrl(self, -1, value='10', min=1, max=100)
  1199 +
  1200 + layout_sizer = wx.FlexGridSizer(rows=4, cols=2, hgap=5, vgap=5)
  1201 + layout_sizer.Add(wx.StaticText(self, -1, _(u'Angle:')), 0, wx.EXPAND)
  1202 + layout_sizer.Add(self.angle, 0, wx.EXPAND)
  1203 + layout_sizer.Add(wx.StaticText(self, -1, _(u'Max. distance:')), 0, wx.EXPAND)
  1204 + layout_sizer.Add(self.max_distance, 0, wx.EXPAND)
  1205 + layout_sizer.Add(wx.StaticText(self, -1, _(u'Min. weight:')), 0, wx.EXPAND)
  1206 + layout_sizer.Add(self.min_weight, 0, wx.EXPAND)
  1207 + layout_sizer.Add(wx.StaticText(self, -1, _(u'N. steps:')), 0, wx.EXPAND)
  1208 + layout_sizer.Add(self.steps, 0, wx.EXPAND)
  1209 +
  1210 + self.main_sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, _('Context aware options')), wx.VERTICAL)
  1211 + self.main_sizer.Add(layout_sizer, 0, wx.EXPAND | wx.ALL, 5)
  1212 + self.SetSizer(self.main_sizer)
  1213 +
  1214 +class SurfaceMethodPanel(wx.Panel):
  1215 + '''
  1216 + This dialog is only shown when the mask whose surface will be generate was
  1217 + edited. So far, the only options available are the choice of method to
  1218 + generate the surface, Binary or `Context aware smoothing', and options from
  1219 + `Context aware smoothing'
  1220 + '''
  1221 + def __init__(self, parent, id, mask_edited=False):
  1222 + wx.Panel.__init__(self, parent, id)
  1223 +
  1224 + self.mask_edited = mask_edited
  1225 + self.alg_types = {_(u'Default'): 'Default',
  1226 + _(u'Context aware smoothing'): 'ca_smoothing',
  1227 + _(u'Binary'): 'Binary'}
  1228 + self.edited_imp = [_(u'Default'), ]
  1229 +
  1230 + self._build_widgets()
  1231 + self._bind_wx()
982 1232  
  1233 + def _build_widgets(self):
983 1234 self.ca_options = CAOptions(self)
  1235 + self.cb_types = wx.ComboBox(self, -1, _(u'Default'),
  1236 + choices=[i for i in sorted(self.alg_types)
  1237 + if not (self.mask_edited and i in self.edited_imp)],
  1238 + style=wx.CB_READONLY)
  1239 + if self.mask_edited:
  1240 + self.cb_types.SetValue(_(u'Context aware smoothing'))
  1241 + self.ca_options.Enable()
  1242 + else:
  1243 + self.ca_options.Disable()
  1244 +
984 1245  
985 1246 method_sizer = wx.BoxSizer(wx.HORIZONTAL)
986 1247 method_sizer.Add(wx.StaticText(self, -1, u'Method:'), 0,
... ... @@ -990,7 +1251,6 @@ class SurfaceDialog(wx.Dialog):
990 1251 self.main_sizer = wx.BoxSizer(wx.VERTICAL)
991 1252 self.main_sizer.Add(method_sizer, 0, wx.EXPAND | wx.ALL, 5)
992 1253 self.main_sizer.Add(self.ca_options, 0, wx.EXPAND | wx.ALL, 5)
993   - self.main_sizer.Add(btn_sizer, 0, wx.EXPAND | wx.ALL, 5)
994 1254  
995 1255 self.SetSizer(self.main_sizer)
996 1256 self.Fit()
... ... @@ -1000,7 +1260,7 @@ class SurfaceDialog(wx.Dialog):
1000 1260  
1001 1261 def _set_cb_types(self, evt):
1002 1262 print evt.GetString()
1003   - if self.alg_types[evt.GetSelection()] == self.alg_types[0]:
  1263 + if self.alg_types[evt.GetString()] == 'ca_smoothing':
1004 1264 self.ca_options.Enable()
1005 1265 else:
1006 1266 self.ca_options.Disable()
... ... @@ -1008,12 +1268,12 @@ class SurfaceDialog(wx.Dialog):
1008 1268  
1009 1269 def GetAlgorithmSelected(self):
1010 1270 try:
1011   - return self.alg_types[self.cb_types.GetSelection()]
  1271 + return self.alg_types[self.cb_types.GetValue()]
1012 1272 except KeyError:
1013 1273 return self.alg_types[0]
1014 1274  
1015 1275 def GetOptions(self):
1016   - if self.GetAlgorithmSelected() == self.alg_types[0]:
  1276 + if self.GetAlgorithmSelected() == 'ca_smoothing':
1017 1277 options = {'angle': self.ca_options.angle.GetValue(),
1018 1278 'max distance': self.ca_options.max_distance.GetValue(),
1019 1279 'min weight': self.ca_options.min_weight.GetValue(),
... ... @@ -1022,4 +1282,20 @@ class SurfaceDialog(wx.Dialog):
1022 1282 options = {}
1023 1283 return options
1024 1284  
  1285 + def GetValue(self):
  1286 + algorithm = self.GetAlgorithmSelected()
  1287 + options = self.GetOptions()
1025 1288  
  1289 + return {"algorithm": algorithm,
  1290 + "options": options}
  1291 +
  1292 + def ReloadMethodsOptions(self):
  1293 + self.cb_types.Clear()
  1294 + self.cb_types.AppendItems([i for i in sorted(self.alg_types)
  1295 + if not (self.mask_edited and i in self.edited_imp)])
  1296 + if self.mask_edited:
  1297 + self.cb_types.SetValue(_(u'Context aware smoothing'))
  1298 + self.ca_options.Enable()
  1299 + else:
  1300 + self.cb_types.SetValue(_(u'Default'))
  1301 + self.ca_options.Disable()
... ...
invesalius/gui/task_slice.py
... ... @@ -155,9 +155,19 @@ class InnerTaskPanel(wx.Panel):
155 155 options = dlgs.GetOptions()
156 156 else:
157 157 return
158   - Publisher.sendMessage('Create surface from index',
159   - (self.GetMaskSelected(),
160   - overwrite, algorithm, options))
  158 +
  159 + mask_index = sl.current_mask.index
  160 + method = {'algorithm': 'Default',
  161 + 'options': options}
  162 + srf_options = {"index": mask_index,
  163 + "name": '',
  164 + "quality": _('Optimal *'),
  165 + "fill": False,
  166 + "keep_largest": False,
  167 + "overwrite": overwrite}
  168 +
  169 + Publisher.sendMessage('Create surface from index',
  170 + {'method': method, 'options': srf_options})
161 171 Publisher.sendMessage('Fold surface task')
162 172 else:
163 173 dlg.InexistentMask()
... ...
invesalius/gui/task_surface.py
... ... @@ -23,6 +23,7 @@ import wx.lib.hyperlink as hl
23 23 from wx.lib.pubsub import pub as Publisher
24 24  
25 25 import constants as const
  26 +import data.slice_ as slice_
26 27 import gui.dialogs as dlg
27 28 import gui.widgets.foldpanelbar as fpb
28 29 import gui.widgets.colourselect as csel
... ... @@ -30,7 +31,6 @@ import gui.widgets.platebtn as pbtn
30 31 import project as prj
31 32 import utils as utl
32 33  
33   -
34 34 #INTERPOLATION_MODE_LIST = ["Cubic", "Linear", "NearestNeighbor"]
35 35 MIN_TRANSPARENCY = 0
36 36 MAX_TRANSPARENCY = 100
... ... @@ -131,7 +131,10 @@ class InnerTaskPanel(wx.Panel):
131 131  
132 132 def OnLinkNewSurface(self, evt=None):
133 133 #import gui.dialogs as dlg
134   - dialog = dlg.NewSurfaceDialog(self, -1, _('InVesalius 3 - New surface'))
  134 + sl = slice_.Slice()
  135 + dialog = dlg.SurfaceCreationDialog(self, -1,
  136 + _('InVesalius 3 - New surface'),
  137 + mask_edited=sl.current_mask.was_edited)
135 138  
136 139 try:
137 140 if dialog.ShowModal() == wx.ID_OK:
... ... @@ -142,26 +145,29 @@ class InnerTaskPanel(wx.Panel):
142 145 ok = 1
143 146  
144 147 if (ok):
145   - # Retrieve information from dialog
146   - (mask_index, surface_name, surface_quality, fill_holes,\
147   - keep_largest) = dialog.GetValue()
148   -
149   - # Retrieve information from mask
150   - proj = prj.Project()
151   - mask = proj.mask_dict[mask_index]
152   -
153   - # Send all information so surface can be created
154   - surface_data = [proj.imagedata,
155   - mask.colour,
156   - mask.threshold_range,
157   - mask.edited_points,
158   - False, # overwrite
159   - surface_name,
160   - surface_quality,
161   - fill_holes,
162   - keep_largest]
163   -
164   - Publisher.sendMessage('Create surface', surface_data)
  148 + ## Retrieve information from dialog
  149 + #(mask_index, surface_name, surface_quality, fill_holes,\
  150 + #keep_largest) = dialog.GetValue()
  151 +
  152 + ## Retrieve information from mask
  153 + #proj = prj.Project()
  154 + #mask = proj.mask_dict[mask_index]
  155 +
  156 + ## Send all information so surface can be created
  157 + #surface_data = [proj.imagedata,
  158 + #mask.colour,
  159 + #mask.threshold_range,
  160 + #mask.edited_points,
  161 + #False, # overwrite
  162 + #surface_name,
  163 + #surface_quality,
  164 + #fill_holes,
  165 + #keep_largest]
  166 +
  167 +
  168 + surface_options = dialog.GetValue()
  169 +
  170 + Publisher.sendMessage('Create surface from index', surface_options)
165 171 dialog.Destroy()
166 172 if evt:
167 173 evt.Skip()
... ...