Commit bba5864282eac415257c9cb2c0bb92cef314d195

Authored by tatiana
1 parent 0c9ee0bd

ENH: Surface connectivity (under devel)

invesalius/constants.py
... ... @@ -180,6 +180,24 @@ MASK_COLOUR = [(0.33, 1, 0.33),
180 180 #(0.792156862745098, 1.0, 0.66666666666666663), # too "light"
181 181 #(0.66666666666666663, 0.792156862745098, 1.0)]
182 182  
  183 +
  184 +SURFACE_COLOUR = [(0.33, 1, 0.33),
  185 + (1, 1, 0.33),
  186 + (0.33, 0.91, 1),
  187 + (1, 0.33, 1),
  188 + (1, 0.68, 0.33),
  189 + (1, 0.33, 0.33),
  190 + (0.33333333333333331, 0.33333333333333331, 1.0),
  191 + (1.0, 0.33333333333333331, 0.66666666666666663),
  192 + (0.74901960784313726, 1.0, 0.0),
  193 + (0.83529411764705885, 0.33333333333333331, 1.0),
  194 + (0.792156862745098, 0.66666666666666663, 1.0),
  195 + (1.0, 0.66666666666666663, 0.792156862745098),
  196 + (0.33333333333333331, 1.0, 0.83529411764705885),
  197 + (1.0, 0.792156862745098, 0.66666666666666663),
  198 + (0.792156862745098, 1.0, 0.66666666666666663),
  199 + (0.66666666666666663, 0.792156862745098, 1.0)]
  200 +
183 201 # Related to slice editor brush
184 202 BRUSH_CIRCLE = 0 #
185 203 BRUSH_SQUARE = 1
... ... @@ -402,6 +420,7 @@ STATE_PAN = 1005
402 420 SLICE_STATE_CROSS = 1006
403 421 SLICE_STATE_SCROLL = 1007
404 422 SLICE_STATE_EDITOR = 1008
  423 +VOLUME_STATE_SEED = 2001
405 424  
406 425  
407 426 TOOL_STATES = [ STATE_WL, STATE_SPIN, STATE_ZOOM,
... ... @@ -414,7 +433,7 @@ SLICE_STYLES = TOOL_STATES + TOOL_SLICE_STATES
414 433 SLICE_STYLES.append(STATE_DEFAULT)
415 434 SLICE_STYLES.append(SLICE_STATE_EDITOR)
416 435  
417   -VOLUME_STYLES = TOOL_STATES + []
  436 +VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED]
418 437 VOLUME_STYLES.append(STATE_DEFAULT)
419 438  
420 439  
... ... @@ -426,4 +445,5 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1,
426 445 STATE_SPIN: 2,
427 446 STATE_ZOOM: 2,
428 447 STATE_ZOOM_SL: 2,
429   - STATE_PAN:2}
  448 + STATE_PAN:2,
  449 + VOLUME_STATE_SEED:1}
... ...
invesalius/data/polydata_utils.py
... ... @@ -57,23 +57,7 @@ def ApplySmoothFilter(polydata, iterations, relaxation_factor):
57 57  
58 58 return smoother.GetOutput()
59 59  
60   -def SelectLargestSurface(polydata):
61   - """
62   - """
63   - pass
64   - return polydata
65 60  
66   -def SplitDisconectedSurfaces(polydata):
67   - """
68   - """
69   - return []
70   -
71   -# TODO: style?
72   -def SelectSurfaceByCell(polytada, list_index = []):
73   - """
74   - """
75   - pass
76   - return []
77 61  
78 62 def FillSurfaceHole(polydata):
79 63 """
... ... @@ -133,7 +117,7 @@ def Import(filename):
133 117 reader.Update()
134 118 return reader.GetOutput()
135 119  
136   -def SelectPolyDataPart(polydata, point):
  120 +def JoinSeedsParts(polydata, point_id_list):
137 121 """
138 122 The function require vtkPolyData and point id
139 123 from vtkPolyData.
... ... @@ -141,7 +125,30 @@ def SelectPolyDataPart(polydata, point):
141 125 conn = vtk.vtkPolyDataConnectivityFilter()
142 126 conn.SetInput(polydata)
143 127 conn.SetExtractionModeToPointSeededRegions()
144   - conn.AddSeed(point)
  128 + for seed in point_id_list:
  129 + conn.AddSeed(seed)
  130 + conn.Update()
  131 +
  132 + result = vtk.vtkPolyData()
  133 + result.DeepCopy(conn.GetOutput())
  134 + result.Update()
  135 + return result
  136 +
  137 +def SelectLargestPart(polydata):
  138 + """
  139 + """
  140 + conn = vtk.vtkPolyDataConnectivityFilter()
  141 + conn.SetInput(polydata)
  142 + conn.SetExtractionModeToLargestRegion()
