Commit 855d18d945af1d79bb186147ab6efd985833ad80

Authored by Thiago Franco de Moraes
1 parent 8d9b272f

Makes the measure mark proportional to image spacing

* Added the parameter radius "Add measurement point" pubsub message. This
  parameter is proportional the image spacing.
* Added PROP_MEASURE to constants.py. This constant is used to set the
  proportion the image spacing.

The measure mark is proportional to the image spacing

Loading measures with circlerepresentation proportional to the image spacing

Adding measures in polydata with circlerepresentation proportional to the image spacing

Added PROP_MEASURE to constants.py
invesalius/constants.py
@@ -38,6 +38,8 @@ DEFAULT_MEASURE_BG_COLOUR = (250/255.0, 247/255.0, 218/255.0) @@ -38,6 +38,8 @@ DEFAULT_MEASURE_BG_COLOUR = (250/255.0, 247/255.0, 218/255.0)
38 DEFAULT_MEASURE_RADIUS = 1 38 DEFAULT_MEASURE_RADIUS = 1
39 DEFAULT_MEASURE_TYPE = MEASURE_LINEAR 39 DEFAULT_MEASURE_TYPE = MEASURE_LINEAR
40 40
  41 +PROP_MEASURE = 0.8
  42 +
41 43
42 STEREO_OFF = _(" Off") 44 STEREO_OFF = _(" Off")
43 STEREO_RED_BLUE = _("Red-blue") 45 STEREO_RED_BLUE = _("Red-blue")
invesalius/control.py
@@ -405,7 +405,7 @@ class Controller(): @@ -405,7 +405,7 @@ class Controller():
405 (mask_name, thresh, colour)) 405 (mask_name, thresh, colour))
406 406
407 Publisher.sendMessage('Load measurement dict', 407 Publisher.sendMessage('Load measurement dict',
408 - proj.measurement_dict) 408 + (proj.measurement_dict, self.Slice.spacing))
409 409
410 Publisher.sendMessage(('Set scroll position', 'AXIAL'),proj.matrix_shape[0]/2) 410 Publisher.sendMessage(('Set scroll position', 'AXIAL'),proj.matrix_shape[0]/2)
411 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),proj.matrix_shape[1]/2) 411 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),proj.matrix_shape[1]/2)
invesalius/data/measures.py
@@ -21,6 +21,7 @@ LOCATION = {const.SURFACE: _(u"3D"), @@ -21,6 +21,7 @@ LOCATION = {const.SURFACE: _(u"3D"),
21 const.SAGITAL: _(u"Sagittal") 21 const.SAGITAL: _(u"Sagittal")
22 } 22 }
23 23
  24 +
24 class MeasurementManager(object): 25 class MeasurementManager(object):
25 """ 26 """
26 A class to manage the use (Addition, remotion and visibility) from 27 A class to manage the use (Addition, remotion and visibility) from
@@ -39,13 +40,31 @@ class MeasurementManager(object): @@ -39,13 +40,31 @@ class MeasurementManager(object):
39 Publisher.subscribe(self._load_measurements, "Load measurement dict") 40 Publisher.subscribe(self._load_measurements, "Load measurement dict")
40 41
41 def _load_measurements(self, pubsub_evt): 42 def _load_measurements(self, pubsub_evt):
42 - dict = pubsub_evt.data 43 + try:
  44 + dict, spacing = pubsub_evt.data
  45 + except ValueError:
  46 + dict = pubsub_evt.data
  47 + spacing = 1.0, 1.0, 1.0
43 for i in dict: 48 for i in dict:
44 m = dict[i] 49 m = dict[i]
  50 +
  51 + if m.location == const.AXIAL:
  52 + radius = min(spacing[1], spacing[2]) * const.PROP_MEASURE
  53 +
  54 + elif m.location == const.CORONAL:
  55 + radius = min(spacing[0], spacing[1]) * const.PROP_MEASURE
  56 +
  57 + elif m.location == const.SAGITAL:
  58 + radius = min(spacing[1], spacing[2]) * const.PROP_MEASURE
  59 +
  60 + else:
  61 + radius = min(spacing) * const.PROP_MEASURE
  62 +
  63 + representation = CirclePointRepresentation(m.colour, radius)
45 if m.type == const.LINEAR: 64 if m.type == const.LINEAR:
46 - mr = LinearMeasure(m.colour) 65 + mr = LinearMeasure(m.colour, representation)
47 else: 66 else:
48 - mr = AngularMeasure(m.colour) 67 + mr = AngularMeasure(m.colour, representation)
49 self.current = (m, mr) 68 self.current = (m, mr)
50 self.measures.append(self.current) 69 self.measures.append(self.current)
51 for point in m.points: 70 for point in m.points:
@@ -66,10 +85,23 @@ class MeasurementManager(object): @@ -66,10 +85,23 @@ class MeasurementManager(object):
66 position = pubsub_evt.data[0] 85 position = pubsub_evt.data[0]
67 type = pubsub_evt.data[1] # Linear or Angular 86 type = pubsub_evt.data[1] # Linear or Angular
68 location = pubsub_evt.data[2] # 3D, AXIAL, SAGITAL, CORONAL 87 location = pubsub_evt.data[2] # 3D, AXIAL, SAGITAL, CORONAL
69 - try:  
70 - slice_number = pubsub_evt.data[3]  
71 - except IndexError: 88 +
  89 + if location == const.SURFACE:
