Commit 275f57c077a2a1e48e2dd3fb77761cd9d1b1bc1e

Authored by tfmoraes
1 parent 2cfc3302

ENH: Using MeasureManager

invesalius/constants.py
... ... @@ -28,7 +28,7 @@ from project import Project
28 28 #---------------
29 29  
30 30 # Measurements
31   -MEASURE_NAME_PATTERN = _("M %d")
  31 +MEASURE_NAME_PATTERN = _("M %d")
32 32 MEASURE_LINEAR = 101
33 33 MEASURE_ANGULAR = 102
34 34  
... ... @@ -79,6 +79,10 @@ SAGITAL = 3
79 79 VOLUME = 4
80 80 SURFACE = 5
81 81  
  82 +# Measure type
  83 +LINEAR = 6
  84 +ANGULAR = 7
  85 +
82 86 # Colour representing each orientation
83 87 ORIENTATION_COLOUR = {'AXIAL': (1,0,0), # Red
84 88 'CORONAL': (0,1,0), # Green
... ...
invesalius/control.py
... ... @@ -24,16 +24,16 @@ import tempfile
24 24 import wx.lib.pubsub as ps
25 25  
26 26 import constants as const
27   -import project as prj
28   -
29 27 import data.imagedata_utils as utils
30 28 import data.mask as msk
  29 +import data.measures
31 30 import data.surface as srf
32 31 import data.volume as volume
33   -import reader.dicom_grouper as dg
34 32 import gui.dialogs as dialog
35   -import reader.dicom_reader as dcm
  33 +import project as prj
36 34 import reader.analyze_reader as analyze
  35 +import reader.dicom_grouper as dg
  36 +import reader.dicom_reader as dcm
37 37 import session as ses
38 38  
39 39 from utils import debug
... ... @@ -51,6 +51,8 @@ class Controller():
51 51 self.cancel_import = False
52 52 #Init session
53 53 session = ses.Session()
  54 + self.measure_manager = data.measures.MeasurementManager()
  55 +
54 56  
55 57 def __bind_events(self):
56 58 ps.Publisher().subscribe(self.OnImportMedicalImages, 'Import directory')
... ...
invesalius/data/measures.py
1 1 #!/usr/bin/env python
2 2 # -*- coding: UTF-8 -*-
3 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   -
10   -from itertools import cycle
11 4 import math
12   -import os
13   -import sys
14   -import time
  5 +import random
15 6  
16   -import wx
  7 +import wx.lib.pubsub as ps
17 8 import vtk
18 9  
19 10 import constants as const
20 11  
  12 +TYPE = {const.LINEAR: _(u"Linear"),
  13 + const.ANGULAR: _(u"Angular"),
  14 + }
  15 +
  16 +LOCATION = {const.SURFACE: _(u"3D"),
  17 + const.AXIAL: _(u"Axial"),
  18 + const.CORONAL: _(u"Coronal"),
  19 + const.SAGITAL: _(u"Sagittal")
  20 + }
  21 +
  22 +class MeasurementManager(object):
  23 + """
  24 + A class to manage the use (Addition, remotion and visibility) from
  25 + measures.
  26 + """
  27 + def __init__(self):
  28 + self.current = None
  29 + self.measures = []
  30 + self._bind_events()
  31 +
  32 + def _bind_events(self):
  33 + ps.Publisher().subscribe(self._add_point, "Add measurement point")
  34 +
  35 + def _add_point(self, pubsub_evt):
  36 + position = pubsub_evt.data[0]
  37 + type = pubsub_evt.data[1] # Linear or Angular
  38 + location = pubsub_evt.data[2] # 3D, AXIAL, SAGITAL, CORONAL
  39 + try:
  40 + slice_number = pubsub_evt.data[3]
  41 + except IndexError:
  42 + slice_number = 0
  43 +
  44 + if self.current is None:
  45 + to_create = True
  46 + elif self.current[0].slice_number != slice_number:
  47 + to_create = True
  48 + elif self.current[0].location != location:
  49 + to_create = True
  50 + else:
  51 + to_create = False
  52 +
  53 + if to_create:
  54 + m = Measurement()
  55 + m.location = location
  56 + m.points.append(position)
  57 + m.slice_number = slice_number
  58 + if type == const.LINEAR:
  59 + mr = LinearMeasure(m.colour)
  60 + else:
  61 + mr = AngularMeasure(m.colour)
  62 + self.current = (m, mr)
  63 +
  64 + x, y, z = position
  65 + actors = self.current[1].AddPoint(x, y, z)
  66 + ps.Publisher().sendMessage(("Add Actors", location), actors)
  67 +
  68 + if self.current[1].IsComplete():
  69 + self.measures.append(self.current)
  70 + index = self.current[0].index
  71 + name = self.current[0].name
  72 + colour = self.current[0].colour
  73 + self.current[0].value = self.current[1].GetValue()
  74 + type_ = TYPE[type]
  75 + location = LOCATION[location]
  76 + value = u"%.2f mm"% self.current[0].value
  77 +
  78 + msg = 'Update measurement info in GUI',
  79 + ps.Publisher().sendMessage(msg,
  80 + (index, name, colour,
  81 + type_, location,
  82 + value))
  83 + self.current = None
  84 +
  85 +
  86 +
21 87 class Measurement():
22 88 general_index = -1
23 89 def __init__(self):
... ... @@ -28,6 +94,7 @@ class Measurement():
28 94 self.value = None
29 95 self.location = const.SURFACE # AXIAL, CORONAL, SAGITTAL
30 96 self.type = const.LINEAR # ANGULAR
  97 + self.slice_number = 0
31 98 self.points = []
32 99 self.is_shown = False
33 100  
... ... @@ -131,16 +198,15 @@ class CrossPointRepresentation(object):
131 198 return a
132 199  
133 200 class LinearMeasure(object):
134   - def __init__(self, render, colour=(1, 0, 0), representation=None):
  201 + def __init__(self, colour=(1, 0, 0), representation=None):
135 202 self.colour = colour
136 203 self.points = []
137 204 self.point_actor1 = None
138 205 self.point_actor2 = None
139 206 self.line_actor = None
140 207 self.text_actor = None
141   - self.render = render
142 208 if not representation:
143   - representation = CirclePointRepresentation()
  209 + representation = CirclePointRepresentation(colour)
144 210 self.representation = representation
145 211 print colour
146 212  
... ... @@ -153,18 +219,18 @@ class LinearMeasure(object):
153 219 def AddPoint(self, x, y, z):
154 220 if not self.point_actor1:
155 221 self.SetPoint1(x, y, z)
  222 + return (self.point_actor1, )
156 223 elif not self.point_actor2:
157 224 self.SetPoint2(x, y, z)
  225 + return (self.point_actor2, self.line_actor, self.text_actor)
158 226  
159 227 def SetPoint1(self, x, y, z):
160 228 self.points.append((x, y, z))
161 229 self.point_actor1 = self.representation.GetRepresentation(x, y, z)
162   - self.render.AddActor(self.point_actor1)
163 230  
164 231 def SetPoint2(self, x, y, z):
165 232 self.points.append((x, y, z))
166 233 self.point_actor2 = self.representation.GetRepresentation(x, y, z)
167   - self.render.AddActor(self.point_actor2)
168 234 self.CreateMeasure()
169 235  
170 236 def CreateMeasure(self):
... ... @@ -187,7 +253,6 @@ class LinearMeasure(object):
187 253 a.SetMapper(m)
188 254 a.GetProperty().SetColor(self.colour)
189 255 self.line_actor = a
190   - self.render.AddActor(self.line_actor)
191 256  
192 257 def _draw_text(self):
193 258 p1, p2 = self.points
... ... @@ -207,8 +272,8 @@ class LinearMeasure(object):
207 272 a.DragableOn()
208 273 a.GetPositionCoordinate().SetCoordinateSystemToWorld()
209 274 a.GetPositionCoordinate().SetValue(x,y,z)
  275 + a.GetProperty().SetColor((0, 1, 0))
210 276 self.text_actor = a
211   - self.render.AddActor(self.text_actor)
212 277  
213 278 def GetNumberOfPoints(self):
214 279 return len(self.points)
... ... @@ -264,7 +329,7 @@ class LinearMeasure(object):
264 329  
265 330  
266 331 class AngularMeasure(object):
267   - def __init__(self, render, colour=(1, 0, 0), representation=None):
  332 + def __init__(self, colour=(1, 0, 0), representation=None):
268 333 self.colour = colour
269 334 self.points = [0, 0, 0]
270 335 self.number_of_points = 0
... ... @@ -273,9 +338,8 @@ class AngularMeasure(object):
273 338 self.point_actor3 = None
274 339 self.line_actor = None
275 340 self.text_actor = None
276   - self.render = render
277 341 if not representation:
278   - representation = CirclePointRepresentation()
  342 + representation = CirclePointRepresentation(colour)
279 343 self.representation = representation
280 344 print colour
281 345  
... ... @@ -285,28 +349,28 @@ class AngularMeasure(object):
285 349 def AddPoint(self, x, y, z):
286 350 if not self.point_actor1:
287 351 self.SetPoint1(x, y, z)
  352 + return (self.point_actor1,)
288 353 elif not self.point_actor2:
289 354 self.SetPoint2(x, y, z)
  355 + return (self.point_actor2,)
290 356 elif not self.point_actor3:
291 357 self.SetPoint3(x, y, z)
  358 + return (self.point_actor3, self.line_actor, self.text_actor)
292 359  
293 360 def SetPoint1(self, x, y, z):
294 361 self.points[0] = (x, y, z)
295 362 self.number_of_points = 1
296 363 self.point_actor1 = self.representation.GetRepresentation(x, y, z)
297   - self.render.AddActor(self.point_actor1)
298 364  
299 365 def SetPoint2(self, x, y, z):
300 366 self.number_of_points = 2
301 367 self.points[1] = (x, y, z)
302 368 self.point_actor2 = self.representation.GetRepresentation(x, y, z)
303   - self.render.AddActor(self.point_actor2)
304 369  
305 370 def SetPoint3(self, x, y, z):
306 371 self.number_of_points = 3
307 372 self.points[2] = (x, y, z)
308 373 self.point_actor3 = self.representation.GetRepresentation(x, y, z)
309   - self.render.AddActor(self.point_actor3)
310 374 self.CreateMeasure()
311 375  
312 376 def CreateMeasure(self):
... ... @@ -340,7 +404,6 @@ class AngularMeasure(object):
340 404 a.SetMapper(m)
341 405 a.GetProperty().SetColor(self.colour)
342 406 self.line_actor = a
343   - self.render.AddActor(self.line_actor)
344 407  
345 408 def DrawArc(self):
346 409  
... ... @@ -389,7 +452,6 @@ class AngularMeasure(object):
389 452 a.GetPositionCoordinate().SetCoordinateSystemToWorld()
390 453 a.GetPositionCoordinate().SetValue(x,y,z)
391 454 self.text_actor = a
392   - self.render.AddActor(self.text_actor)
393 455  
394 456 def GetNumberOfPoints(self):
395 457 return self.number_of_points
... ...
invesalius/data/viewer_slice.py
... ... @@ -44,9 +44,9 @@ ID_TO_TOOL_ITEM = {}
44 44 STR_WL = "WL: %d WW: %d"
45 45  
46 46 ORIENTATIONS = {
47   - "AXIAL": _("Axial"),
48   - "CORONAL": _("Coronal"),
49   - "SAGITAL": _("Sagital"),
  47 + "AXIAL": const.AXIAL,
  48 + "CORONAL": const.CORONAL,
  49 + "SAGITAL": const.SAGITAL,
50 50 }
51 51  
52 52 class Viewer(wx.Panel):
... ... @@ -863,6 +863,8 @@ class Viewer(wx.Panel):
863 863 ps.Publisher().subscribe(self.OnExportPicture,'Export picture to file')
864 864 ps.Publisher().subscribe(self.SetDefaultCursor, 'Set interactor default cursor')
865 865  
  866 + ps.Publisher().subscribe(self.AddActors, ('Add Actors', ORIENTATIONS[self.orientation]))
  867 +
866 868 def SetDefaultCursor(self, pusub_evt):
867 869 self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
868 870  
... ... @@ -1444,17 +1446,21 @@ class Viewer(wx.Panel):
1444 1446 x, y, z = self.pick.GetPickPosition()
1445 1447 if self.pick.GetViewProp():
1446 1448 print "Hey, you inserted measure point"
1447   - if not self.measures or self.measures[-1][1].IsComplete():
1448   - m = measures.LinearMeasure(render)
1449   - m.AddPoint(x, y, z)
1450   - self.measures.append((slice_number, m))
1451   - else:
1452   - m = self.measures[-1][1]
1453   - m.AddPoint(x, y, z)
1454   - if m.IsComplete():
1455   - ps.Publisher().sendMessage("Add measure to list",
1456   - (ORIENTATIONS[self.orientation],
1457   - _(u"%.3f mm" % m.GetValue())))
  1449 + # if not self.measures or self.measures[-1][1].IsComplete():
  1450 + # m = measures.LinearMeasure(render)
  1451 + # m.AddPoint(x, y, z)
  1452 + # self.measures.append((slice_number, m))
  1453 + # else:
  1454 + # m = self.measures[-1][1]
  1455 + # m.AddPoint(x, y, z)
  1456 + # if m.IsComplete():
  1457 + # ps.Publisher().sendMessage("Add measure to list",
  1458 + # (ORIENTATIONS[self.orientation],
  1459 + # _(u"%.3f mm" % m.GetValue())))
  1460 + self.render_to_add = slice_data.renderer
  1461 + ps.Publisher().sendMessage("Add measurement point",
  1462 + ((x, y,z), const.LINEAR, ORIENTATIONS[self.orientation],
  1463 + slice_number))
1458 1464 self.interactor.Render()
1459 1465  
1460 1466 def OnInsertAngularMeasurePoint(self, obj, evt):
... ... @@ -1466,15 +1472,25 @@ class Viewer(wx.Panel):
1466 1472 self.pick.Pick(x, y, 0, render)
1467 1473 x, y, z = self.pick.GetPickPosition()
1468 1474 if self.pick.GetViewProp():
1469   - if not self.measures or self.measures[-1][1].IsComplete():
1470   - m = measures.AngularMeasure(render)
1471   - m.AddPoint(x, y, z)
1472   - self.measures.append((slice_number, m))
1473   - else:
1474   - m = self.measures[-1][1]
1475   - m.AddPoint(x, y, z)
1476   - if m.IsComplete():
1477   - ps.Publisher().sendMessage("Add measure to list",
1478   - (ORIENTATIONS[self.orientation],
1479   - _(u"%.3fº" % m.GetValue())))
  1475 + # if not self.measures or self.measures[-1][1].IsComplete():
  1476 + # m = measures.AngularMeasure(render)
  1477 + # m.AddPoint(x, y, z)
  1478 + # self.measures.append((slice_number, m))
  1479 + # else:
  1480 + # m = self.measures[-1][1]
  1481 + # m.AddPoint(x, y, z)
  1482 + # if m.IsComplete():
  1483 + # ps.Publisher().sendMessage("Add measure to list",
  1484 + # (ORIENTATIONS[self.orientation],
  1485 + # _(u"%.3fº" % m.GetValue())))
  1486 + self.render_to_add = slice_data.renderer
  1487 + ps.Publisher().sendMessage("Add measurement point",
  1488 + ((x, y,z), const.ANGULAR, ORIENTATIONS[self.orientation],
  1489 + slice_number))
1480 1490 self.interactor.Render()
  1491 +
  1492 + def AddActors(self, pubsub_evt):
  1493 + "Inserting actors"
  1494 + actors = pubsub_evt.data
  1495 + for actor in actors:
  1496 + self.render_to_add.AddActor(actor)
... ...
invesalius/data/viewer_volume.py
... ... @@ -142,6 +142,8 @@ class Viewer(wx.Panel):
142 142 ps.Publisher().subscribe(self.OnHideText,
143 143 'Hide text actors on viewers')
144 144  
  145 + ps.Publisher().subscribe(self.AddActors, ('Add Actors', const.SURFACE))
  146 +
145 147 ps.Publisher().subscribe(self.OnShowText,
146 148 'Show text actors on viewers')
147 149 ps.Publisher().subscribe(self.OnCloseProject, 'Close project data')
... ... @@ -225,6 +227,12 @@ class Viewer(wx.Panel):
225 227 self.text.Show()
226 228 self.interactor.Render()
227 229  
  230 + def AddActors(self, pubsub_evt):
  231 + "Inserting actors"
  232 + actors = pubsub_evt.data
  233 + for actor in actors:
  234 + self.ren.AddActor(actor)
  235 +
228 236 def AddPointReference(self, position, radius=1, colour=(1, 0, 0)):
229 237 """
230 238 Add a point representation in the given x,y,z position with a optional
... ... @@ -628,26 +636,18 @@ class Viewer(wx.Panel):
628 636 self.measure_picker.Pick(x, y, 0, self.ren)
629 637 x, y, z = self.measure_picker.GetPickPosition()
630 638 if self.measure_picker.GetActor():
631   - if not self.measures or self.measures[-1].IsComplete():
632   - m = measures.LinearMeasure(self.ren)
633   - m.AddPoint(x, y, z)
634   - self.measures.append(m)
635   - else:
636   - m = self.measures[-1]
637   - m.AddPoint(x, y, z)
638   - if m.IsComplete():
639   - index = len(self.measures) - 1
640   - name = "M"
641   - colour = m.colour
642   - type_ = _("Linear")
643   - location = u"3D"
644   - value = u"%.2f mm"% m.GetValue()
645   -
646   - msg = 'Update measurement info in GUI',
647   - ps.Publisher().sendMessage(msg,
648   - (index, name, colour,
649   - type_, location,
650   - value))
  639 + # if not self.measures or self.measures[-1].IsComplete():
  640 + # m = measures.LinearMeasure(self.ren)
  641 + # m.AddPoint(x, y, z)
  642 + # self.measures.append(m)
  643 + # else:
  644 + # m = self.measures[-1]
  645 + # m.AddPoint(x, y, z)
  646 + # if m.IsComplete():
  647 + # ps.Publisher().sendMessage("Add measure to list",
  648 + # (u"3D", _(u"%.3f mm" % m.GetValue())))
  649 + ps.Publisher().sendMessage("Add measurement point",
  650 + ((x, y,z), const.LINEAR, const.SURFACE))
651 651 self.interactor.Render()
652 652  
653 653 def OnInsertAngularMeasurePoint(self, obj, evt):
... ... @@ -656,25 +656,27 @@ class Viewer(wx.Panel):
656 656 self.measure_picker.Pick(x, y, 0, self.ren)
657 657 x, y, z = self.measure_picker.GetPickPosition()
658 658 if self.measure_picker.GetActor():
659   - if not self.measures or self.measures[-1].IsComplete():
660   - m = measures.AngularMeasure(self.ren)
661   - m.AddPoint(x, y, z)
662   - self.measures.append(m)
663   - else:
664   - m = self.measures[-1]
665   - m.AddPoint(x, y, z)
666   - if m.IsComplete():
667   - index = len(self.measures) - 1
668   - name = "M"
669   - colour = m.colour
670   - type_ = _("Angular")
671   - location = u"3D"
672   - value = u"%.2f˚"% m.GetValue()
673   - msg = 'Update measurement info in GUI',
674   - ps.Publisher().sendMessage(msg,
675   - (index, name, colour,
676   - type_, location,
677   - value))
  659 + # if not self.measures or self.measures[-1].IsComplete():
  660 + # m = measures.AngularMeasure(self.ren)
  661 + # m.AddPoint(x, y, z)
  662 + # self.measures.append(m)
  663 + # else:
  664 + # m = self.measures[-1]
  665 + # m.AddPoint(x, y, z)
  666 + # if m.IsComplete():
  667 + # index = len(self.measures) - 1
  668 + # name = "M"
  669 + # colour = m.colour
  670 + # type_ = _("Angular")
  671 + # location = u"3D"
  672 + # value = u"%.2f˚"% m.GetValue()
  673 + # msg = 'Update measurement info in GUI',
  674 + # ps.Publisher().sendMessage(msg,
  675 + # (index, name, colour,
  676 + # type_, location,
  677 + # value))
  678 + ps.Publisher().sendMessage("Add measurement point",
  679 + ((x, y,z), const.ANGULAR, const.SURFACE))
678 680 self.interactor.Render()
679 681  
680 682  
... ...