145 143 conn.Update()
146 144  
147   - return conn.GetOutput()
  145 + result = vtk.vtkPolyData()
  146 + result.DeepCopy(conn.GetOutput())
  147 + result.Update()
  148 + return result
  149 +
  150 +def SplitDisconectedParts(polydata):
  151 + """
  152 + """
  153 + return [polydata]
  154 +
... ...
invesalius/data/surface.py
... ... @@ -20,6 +20,7 @@
20 20 import multiprocessing
21 21 import os
22 22 import plistlib
  23 +import random
23 24 import sys
24 25 import tempfile
25 26  
... ... @@ -118,6 +119,81 @@ class SurfaceManager():
118 119 ps.Publisher().subscribe(self.OnLoadSurfaceDict, 'Load surface dict')
119 120 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data')
120 121 ps.Publisher().subscribe(self.OnSelectSurface, 'Change surface selected')
  122 + #----
  123 + ps.Publisher().subscribe(self.OnSplitSurface, 'Split surface')
  124 + ps.Publisher().subscribe(self.OnLargestSurface,
  125 + 'Create surface from largest region')
  126 + ps.Publisher().subscribe(self.OnSeedSurface, "Create surface from seeds")
  127 +
  128 + def OnSeedSurface(self, pubsub_evt):
  129 + index, points_id_list = pubsub_evt.data
  130 + proj = prj.Project()
  131 + surface = proj.surface_dict[index]
  132 +
  133 + new_polydata = pu.JoinSeedsParts(surface.polydata,
  134 + points_id_list)
  135 + self.CreateSurfaceFromPolydata(new_polydata)
  136 +
  137 + def OnSplitSurface(self, pubsub_evt):
  138 + index = pubsub_evt.data
  139 + proj = prj.Project()
  140 + surface = proj.surface_dict[index]
  141 +
  142 + new_polydata_list = pu.SplitDisconectedParts(surface.polydata)
  143 + for polydata in new_polydata_list:
  144 + self.CreateSurfaceFromPolydata(polydata)
  145 +
  146 + def OnLargestSurface(self, pubsub_evt):
  147 + index = pubsub_evt.data
  148 + proj = prj.Project()
  149 + surface = proj.surface_dict[index]
  150 +
  151 + new_polydata = pu.SelectLargestPart(surface.polydata)
  152 + self.CreateSurfaceFromPolydata(new_polydata)
  153 +
  154 + def CreateSurfaceFromPolydata(self, polydata, overwrite=False):
  155 + mapper = vtk.vtkPolyDataMapper()
  156 + mapper.SetInput(polydata)
  157 + mapper.ScalarVisibilityOff()
  158 +
  159 + actor = vtk.vtkActor()
  160 + actor.SetMapper(mapper)
  161 +
  162 + if overwrite:
  163 + surface = Surface(index = self.last_surface_index)
  164 + else:
  165 + surface = Surface()
  166 +
  167 + surface.colour = random.choice(const.SURFACE_COLOUR)
  168 + surface.polydata = polydata
  169 +
  170 + # Set actor colour and transparency
  171 + actor.GetProperty().SetColor(surface.colour)
  172 + actor.GetProperty().SetOpacity(1-surface.transparency)
  173 +
  174 + # Append surface into Project.surface_dict
  175 + proj = prj.Project()
  176 + if overwrite:
  177 + proj.ChangeSurface(surface)
  178 + else:
  179 + index = proj.AddSurface(surface)
  180 + surface.index = index
  181 + self.last_surface_index = index
  182 +
  183 + session = ses.Session()
  184 + session.ChangeProject()
  185 +
  186 + # The following lines have to be here, otherwise all volumes disappear
  187 + measured_polydata = vtk.vtkMassProperties()
  188 + measured_polydata.AddObserver("ProgressEvent", lambda obj,evt:
  189 + UpdateProgress(obj, _("Generating 3D surface...")))
  190 + measured_polydata.SetInput(polydata)
  191 + volume = measured_polydata.GetVolume()
  192 + surface.volume = volume
  193 + self.last_surface_index = surface.index
  194 +
  195 + ps.Publisher().sendMessage('Load surface actor into viewer', actor)
  196 +
121 197  
122 198 def OnCloseProject(self, pubsub_evt):
123 199 self.CloseProject()
... ...
invesalius/data/viewer_volume.py
... ... @@ -83,6 +83,12 @@ class Viewer(wx.Panel):
83 83 self.mouse_pressed = 0
84 84 self.on_wl = False
85 85  
  86 + self.picker = vtk.vtkPointPicker()
  87 + interactor.SetPicker(self.picker)
  88 + self.seed_points = []
  89 + self.current_surface_index = 0
  90 +
  91 +
