Commit 41d183fe015e1b8add1ae88100f01bf92d510847
Exists in
master
and in
57 other branches
Merge pull request #17 from tfmoraes/measure_spacing
Measure spacing
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) |