Commit b4ead449f1844e991b016736ee4a0764162ccde9
1 parent
4014a308
Exists in
master
and in
68 other branches
ADD: Editor brush - change type, change size, change colour
Showing
2 changed files
with
224 additions
and
17 deletions
Show diff stats
invesalius/data/cursor_actors.py
1 | from math import * | 1 | from math import * |
2 | + | ||
2 | import vtk | 3 | import vtk |
4 | +import wx.lib.pubsub as ps | ||
5 | + | ||
3 | import utils | 6 | import utils |
4 | 7 | ||
5 | class CursorCircle: | 8 | class CursorCircle: |
@@ -10,7 +13,7 @@ class CursorCircle: | @@ -10,7 +13,7 @@ class CursorCircle: | ||
10 | 13 | ||
11 | self.colour = (0.0, 0.0, 1.0) | 14 | self.colour = (0.0, 0.0, 1.0) |
12 | self.opacity = 1 | 15 | self.opacity = 1 |
13 | - self.radius = 20 | 16 | + self.radius = 15.0 |
14 | self.position = (0 ,0, 1) | 17 | self.position = (0 ,0, 1) |
15 | self.points = [] | 18 | self.points = [] |
16 | self.orientation = "AXIAL" | 19 | self.orientation = "AXIAL" |
@@ -22,7 +25,8 @@ class CursorCircle: | @@ -22,7 +25,8 @@ class CursorCircle: | ||
22 | 25 | ||
23 | self.__build_actor() | 26 | self.__build_actor() |
24 | self.__calculate_area_pixels() | 27 | self.__calculate_area_pixels() |
25 | - | 28 | + |
29 | + | ||
26 | def __build_actor(self): | 30 | def __build_actor(self): |
27 | """ | 31 | """ |
28 | Function to plot the circle | 32 | Function to plot the circle |
@@ -75,14 +79,15 @@ class CursorCircle: | @@ -75,14 +79,15 @@ class CursorCircle: | ||
75 | for k in utils.frange(xi,xf,xs): | 79 | for k in utils.frange(xi,xf,xs): |
76 | self.pixel_list.append((k, yi)) | 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 | self.disk.SetInnerRadius(radius-1) # filled = self.radius | 84 | self.disk.SetInnerRadius(radius-1) # filled = self.radius |
81 | - self.disk.SetOuterRadius(radius) # filled = 0x | 85 | + self.disk.SetOuterRadius(radius) # filled = 0 |
82 | self.__calculate_area_pixels() | 86 | self.__calculate_area_pixels() |
83 | 87 | ||
84 | def SetColour(self, colour): | 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 | def SetOrientation(self, orientation): | 92 | def SetOrientation(self, orientation): |
88 | self.orientation = orientation | 93 | self.orientation = orientation |
@@ -94,13 +99,120 @@ class CursorCircle: | @@ -94,13 +99,120 @@ class CursorCircle: | ||
94 | self.actor.RotateY(90) | 99 | self.actor.RotateY(90) |
95 | 100 | ||
96 | def SetPosition(self, position): | 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 | self.position = position | 216 | self.position = position |
105 | self.actor.SetPosition(position) | 217 | self.actor.SetPosition(position) |
106 | 218 | ||
@@ -110,7 +222,64 @@ class CursorCircle: | @@ -110,7 +222,64 @@ class CursorCircle: | ||
110 | def SetSpacing(self, spacing): | 222 | def SetSpacing(self, spacing): |
111 | self.spacing = spacing | 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 | def GetPixels(self): | 279 | def GetPixels(self): |
280 | + """ | ||
281 | + Return the points of the rectangle | ||
282 | + """ | ||
114 | px, py, pz = self.edition_position | 283 | px, py, pz = self.edition_position |
115 | orient = self.orientation | 284 | orient = self.orientation |
116 | xs, ys, zs = self.spacing | 285 | xs, ys, zs = self.spacing |
@@ -119,7 +288,8 @@ class CursorCircle: | @@ -119,7 +288,8 @@ class CursorCircle: | ||
119 | # the area, and not the cursor position). | 288 | # the area, and not the cursor position). |
120 | # Let's calculate the absolute position | 289 | # Let's calculate the absolute position |
121 | # TODO: Optimize this!!!! | 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 | \ No newline at end of file | 296 | \ No newline at end of file |
invesalius/data/viewer_slice.py
@@ -131,11 +131,43 @@ class Viewer(wx.Panel): | @@ -131,11 +131,43 @@ class Viewer(wx.Panel): | ||
131 | 131 | ||
132 | def ChangeBrushSize(self, pubsub_evt): | 132 | def ChangeBrushSize(self, pubsub_evt): |
133 | size = pubsub_evt.data | 133 | size = pubsub_evt.data |
134 | + self.brush_cursor_size = size | ||
134 | self.cursor.SetSize(size) | 135 | self.cursor.SetSize(size) |
135 | self.ren.Render() | 136 | self.ren.Render() |
136 | self.interactor.Render() | 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 | def OnMouseClick(self, obj, evt_vtk): | 171 | def OnMouseClick(self, obj, evt_vtk): |
140 | self.mouse_pressed = 1 | 172 | self.mouse_pressed = 1 |
141 | 173 | ||
@@ -263,7 +295,11 @@ class Viewer(wx.Panel): | @@ -263,7 +295,11 @@ class Viewer(wx.Panel): | ||
263 | ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer') | 295 | ps.Publisher().subscribe(self.UpdateRender, 'Update slice viewer') |
264 | ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position', | 296 | ps.Publisher().subscribe(self.ChangeSliceNumber, ('Set scroll position', |
265 | self.orientation)) | 297 | self.orientation)) |
298 | + | ||
299 | + ### | ||
266 | ps.Publisher().subscribe(self.ChangeBrushSize,'Set edition brush size') | 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 | def __bind_events_wx(self): | 304 | def __bind_events_wx(self): |
269 | self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar) | 305 | self.scroll.Bind(wx.EVT_SCROLL, self.OnScrollBar) |
@@ -373,6 +409,7 @@ class Viewer(wx.Panel): | @@ -373,6 +409,7 @@ class Viewer(wx.Panel): | ||
373 | def SetColour(self, pubsub_evt): | 409 | def SetColour(self, pubsub_evt): |
374 | colour_wx = pubsub_evt.data | 410 | colour_wx = pubsub_evt.data |
375 | colour_vtk = [colour/float(255) for colour in colour_wx] | 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 | self.interactor.Render() | 414 | self.interactor.Render() |
378 | 415 |