86 92 def __bind_events(self):
87 93 ps.Publisher().subscribe(self.LoadActor,
88 94 'Load surface actor into viewer')
... ... @@ -132,7 +138,19 @@ class Viewer(wx.Panel):
132 138  
133 139 ps.Publisher().subscribe(self.OnExportPicture,'Export picture to file')
134 140  
  141 + ps.Publisher().subscribe(self.OnStartSeed,'Create surface by seeding - start')
  142 + ps.Publisher().subscribe(self.OnEndSeed,'Create surface by seeding - end')
135 143  
  144 + def OnStartSeed(self, pubsub_evt):
  145 + index = pubsub_evt.data
  146 + self.current_surface_index = index
  147 + self.seed_points = []
  148 +
  149 + def OnEndSeed(self, pubsub_evt):
  150 + ps.Publisher().sendMessage("Create surface from seeds",
  151 + (self.current_surface_index ,
  152 + self.seed_points))
  153 +
136 154  
137 155 def OnExportPicture(self, pubsub_evt):
138 156 ps.Publisher().sendMessage('Begin busy cursor')
... ... @@ -189,13 +207,6 @@ class Viewer(wx.Panel):
189 207 self.mouse_pressed = 0
190 208 self.on_wl = False
191 209 self.slice_plane = 0
192   -
193   - #if self.text:
194   - # del self.text
195   - # self.text = 0
196   -
197   -
198   -
199 210  
200 211 def OnHideText(self, pubsub_evt):
201 212 self.text.Hide()
... ... @@ -238,6 +249,10 @@ class Viewer(wx.Panel):
238 249 },
239 250 const.STATE_DEFAULT:
240 251 {
  252 + },
  253 + const.VOLUME_STATE_SEED:
  254 + {
  255 + "LeftButtonPressEvent": self.OnInsertSeed
241 256 }
242 257 }
243 258  
... ... @@ -535,6 +550,12 @@ class Viewer(wx.Panel):
535 550 def AppendActor(self, evt_pubsub=None):
536 551 self.ren.AddActor(evt_pubsub.data)
537 552  
  553 + def OnInsertSeed(self, obj, evt):
  554 + x,y = self.interactor.GetEventPosition()
  555 + #x,y = obj.GetLastEventPosition()
  556 + self.picker.Pick(x, y, 0, self.ren)
  557 + point_id = self.picker.GetPointId()
  558 + self.seed_points.append(point_id)
538 559  
539 560 class SlicePlane:
540 561 def __init__(self):
... ... @@ -783,11 +804,4 @@ class SlicePlane:
783 804 del self.plane_y
784 805 del self.plane_z
785 806  
786   - def PointId(self, evt, obj):
787   - #TODO: add in the code
788   - # picker = vtk.vtkPointPicker()
789   - # interactor.SetPicker(picker)
790   - # interactor.AddObserver("left...", self.PointId)
791   - x,y = evt.GetLastEventPosition()
792   - self.picker.Pick(x, y, 0, self.ren1)
793   - point_id = self.picker.GetPointId()
  807 +
... ...
invesalius/gui/task_surface.py
... ... @@ -22,6 +22,7 @@ import wx
22 22 import wx.lib.hyperlink as hl
23 23 import wx.lib.pubsub as ps
24 24  
  25 +import constants as const
25 26 import gui.dialogs as dlg
26 27 import gui.widgets.foldpanelbar as fpb
27 28 import gui.widgets.colourselect as csel
... ... @@ -335,11 +336,12 @@ class SurfaceTools(wx.Panel):
335 336  
336 337 def SelectLargest(self):
337 338 index = self.combo_surface_name.GetSelection()
338   - ps.Publisher().sendMessage('Split surface by largest region', index)
  339 + ps.Publisher().sendMessage('Split surface', index)
339 340  
340 341 def SplitSurface(self):
341 342 index = self.combo_surface_name.GetSelection()
342   - ps.Publisher().sendMessage('Create surface by largest region', index)
  343 + ps.Publisher().sendMessage('Create surface from largest region', index)
  344 + # surface_manager
343 345  
344 346 def SelectSeed(self):
345 347 if self.button_seeds.IsPressed():
... ... @@ -349,10 +351,13 @@ class SurfaceTools(wx.Panel):
349 351  
350 352 def StartSeeding(self):
351 353 index = self.combo_surface_name.GetSelection()
352   - ps.Publisher().sendMessage('Create surface by seeding - start', index)
  354 + ps.Publisher().sendMessage('Enable style', const.VOLUME_STATE_SEED)
  355 + ps.Publisher().sendMessage('Create surface by seeding - start', index)
353 356  
354 357 def EndSeeding(self):
355   - ps.Publisher().sendMessage('Create surface by seeding - end')
  358 + ps.Publisher().sendMessage('Disable style', const.VOLUME_STATE_SEED)
  359 + ps.Publisher().sendMessage('Create surface by seeding - end')
  360 + # volume_viewer -> surface_manager
356 361  
357 362  
358 363  
... ...