Commit 855d18d945af1d79bb186147ab6efd985833ad80
1 parent
8d9b272f
Exists in
master
and in
58 other branches
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
Showing
6 changed files
with
82 additions
and
14 deletions
Show diff stats
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) |