72 slice_number = 0 90 slice_number = 0
  91 + try:
  92 + radius = pubsub_evt.data[3]
  93 + except IndexError:
  94 + radius = const.PROP_MEASURE
  95 + else:
  96 + try:
  97 + slice_number = pubsub_evt.data[3]
  98 + except IndexError:
  99 + slice_number = 0
  100 +
  101 + try:
  102 + radius = pubsub_evt.data[4]
  103 + except IndexError:
  104 + radius = const.PROP_MEASURE
73 105
74 to_remove = False 106 to_remove = False
75 if self.current is None: 107 if self.current is None:
@@ -95,10 +127,11 @@ class MeasurementManager(object): @@ -95,10 +127,11 @@ class MeasurementManager(object):
95 m.location = location 127 m.location = location
96 m.slice_number = slice_number 128 m.slice_number = slice_number
97 m.type = type 129 m.type = type
  130 + representation = CirclePointRepresentation(m.colour, radius)
98 if type == const.LINEAR: 131 if type == const.LINEAR:
99 - mr = LinearMeasure(m.colour) 132 + mr = LinearMeasure(m.colour, representation)
100 else: 133 else:
101 - mr = AngularMeasure(m.colour) 134 + mr = AngularMeasure(m.colour, representation)
102 if to_remove: 135 if to_remove:
103 print "---To REMOVE" 136 print "---To REMOVE"
104 actors = self.current[1].GetActors() 137 actors = self.current[1].GetActors()
invesalius/data/styles.py
@@ -271,6 +271,17 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle): @@ -271,6 +271,17 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle):
271 self.orientation = viewer.orientation 271 self.orientation = viewer.orientation
272 self.slice_data = viewer.slice_data 272 self.slice_data = viewer.slice_data
273 273
  274 + spacing = self.slice_data.actor.GetInput().GetSpacing()
  275 +
  276 + if self.orientation == "AXIAL":
  277 + self.radius = min(spacing[1], spacing[2]) * 0.8
  278 +
  279 + elif self.orientation == 'CORONAL':
  280 + self.radius = min(spacing[0], spacing[1]) * 0.8
  281 +
  282 + elif self.orientation == 'SAGITAL':
  283 + self.radius = min(spacing[1], spacing[2]) * 0.8
  284 +
274 self.picker = vtk.vtkCellPicker() 285 self.picker = vtk.vtkCellPicker()
275 286
276 self.AddObserver("LeftButtonPressEvent", self.OnInsertLinearMeasurePoint) 287 self.AddObserver("LeftButtonPressEvent", self.OnInsertLinearMeasurePoint)
@@ -286,7 +297,7 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle): @@ -286,7 +297,7 @@ class LinearMeasureInteractorStyle(DefaultInteractorStyle):
286 Publisher.sendMessage("Add measurement point", 297 Publisher.sendMessage("Add measurement point",
287 ((x, y,z), const.LINEAR, 298 ((x, y,z), const.LINEAR,
288 ORIENTATIONS[self.orientation], 299 ORIENTATIONS[self.orientation],
289 - slice_number)) 300 + slice_number, self.radius))
290 self.viewer.interactor.Render() 301 self.viewer.interactor.Render()
291 302
292 303
@@ -301,6 +312,17 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle): @@ -301,6 +312,17 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle):
301 self.orientation = viewer.orientation 312 self.orientation = viewer.orientation
302 self.slice_data = viewer.slice_data 313 self.slice_data = viewer.slice_data
303 314
  315 + spacing = self.slice_data.actor.GetInput().GetSpacing()
  316 +
  317 + if self.orientation == "AXIAL":
  318 + self.radius = min(spacing[1], spacing[2]) * 0.8
  319 +
  320 + elif self.orientation == 'CORONAL':
  321 + self.radius = min(spacing[0], spacing[1]) * 0.8
  322 +
  323 + elif self.orientation == 'SAGITAL':
  324 + self.radius = min(spacing[1], spacing[2]) * 0.8
  325 +
304 self.picker = vtk.vtkCellPicker() 326 self.picker = vtk.vtkCellPicker()
305 327
306 self.AddObserver("LeftButtonPressEvent", self.OnInsertAngularMeasurePoint) 328 self.AddObserver("LeftButtonPressEvent", self.OnInsertAngularMeasurePoint)
@@ -316,7 +338,7 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle): @@ -316,7 +338,7 @@ class AngularMeasureInteractorStyle(DefaultInteractorStyle):
316 Publisher.sendMessage("Add measurement point", 338 Publisher.sendMessage("Add measurement point",
317 ((x, y,z), const.ANGULAR, 339 ((x, y,z), const.ANGULAR,
318 ORIENTATIONS[self.orientation], 340 ORIENTATIONS[self.orientation],
319 - slice_number)) 341 + slice_number, self.radius))
320 self.viewer.interactor.Render() 342 self.viewer.interactor.Render()
321 343
322 344
invesalius/data/viewer_volume.py
@@ -37,6 +37,8 @@ import utils @@ -37,6 +37,8 @@ import utils
37 37
38 from data import measures 38 from data import measures
39 39
  40 +PROP_MEASURE = 0.8
  41 +
