diff --git a/invesalius/data/cursor_actors.py b/invesalius/data/cursor_actors.py index dc7a92f..566f72d 100644 --- a/invesalius/data/cursor_actors.py +++ b/invesalius/data/cursor_actors.py @@ -1,5 +1,8 @@ from math import * + import vtk +import wx.lib.pubsub as ps + import utils class CursorCircle: @@ -10,7 +13,7 @@ class CursorCircle: self.colour = (0.0, 0.0, 1.0) self.opacity = 1 - self.radius = 20 + self.radius = 15.0 self.position = (0 ,0, 1) self.points = [] self.orientation = "AXIAL" @@ -22,7 +25,8 @@ class CursorCircle: self.__build_actor() self.__calculate_area_pixels() - + + def __build_actor(self): """ Function to plot the circle @@ -75,14 +79,15 @@ class CursorCircle: for k in utils.frange(xi,xf,xs): self.pixel_list.append((k, yi)) - def SetSize(self, radius): - self.radius = radius + def SetSize(self, diameter): + radius = self.radius = diameter/2.0 self.disk.SetInnerRadius(radius-1) # filled = self.radius - self.disk.SetOuterRadius(radius) # filled = 0x + self.disk.SetOuterRadius(radius) # filled = 0 self.__calculate_area_pixels() def SetColour(self, colour): - self.actor.GetProperty().SetColor(self.colour) + self.colour = colour + self.actor.GetProperty().SetColor(colour) def SetOrientation(self, orientation): self.orientation = orientation @@ -94,13 +99,120 @@ class CursorCircle: self.actor.RotateY(90) def SetPosition(self, position): + self.position = position + self.actor.SetPosition(position) + + def SetEditionPosition(self, position): + self.edition_position = position + + def SetSpacing(self, spacing): + self.spacing = spacing + + def GetPixels(self): + px, py, pz = self.edition_position + orient = self.orientation + xs, ys, zs = self.spacing + for pixel_0,pixel_1 in self.pixel_list: + # The position of the pixels in this list is relative (based only on + # the area, and not the cursor position). + # Let's calculate the absolute position + # TODO: Optimize this!!!! + abs_pixel = {"AXIAL": [px+pixel_0/xs, py+(pixel_1/ys), pz], + "CORONAL": [px+(pixel_0/xs), py, pz+(pixel_1/zs)], + "SAGITAL": [px, py+(pixel_0/ys), pz+(pixel_1/zs)]} + yield abs_pixel[orient] + + +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- + +class CursorRectangle: - #if self.orientation == "AXIAL": - # z = 1 - #elif self.orientation == "CORONAL": - # y = 1 - #elif self.orientation == "SAGITAL": - # x = 1 + def __init__(self): + + self.colour = (0.0, 0.0, 1.0) + self.opacity = 1 + + self.x_length = 30 + self.y_length = 30 + + self.dimension = (self.x_length, self.y_length) + self.position = (0 ,0) + + self.mapper = vtk.vtkPolyDataMapper() + + self.retangle = vtk.vtkCubeSource() + self.actor = vtk.vtkActor() + + self.seeds_yi = vtk.vtkLineSource() + self.seeds_yf = vtk.vtkLineSource() + self.seeds_xi = vtk.vtkLineSource() + self.seeds_xf = vtk.vtkLineSource() + self.join_lines = vtk.vtkAppendPolyData() + + self.__build_actor() + self.__calculate_area_pixels() + + def SetSize(self, size): + print "SetSize", size + self.x_length = size + self.y_length = size + retangle = self.retangle + retangle.SetXLength(size) + retangle.SetYLength(size) + + seeds_yi = self.seeds_yi + seeds_yi.SetPoint1(0, 0, 0) + seeds_yi.SetPoint2(0, self.y_length, 0) + + seeds_yf = self.seeds_yf + seeds_yf.SetPoint1(self.x_length, self.y_length, 0) + seeds_yf.SetPoint2(self.x_length, 0, 0) + + seeds_xi = self.seeds_xi + seeds_xi.SetPoint1(0, self.y_length, 0) + seeds_xi.SetPoint2(self.x_length, self.y_length, 0) + + seeds_xf = self.seeds_xf + seeds_xf.SetPoint1(0, 0, 0) + seeds_xf.SetPoint2(self.x_length, 0, 0) + + join_lines = self.join_lines + join_lines.AddInput(seeds_yi.GetOutput()) + join_lines.AddInput(seeds_yf.GetOutput()) + join_lines.AddInput(seeds_xi.GetOutput()) + join_lines.AddInput(seeds_xf.GetOutput()) + + self.__calculate_area_pixels() + + def SetOrientation(self, orientation): + self.orientation = orientation + + def SetColour(self, colour): + self.colour = colour + self.actor.GetProperty().SetColor(colour) + + def SetOrientation(self, orientation): + self.orientation = orientation + + if orientation == "CORONAL": + self.actor.RotateX(90) + + if orientation == "SAGITAL": + self.actor.RotateY(90) + + def SetPosition(self, position): self.position = position self.actor.SetPosition(position) @@ -110,7 +222,64 @@ class CursorCircle: def SetSpacing(self, spacing): self.spacing = spacing + def __build_actor(self): + """ + Function to plot the Retangle + """ + retangle = self.retangle + retangle.SetXLength(self.x_length) + retangle.SetYLength(self.y_length) + + seeds_yi = self.seeds_yi + seeds_yi.SetPoint1(0, 0, 0) + seeds_yi.SetPoint2(0, self.y_length, 0) + + seeds_yf = self.seeds_yf + seeds_yf.SetPoint1(self.x_length, self.y_length, 0) + seeds_yf.SetPoint2(self.x_length, 0, 0) + + seeds_xi = self.seeds_xi + seeds_xi.SetPoint1(0, self.y_length, 0) + seeds_xi.SetPoint2(self.x_length, self.y_length, 0) + + seeds_xf = self.seeds_xf + seeds_xf.SetPoint1(0, 0, 0) + seeds_xf.SetPoint2(self.x_length, 0, 0) + + join_lines = self.join_lines + join_lines.AddInput(seeds_yi.GetOutput()) + join_lines.AddInput(seeds_yf.GetOutput()) + join_lines.AddInput(seeds_xi.GetOutput()) + join_lines.AddInput(seeds_xf.GetOutput()) + + mapper = self.mapper + mapper.SetScalarRange(0, 360) + + actor = self.actor + + mapper.SetInput(join_lines.GetOutput()) + actor.SetPosition(self.position[0]-self.x_length/2, # if filled remov - + self.position[1]-self.y_length/2, 1) # idem + + actor.SetMapper(mapper) + actor.GetProperty().SetOpacity(self.opacity) + actor.GetProperty().SetColor(self.colour) + actor.SetVisibility(1) + + def __calculate_area_pixels(self): + xc = 0 + yc = 0 + z = 0 + self.pixel_list = [] + for i in xrange(int(yc - self.y_length/2), int(yc + self.y_length/2)): + for k in xrange(xc - self.x_length/2, xc + self.x_length/2): + self.pixel_list.append((k, i)) + + def GetPixels(self): + """ + Return the points of the rectangle + """ px, py, pz = self.edition_position orient = self.orientation xs, ys, zs = self.spacing @@ -119,7 +288,8 @@ class CursorCircle: # the area, and not the cursor position). # Let's calculate the absolute position # TODO: Optimize this!!!! - absolute_pixel = {"AXIAL": (px + pixel_0 / xs , py + pixel_1 / ys, pz), - "CORONAL": (px + pixel_0 / xs, py, pz + pixel_1 / zs), - "SAGITAL": (px, py + pixel_0 / ys, pz + pixel_1 / zs) } - yield absolute_pixel[orient] + abs_pixel = {"AXIAL": [px+pixel_0/xs, py+(pixel_1/ys), pz], + "CORONAL": [px+(pixel_0/xs), py, pz+(pixel_1/zs)], + "SAGITAL": [px, py+(pixel_0/ys), pz+(pixel_1/zs)]} + yield abs_pixel[orient] + \ No newline at end of file diff --git a/invesalius/data/viewer_slice.py b/invesalius/data/viewer_slice.py index f170e7e..1e10bf3 100755 --- a/invesalius/data/viewer_slice.py +++ b/invesalius/data/viewer_slice.py @@ -131,11 +131,43 @@ class Viewer(wx.Panel): def ChangeBrushSize(self, pubsub_evt): size = pubsub_evt.data + self.brush_cursor_size = size self.cursor.SetSize(size) self.ren.Render() self.interactor.Render() + + def ChangeBrushColour(self, pubsub_evt): + vtk_colour = pubsub_evt.data[3] + self.cursor.SetColour(vtk_colour) + self._brush_cursor_colour = vtk_colour + self.ren.Render() + self.interactor.Render() + def ChangeBrushActor(self, pubsub_evt): + brush_type = pubsub_evt.data + self.ren.RemoveActor(self.cursor.actor) + + if brush_type == 'square': + cursor = ca.CursorRectangle() + elif brush_type == 'circle': + cursor = ca.CursorCircle() + self.cursor = cursor + + cursor.SetOrientation(self.orientation) + coordinates = {"SAGITAL": [self.slice_number, 0, 0], + "CORONAL": [0, self.slice_number, 0], + "AXIAL": [0, 0, self.slice_number]} + cursor.SetPosition(coordinates[self.orientation]) + cursor.SetSpacing(self.imagedata.GetSpacing()) + cursor.SetColour(self._brush_cursor_colour) + cursor.SetSize(self.brush_cursor_size) + self.ren.AddActor(cursor.actor) + self.ren.Render() + self.interactor.Render() + self.cursor = cursor + + def OnMouseClick(self, obj, evt_vtk): self.mouse_pressed = 1 @@ -263,7 +295,11 @@ class Viewer(wx.Panel): ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer') ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position', self.orientation)) + + ### ps.Publisher().subscribe(self.ChangeBrushSize,'Set edition brush size') + ps.Publisher().subscribe(self.ChangeBrushColour, 'Add mask') + ps.Publisher().subscribe(self.ChangeBrushActor, 'Set brush format') def __bind_events_wx(self): self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar) @@ -373,6 +409,7 @@ class Viewer(wx.Panel): def SetColour(self, pubsub_evt): colour_wx = pubsub_evt.data colour_vtk = [colour/float(255) for colour in colour_wx] - #self.editor.SetColour(colour_vtk) + self._brush_cursor_colour = vtk_colour + self.cursor.SetColour(colour_vtk) self.interactor.Render() -- libgit2 0.21.2