Commit 0f30fe61b8c6b18f491c123b13f7fae165c26f7e
1 parent
259d97fe
Exists in
master
and in
6 other branches
ADD: Initial works in measures
Showing
7 changed files
with
394 additions
and
16 deletions
Show diff stats
.gitattributes
@@ -141,6 +141,7 @@ invesalius/data/cursor_actors.py -text | @@ -141,6 +141,7 @@ invesalius/data/cursor_actors.py -text | ||
141 | invesalius/data/editor.py -text | 141 | invesalius/data/editor.py -text |
142 | invesalius/data/imagedata_utils.py -text | 142 | invesalius/data/imagedata_utils.py -text |
143 | invesalius/data/mask.py -text | 143 | invesalius/data/mask.py -text |
144 | +invesalius/data/measures.py -text | ||
144 | invesalius/data/orientation.py -text | 145 | invesalius/data/orientation.py -text |
145 | invesalius/data/polydata_utils.py -text | 146 | invesalius/data/polydata_utils.py -text |
146 | invesalius/data/slice_.py -text | 147 | invesalius/data/slice_.py -text |
invesalius/constants.py
@@ -350,6 +350,7 @@ MODE_ZOOM_SELECTION = 1 #:"Set Zoom Select Mode", | @@ -350,6 +350,7 @@ MODE_ZOOM_SELECTION = 1 #:"Set Zoom Select Mode", | ||
350 | MODE_ROTATE = 2#:"Set Spin Mode", | 350 | MODE_ROTATE = 2#:"Set Spin Mode", |
351 | MODE_MOVE = 3#:"Set Pan Mode", | 351 | MODE_MOVE = 3#:"Set Pan Mode", |
352 | MODE_WW_WL = 4#:"Bright and contrast adjustment"} | 352 | MODE_WW_WL = 4#:"Bright and contrast adjustment"} |
353 | +MODE_LINEAR_MEASURE = 5 | ||
353 | 354 | ||
354 | 355 | ||
355 | # self.states = {0:"Set Zoom Mode", 1:"Set Zoom Select Mode", | 356 | # self.states = {0:"Set Zoom Mode", 1:"Set Zoom Select Mode", |
@@ -431,6 +432,7 @@ SLICE_STATE_CROSS = 1006 | @@ -431,6 +432,7 @@ SLICE_STATE_CROSS = 1006 | ||
431 | SLICE_STATE_SCROLL = 1007 | 432 | SLICE_STATE_SCROLL = 1007 |
432 | SLICE_STATE_EDITOR = 1008 | 433 | SLICE_STATE_EDITOR = 1008 |
433 | VOLUME_STATE_SEED = 2001 | 434 | VOLUME_STATE_SEED = 2001 |
435 | +STATE_LINEAR_MEASURE = 3001 | ||
434 | 436 | ||
435 | 437 | ||
436 | TOOL_STATES = [ STATE_WL, STATE_SPIN, STATE_ZOOM, | 438 | TOOL_STATES = [ STATE_WL, STATE_SPIN, STATE_ZOOM, |
@@ -443,7 +445,7 @@ SLICE_STYLES = TOOL_STATES + TOOL_SLICE_STATES | @@ -443,7 +445,7 @@ SLICE_STYLES = TOOL_STATES + TOOL_SLICE_STATES | ||
443 | SLICE_STYLES.append(STATE_DEFAULT) | 445 | SLICE_STYLES.append(STATE_DEFAULT) |
444 | SLICE_STYLES.append(SLICE_STATE_EDITOR) | 446 | SLICE_STYLES.append(SLICE_STATE_EDITOR) |
445 | 447 | ||
446 | -VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED] | 448 | +VOLUME_STYLES = TOOL_STATES + [VOLUME_STATE_SEED, STATE_LINEAR_MEASURE] |
447 | VOLUME_STYLES.append(STATE_DEFAULT) | 449 | VOLUME_STYLES.append(STATE_DEFAULT) |
448 | 450 | ||
449 | 451 | ||
@@ -456,4 +458,5 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, | @@ -456,4 +458,5 @@ STYLE_LEVEL = {SLICE_STATE_EDITOR: 1, | ||
456 | STATE_ZOOM: 2, | 458 | STATE_ZOOM: 2, |
457 | STATE_ZOOM_SL: 2, | 459 | STATE_ZOOM_SL: 2, |
458 | STATE_PAN:2, | 460 | STATE_PAN:2, |
459 | - VOLUME_STATE_SEED:1} | 461 | + VOLUME_STATE_SEED:1, |
462 | + STATE_LINEAR_MEASURE: 2} |
@@ -0,0 +1,341 @@ | @@ -0,0 +1,341 @@ | ||
1 | +#!/usr/bin/env python | ||
2 | +# -*- coding: UTF-8 -*- | ||
3 | + | ||
4 | +# This example demonstrates the use of vtkSTLReader to load data into | ||
5 | +# VTK from a file. This example also uses vtkLODActor which changes | ||
6 | +# its graphical representation of the data to maintain interactive | ||
7 | +# performance. | ||
8 | + | ||
9 | +import wx | ||
10 | +import sys | ||
11 | +import os | ||
12 | +import time | ||
13 | +import math | ||
14 | + | ||
15 | +from itertools import cycle | ||
16 | +from wx.grid import Grid, GridCellBoolRenderer, GridCellBoolEditor, EVT_GRID_CELL_CHANGE | ||
17 | + | ||
18 | +import vtk | ||
19 | +from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor | ||
20 | + | ||
21 | +class CirclePointRepresentation(object): | ||
22 | + """ | ||
23 | + This class represents a circle that indicate a point in the surface | ||
24 | + """ | ||
25 | + def __init__(self, color=(1, 0, 0), radius=1.0): | ||
26 | + """ | ||
27 | + color: the color of the representation | ||
28 | + radius: the radius of circle representation | ||
29 | + """ | ||
30 | + self.color = color | ||
31 | + self.radius = radius | ||
32 | + | ||
33 | + def GetRepresentation(self, x, y, z): | ||
34 | + """ | ||
35 | + Return a actor that represents the point in the given x, y, z point | ||
36 | + """ | ||
37 | + sphere = vtk.vtkSphereSource() | ||
38 | + sphere.SetCenter(x, y, z) | ||
39 | + sphere.SetRadius(self.radius) | ||
40 | + | ||
41 | + c = vtk.vtkCoordinate() | ||
42 | + c.SetCoordinateSystemToWorld() | ||
43 | + | ||
44 | + m = vtk.vtkPolyDataMapper2D() | ||
45 | + m.SetInputConnection(sphere.GetOutputPort()) | ||
46 | + m.SetTransformCoordinate(c) | ||
47 | + | ||
48 | + a = vtk.vtkActor2D() | ||
49 | + a.SetMapper(m) | ||
50 | + a.GetProperty().SetColor(self.color) | ||
51 | + | ||
52 | + return a | ||
53 | + | ||
54 | +class CrossPointRepresentation(object): | ||
55 | + """ | ||
56 | + This class represents a cross that indicate a point in the surface | ||
57 | + """ | ||
58 | + def __init__(self, camera, color=(1, 0, 0), size=1.0): | ||
59 | + """ | ||
60 | + color: the color of the representation | ||
61 | + size: the size of the representation | ||
62 | + camera: the active camera, to get the orientation to draw the cross | ||
63 | + """ | ||
64 | + self.camera = camera | ||
65 | + self.color = color | ||
66 | + self.size = size | ||
67 | + | ||
68 | + def GetRepresentation(self, x, y, z): | ||
69 | + pc = self.camera.GetPosition() # camera position | ||
70 | + pf = self.camera.GetFocalPoint() # focal position | ||
71 | + pp = (x, y, z) # point where the user clicked | ||
72 | + | ||
73 | + # Vector from camera position to user clicked point | ||
74 | + vcp = [j-i for i,j in zip(pc, pp)] | ||
75 | + # Vector from camera position to camera focal point | ||
76 | + vcf = [j-i for i,j in zip(pc, pf)] | ||
77 | + # the vector where the perpendicular vector will be given | ||
78 | + n = [0,0,0] | ||
79 | + # The cross, or vectorial product, give a vector perpendicular to vcp | ||
80 | + # and vcf, in this case this vector will be in horizontal, this vector | ||
81 | + # will be stored in the variable "n" | ||
82 | + vtk.vtkMath.Cross(vcp, vcf, n) | ||
83 | + # then normalize n to only indicate the direction of this vector | ||
84 | + vtk.vtkMath.Normalize(n) | ||
85 | + # then | ||
86 | + p1 = [i*self.size + j for i,j in zip(n, pp)] | ||
87 | + p2 = [i*-self.size + j for i,j in zip(n, pp)] | ||
88 | + | ||
89 | + sh = vtk.vtkLineSource() | ||
90 | + sh.SetPoint1(p1) | ||
91 | + sh.SetPoint2(p2) | ||
92 | + | ||
93 | + n = [0,0,0] | ||
94 | + vcn = [j-i for i,j in zip(p1, pc)] | ||
95 | + vtk.vtkMath.Cross(vcp, vcn, n) | ||
96 | + vtk.vtkMath.Normalize(n) | ||
97 | + p3 = [i*self.size + j for i,j in zip(n, pp)] | ||
98 | + p4 = [i*-self.size +j for i,j in zip(n, pp)] | ||
99 | + | ||
100 | + sv = vtk.vtkLineSource() | ||
101 | + sv.SetPoint1(p3) | ||
102 | + sv.SetPoint2(p4) | ||
103 | + | ||
104 | + cruz = vtk.vtkAppendPolyData() | ||
105 | + cruz.AddInput(sv.GetOutput()) | ||
106 | + cruz.AddInput(sh.GetOutput()) | ||
107 | + | ||
108 | + c = vtk.vtkCoordinate() | ||
109 | + c.SetCoordinateSystemToWorld() | ||
110 | + | ||
111 | + m = vtk.vtkPolyDataMapper2D() | ||
112 | + m.SetInputConnection(cruz.GetOutputPort()) | ||
113 | + m.SetTransformCoordinate(c) | ||
114 | + | ||
115 | + a = vtk.vtkActor2D() | ||
116 | + a.SetMapper(m) | ||
117 | + a.GetProperty().SetColor(self.color) | ||
118 | + return a | ||
119 | + | ||
120 | +class LinearMeasure(object): | ||
121 | + def __init__(self, render, color=(1, 0, 0), representation=None): | ||
122 | + self.color = color | ||
123 | + self.points = [] | ||
124 | + self.point_actor1 = None | ||
125 | + self.point_actor2 = None | ||
126 | + self.line_actor = None | ||
127 | + self.render = render | ||
128 | + if not representation: | ||
129 | + representation = CirclePointRepresentation() | ||
130 | + self.representation = representation | ||
131 | + print color | ||
132 | + | ||
133 | + def SetPoint1(self, x, y, z): | ||
134 | + self.points.append((x, y, z)) | ||
135 | + self.point_actor1 = self.representation.GetRepresentation(x, y, z) | ||
136 | + self.render.AddActor(self.point_actor1) | ||
137 | + | ||
138 | + def SetPoint2(self, x, y, z): | ||
139 | + self.points.append((x, y, z)) | ||
140 | + self.point_actor2 = self.representation.GetRepresentation(x, y, z) | ||
141 | + self.render.AddActor(self.point_actor2) | ||
142 | + self.CreateMeasure() | ||
143 | + | ||
144 | + def CreateMeasure(self): | ||
145 | + self._draw_line() | ||
146 | + self._draw_text() | ||
147 | + | ||
148 | + def _draw_line(self): | ||
149 | + line = vtk.vtkLineSource() | ||
150 | + line.SetPoint1(self.points[0]) | ||
151 | + line.SetPoint2(self.points[1]) | ||
152 | + | ||
153 | + c = vtk.vtkCoordinate() | ||
154 | + c.SetCoordinateSystemToWorld() | ||
155 | + | ||
156 | + m = vtk.vtkPolyDataMapper2D() | ||
157 | + m.SetInputConnection(line.GetOutputPort()) | ||
158 | + m.SetTransformCoordinate(c) | ||
159 | + | ||
160 | + a = vtk.vtkActor2D() | ||
161 | + a.SetMapper(m) | ||
162 | + a.GetProperty().SetColor(self.color) | ||
163 | + self.line_actor = a | ||
164 | + self.render.AddActor(self.line_actor) | ||
165 | + | ||
166 | + def _draw_text(self): | ||
167 | + p1, p2 = self.points | ||
168 | + text = ' %.2f mm ' % \ | ||
169 | + math.sqrt(vtk.vtkMath.Distance2BetweenPoints(p1, p2)) | ||
170 | + x,y,z=[(i+j)/2 for i,j in zip(p1, p2)] | ||
171 | + textsource = vtk.vtkTextSource() | ||
172 | + textsource.SetText(text) | ||
173 | + textsource.SetBackgroundColor((250/255.0, 247/255.0, 218/255.0)) | ||
174 | + textsource.SetForegroundColor(self.color) | ||
175 | + | ||
176 | + m = vtk.vtkPolyDataMapper2D() | ||
177 | + m.SetInputConnection(textsource.GetOutputPort()) | ||
178 | + | ||
179 | + a = vtk.vtkActor2D() | ||
180 | + a.SetMapper(m) | ||
181 | + a.DragableOn() | ||
182 | + a.GetPositionCoordinate().SetCoordinateSystemToWorld() | ||
183 | + a.GetPositionCoordinate().SetValue(x,y,z) | ||
184 | + self.text_actor = a | ||
185 | + self.render.AddActor(self.text_actor) | ||
186 | + | ||
187 | + def GetNumberOfPoints(self): | ||
188 | + return len(self.points) | ||
189 | + | ||
190 | + def GetValue(self): | ||
191 | + p1, p2 = self.points | ||
192 | + return math.sqrt(vtk.vtkMath.Distance2BetweenPoints(p1, p2)) | ||
193 | + | ||
194 | + def SetVisibility(self, v): | ||
195 | + self.point_actor1.SetVisibility(v) | ||
196 | + self.point_actor2.SetVisibility(v) | ||
197 | + self.line_actor.SetVisibility(v) | ||
198 | + self.text_actor.SetVisibility(v) | ||
199 | + | ||
200 | + | ||
201 | +class AngularMeasure(object): | ||
202 | + def __init__(self, render, color=(1, 0, 0), representation=None): | ||
203 | + self.color = color | ||
204 | + self.points = [0, 0, 0] | ||
205 | + self.number_of_points = 0 | ||
206 | + self.point_actor1 = None | ||
207 | + self.point_actor2 = None | ||
208 | + self.point_actor3 = None | ||
209 | + self.line_actor = None | ||
210 | + self.render = render | ||
211 | + if not representation: | ||
212 | + representation = CirclePointRepresentation() | ||
213 | + self.representation = representation | ||
214 | + print color | ||
215 | + | ||
216 | + def SetPoint1(self, x, y, z): | ||
217 | + self.points[0] = (x, y, z) | ||
218 | + self.number_of_points = 1 | ||
219 | + self.point_actor1 = self.representation.GetRepresentation(x, y, z) | ||
220 | + self.render.AddActor(self.point_actor1) | ||
221 | + | ||
222 | + def SetPoint2(self, x, y, z): | ||
223 | + self.number_of_points = 2 | ||
224 | + self.points[1] = (x, y, z) | ||
225 | + self.point_actor2 = self.representation.GetRepresentation(x, y, z) | ||
226 | + self.render.AddActor(self.point_actor2) | ||
227 | + | ||
228 | + def SetPoint3(self, x, y, z): | ||
229 | + self.number_of_points = 3 | ||
230 | + self.points[2] = (x, y, z) | ||
231 | + self.point_actor3 = self.representation.GetRepresentation(x, y, z) | ||
232 | + self.render.AddActor(self.point_actor3) | ||
233 | + | ||
234 | + def _draw_line(self): | ||
235 | + line1 = vtk.vtkLineSource() | ||
236 | + line1.SetPoint1(self.points[0]) | ||
237 | + line1.SetPoint2(self.points[1]) | ||
238 | + | ||
239 | + line2 = vtk.vtkLineSource() | ||
240 | + line2.SetPoint1(self.points[1]) | ||
241 | + line2.SetPoint2(self.points[2]) | ||
242 | + | ||
243 | + arc = self.DrawArc() | ||
244 | + | ||
245 | + line = vtk.vtkAppendPolyData() | ||
246 | + line.AddInput(line1.GetOutput()) | ||
247 | + line.AddInput(line2.GetOutput()) | ||
248 | + line.AddInput(arc.GetOutput()) | ||
249 | + | ||
250 | + c = vtk.vtkCoordinate() | ||
251 | + c.SetCoordinateSystemToWorld() | ||
252 | + | ||
253 | + m = vtk.vtkPolyDataMapper2D() | ||
254 | + m.SetInputConnection(line.GetOutputPort()) | ||
255 | + m.SetTransformCoordinate(c) | ||
256 | + | ||
257 | + a = vtk.vtkActor2D() | ||
258 | + a.SetMapper(m) | ||
259 | + a.GetProperty().SetColor(self.color) | ||
260 | + self.line_actor = a | ||
261 | + return a | ||
262 | + | ||
263 | + def DrawArc(self): | ||
264 | + | ||
265 | + d1 = math.sqrt(vtk.vtkMath.Distance2BetweenPoints(self.points[0], | ||
266 | + self.points[1])) | ||
267 | + d2 = math.sqrt(vtk.vtkMath.Distance2BetweenPoints(self.points[2], | ||
268 | + self.points[1])) | ||
269 | + | ||
270 | + if d1 < d2: | ||
271 | + d = d1 | ||
272 | + p1 = self.points[0] | ||
273 | + a,b,c = [j-i for i,j in zip(self.points[1], self.points[2])] | ||
274 | + else: | ||
275 | + d = d2 | ||
276 | + p1 = self.points[2] | ||
277 | + a,b,c = [j-i for i,j in zip(self.points[1], self.points[0])] | ||
278 | + | ||
279 | + t = (d / math.sqrt(a**2 + b**2 + c**2)) | ||
280 | + x = self.points[1][0] + a*t | ||
281 | + y = self.points[1][1] + b*t | ||
282 | + z = self.points[1][2] + c*t | ||
283 | + p2 = (x, y, z) | ||
284 | + | ||
285 | + arc = vtk.vtkArcSource() | ||
286 | + arc.SetPoint1(p1) | ||
287 | + arc.SetPoint2(p2) | ||
288 | + arc.SetCenter(self.points[1]) | ||
289 | + arc.SetResolution(20) | ||
290 | + return arc | ||
291 | + | ||
292 | + def _draw_text(self): | ||
293 | + text = u' %.2f ' % \ | ||
294 | + self.CalculateAngle() | ||
295 | + x,y,z= self.points[1] | ||
296 | + textsource = vtk.vtkTextSource() | ||
297 | + textsource.SetText(text) | ||
298 | + textsource.SetBackgroundColor((250/255.0, 247/255.0, 218/255.0)) | ||
299 | + textsource.SetForegroundColor(self.color) | ||
300 | + | ||
301 | + m = vtk.vtkPolyDataMapper2D() | ||
302 | + m.SetInputConnection(textsource.GetOutputPort()) | ||
303 | + | ||
304 | + a = vtk.vtkActor2D() | ||
305 | + a.SetMapper(m) | ||
306 | + a.DragableOn() | ||
307 | + a.GetPositionCoordinate().SetCoordinateSystemToWorld() | ||
308 | + a.GetPositionCoordinate().SetValue(x,y,z) | ||
309 | + self.text_actor = a | ||
310 | + return a | ||
311 | + | ||
312 | + def GetNumberOfPoints(self): | ||
313 | + return self.number_of_points | ||
314 | + | ||
315 | + def GetValue(self): | ||
316 | + return self.CalculateAngle() | ||
317 | + | ||
318 | + def SetVisibility(self, v): | ||
319 | + self.point_actor1.SetVisibility(v) | ||
320 | + self.point_actor2.SetVisibility(v) | ||
321 | + self.point_actor3.SetVisibility(v) | ||
322 | + self.line_actor.SetVisibility(v) | ||
323 | + self.text_actor.SetVisibility(v) | ||
324 | + | ||
325 | + def CalculateAngle(self): | ||
326 | + """ | ||
327 | + Calculate the angle between 2 vectors in 3D space. It is based on law of | ||
328 | + cosines for vector. | ||
329 | + The Alpha Cosine is equal the dot product from two vector divided for | ||
330 | + product between the magnitude from that vectors. Then the angle is inverse | ||
331 | + cosine. | ||
332 | + """ | ||
333 | + v1 = [j-i for i,j in zip(self.points[0], self.points[1])] | ||
334 | + v2 = [j-i for i,j in zip(self.points[2], self.points[1])] | ||
335 | + #print vtk.vtkMath.Normalize(v1) | ||
336 | + #print vtk.vtkMath.Normalize(v2) | ||
337 | + cos = vtk.vtkMath.Dot(v1, v2)/(vtk.vtkMath.Norm(v1)*vtk.vtkMath.Norm(v2)) | ||
338 | + angle = math.degrees(math.acos(cos)) | ||
339 | + return angle | ||
340 | + | ||
341 | + |
invesalius/data/viewer_volume.py
@@ -30,6 +30,8 @@ import project as prj | @@ -30,6 +30,8 @@ import project as prj | ||
30 | import style as st | 30 | import style as st |
31 | import utils | 31 | import utils |
32 | 32 | ||
33 | +from data import measures | ||
34 | + | ||
33 | class Viewer(wx.Panel): | 35 | class Viewer(wx.Panel): |
34 | def __init__(self, parent): | 36 | def __init__(self, parent): |
35 | wx.Panel.__init__(self, parent, size=wx.Size(320, 320)) | 37 | wx.Panel.__init__(self, parent, size=wx.Size(320, 320)) |
@@ -88,6 +90,10 @@ class Viewer(wx.Panel): | @@ -88,6 +90,10 @@ class Viewer(wx.Panel): | ||
88 | self.seed_points = [] | 90 | self.seed_points = [] |
89 | 91 | ||
90 | self.points_reference = [] | 92 | self.points_reference = [] |
93 | + | ||
94 | + self.measure_picker = vtk.vtkPointPicker() | ||
95 | + self.measure_picker.SetTolerance(0.005) | ||
96 | + self.measures = [] | ||
91 | 97 | ||
92 | 98 | ||
93 | def __bind_events(self): | 99 | def __bind_events(self): |
@@ -287,7 +293,11 @@ class Viewer(wx.Panel): | @@ -287,7 +293,11 @@ class Viewer(wx.Panel): | ||
287 | const.VOLUME_STATE_SEED: | 293 | const.VOLUME_STATE_SEED: |
288 | { | 294 | { |
289 | "LeftButtonPressEvent": self.OnInsertSeed | 295 | "LeftButtonPressEvent": self.OnInsertSeed |
290 | - } | 296 | + }, |
297 | + const.STATE_LINEAR_MEASURE: | ||
298 | + { | ||
299 | + "LeftButtonPressEvent": self.OnInsertLinearMeasurePoint | ||
300 | + } | ||
291 | } | 301 | } |
292 | 302 | ||
293 | if state == const.STATE_WL: | 303 | if state == const.STATE_WL: |
@@ -309,6 +319,9 @@ class Viewer(wx.Panel): | @@ -309,6 +319,9 @@ class Viewer(wx.Panel): | ||
309 | self.interactor.SetInteractorStyle(style) | 319 | self.interactor.SetInteractorStyle(style) |
310 | self.style = style | 320 | self.style = style |
311 | 321 | ||
322 | + if state == const.STATE_LINEAR_MEASURE: | ||
323 | + self.interactor.SetPicker(self.measure_picker) | ||
324 | + | ||
312 | # Check each event available for each mode | 325 | # Check each event available for each mode |
313 | for event in action[state]: | 326 | for event in action[state]: |
314 | # Bind event | 327 | # Bind event |
@@ -590,6 +603,21 @@ class Viewer(wx.Panel): | @@ -590,6 +603,21 @@ class Viewer(wx.Panel): | ||
590 | self.seed_points.append(point_id) | 603 | self.seed_points.append(point_id) |
591 | self.interactor.Render() | 604 | self.interactor.Render() |
592 | 605 | ||
606 | + def OnInsertLinearMeasurePoint(self, obj, evt): | ||
607 | + print "Hey, you inserted measure point" | ||
608 | + x,y = self.interactor.GetEventPosition() | ||
609 | + self.measure_picker.Pick(x, y, 0, self.ren) | ||
610 | + x, y, z = self.measure_picker.GetPickPosition() | ||
611 | + if self.measure_picker.GetPointId() != -1: | ||
612 | + if not self.measures or self.measures[-1].point_actor2: | ||
613 | + m = measures.LinearMeasure(self.ren) | ||
614 | + m.SetPoint1(x, y, z) | ||
615 | + self.measures.append(m) | ||
616 | + else: | ||
617 | + m = self.measures[-1] | ||
618 | + m.SetPoint2(x, y, z) | ||
619 | + self.interactor.Render() | ||
620 | + | ||
593 | 621 | ||
594 | class SlicePlane: | 622 | class SlicePlane: |
595 | def __init__(self): | 623 | def __init__(self): |
invesalius/gui/data_notebook.py
@@ -50,8 +50,8 @@ class NotebookPanel(wx.Panel): | @@ -50,8 +50,8 @@ class NotebookPanel(wx.Panel): | ||
50 | 50 | ||
51 | book.AddPage(MaskPage(book), _("Masks")) | 51 | book.AddPage(MaskPage(book), _("Masks")) |
52 | book.AddPage(SurfacePage(book), _("Surfaces")) | 52 | book.AddPage(SurfacePage(book), _("Surfaces")) |
53 | - #book.AddPage(MeasuresListCtrlPanel(book), _("Measures")) | ||
54 | - #book.AddPage(AnnotationsListCtrlPanel(book), _("Annotations")) | 53 | + book.AddPage(MeasuresListCtrlPanel(book), _("Measures")) |
54 | + book.AddPage(AnnotationsListCtrlPanel(book), _("Annotations")) | ||
55 | 55 | ||
56 | book.SetSelection(0) | 56 | book.SetSelection(0) |
57 | 57 |
invesalius/gui/default_tasks.py
@@ -144,15 +144,15 @@ class LowerTaskPanel(wx.Panel): | @@ -144,15 +144,15 @@ class LowerTaskPanel(wx.Panel): | ||
144 | # Fold 2 - Tools | 144 | # Fold 2 - Tools |
145 | # Measures | 145 | # Measures |
146 | # Text Annotations | 146 | # Text Annotations |
147 | - #item = fold_panel.AddFoldPanel(_("Tools"), collapsed=False, | ||
148 | - # foldIcons=image_list) | ||
149 | - #style = fold_panel.GetCaptionStyle(item) | ||
150 | - #col = style.GetFirstColour() | ||
151 | - #self.enable_items.append(item) | ||
152 | - # | ||
153 | - #fold_panel.AddFoldPanelWindow(item, tools.TaskPanel(item), Spacing= 0, | ||
154 | - # leftSpacing=0, rightSpacing=0) | ||
155 | - #fold_panel.Expand(fold_panel.GetFoldPanel(1)) | 147 | + item = fold_panel.AddFoldPanel(_("Tools"), collapsed=False, |
148 | + foldIcons=image_list) | ||
149 | + style = fold_panel.GetCaptionStyle(item) | ||
150 | + col = style.GetFirstColour() | ||
151 | + self.enable_items.append(item) | ||
152 | + | ||
153 | + fold_panel.AddFoldPanelWindow(item, tools.TaskPanel(item), Spacing= 0, | ||
154 | + leftSpacing=0, rightSpacing=0) | ||
155 | + fold_panel.Expand(fold_panel.GetFoldPanel(1)) | ||
156 | 156 | ||
157 | self.SetStateProjectClose() | 157 | self.SetStateProjectClose() |
158 | self.__bind_events() | 158 | self.__bind_events() |
invesalius/gui/task_tools.py
@@ -18,9 +18,12 @@ | @@ -18,9 +18,12 @@ | ||
18 | #-------------------------------------------------------------------------- | 18 | #-------------------------------------------------------------------------- |
19 | 19 | ||
20 | import wx | 20 | import wx |
21 | +import wx.lib.embeddedimage as emb | ||
21 | import wx.lib.hyperlink as hl | 22 | import wx.lib.hyperlink as hl |
22 | import wx.lib.platebtn as pbtn | 23 | import wx.lib.platebtn as pbtn |
23 | -import wx.lib.embeddedimage as emb | 24 | +import wx.lib.pubsub as ps |
25 | + | ||
26 | +import constants | ||
24 | 27 | ||
25 | ID_BTN_MEASURE_LINEAR = wx.NewId() | 28 | ID_BTN_MEASURE_LINEAR = wx.NewId() |
26 | ID_BTN_MEASURE_ANGULAR = wx.NewId() | 29 | ID_BTN_MEASURE_ANGULAR = wx.NewId() |
@@ -118,7 +121,9 @@ class InnerTaskPanel(wx.Panel): | @@ -118,7 +121,9 @@ class InnerTaskPanel(wx.Panel): | ||
118 | print "TODO: Send Signal - Add text annotation (both 2d and 3d)" | 121 | print "TODO: Send Signal - Add text annotation (both 2d and 3d)" |
119 | 122 | ||
120 | def OnLinkLinearMeasure(self): | 123 | def OnLinkLinearMeasure(self): |
121 | - print "TODO: Send Signal - Add linear measure (both 2d and 3d)" | 124 | + #print "TODO: Send Signal - Add linear measure (both 2d and 3d)" |
125 | + ps.Publisher().sendMessage('Enable style', | ||
126 | + constants.STATE_LINEAR_MEASURE) | ||
122 | 127 | ||
123 | def OnLinkAngularMeasure(self): | 128 | def OnLinkAngularMeasure(self): |
124 | print "TODO: Send Signal - Add angular measure (both 2d and 3d)" | 129 | print "TODO: Send Signal - Add angular measure (both 2d and 3d)" |