40 class Viewer(wx.Panel): 42 class Viewer(wx.Panel):
41 def __init__(self, parent): 43 def __init__(self, parent):
42 wx.Panel.__init__(self, parent, size=wx.Size(320, 320)) 44 wx.Panel.__init__(self, parent, size=wx.Size(320, 320))
@@ -815,6 +817,9 @@ class Viewer(wx.Panel): @@ -815,6 +817,9 @@ class Viewer(wx.Panel):
815 x,y = self.interactor.GetEventPosition() 817 x,y = self.interactor.GetEventPosition()
816 self.measure_picker.Pick(x, y, 0, self.ren) 818 self.measure_picker.Pick(x, y, 0, self.ren)
817 x, y, z = self.measure_picker.GetPickPosition() 819 x, y, z = self.measure_picker.GetPickPosition()
  820 +
  821 + proj = prj.Project()
  822 + radius = min(proj.spacing) * PROP_MEASURE
818 if self.measure_picker.GetActor(): 823 if self.measure_picker.GetActor():
819 # if not self.measures or self.measures[-1].IsComplete(): 824 # if not self.measures or self.measures[-1].IsComplete():
820 # m = measures.LinearMeasure(self.ren) 825 # m = measures.LinearMeasure(self.ren)
@@ -827,7 +832,7 @@ class Viewer(wx.Panel): @@ -827,7 +832,7 @@ class Viewer(wx.Panel):
827 # Publisher.sendMessage("Add measure to list", 832 # Publisher.sendMessage("Add measure to list",
828 # (u"3D", _(u"%.3f mm" % m.GetValue()))) 833 # (u"3D", _(u"%.3f mm" % m.GetValue())))
829 Publisher.sendMessage("Add measurement point", 834 Publisher.sendMessage("Add measurement point",
830 - ((x, y,z), const.LINEAR, const.SURFACE)) 835 + ((x, y,z), const.LINEAR, const.SURFACE, radius))
831 self.interactor.Render() 836 self.interactor.Render()
832 837
833 def OnInsertAngularMeasurePoint(self, obj, evt): 838 def OnInsertAngularMeasurePoint(self, obj, evt):
@@ -835,6 +840,9 @@ class Viewer(wx.Panel): @@ -835,6 +840,9 @@ class Viewer(wx.Panel):
835 x,y = self.interactor.GetEventPosition() 840 x,y = self.interactor.GetEventPosition()
836 self.measure_picker.Pick(x, y, 0, self.ren) 841 self.measure_picker.Pick(x, y, 0, self.ren)
837 x, y, z = self.measure_picker.GetPickPosition() 842 x, y, z = self.measure_picker.GetPickPosition()
  843 +
  844 + proj = prj.Project()
  845 + radius = min(proj.spacing) * PROP_MEASURE
838 if self.measure_picker.GetActor(): 846 if self.measure_picker.GetActor():
839 # if not self.measures or self.measures[-1].IsComplete(): 847 # if not self.measures or self.measures[-1].IsComplete():
840 # m = measures.AngularMeasure(self.ren) 848 # m = measures.AngularMeasure(self.ren)
@@ -856,7 +864,7 @@ class Viewer(wx.Panel): @@ -856,7 +864,7 @@ class Viewer(wx.Panel):
856 # type_, location, 864 # type_, location,
857 # value)) 865 # value))
858 Publisher.sendMessage("Add measurement point", 866 Publisher.sendMessage("Add measurement point",
859 - ((x, y,z), const.ANGULAR, const.SURFACE)) 867 + ((x, y,z), const.ANGULAR, const.SURFACE, radius))
860 self.interactor.Render() 868 self.interactor.Render()
861 869
862 def Reposition3DPlane(self, evt_pubsub): 870 def Reposition3DPlane(self, evt_pubsub):
invesalius/gui/data_notebook.py
@@ -1064,7 +1064,10 @@ class MeasuresListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin): @@ -1064,7 +1064,10 @@ class MeasuresListCtrlPanel(wx.ListCtrl, listmix.TextEditMixin):
1064 (index, visibility)) 1064 (index, visibility))
1065 1065
1066 def OnLoadData(self, pubsub_evt): 1066 def OnLoadData(self, pubsub_evt):
1067 - items_dict = pubsub_evt.data 1067 + try:
  1068 + items_dict, spacing = pubsub_evt.data
  1069 + except ValueError:
  1070 + items_dict = pubsub_evt.data
1068 for i in items_dict: 1071 for i in items_dict:
1069 m = items_dict[i] 1072 m = items_dict[i]
1070 image = self.CreateColourBitmap(m.colour) 1073 image = self.CreateColourBitmap(m.colour)