Commit 08e6f1bdae672082c685fe7a010b4a1244238ad5
Committed by
GitHub
1 parent
794ea503
Exists in
master
Drag and drop support to measures in slices
* Created an class to keep measurements data * Picking only the slice actor when adding measure * Moving measure points * melhorias * Improvements * Improvements * Improvements * Improvements
Showing
5 changed files
with
324 additions
and
110 deletions
Show diff stats
invesalius/data/measures.py
@@ -10,6 +10,7 @@ import vtk | @@ -10,6 +10,7 @@ import vtk | ||
10 | import constants as const | 10 | import constants as const |
11 | import project as prj | 11 | import project as prj |
12 | import session as ses | 12 | import session as ses |
13 | +import utils | ||
13 | 14 | ||
14 | TYPE = {const.LINEAR: _(u"Linear"), | 15 | TYPE = {const.LINEAR: _(u"Linear"), |
15 | const.ANGULAR: _(u"Angular"), | 16 | const.ANGULAR: _(u"Angular"), |
@@ -21,6 +22,63 @@ LOCATION = {const.SURFACE: _(u"3D"), | @@ -21,6 +22,63 @@ LOCATION = {const.SURFACE: _(u"3D"), | ||
21 | const.SAGITAL: _(u"Sagittal") | 22 | const.SAGITAL: _(u"Sagittal") |
22 | } | 23 | } |
23 | 24 | ||
25 | +map_locations_id = { | ||
26 | + "3D": const.SURFACE, | ||
27 | + "AXIAL": const.AXIAL, | ||
28 | + "CORONAL": const.CORONAL, | ||
29 | + "SAGITAL": const.SAGITAL, | ||
30 | +} | ||
31 | + | ||
32 | +map_id_locations = {const.SURFACE: "3D", | ||
33 | + const.AXIAL: "AXIAL", | ||
34 | + const.CORONAL: "CORONAL", | ||
35 | + const.SAGITAL: "SAGITAL", | ||
36 | + } | ||
37 | + | ||
38 | +class MeasureData: | ||
39 | + """ | ||
40 | + Responsible to keep measures data. | ||
41 | + """ | ||
42 | + __metaclass__= utils.Singleton | ||
43 | + def __init__(self): | ||
44 | + self.measures = {const.SURFACE: {}, | ||
45 | + const.AXIAL: {}, | ||
46 | + const.CORONAL: {}, | ||
47 | + const.SAGITAL: {}} | ||
48 | + self._list_measures = [] | ||
49 | + | ||
50 | + def append(self, m): | ||
51 | + try: | ||
52 | + self.measures[m[0].location][m[0].slice_number].append(m) | ||
53 | + except KeyError: | ||
54 | + self.measures[m[0].location][m[0].slice_number] = [m, ] | ||
55 | + | ||
56 | + self._list_measures.append(m) | ||
57 | + | ||
58 | + def get(self, location, slice_number): | ||
59 | + return self.measures[map_locations_id[location]].get(slice_number, []) | ||
60 | + | ||
61 | + def pop(self, idx=None): | ||
62 | + if idx is None: | ||
63 | + m = self._list_measures.pop() | ||
64 | + else: | ||
65 | + m = self._list_measures.pop(idx) | ||
66 | + self.measures[m[0].location][m[0].slice_number].remove(m) | ||
67 | + return m | ||
68 | + | ||
69 | + def remove(self, m): | ||
70 | + self._list_measures.remove(m) | ||
71 | + self.measures[m[0].location][m[0].slice_number].remove(m) | ||
72 | + | ||
73 | + def __contains__(self, m): | ||
74 | + return m in self._list_measures | ||
75 | + | ||
76 | + def __getitem__(self, idx): | ||
77 | + return self._list_measures[idx] | ||
78 | + | ||
79 | + def __len__(self): | ||
80 | + return len(self._list_measures) | ||
81 | + | ||
24 | 82 | ||
25 | class MeasurementManager(object): | 83 | class MeasurementManager(object): |
26 | """ | 84 | """ |
@@ -29,7 +87,7 @@ class MeasurementManager(object): | @@ -29,7 +87,7 @@ class MeasurementManager(object): | ||
29 | """ | 87 | """ |
30 | def __init__(self): | 88 | def __init__(self): |
31 | self.current = None | 89 | self.current = None |
32 | - self.measures = [] | 90 | + self.measures = MeasureData() |
33 | self._bind_events() | 91 | self._bind_events() |
34 | 92 | ||
35 | def _bind_events(self): | 93 | def _bind_events(self): |
@@ -40,6 +98,7 @@ class MeasurementManager(object): | @@ -40,6 +98,7 @@ class MeasurementManager(object): | ||
40 | Publisher.subscribe(self._load_measurements, "Load measurement dict") | 98 | Publisher.subscribe(self._load_measurements, "Load measurement dict") |
41 | Publisher.subscribe(self._rm_incomplete_measurements, | 99 | Publisher.subscribe(self._rm_incomplete_measurements, |
42 | "Remove incomplete measurements") | 100 | "Remove incomplete measurements") |
101 | + Publisher.subscribe(self._change_measure_point_pos, 'Change measurement point position') | ||
43 | 102 | ||
44 | def _load_measurements(self, pubsub_evt): | 103 | def _load_measurements(self, pubsub_evt): |
45 | try: | 104 | try: |
@@ -49,7 +108,7 @@ class MeasurementManager(object): | @@ -49,7 +108,7 @@ class MeasurementManager(object): | ||
49 | spacing = 1.0, 1.0, 1.0 | 108 | spacing = 1.0, 1.0, 1.0 |
50 | for i in dict: | 109 | for i in dict: |
51 | m = dict[i] | 110 | m = dict[i] |
52 | - | 111 | + |
53 | if m.location == const.AXIAL: | 112 | if m.location == const.AXIAL: |
54 | radius = min(spacing[1], spacing[2]) * const.PROP_MEASURE | 113 | radius = min(spacing[1], spacing[2]) * const.PROP_MEASURE |
55 | 114 | ||
@@ -72,8 +131,10 @@ class MeasurementManager(object): | @@ -72,8 +131,10 @@ class MeasurementManager(object): | ||
72 | for point in m.points: | 131 | for point in m.points: |
73 | x, y, z = point | 132 | x, y, z = point |
74 | actors = mr.AddPoint(x, y, z) | 133 | actors = mr.AddPoint(x, y, z) |
75 | - Publisher.sendMessage(("Add actors " + str(m.location)), | ||
76 | - (actors, m.slice_number)) | 134 | + |
135 | + if m.location == const.SURFACE: | ||
136 | + Publisher.sendMessage(("Add actors " + str(m.location)), | ||
137 | + (actors, m.slice_number)) | ||
77 | self.current = None | 138 | self.current = None |
78 | 139 | ||
79 | if not m.is_shown: | 140 | if not m.is_shown: |
@@ -136,14 +197,15 @@ class MeasurementManager(object): | @@ -136,14 +197,15 @@ class MeasurementManager(object): | ||
136 | mr = AngularMeasure(m.colour, representation) | 197 | mr = AngularMeasure(m.colour, representation) |
137 | if to_remove: | 198 | if to_remove: |
138 | print "---To REMOVE" | 199 | print "---To REMOVE" |
139 | - actors = self.current[1].GetActors() | ||
140 | - slice_number = self.current[0].slice_number | ||
141 | - Publisher.sendMessage(('Remove actors ' + str(self.current[0].location)), | ||
142 | - (actors, slice_number)) | 200 | + # actors = self.current[1].GetActors() |
201 | + # slice_number = self.current[0].slice_number | ||
202 | + # Publisher.sendMessage(('Remove actors ' + str(self.current[0].location)), | ||
203 | + # (actors, slice_number)) | ||
204 | + self.measures.pop()[1].Remove() | ||
143 | if self.current[0].location == const.SURFACE: | 205 | if self.current[0].location == const.SURFACE: |
144 | Publisher.sendMessage('Render volume viewer') | 206 | Publisher.sendMessage('Render volume viewer') |
145 | else: | 207 | else: |
146 | - Publisher.sendMessage('Update slice viewer') | 208 | + Publisher.sendMessage('Reload actual slice') |
147 | 209 | ||
148 | session = ses.Session() | 210 | session = ses.Session() |
149 | session.ChangeProject() | 211 | session.ChangeProject() |
@@ -156,13 +218,17 @@ class MeasurementManager(object): | @@ -156,13 +218,17 @@ class MeasurementManager(object): | ||
156 | x, y, z = position | 218 | x, y, z = position |
157 | actors = mr.AddPoint(x, y, z) | 219 | actors = mr.AddPoint(x, y, z) |
158 | m.points.append(position) | 220 | m.points.append(position) |
159 | - Publisher.sendMessage("Add actors " + str(location), | ||
160 | - (actors, m.slice_number)) | 221 | + |
222 | + if m.location == const.SURFACE: | ||
223 | + Publisher.sendMessage("Add actors " + str(location), | ||
224 | + (actors, m.slice_number)) | ||
225 | + | ||
226 | + if self.current not in self.measures: | ||
227 | + self.measures.append(self.current) | ||
161 | 228 | ||
162 | if mr.IsComplete(): | 229 | if mr.IsComplete(): |
163 | index = prj.Project().AddMeasurement(m) | 230 | index = prj.Project().AddMeasurement(m) |
164 | #m.index = index # already done in proj | 231 | #m.index = index # already done in proj |
165 | - self.measures.append(self.current) | ||
166 | name = m.name | 232 | name = m.name |
167 | colour = m.colour | 233 | colour = m.colour |
168 | m.value = mr.GetValue() | 234 | m.value = mr.GetValue() |
@@ -181,19 +247,57 @@ class MeasurementManager(object): | @@ -181,19 +247,57 @@ class MeasurementManager(object): | ||
181 | value)) | 247 | value)) |
182 | self.current = None | 248 | self.current = None |
183 | 249 | ||
250 | + def _change_measure_point_pos(self, pubsub_evt): | ||
251 | + index, npoint, pos = pubsub_evt.data | ||
252 | + print index, npoint, pos | ||
253 | + m, mr = self.measures[index] | ||
254 | + x, y, z = pos | ||
255 | + if npoint == 0: | ||
256 | + mr.SetPoint1(x, y, z) | ||
257 | + m.points[0] = x, y, z | ||
258 | + elif npoint == 1: | ||
259 | + mr.SetPoint2(x, y, z) | ||
260 | + m.points[1] = x, y, z | ||
261 | + elif npoint == 2: | ||
262 | + mr.SetPoint3(x, y, z) | ||
263 | + m.points[2] = x, y, z | ||
264 | + | ||
265 | + m.value = mr.GetValue() | ||
266 | + | ||
267 | + name = m.name | ||
268 | + colour = m.colour | ||
269 | + m.value = mr.GetValue() | ||
270 | + type_ = TYPE[m.type] | ||
271 | + location = LOCATION[m.location] | ||
272 | + | ||
273 | + if m.type == const.LINEAR: | ||
274 | + value = u"%.2f mm"% m.value | ||
275 | + else: | ||
276 | + value = u"%.2f°"% m.value | ||
277 | + | ||
278 | + Publisher.sendMessage('Update measurement info in GUI', | ||
279 | + (index, name, colour, | ||
280 | + location, | ||
281 | + type_, | ||
282 | + value)) | ||
283 | + | ||
184 | def _change_name(self, pubsub_evt): | 284 | def _change_name(self, pubsub_evt): |
185 | index, new_name = pubsub_evt.data | 285 | index, new_name = pubsub_evt.data |
186 | - self.measures[index][0].name = new_name | 286 | + self.measures[index].name = new_name |
187 | 287 | ||
188 | def _remove_measurements(self, pubsub_evt): | 288 | def _remove_measurements(self, pubsub_evt): |
189 | indexes = pubsub_evt.data | 289 | indexes = pubsub_evt.data |
190 | - print indexes | ||
191 | for index in indexes: | 290 | for index in indexes: |
192 | m, mr = self.measures.pop(index) | 291 | m, mr = self.measures.pop(index) |
193 | - actors = mr.GetActors() | 292 | + try: |
293 | + mr.Remove() | ||
294 | + except AttributeError: | ||
295 | + # The is not being displayed | ||
296 | + pass | ||
194 | prj.Project().RemoveMeasurement(index) | 297 | prj.Project().RemoveMeasurement(index) |
195 | - Publisher.sendMessage(('Remove actors ' + str(m.location)), | ||
196 | - (actors, m.slice_number)) | 298 | + if m.location == const.SURFACE: |
299 | + Publisher.sendMessage(('Remove actors ' + str(m.location)), | ||
300 | + (mr.GetActors(), m.slice_number)) | ||
197 | Publisher.sendMessage('Update slice viewer') | 301 | Publisher.sendMessage('Update slice viewer') |
198 | Publisher.sendMessage('Render volume viewer') | 302 | Publisher.sendMessage('Render volume viewer') |
199 | 303 | ||
@@ -212,12 +316,13 @@ class MeasurementManager(object): | @@ -212,12 +316,13 @@ class MeasurementManager(object): | ||
212 | 316 | ||
213 | def _rm_incomplete_measurements(self, pubsub_evt): | 317 | def _rm_incomplete_measurements(self, pubsub_evt): |
214 | if self.current is None: | 318 | if self.current is None: |
215 | - return | 319 | + return |
216 | 320 | ||
217 | mr = self.current[1] | 321 | mr = self.current[1] |
218 | print "RM INC M", self.current, mr.IsComplete() | 322 | print "RM INC M", self.current, mr.IsComplete() |
219 | if not mr.IsComplete(): | 323 | if not mr.IsComplete(): |
220 | print "---To REMOVE" | 324 | print "---To REMOVE" |
325 | + self.measures.pop() | ||
221 | actors = mr.GetActors() | 326 | actors = mr.GetActors() |
222 | slice_number = self.current[0].slice_number | 327 | slice_number = self.current[0].slice_number |
223 | Publisher.sendMessage(('Remove actors ' + str(self.current[0].location)), | 328 | Publisher.sendMessage(('Remove actors ' + str(self.current[0].location)), |
@@ -364,6 +469,7 @@ class LinearMeasure(object): | @@ -364,6 +469,7 @@ class LinearMeasure(object): | ||
364 | self.point_actor2 = None | 469 | self.point_actor2 = None |
365 | self.line_actor = None | 470 | self.line_actor = None |
366 | self.text_actor = None | 471 | self.text_actor = None |
472 | + self.renderer = None | ||
367 | if not representation: | 473 | if not representation: |
368 | representation = CirclePointRepresentation(colour) | 474 | representation = CirclePointRepresentation(colour) |
369 | self.representation = representation | 475 | self.representation = representation |
@@ -384,13 +490,31 @@ class LinearMeasure(object): | @@ -384,13 +490,31 @@ class LinearMeasure(object): | ||
384 | return (self.point_actor2, self.line_actor, self.text_actor) | 490 | return (self.point_actor2, self.line_actor, self.text_actor) |
385 | 491 | ||
386 | def SetPoint1(self, x, y, z): | 492 | def SetPoint1(self, x, y, z): |
387 | - self.points.append((x, y, z)) | ||
388 | - self.point_actor1 = self.representation.GetRepresentation(x, y, z) | 493 | + if len(self.points) == 0: |
494 | + self.points.append((x, y, z)) | ||
495 | + self.point_actor1 = self.representation.GetRepresentation(x, y, z) | ||
496 | + else: | ||
497 | + self.points[0] = (x, y, z) | ||
498 | + if len(self.points) == 2: | ||
499 | + self.Remove() | ||
500 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
501 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
502 | + self.CreateMeasure() | ||
503 | + else: | ||
504 | + self.Remove() | ||
505 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
389 | 506 | ||
390 | def SetPoint2(self, x, y, z): | 507 | def SetPoint2(self, x, y, z): |
391 | - self.points.append((x, y, z)) | ||
392 | - self.point_actor2 = self.representation.GetRepresentation(x, y, z) | ||
393 | - self.CreateMeasure() | 508 | + if len(self.points) == 1: |
509 | + self.points.append((x, y, z)) | ||
510 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
511 | + self.CreateMeasure() | ||
512 | + else: | ||
513 | + self.points[1] = (x, y, z) | ||
514 | + self.Remove() | ||
515 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
516 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
517 | + self.CreateMeasure() | ||
394 | 518 | ||
395 | def CreateMeasure(self): | 519 | def CreateMeasure(self): |
396 | self._draw_line() | 520 | self._draw_line() |
@@ -432,6 +556,7 @@ class LinearMeasure(object): | @@ -432,6 +556,7 @@ class LinearMeasure(object): | ||
432 | a.GetPositionCoordinate().SetCoordinateSystemToWorld() | 556 | a.GetPositionCoordinate().SetCoordinateSystemToWorld() |
433 | a.GetPositionCoordinate().SetValue(x,y,z) | 557 | a.GetPositionCoordinate().SetValue(x,y,z) |
434 | a.GetProperty().SetColor((0, 1, 0)) | 558 | a.GetProperty().SetColor((0, 1, 0)) |
559 | + a.GetProperty().SetOpacity(0.75) | ||
435 | self.text_actor = a | 560 | self.text_actor = a |
436 | 561 | ||
437 | def GetNumberOfPoints(self): | 562 | def GetNumberOfPoints(self): |
@@ -443,22 +568,22 @@ class LinearMeasure(object): | @@ -443,22 +568,22 @@ class LinearMeasure(object): | ||
443 | 568 | ||
444 | def SetRenderer(self, renderer): | 569 | def SetRenderer(self, renderer): |
445 | if self.point_actor1: | 570 | if self.point_actor1: |
446 | - self.render.RemoveActor(self.point_actor1) | 571 | + self.renderer.RemoveActor(self.point_actor1) |
447 | renderer.AddActor(self.point_actor1) | 572 | renderer.AddActor(self.point_actor1) |
448 | 573 | ||
449 | if self.point_actor2: | 574 | if self.point_actor2: |
450 | - self.render.RemoveActor(self.point_actor2) | 575 | + self.renderer.RemoveActor(self.point_actor2) |
451 | renderer.AddActor(self.point_actor2) | 576 | renderer.AddActor(self.point_actor2) |
452 | 577 | ||
453 | if self.line_actor: | 578 | if self.line_actor: |
454 | - self.render.RemoveActor(self.line_actor) | 579 | + self.renderer.RemoveActor(self.line_actor) |
455 | renderer.AddActor(self.line_actor) | 580 | renderer.AddActor(self.line_actor) |
456 | 581 | ||
457 | if self.text_actor: | 582 | if self.text_actor: |
458 | - self.render.RemoveActor(self.text_actor) | 583 | + self.renderer.RemoveActor(self.text_actor) |
459 | renderer.AddActor(self.text_actor) | 584 | renderer.AddActor(self.text_actor) |
460 | 585 | ||
461 | - self.render = renderer | 586 | + self.renderer = renderer |
462 | 587 | ||
463 | def SetVisibility(self, v): | 588 | def SetVisibility(self, v): |
464 | self.point_actor1.SetVisibility(v) | 589 | self.point_actor1.SetVisibility(v) |
@@ -483,19 +608,19 @@ class LinearMeasure(object): | @@ -483,19 +608,19 @@ class LinearMeasure(object): | ||
483 | 608 | ||
484 | def Remove(self): | 609 | def Remove(self): |
485 | if self.point_actor1: | 610 | if self.point_actor1: |
486 | - self.render.RemoveActor(self.point_actor1) | 611 | + self.renderer.RemoveActor(self.point_actor1) |
487 | del self.point_actor1 | 612 | del self.point_actor1 |
488 | 613 | ||
489 | if self.point_actor2: | 614 | if self.point_actor2: |
490 | - self.render.RemoveActor(self.point_actor2) | 615 | + self.renderer.RemoveActor(self.point_actor2) |
491 | del self.point_actor2 | 616 | del self.point_actor2 |
492 | 617 | ||
493 | if self.line_actor: | 618 | if self.line_actor: |
494 | - self.render.RemoveActor(self.line_actor) | 619 | + self.renderer.RemoveActor(self.line_actor) |
495 | del self.line_actor | 620 | del self.line_actor |
496 | 621 | ||
497 | if self.text_actor: | 622 | if self.text_actor: |
498 | - self.render.RemoveActor(self.text_actor) | 623 | + self.renderer.RemoveActor(self.text_actor) |
499 | del self.text_actor | 624 | del self.text_actor |
500 | 625 | ||
501 | # def __del__(self): | 626 | # def __del__(self): |
@@ -532,20 +657,59 @@ class AngularMeasure(object): | @@ -532,20 +657,59 @@ class AngularMeasure(object): | ||
532 | return (self.point_actor3, self.line_actor, self.text_actor) | 657 | return (self.point_actor3, self.line_actor, self.text_actor) |
533 | 658 | ||
534 | def SetPoint1(self, x, y, z): | 659 | def SetPoint1(self, x, y, z): |
535 | - self.points[0] = (x, y, z) | ||
536 | - self.number_of_points = 1 | ||
537 | - self.point_actor1 = self.representation.GetRepresentation(x, y, z) | 660 | + if self.number_of_points == 0: |
661 | + self.points[0] = (x, y, z) | ||
662 | + self.number_of_points = 1 | ||
663 | + self.point_actor1 = self.representation.GetRepresentation(x, y, z) | ||
664 | + else: | ||
665 | + self.points[0] = (x, y, z) | ||
666 | + if len(self.points) == 3: | ||
667 | + self.Remove() | ||
668 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
669 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
670 | + self.point_actor3 = self.representation.GetRepresentation(*self.points[2]) | ||
671 | + self.CreateMeasure() | ||
672 | + else: | ||
673 | + self.Remove() | ||
674 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
675 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
538 | 676 | ||
539 | def SetPoint2(self, x, y, z): | 677 | def SetPoint2(self, x, y, z): |
540 | - self.number_of_points = 2 | ||
541 | - self.points[1] = (x, y, z) | ||
542 | - self.point_actor2 = self.representation.GetRepresentation(x, y, z) | 678 | + if self.number_of_points == 1: |
679 | + self.number_of_points = 2 | ||
680 | + self.points[1] = (x, y, z) | ||
681 | + self.point_actor2 = self.representation.GetRepresentation(x, y, z) | ||
682 | + else: | ||
683 | + self.points[1] = (x, y, z) | ||
684 | + if len(self.points) == 3: | ||
685 | + self.Remove() | ||
686 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
687 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
688 | + self.point_actor3 = self.representation.GetRepresentation(*self.points[2]) | ||
689 | + self.CreateMeasure() | ||
690 | + else: | ||
691 | + self.Remove() | ||
692 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
693 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
543 | 694 | ||
544 | def SetPoint3(self, x, y, z): | 695 | def SetPoint3(self, x, y, z): |
545 | - self.number_of_points = 3 | ||
546 | - self.points[2] = (x, y, z) | ||
547 | - self.point_actor3 = self.representation.GetRepresentation(x, y, z) | ||
548 | - self.CreateMeasure() | 696 | + if self.number_of_points == 2: |
697 | + self.number_of_points = 3 | ||
698 | + self.points[2] = (x, y, z) | ||
699 | + self.point_actor3 = self.representation.GetRepresentation(x, y, z) | ||
700 | + self.CreateMeasure() | ||
701 | + else: | ||
702 | + self.points[2] = (x, y, z) | ||
703 | + if len(self.points) == 3: | ||
704 | + self.Remove() | ||
705 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
706 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
707 | + self.point_actor3 = self.representation.GetRepresentation(*self.points[2]) | ||
708 | + self.CreateMeasure() | ||
709 | + else: | ||
710 | + self.Remove() | ||
711 | + self.point_actor1 = self.representation.GetRepresentation(*self.points[0]) | ||
712 | + self.point_actor2 = self.representation.GetRepresentation(*self.points[1]) | ||
549 | 713 | ||
550 | def CreateMeasure(self): | 714 | def CreateMeasure(self): |
551 | self._draw_line() | 715 | self._draw_line() |
@@ -677,47 +841,47 @@ class AngularMeasure(object): | @@ -677,47 +841,47 @@ class AngularMeasure(object): | ||
677 | 841 | ||
678 | def Remove(self): | 842 | def Remove(self): |
679 | if self.point_actor1: | 843 | if self.point_actor1: |
680 | - self.render.RemoveActor(self.point_actor1) | 844 | + self.renderer.RemoveActor(self.point_actor1) |
681 | del self.point_actor1 | 845 | del self.point_actor1 |
682 | 846 | ||
683 | if self.point_actor2: | 847 | if self.point_actor2: |
684 | - self.render.RemoveActor(self.point_actor2) | 848 | + self.renderer.RemoveActor(self.point_actor2) |
685 | del self.point_actor2 | 849 | del self.point_actor2 |
686 | 850 | ||
687 | if self.point_actor3: | 851 | if self.point_actor3: |
688 | - self.render.RemoveActor(self.point_actor3) | 852 | + self.renderer.RemoveActor(self.point_actor3) |
689 | del self.point_actor3 | 853 | del self.point_actor3 |
690 | 854 | ||
691 | if self.line_actor: | 855 | if self.line_actor: |
692 | - self.render.RemoveActor(self.line_actor) | 856 | + self.renderer.RemoveActor(self.line_actor) |
693 | del self.line_actor | 857 | del self.line_actor |
694 | 858 | ||
695 | if self.text_actor: | 859 | if self.text_actor: |
696 | - self.render.RemoveActor(self.text_actor) | 860 | + self.renderer.RemoveActor(self.text_actor) |
697 | del self.text_actor | 861 | del self.text_actor |
698 | 862 | ||
699 | def SetRenderer(self, renderer): | 863 | def SetRenderer(self, renderer): |
700 | if self.point_actor1: | 864 | if self.point_actor1: |
701 | - self.render.RemoveActor(self.point_actor1) | 865 | + self.renderer.RemoveActor(self.point_actor1) |
702 | renderer.AddActor(self.point_actor1) | 866 | renderer.AddActor(self.point_actor1) |
703 | 867 | ||
704 | if self.point_actor2: | 868 | if self.point_actor2: |
705 | - self.render.RemoveActor(self.point_actor2) | 869 | + self.renderer.RemoveActor(self.point_actor2) |
706 | renderer.AddActor(self.point_actor2) | 870 | renderer.AddActor(self.point_actor2) |
707 | 871 | ||
708 | if self.point_actor3: | 872 | if self.point_actor3: |
709 | - self.render.RemoveActor(self.point_actor3) | 873 | + self.renderer.RemoveActor(self.point_actor3) |
710 | renderer.AddActor(self.point_actor3) | 874 | renderer.AddActor(self.point_actor3) |
711 | 875 | ||
712 | if self.line_actor: | 876 | if self.line_actor: |
713 | - self.render.RemoveActor(self.line_actor) | 877 | + self.renderer.RemoveActor(self.line_actor) |
714 | renderer.AddActor(self.line_actor) | 878 | renderer.AddActor(self.line_actor) |
715 | 879 | ||
716 | if self.text_actor: | 880 | if self.text_actor: |
717 | - self.render.RemoveActor(self.text_actor) | 881 | + self.renderer.RemoveActor(self.text_actor) |
718 | renderer.AddActor(self.text_actor) | 882 | renderer.AddActor(self.text_actor) |
719 | 883 | ||
720 | - self.render = renderer | 884 | + self.renderer = renderer |
721 | 885 | ||
722 | # def __del__(self): | 886 | # def __del__(self): |
723 | # self.Remove() | 887 | # self.Remove() |
invesalius/data/styles.py
@@ -40,6 +40,8 @@ from scipy.ndimage import watershed_ift, generate_binary_structure | @@ -40,6 +40,8 @@ from scipy.ndimage import watershed_ift, generate_binary_structure | ||
40 | from skimage.morphology import watershed | 40 | from skimage.morphology import watershed |
41 | from skimage import filter | 41 | from skimage import filter |
42 | 42 | ||
43 | +from .measures import MeasureData | ||
44 | + | ||
43 | import watershed_process | 45 | import watershed_process |
44 | 46 | ||
45 | import utils | 47 | import utils |
@@ -350,78 +352,107 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle): | @@ -350,78 +352,107 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle): | ||
350 | self.orientation = viewer.orientation | 352 | self.orientation = viewer.orientation |
351 | self.slice_data = viewer.slice_data | 353 | self.slice_data = viewer.slice_data |
352 | 354 | ||
355 | + self.measures = MeasureData() | ||
356 | + self.selected = None | ||
357 | + | ||
358 | + self._type = const.LINEAR | ||
359 | + | ||
353 | spacing = self.slice_data.actor.GetInput().GetSpacing() | 360 | spacing = self.slice_data.actor.GetInput().GetSpacing() |
354 | 361 | ||
355 | if self.orientation == "AXIAL": | 362 | if self.orientation == "AXIAL": |
356 | self.radius = min(spacing[1], spacing[2]) * 0.8 | 363 | self.radius = min(spacing[1], spacing[2]) * 0.8 |
364 | + self._ori = const.AXIAL | ||
357 | 365 | ||
358 | elif self.orientation == 'CORONAL': | 366 | elif self.orientation == 'CORONAL': |
359 | self.radius = min(spacing[0], spacing[1]) * 0.8 | 367 | self.radius = min(spacing[0], spacing[1]) * 0.8 |
368 | + self._ori = const.CORONAL | ||
360 | 369 | ||
361 | elif self.orientation == 'SAGITAL': | 370 | elif self.orientation == 'SAGITAL': |
362 | self.radius = min(spacing[1], spacing[2]) * 0.8 | 371 | self.radius = min(spacing[1], spacing[2]) * 0.8 |
372 | + self._ori = const.SAGITAL | ||
363 | 373 | ||
364 | self.picker = vtk.vtkCellPicker() | 374 | self.picker = vtk.vtkCellPicker() |
375 | + self.picker.PickFromListOn() | ||
365 | 376 | ||
377 | + self._bind_events() | ||
378 | + | ||
379 | + def _bind_events(self): | ||
366 | self.AddObserver("LeftButtonPressEvent", self.OnInsertLinearMeasurePoint) | 380 | self.AddObserver("LeftButtonPressEvent", self.OnInsertLinearMeasurePoint) |
381 | + self.AddObserver("LeftButtonReleaseEvent", self.OnReleaseMeasurePoint) | ||
382 | + self.AddObserver("MouseMoveEvent", self.OnMoveMeasurePoint) | ||
367 | 383 | ||
368 | def OnInsertLinearMeasurePoint(self, obj, evt): | 384 | def OnInsertLinearMeasurePoint(self, obj, evt): |
369 | - iren = obj.GetInteractor() | ||
370 | - x,y = iren.GetEventPosition() | ||
371 | - render = iren.FindPokedRenderer(x, y) | ||
372 | slice_number = self.slice_data.number | 385 | slice_number = self.slice_data.number |
373 | - self.picker.Pick(x, y, 0, render) | ||
374 | - x, y, z = self.picker.GetPickPosition() | ||
375 | - if self.picker.GetViewProp(): | ||
376 | - Publisher.sendMessage("Add measurement point", | ||
377 | - ((x, y,z), const.LINEAR, | ||
378 | - ORIENTATIONS[self.orientation], | ||
379 | - slice_number, self.radius)) | ||
380 | - self.viewer.interactor.Render() | 386 | + x, y, z = self._get_pos_clicked() |
387 | + | ||
388 | + selected = self._verify_clicked(x, y, z) | ||
389 | + if selected: | ||
390 | + self.selected = selected | ||
391 | + else: | ||
392 | + if self.picker.GetViewProp(): | ||
393 | + renderer = self.viewer.slice_data.renderer | ||
394 | + Publisher.sendMessage("Add measurement point", | ||
395 | + ((x, y,z), self._type, | ||
396 | + ORIENTATIONS[self.orientation], | ||
397 | + slice_number, self.radius)) | ||
398 | + Publisher.sendMessage('Reload actual slice %s' % self.orientation) | ||
399 | + | ||
400 | + def OnReleaseMeasurePoint(self, obj, evt): | ||
401 | + if self.selected: | ||
402 | + n, m, mr = self.selected | ||
403 | + x, y, z = self._get_pos_clicked() | ||
404 | + idx = self.measures._list_measures.index((m, mr)) | ||
405 | + Publisher.sendMessage('Change measurement point position', (idx, n, (x, y, z))) | ||
406 | + Publisher.sendMessage('Reload actual slice %s' % self.orientation) | ||
407 | + self.selected = None | ||
408 | + | ||
409 | + def OnMoveMeasurePoint(self, obj, evt): | ||
410 | + if self.selected: | ||
411 | + n, m, mr = self.selected | ||
412 | + x, y, z = self._get_pos_clicked() | ||
413 | + idx = self.measures._list_measures.index((m, mr)) | ||
414 | + Publisher.sendMessage('Change measurement point position', (idx, n, (x, y, z))) | ||
415 | + | ||
416 | + Publisher.sendMessage('Reload actual slice %s' % self.orientation) | ||
381 | 417 | ||
382 | def CleanUp(self): | 418 | def CleanUp(self): |
419 | + self.picker.PickFromListOff() | ||
383 | Publisher.sendMessage("Remove incomplete measurements") | 420 | Publisher.sendMessage("Remove incomplete measurements") |
384 | 421 | ||
422 | + def _get_pos_clicked(self): | ||
423 | + iren = self.viewer.interactor | ||
424 | + mx,my = iren.GetEventPosition() | ||
425 | + render = iren.FindPokedRenderer(mx, my) | ||
426 | + self.picker.AddPickList(self.slice_data.actor) | ||
427 | + self.picker.Pick(mx, my, 0, render) | ||
428 | + x, y, z = self.picker.GetPickPosition() | ||
429 | + self.picker.DeletePickList(self.slice_data.actor) | ||
430 | + return (x, y, z) | ||
385 | 431 | ||
386 | -class AngularMeasureInteractorStyle(DefaultInteractorStyle): | ||
387 | - """ | ||
388 | - Interactor style responsible for insert angular measurements. | ||
389 | - """ | ||
390 | - def __init__(self, viewer): | ||
391 | - DefaultInteractorStyle.__init__(self, viewer) | ||
392 | - | ||
393 | - self.viewer = viewer | ||
394 | - self.orientation = viewer.orientation | ||
395 | - self.slice_data = viewer.slice_data | ||
396 | - | ||
397 | - spacing = self.slice_data.actor.GetInput().GetSpacing() | ||
398 | - | ||
399 | - if self.orientation == "AXIAL": | ||
400 | - self.radius = min(spacing[1], spacing[2]) * 0.8 | ||
401 | - | ||
402 | - elif self.orientation == 'CORONAL': | ||
403 | - self.radius = min(spacing[0], spacing[1]) * 0.8 | ||
404 | - | ||
405 | - elif self.orientation == 'SAGITAL': | ||
406 | - self.radius = min(spacing[1], spacing[2]) * 0.8 | ||
407 | - | ||
408 | - self.picker = vtk.vtkCellPicker() | ||
409 | - | ||
410 | - self.AddObserver("LeftButtonPressEvent", self.OnInsertAngularMeasurePoint) | ||
411 | - | ||
412 | - def OnInsertAngularMeasurePoint(self, obj, evt): | ||
413 | - iren = obj.GetInteractor() | ||
414 | - x,y = iren.GetEventPosition() | ||
415 | - render = iren.FindPokedRenderer(x, y) | 432 | + def _verify_clicked(self, x, y, z): |
416 | slice_number = self.slice_data.number | 433 | slice_number = self.slice_data.number |
417 | - self.picker.Pick(x, y, 0, render) | ||
418 | - x, y, z = self.picker.GetPickPosition() | ||
419 | - if self.picker.GetViewProp(): | ||
420 | - Publisher.sendMessage("Add measurement point", | ||
421 | - ((x, y,z), const.ANGULAR, | ||
422 | - ORIENTATIONS[self.orientation], | ||
423 | - slice_number, self.radius)) | ||
424 | - self.viewer.interactor.Render() | 434 | + sx, sy, sz = self.viewer.slice_.spacing |
435 | + if self.orientation == "AXIAL": | ||
436 | + max_dist = 2 * max(sx, sy) | ||
437 | + elif self.orientation == "CORONAL": | ||
438 | + max_dist = 2 * max(sx, sz) | ||
439 | + elif self.orientation == "SAGITAL": | ||
440 | + max_dist = 2 * max(sy, sz) | ||
441 | + | ||
442 | + if slice_number in self.measures.measures[self._ori]: | ||
443 | + for m, mr in self.measures.measures[self._ori][slice_number]: | ||
444 | + if mr.IsComplete(): | ||
445 | + for n, p in enumerate(m.points): | ||
446 | + px, py, pz = p | ||
447 | + dist = ((px-x)**2 + (py-y)**2 + (pz-z)**2)**0.5 | ||
448 | + if dist < max_dist: | ||
449 | + return (n, m, mr) | ||
450 | + return None | ||
451 | + | ||
452 | +class AngularMeasureInteractorStyle(LinearMeasureInteractorStyle): | ||
453 | + def __init__(self, viewer): | ||
454 | + LinearMeasureInteractorStyle.__init__(self, viewer) | ||
455 | + self._type = const.ANGULAR | ||
425 | 456 | ||
426 | 457 | ||
427 | class PanMoveInteractorStyle(DefaultInteractorStyle): | 458 | class PanMoveInteractorStyle(DefaultInteractorStyle): |
invesalius/data/viewer_slice.py
@@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
19 | # detalhes. | 19 | # detalhes. |
20 | #-------------------------------------------------------------------------- | 20 | #-------------------------------------------------------------------------- |
21 | 21 | ||
22 | +import collections | ||
22 | import itertools | 23 | import itertools |
23 | import tempfile | 24 | import tempfile |
24 | 25 | ||
@@ -171,8 +172,8 @@ class Viewer(wx.Panel): | @@ -171,8 +172,8 @@ class Viewer(wx.Panel): | ||
171 | self.layout = (1, 1) | 172 | self.layout = (1, 1) |
172 | self.orientation_texts = [] | 173 | self.orientation_texts = [] |
173 | 174 | ||
174 | - self.measures = [] | ||
175 | - self.actors_by_slice_number = {} | 175 | + self.measures = measures.MeasureData() |
176 | + self.actors_by_slice_number = collections.defaultdict(list) | ||
176 | self.renderers_by_slice_number = {} | 177 | self.renderers_by_slice_number = {} |
177 | 178 | ||
178 | self.orientation = orientation | 179 | self.orientation = orientation |
@@ -1178,11 +1179,20 @@ class Viewer(wx.Panel): | @@ -1178,11 +1179,20 @@ class Viewer(wx.Panel): | ||
1178 | image = self.slice_.GetSlices(self.orientation, index, | 1179 | image = self.slice_.GetSlices(self.orientation, index, |
1179 | self.number_slices, inverted, border_size) | 1180 | self.number_slices, inverted, border_size) |
1180 | self.slice_data.actor.SetInputData(image) | 1181 | self.slice_data.actor.SetInputData(image) |
1181 | - for actor in self.actors_by_slice_number.get(self.slice_data.number, []): | 1182 | + for actor in self.actors_by_slice_number[self.slice_data.number]: |
1182 | self.slice_data.renderer.RemoveActor(actor) | 1183 | self.slice_data.renderer.RemoveActor(actor) |
1183 | - for actor in self.actors_by_slice_number.get(index, []): | 1184 | + for actor in self.actors_by_slice_number[index]: |
1184 | self.slice_data.renderer.AddActor(actor) | 1185 | self.slice_data.renderer.AddActor(actor) |
1185 | 1186 | ||
1187 | + for (m, mr) in self.measures.get(self.orientation, self.slice_data.number): | ||
1188 | + for actor in mr.GetActors(): | ||
1189 | + self.slice_data.renderer.RemoveActor(actor) | ||
1190 | + | ||
1191 | + for (m, mr) in self.measures.get(self.orientation, index): | ||
1192 | + mr.renderer = self.slice_data.renderer | ||
1193 | + for actor in mr.GetActors(): | ||
1194 | + self.slice_data.renderer.AddActor(actor) | ||
1195 | + | ||
1186 | if self.slice_._type_projection == const.PROJECTION_NORMAL: | 1196 | if self.slice_._type_projection == const.PROJECTION_NORMAL: |
1187 | self.slice_data.SetNumber(index) | 1197 | self.slice_data.SetNumber(index) |
1188 | else: | 1198 | else: |
@@ -1239,10 +1249,7 @@ class Viewer(wx.Panel): | @@ -1239,10 +1249,7 @@ class Viewer(wx.Panel): | ||
1239 | for actor in actors: | 1249 | for actor in actors: |
1240 | self.slice_data.renderer.AddActor(actor) | 1250 | self.slice_data.renderer.AddActor(actor) |
1241 | 1251 | ||
1242 | - try: | ||
1243 | - self.actors_by_slice_number[n].extend(actors) | ||
1244 | - except KeyError: | ||
1245 | - self.actors_by_slice_number[n] = list(actors) | 1252 | + self.actors_by_slice_number[n].extend(actors) |
1246 | 1253 | ||
1247 | def RemoveActors(self, pubsub_evt): | 1254 | def RemoveActors(self, pubsub_evt): |
1248 | "Remove a list of actors" | 1255 | "Remove a list of actors" |
invesalius/gui/data_notebook.py
@@ -1127,6 +1127,8 @@ class MeasuresListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin): | @@ -1127,6 +1127,8 @@ class MeasuresListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin): | ||
1127 | self.UpdateItemInfo(index, name, colour, location, type_, value) | 1127 | self.UpdateItemInfo(index, name, colour, location, type_, value) |
1128 | else: | 1128 | else: |
1129 | self.InsertNewItem(index, name, colour, location, type_, value) | 1129 | self.InsertNewItem(index, name, colour, location, type_, value) |
1130 | + else: | ||
1131 | + self.UpdateItemInfo(index, name, colour, location, type_, value) | ||
1130 | 1132 | ||
1131 | 1133 | ||
1132 | 1134 |
invesalius/utils.py
@@ -23,6 +23,8 @@ import re | @@ -23,6 +23,8 @@ import re | ||
23 | import locale | 23 | import locale |
24 | import math | 24 | import math |
25 | 25 | ||
26 | +import numpy as np | ||
27 | + | ||
26 | def format_time(value): | 28 | def format_time(value): |
27 | sp1 = value.split(".") | 29 | sp1 = value.split(".") |
28 | sp2 = value.split(":") | 30 | sp2 = value.split(":") |
@@ -418,3 +420,11 @@ def UpdateCheck(): | @@ -418,3 +420,11 @@ def UpdateCheck(): | ||
418 | if (last!=const.INVESALIUS_VERSION): | 420 | if (last!=const.INVESALIUS_VERSION): |
419 | print " ...New update found!!! -> version:", last #, ", url=",url | 421 | print " ...New update found!!! -> version:", last #, ", url=",url |
420 | wx.CallAfter(wx.CallLater, 1000, _show_update_info) | 422 | wx.CallAfter(wx.CallLater, 1000, _show_update_info) |
423 | + | ||
424 | + | ||
425 | +def vtkarray_to_numpy(m): | ||
426 | + nm = np.zeros((4, 4)) | ||
427 | + for i in xrange(4): | ||
428 | + for j in xrange(4): | ||
429 | + nm[i, j] = m.GetElement(i, j) | ||
430 | + return nm |