From bba5864282eac415257c9cb2c0bb92cef314d195 Mon Sep 17 00:00:00 2001 From: tatiana Date: Tue, 26 Jan 2010 17:22:15 +0000 Subject: [PATCH] ENH: Surface connectivity (under devel) --- invesalius/constants.py | 24 ++++++++++++++++++++++-- invesalius/data/polydata_utils.py | 45 ++++++++++++++++++++++++++------------------- invesalius/data/surface.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ invesalius/data/viewer_volume.py | 44 +++++++++++++++++++++++++++++--------------- invesalius/gui/task_surface.py | 13 +++++++++---- 5 files changed, 162 insertions(+), 40 deletions(-) diff --git a/invesalius/constants.py b/invesalius/constants.py index ed91087..f8110be 100644 --- a/invesalius/constants.py +++ b/invesalius/constants.py @@ -180,6 +180,24 @@ MASK_COLOUR = [(0.33, 1, 0.33), #(0.792156862745098, 1.0, 0.66666666666666663), # too "light" #(0.66666666666666663, 0.792156862745098, 1.0)] + +SURFACE_COLOUR = [(0.33, 1, 0.33), + (1, 1, 0.33), + (0.33, 0.91, 1), + (1, 0.33, 1), + (1, 0.68, 0.33), + (1, 0.33, 0.33), + (0.33333333333333331, 0.33333333333333331, 1.0), + (1.0, 0.33333333333333331, 0.66666666666666663), + (0.74901960784313726, 1.0, 0.0), + (0.83529411764705885, 0.33333333333333331, 1.0), + (0.792156862745098, 0.66666666666666663, 1.0), + (1.0, 0.66666666666666663, 0.792156862745098), + (0.33333333333333331, 1.0, 0.83529411764705885), + (1.0, 0.792156862745098, 0.66666666666666663), + (0.792156862745098, 1.0, 0.66666666666666663), + (0.66666666666666663, 0.792156862745098, 1.0)] + # Related to slice editor brush BRUSH_CIRCLE = 0 # BRUSH_SQUARE = 1 @@ -402,6 +420,7 @@ STATE_PAN = 1005 SLICE_STATE_CROSS = 1006 SLICE_STATE_SCROLL = 1007 SLICE_STATE_EDITOR = 1008 +VOLUME_STATE_SEED = 2001 TOOL_STATES = [ STATE_WL, STATE_SPIN, STATE_ZOOM, @@ -414,7 +433,7 @@ SLICE_STYLES = TOOL_STATES + TOOL_SLICE_STATES SLICE_STYLES.append(STATE_DEFAULT) SLICE_STYLES.append(SLICE_STATE_EDITOR) -VOLUME_STYLES = TOOL_STATES + [] +VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED] VOLUME_STYLES.append(STATE_DEFAULT) @@ -426,4 +445,5 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, STATE_SPIN: 2, STATE_ZOOM: 2, STATE_ZOOM_SL: 2, - STATE_PAN:2} + STATE_PAN:2, + VOLUME_STATE_SEED:1} diff --git a/invesalius/data/polydata_utils.py b/invesalius/data/polydata_utils.py index b71f5d3..fd52ef6 100644 --- a/invesalius/data/polydata_utils.py +++ b/invesalius/data/polydata_utils.py @@ -57,23 +57,7 @@ def ApplySmoothFilter(polydata, iterations, relaxation_factor): return smoother.GetOutput() -def SelectLargestSurface(polydata): - """ - """ - pass - return polydata -def SplitDisconectedSurfaces(polydata): - """ - """ - return [] - -# TODO: style? -def SelectSurfaceByCell(polytada, list_index = []): - """ - """ - pass - return [] def FillSurfaceHole(polydata): """ @@ -133,7 +117,7 @@ def Import(filename): reader.Update() return reader.GetOutput() -def SelectPolyDataPart(polydata, point): +def JoinSeedsParts(polydata, point_id_list): """ The function require vtkPolyData and point id from vtkPolyData. @@ -141,7 +125,30 @@ def SelectPolyDataPart(polydata, point): conn = vtk.vtkPolyDataConnectivityFilter() conn.SetInput(polydata) conn.SetExtractionModeToPointSeededRegions() - conn.AddSeed(point) + for seed in point_id_list: + conn.AddSeed(seed) + conn.Update() + + result = vtk.vtkPolyData() + result.DeepCopy(conn.GetOutput()) + result.Update() + return result + +def SelectLargestPart(polydata): + """ + """ + conn = vtk.vtkPolyDataConnectivityFilter() + conn.SetInput(polydata) + conn.SetExtractionModeToLargestRegion() conn.Update() - return conn.GetOutput() + result = vtk.vtkPolyData() + result.DeepCopy(conn.GetOutput()) + result.Update() + return result + +def SplitDisconectedParts(polydata): + """ + """ + return [polydata] + diff --git a/invesalius/data/surface.py b/invesalius/data/surface.py index d0feaf5..abf144f 100644 --- a/invesalius/data/surface.py +++ b/invesalius/data/surface.py @@ -20,6 +20,7 @@ import multiprocessing import os import plistlib +import random import sys import tempfile @@ -118,6 +119,81 @@ class SurfaceManager(): ps.Publisher().subscribe(self.OnLoadSurfaceDict, 'Load surface dict') ps.Publisher().subscribe(self.OnCloseProject, 'Close project data') ps.Publisher().subscribe(self.OnSelectSurface, 'Change surface selected') + #---- + ps.Publisher().subscribe(self.OnSplitSurface, 'Split surface') + ps.Publisher().subscribe(self.OnLargestSurface, + 'Create surface from largest region') + ps.Publisher().subscribe(self.OnSeedSurface, "Create surface from seeds") + + def OnSeedSurface(self, pubsub_evt): + index, points_id_list = pubsub_evt.data + proj = prj.Project() + surface = proj.surface_dict[index] + + new_polydata = pu.JoinSeedsParts(surface.polydata, + points_id_list) + self.CreateSurfaceFromPolydata(new_polydata) + + def OnSplitSurface(self, pubsub_evt): + index = pubsub_evt.data + proj = prj.Project() + surface = proj.surface_dict[index] + + new_polydata_list = pu.SplitDisconectedParts(surface.polydata) + for polydata in new_polydata_list: + self.CreateSurfaceFromPolydata(polydata) + + def OnLargestSurface(self, pubsub_evt): + index = pubsub_evt.data + proj = prj.Project() + surface = proj.surface_dict[index] + + new_polydata = pu.SelectLargestPart(surface.polydata) + self.CreateSurfaceFromPolydata(new_polydata) + + def CreateSurfaceFromPolydata(self, polydata, overwrite=False): + mapper = vtk.vtkPolyDataMapper() + mapper.SetInput(polydata) + mapper.ScalarVisibilityOff() + + actor = vtk.vtkActor() + actor.SetMapper(mapper) + + if overwrite: + surface = Surface(index = self.last_surface_index) + else: + surface = Surface() + + surface.colour = random.choice(const.SURFACE_COLOUR) + surface.polydata = polydata + + # Set actor colour and transparency + actor.GetProperty().SetColor(surface.colour) + actor.GetProperty().SetOpacity(1-surface.transparency) + + # Append surface into Project.surface_dict + proj = prj.Project() + if overwrite: + proj.ChangeSurface(surface) + else: + index = proj.AddSurface(surface) + surface.index = index + self.last_surface_index = index + + session = ses.Session() + session.ChangeProject() + + # The following lines have to be here, otherwise all volumes disappear + measured_polydata = vtk.vtkMassProperties() + measured_polydata.AddObserver("ProgressEvent", lambda obj,evt: + UpdateProgress(obj, _("Generating 3D surface..."))) + measured_polydata.SetInput(polydata) + volume = measured_polydata.GetVolume() + surface.volume = volume + self.last_surface_index = surface.index + + ps.Publisher().sendMessage('Load surface actor into viewer', actor) + def OnCloseProject(self, pubsub_evt): self.CloseProject() diff --git a/invesalius/data/viewer_volume.py b/invesalius/data/viewer_volume.py index cb1b830..e8209e2 100755 --- a/invesalius/data/viewer_volume.py +++ b/invesalius/data/viewer_volume.py @@ -83,6 +83,12 @@ class Viewer(wx.Panel): self.mouse_pressed = 0 self.on_wl = False + self.picker = vtk.vtkPointPicker() + interactor.SetPicker(self.picker) + self.seed_points = [] + self.current_surface_index = 0 + + def __bind_events(self): ps.Publisher().subscribe(self.LoadActor, 'Load surface actor into viewer') @@ -132,7 +138,19 @@ class Viewer(wx.Panel): ps.Publisher().subscribe(self.OnExportPicture,'Export picture to file') + ps.Publisher().subscribe(self.OnStartSeed,'Create surface by seeding - start') + ps.Publisher().subscribe(self.OnEndSeed,'Create surface by seeding - end') + def OnStartSeed(self, pubsub_evt): + index = pubsub_evt.data + self.current_surface_index = index + self.seed_points = [] + + def OnEndSeed(self, pubsub_evt): + ps.Publisher().sendMessage("Create surface from seeds", + (self.current_surface_index , + self.seed_points)) + def OnExportPicture(self, pubsub_evt): ps.Publisher().sendMessage('Begin busy cursor') @@ -189,13 +207,6 @@ class Viewer(wx.Panel): self.mouse_pressed = 0 self.on_wl = False self.slice_plane = 0 - - #if self.text: - # del self.text - # self.text = 0 - - - def OnHideText(self, pubsub_evt): self.text.Hide() @@ -238,6 +249,10 @@ class Viewer(wx.Panel): }, const.STATE_DEFAULT: { + }, + const.VOLUME_STATE_SEED: + { + "LeftButtonPressEvent": self.OnInsertSeed } } @@ -535,6 +550,12 @@ class Viewer(wx.Panel): def AppendActor(self, evt_pubsub=None): self.ren.AddActor(evt_pubsub.data) + def OnInsertSeed(self, obj, evt): + x,y = self.interactor.GetEventPosition() + #x,y = obj.GetLastEventPosition() + self.picker.Pick(x, y, 0, self.ren) + point_id = self.picker.GetPointId() + self.seed_points.append(point_id) class SlicePlane: def __init__(self): @@ -783,11 +804,4 @@ class SlicePlane: del self.plane_y del self.plane_z - def PointId(self, evt, obj): - #TODO: add in the code - # picker = vtk.vtkPointPicker() - # interactor.SetPicker(picker) - # interactor.AddObserver("left...", self.PointId) - x,y = evt.GetLastEventPosition() - self.picker.Pick(x, y, 0, self.ren1) - point_id = self.picker.GetPointId() + diff --git a/invesalius/gui/task_surface.py b/invesalius/gui/task_surface.py index e1ce0d6..974e923 100644 --- a/invesalius/gui/task_surface.py +++ b/invesalius/gui/task_surface.py @@ -22,6 +22,7 @@ import wx import wx.lib.hyperlink as hl import wx.lib.pubsub as ps +import constants as const import gui.dialogs as dlg import gui.widgets.foldpanelbar as fpb import gui.widgets.colourselect as csel @@ -335,11 +336,12 @@ class SurfaceTools(wx.Panel): def SelectLargest(self): index = self.combo_surface_name.GetSelection() - ps.Publisher().sendMessage('Split surface by largest region', index) + ps.Publisher().sendMessage('Split surface', index) def SplitSurface(self): index = self.combo_surface_name.GetSelection() - ps.Publisher().sendMessage('Create surface by largest region', index) + ps.Publisher().sendMessage('Create surface from largest region', index) + # surface_manager def SelectSeed(self): if self.button_seeds.IsPressed(): @@ -349,10 +351,13 @@ class SurfaceTools(wx.Panel): def StartSeeding(self): index = self.combo_surface_name.GetSelection() - ps.Publisher().sendMessage('Create surface by seeding - start', index) + ps.Publisher().sendMessage('Enable style', const.VOLUME_STATE_SEED) + ps.Publisher().sendMessage('Create surface by seeding - start', index) def EndSeeding(self): - ps.Publisher().sendMessage('Create surface by seeding - end') + ps.Publisher().sendMessage('Disable style', const.VOLUME_STATE_SEED) + ps.Publisher().sendMessage('Create surface by seeding - end') + # volume_viewer -> surface_manager -- libgit2 0.21.2