Commit b4ead449f1844e991b016736ee4a0764162ccde9

Authored by tatiana
1 parent 4014a308

ADD: Editor brush - change type, change size, change colour

invesalius/data/cursor_actors.py
1 1 from math import *
  2 +
2 3 import vtk
  4 +import wx.lib.pubsub as ps
  5 +
3 6 import utils
4 7  
5 8 class CursorCircle:
... ... @@ -10,7 +13,7 @@ class CursorCircle:
10 13  
11 14 self.colour = (0.0, 0.0, 1.0)
12 15 self.opacity = 1
13   - self.radius = 20
  16 + self.radius = 15.0
14 17 self.position = (0 ,0, 1)
15 18 self.points = []
16 19 self.orientation = "AXIAL"
... ... @@ -22,7 +25,8 @@ class CursorCircle:
22 25  
23 26 self.__build_actor()
24 27 self.__calculate_area_pixels()
25   -
  28 +
  29 +
26 30 def __build_actor(self):
27 31 """
28 32 Function to plot the circle
... ... @@ -75,14 +79,15 @@ class CursorCircle:
75 79 for k in utils.frange(xi,xf,xs):
76 80 self.pixel_list.append((k, yi))
77 81  
78   - def SetSize(self, radius):
79   - self.radius = radius
  82 + def SetSize(self, diameter):
  83 + radius = self.radius = diameter/2.0
80 84 self.disk.SetInnerRadius(radius-1) # filled = self.radius
81   - self.disk.SetOuterRadius(radius) # filled = 0x
  85 + self.disk.SetOuterRadius(radius) # filled = 0
82 86 self.__calculate_area_pixels()
83 87  
84 88 def SetColour(self, colour):
85   - self.actor.GetProperty().SetColor(self.colour)
  89 + self.colour = colour
  90 + self.actor.GetProperty().SetColor(colour)
86 91  
87 92 def SetOrientation(self, orientation):
88 93 self.orientation = orientation
... ... @@ -94,13 +99,120 @@ class CursorCircle:
94 99 self.actor.RotateY(90)
95 100  
96 101 def SetPosition(self, position):
  102 + self.position = position
  103 + self.actor.SetPosition(position)
  104 +
  105 + def SetEditionPosition(self, position):
  106 + self.edition_position = position
  107 +
  108 + def SetSpacing(self, spacing):
  109 + self.spacing = spacing
  110 +
  111 + def GetPixels(self):
  112 + px, py, pz = self.edition_position
  113 + orient = self.orientation
  114 + xs, ys, zs = self.spacing
  115 + for pixel_0,pixel_1 in self.pixel_list:
  116 + # The position of the pixels in this list is relative (based only on
  117 + # the area, and not the cursor position).
  118 + # Let's calculate the absolute position
  119 + # TODO: Optimize this!!!!
  120 + abs_pixel = {"AXIAL": [px+pixel_0/xs, py+(pixel_1/ys), pz],
  121 + "CORONAL": [px+(pixel_0/xs), py, pz+(pixel_1/zs)],
  122 + "SAGITAL": [px, py+(pixel_0/ys), pz+(pixel_1/zs)]}
  123 + yield abs_pixel[orient]
  124 +
  125 +
  126 +#-------------------------------------------------------------------------------
  127 +#-------------------------------------------------------------------------------
  128 +#-------------------------------------------------------------------------------
  129 +#-------------------------------------------------------------------------------
  130 +#-------------------------------------------------------------------------------
  131 +#-------------------------------------------------------------------------------#-------------------------------------------------------------------------------
  132 +#-------------------------------------------------------------------------------
  133 +#-------------------------------------------------------------------------------
  134 +#-------------------------------------------------------------------------------
  135 +#-------------------------------------------------------------------------------
  136 +#-------------------------------------------------------------------------------
  137 +#-------------------------------------------------------------------------------
  138 +#-------------------------------------------------------------------------------
  139 +
  140 +class CursorRectangle:
97 141  
98   - #if self.orientation == "AXIAL":
99   - # z = 1
100   - #elif self.orientation == "CORONAL":
101   - # y = 1
102   - #elif self.orientation == "SAGITAL":
103   - # x = 1
  142 + def __init__(self):
  143 +
  144 + self.colour = (0.0, 0.0, 1.0)
  145 + self.opacity = 1
  146 +
  147 + self.x_length = 30
  148 + self.y_length = 30
  149 +
  150 + self.dimension = (self.x_length, self.y_length)
  151 + self.position = (0 ,0)
  152 +
  153 + self.mapper = vtk.vtkPolyDataMapper()
  154 +
  155 + self.retangle = vtk.vtkCubeSource()
  156 + self.actor = vtk.vtkActor()
  157 +
  158 + self.seeds_yi = vtk.vtkLineSource()
  159 + self.seeds_yf = vtk.vtkLineSource()
  160 + self.seeds_xi = vtk.vtkLineSource()
  161 + self.seeds_xf = vtk.vtkLineSource()
  162 + self.join_lines = vtk.vtkAppendPolyData()
  163 +
  164 + self.__build_actor()
  165 + self.__calculate_area_pixels()
  166 +
  167 + def SetSize(self, size):
  168 + print "SetSize", size
  169 + self.x_length = size
  170 + self.y_length = size
  171 + retangle = self.retangle
  172 + retangle.SetXLength(size)
  173 + retangle.SetYLength(size)
  174 +
  175 + seeds_yi = self.seeds_yi
  176 + seeds_yi.SetPoint1(0, 0, 0)
  177 + seeds_yi.SetPoint2(0, self.y_length, 0)
  178 +
  179 + seeds_yf = self.seeds_yf
  180 + seeds_yf.SetPoint1(self.x_length, self.y_length, 0)
  181 + seeds_yf.SetPoint2(self.x_length, 0, 0)
  182 +
  183 + seeds_xi = self.seeds_xi
  184 + seeds_xi.SetPoint1(0, self.y_length, 0)
  185 + seeds_xi.SetPoint2(self.x_length, self.y_length, 0)
  186 +
  187 + seeds_xf = self.seeds_xf
  188 + seeds_xf.SetPoint1(0, 0, 0)
  189 + seeds_xf.SetPoint2(self.x_length, 0, 0)
  190 +
  191 + join_lines = self.join_lines
  192 + join_lines.AddInput(seeds_yi.GetOutput())
  193 + join_lines.AddInput(seeds_yf.GetOutput())
  194 + join_lines.AddInput(seeds_xi.GetOutput())
  195 + join_lines.AddInput(seeds_xf.GetOutput())
  196 +
  197 + self.__calculate_area_pixels()
  198 +
  199 + def SetOrientation(self, orientation):
  200 + self.orientation = orientation
  201 +
  202 + def SetColour(self, colour):
  203 + self.colour = colour
  204 + self.actor.GetProperty().SetColor(colour)
  205 +
  206 + def SetOrientation(self, orientation):
  207 + self.orientation = orientation
  208 +
  209 + if orientation == "CORONAL":
  210 + self.actor.RotateX(90)
  211 +
  212 + if orientation == "SAGITAL":
  213 + self.actor.RotateY(90)
  214 +
  215 + def SetPosition(self, position):
104 216 self.position = position
105 217 self.actor.SetPosition(position)
106 218  
... ... @@ -110,7 +222,64 @@ class CursorCircle:
110 222 def SetSpacing(self, spacing):
111 223 self.spacing = spacing
112 224  
  225 + def __build_actor(self):
  226 + """
  227 + Function to plot the Retangle
  228 + """
  229 + retangle = self.retangle
  230 + retangle.SetXLength(self.x_length)
  231 + retangle.SetYLength(self.y_length)
  232 +
  233 + seeds_yi = self.seeds_yi
  234 + seeds_yi.SetPoint1(0, 0, 0)
  235 + seeds_yi.SetPoint2(0, self.y_length, 0)
  236 +
  237 + seeds_yf = self.seeds_yf
  238 + seeds_yf.SetPoint1(self.x_length, self.y_length, 0)
  239 + seeds_yf.SetPoint2(self.x_length, 0, 0)
  240 +
  241 + seeds_xi = self.seeds_xi
  242 + seeds_xi.SetPoint1(0, self.y_length, 0)
  243 + seeds_xi.SetPoint2(self.x_length, self.y_length, 0)
  244 +
  245 + seeds_xf = self.seeds_xf
  246 + seeds_xf.SetPoint1(0, 0, 0)
  247 + seeds_xf.SetPoint2(self.x_length, 0, 0)
  248 +
  249 + join_lines = self.join_lines
  250 + join_lines.AddInput(seeds_yi.GetOutput())
  251 + join_lines.AddInput(seeds_yf.GetOutput())
  252 + join_lines.AddInput(seeds_xi.GetOutput())
  253 + join_lines.AddInput(seeds_xf.GetOutput())
  254 +
  255 + mapper = self.mapper
  256 + mapper.SetScalarRange(0, 360)
  257 +
  258 + actor = self.actor
  259 +
  260 + mapper.SetInput(join_lines.GetOutput())
  261 + actor.SetPosition(self.position[0]-self.x_length/2, # if filled remov -
  262 + self.position[1]-self.y_length/2, 1) # idem
  263 +
  264 + actor.SetMapper(mapper)
  265 + actor.GetProperty().SetOpacity(self.opacity)
  266 + actor.GetProperty().SetColor(self.colour)
  267 + actor.SetVisibility(1)
  268 +
  269 + def __calculate_area_pixels(self):
  270 + xc = 0
  271 + yc = 0
  272 + z = 0
  273 + self.pixel_list = []
  274 + for i in xrange(int(yc - self.y_length/2), int(yc + self.y_length/2)):
  275 + for k in xrange(xc - self.x_length/2, xc + self.x_length/2):
  276 + self.pixel_list.append((k, i))
  277 +
  278 +
113 279 def GetPixels(self):
  280 + """
  281 + Return the points of the rectangle
  282 + """
114 283 px, py, pz = self.edition_position
115 284 orient = self.orientation
116 285 xs, ys, zs = self.spacing
... ... @@ -119,7 +288,8 @@ class CursorCircle:
119 288 # the area, and not the cursor position).
120 289 # Let's calculate the absolute position
121 290 # TODO: Optimize this!!!!
122   - absolute_pixel = {"AXIAL": (px + pixel_0 / xs , py + pixel_1 / ys, pz),
123   - "CORONAL": (px + pixel_0 / xs, py, pz + pixel_1 / zs),
124   - "SAGITAL": (px, py + pixel_0 / ys, pz + pixel_1 / zs) }
125   - yield absolute_pixel[orient]
  291 + abs_pixel = {"AXIAL": [px+pixel_0/xs, py+(pixel_1/ys), pz],
  292 + "CORONAL": [px+(pixel_0/xs), py, pz+(pixel_1/zs)],
  293 + "SAGITAL": [px, py+(pixel_0/ys), pz+(pixel_1/zs)]}
  294 + yield abs_pixel[orient]
  295 +
126 296 \ No newline at end of file
... ...
invesalius/data/viewer_slice.py
... ... @@ -131,11 +131,43 @@ class Viewer(wx.Panel):
131 131  
132 132 def ChangeBrushSize(self, pubsub_evt):
133 133 size = pubsub_evt.data
  134 + self.brush_cursor_size = size
134 135 self.cursor.SetSize(size)
135 136 self.ren.Render()
136 137 self.interactor.Render()
  138 +
  139 + def ChangeBrushColour(self, pubsub_evt):
  140 + vtk_colour = pubsub_evt.data[3]
  141 + self.cursor.SetColour(vtk_colour)
  142 + self._brush_cursor_colour = vtk_colour
  143 + self.ren.Render()
  144 + self.interactor.Render()
137 145  
138 146  
  147 + def ChangeBrushActor(self, pubsub_evt):
  148 + brush_type = pubsub_evt.data
  149 + self.ren.RemoveActor(self.cursor.actor)
  150 +
  151 + if brush_type == 'square':
  152 + cursor = ca.CursorRectangle()
  153 + elif brush_type == 'circle':
  154 + cursor = ca.CursorCircle()
  155 + self.cursor = cursor
  156 +
  157 + cursor.SetOrientation(self.orientation)
  158 + coordinates = {"SAGITAL": [self.slice_number, 0, 0],
  159 + "CORONAL": [0, self.slice_number, 0],
  160 + "AXIAL": [0, 0, self.slice_number]}
  161 + cursor.SetPosition(coordinates[self.orientation])
  162 + cursor.SetSpacing(self.imagedata.GetSpacing())
  163 + cursor.SetColour(self._brush_cursor_colour)
  164 + cursor.SetSize(self.brush_cursor_size)
  165 + self.ren.AddActor(cursor.actor)
  166 + self.ren.Render()
  167 + self.interactor.Render()
  168 + self.cursor = cursor
  169 +
  170 +
139 171 def OnMouseClick(self, obj, evt_vtk):
140 172 self.mouse_pressed = 1
141 173  
... ... @@ -263,7 +295,11 @@ class Viewer(wx.Panel):
263 295 ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer')
264 296 ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position',
265 297 self.orientation))
  298 +
  299 + ###
266 300 ps.Publisher().subscribe(self.ChangeBrushSize,'Set edition brush size')
  301 + ps.Publisher().subscribe(self.ChangeBrushColour, 'Add mask')
  302 + ps.Publisher().subscribe(self.ChangeBrushActor, 'Set brush format')
267 303  
268 304 def __bind_events_wx(self):
269 305 self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar)
... ... @@ -373,6 +409,7 @@ class Viewer(wx.Panel):
373 409 def SetColour(self, pubsub_evt):
374 410 colour_wx = pubsub_evt.data
375 411 colour_vtk = [colour/float(255) for colour in colour_wx]
376   - #self.editor.SetColour(colour_vtk)
  412 + self._brush_cursor_colour = vtk_colour
  413 + self.cursor.SetColour(colour_vtk)
377 414 self.interactor.Render()
378 415  
... ...