From 3f79dd82d0bbdf493074ba34557dd45ec40d1c16 Mon Sep 17 00:00:00 2001 From: Thiago Franco de Moraes Date: Fri, 13 May 2016 15:39:07 -0300 Subject: [PATCH] Almost done --- invesalius/control.py | 5 +++++ invesalius/data/slice_.py | 35 ++++++++++++++++++++++++++++------- invesalius/data/styles.py | 51 +++++---------------------------------------------- invesalius/gui/dialogs.py | 24 ++++++++++++++++++------ 4 files changed, 56 insertions(+), 59 deletions(-) diff --git a/invesalius/control.py b/invesalius/control.py index c94d0dc..f5281ea 100644 --- a/invesalius/control.py +++ b/invesalius/control.py @@ -84,6 +84,8 @@ class Controller(): Publisher.subscribe(self.ShowBooleanOpDialog, 'Show boolean dialog') + Publisher.subscribe(self.ApplyReorientation, 'Apply reorientation') + def OnCancelImport(self, pubsub_evt): #self.cancel_import = True @@ -631,3 +633,6 @@ class Controller(): def ShowBooleanOpDialog(self, pubsub_evt): dlg = dialogs.MaskBooleanDialog(prj.Project().mask_dict) dlg.Show() + + def ApplyReorientation(self, pubsub_evt): + self.Slice.apply_reorientation() diff --git a/invesalius/data/slice_.py b/invesalius/data/slice_.py index a77e1f5..74f054d 100644 --- a/invesalius/data/slice_.py +++ b/invesalius/data/slice_.py @@ -94,7 +94,6 @@ class Slice(object): self.n_border = const.PROJECTION_BORDER_SIZE self._spacing = (1.0, 1.0, 1.0) - self.rotations = [0, 0, 0] self.center = [0, 0, 0] self.q_orientation = np.array((1, 0, 0, 0)) @@ -580,10 +579,8 @@ class Slice(object): if self._type_projection == const.PROJECTION_NORMAL: number_slices = 1 - if np.any(self.rotations): + if np.any(self.q_orientation[1::]): cx, cy, cz = self.center - rx, ry, rz = self.rotations - sx, sy, sz = self.spacing T0 = transformations.translation_matrix((-cz, -cy, -cx)) # Rx = transformations.rotation_matrix(rx, (0, 0, 1)) # Ry = transformations.rotation_matrix(ry, (0, 1, 0)) @@ -597,7 +594,7 @@ class Slice(object): if orientation == 'AXIAL': tmp_array = np.array(self.matrix[slice_number:slice_number + number_slices]) - if np.any(self.rotations): + if np.any(self.q_orientation[1::]): transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 2, self.matrix.min(), tmp_array) if self._type_projection == const.PROJECTION_NORMAL: n_image = tmp_array.squeeze() @@ -644,7 +641,7 @@ class Slice(object): elif orientation == 'CORONAL': tmp_array = np.array(self.matrix[:, slice_number: slice_number + number_slices, :]) - if np.any(self.rotations): + if np.any(self.q_orientation[1::]): transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) if self._type_projection == const.PROJECTION_NORMAL: @@ -694,7 +691,7 @@ class Slice(object): n_image = np.array(self.matrix[:, slice_number, :]) elif orientation == 'SAGITAL': tmp_array = np.array(self.matrix[:, :, slice_number: slice_number + number_slices]) - if np.any(self.rotations): + if np.any(self.q_orientation[1::]): transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) if self._type_projection == const.PROJECTION_NORMAL: @@ -1365,6 +1362,30 @@ class Slice(object): self.buffer_slices[o].discard_vtk_mask() Publisher.sendMessage('Reload actual slice') + def apply_reorientation(self): + temp_file = tempfile.mktemp() + mcopy = np.memmap(temp_file, shape=self.matrix.shape, dtype=self.matrix.dtype, mode='w+') + mcopy[:] = self.matrix + + cx, cy, cz = self.center + T0 = transformations.translation_matrix((-cz, -cy, -cx)) + R = transformations.quaternion_matrix(self.q_orientation) + T1 = transformations.translation_matrix((cz, cy, cx)) + M = transformations.concatenate_matrices(T1, R.T, T0) + + transforms.apply_view_matrix_transform(mcopy, self.spacing, M, 0, 'AXIAL', 2, mcopy.min(), self.matrix) + + del mcopy + os.remove(temp_file) + + self.q_orientation = np.array((1, 0, 0, 0)) + self.center = [(s * d/2.0) for (d, s) in zip(self.matrix.shape[::-1], self.spacing)] + + self.__clean_current_mask(None) + self.current_mask.matrix[:] = 0 + + Publisher.sendMessage('Reload actual slice') + def __undo_edition(self, pub_evt): buffer_slices = self.buffer_slices actual_slices = {"AXIAL": buffer_slices["AXIAL"].index, diff --git a/invesalius/data/styles.py b/invesalius/data/styles.py index bc9ee55..6ce9c4d 100644 --- a/invesalius/data/styles.py +++ b/invesalius/data/styles.py @@ -1426,7 +1426,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): self.picker = vtk.vtkWorldPointPicker() - # self.AddObserver("KeyPressEvent", self.OnKeyPress) self.AddObserver("LeftButtonPressEvent",self.OnLeftClick) self.AddObserver("LeftButtonReleaseEvent", self.OnLeftRelease) self.AddObserver("MouseMoveEvent", self.OnMouseMove) @@ -1435,37 +1434,19 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnDblClick) def SetUp(self): - self.viewer.slice_.current_mask.is_shown = False self.draw_lines() + Publisher.sendMessage('Show mask', (self.viewer.slice_.current_mask.index, False)) Publisher.sendMessage('Reload actual slice') def CleanUp(self): for actor in self.actors: self.viewer.slice_data.renderer.RemoveActor(actor) - def OnKeyPress(self, evt, obj): - key = self.viewer.interactor.GetKeyCode() - if key == '+': - delta = 1 - elif key == '-': - delta = -1 - else: - return - - rx, ry, rz = self.viewer.slice_.rotations - orientation = self.viewer.orientation - if orientation == 'AXIAL': - rz += np.deg2rad(delta) - elif orientation == 'CORONAL': - ry += np.deg2rad(delta) - elif orientation == 'SAGITAL': - rx += np.deg2rad(delta) - - self.viewer.slice_.rotations = (rx, ry, rz) + self.viewer.slice_.rotations = [0, 0, 0] + self.viewer.slice_.q_orientation = np.array((1, 0, 0, 0)) self._discard_buffers() - - self.viewer.slice_.current_mask.clear_history() - Publisher.sendMessage('Reload actual slice') + Publisher.sendMessage('Show mask', (self.viewer.slice_.current_mask.index, True)) + Publisher.sendMessage('Reload actual slice %s' % self.viewer.orientation) def OnLeftClick(self, obj, evt): if self._over_center: @@ -1480,16 +1461,9 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) x, y, z = self.picker.GetPickPosition() - # if self.viewer.orientation == 'AXIAL': - # self.p0 = np.array((y-cy, x-cx)) - # elif self.viewer.orientation == 'CORONAL': - # self.p0 = np.array((z-cz, x-cx)) - # elif self.viewer.orientation == 'SAGITAL': - # self.p0 = np.array((z-cz, y-cy)) self.p0 = self.get_image_point_coord(x, y, z) self.to_rot = True - def OnLeftRelease(self, obj, evt): self.dragging = False @@ -1501,7 +1475,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): """ This event is responsible to reorient image, set mouse cursors """ - if self.dragging: self._move_center_rot() elif self.to_rot: @@ -1599,19 +1572,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): self.viewer.slice_.q_orientation = transformations.quaternion_multiply(self.viewer.slice_.q_orientation, transformations.quaternion_about_axis(angle, axis)) - # print axis, angle, self.viewer.slice_.q_orientation - print axis, angle - - if self.viewer.orientation == 'AXIAL': - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) - self.viewer.slice_.rotations[2] = angle - elif self.viewer.orientation == 'CORONAL': - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) - self.viewer.slice_.rotations[1] = angle - elif self.viewer.orientation == 'SAGITAL': - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) - self.viewer.slice_.rotations[0] = angle - az, ay, ax = transformations.euler_from_quaternion(self.viewer.slice_.q_orientation) Publisher.sendMessage('Update reorient angles', (ax, ay, az)) @@ -1677,7 +1637,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): self.line1 = self._create_line(0, 0.5, 1, 0.5, color1) self.line2 = self._create_line(0.5, 0, 0.5, 1, color2) - def _discard_buffers(self): for buffer_ in self.viewer.slice_.buffer_slices.values(): buffer_.discard_vtk_image() diff --git a/invesalius/gui/dialogs.py b/invesalius/gui/dialogs.py index eb4bf2f..0e1a0fa 100644 --- a/invesalius/gui/dialogs.py +++ b/invesalius/gui/dialogs.py @@ -1576,13 +1576,14 @@ class ReorientImageDialog(wx.Dialog): self._init_gui() self._bind_events() + self._bind_events_wx() def _init_gui(self): - self.anglex = wx.TextCtrl(self, -1, "0.0") - self.angley = wx.TextCtrl(self, -1, "0.0") - self.anglez = wx.TextCtrl(self, -1, "0.0") + self.anglex = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) + self.angley = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) + self.anglez = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) - btnapply = wx.Button(self, -1, _("Apply")) + self.btnapply = wx.Button(self, -1, _("Apply")) sizer = wx.BoxSizer(wx.HORIZONTAL) @@ -1598,7 +1599,7 @@ class ReorientImageDialog(wx.Dialog): sizer.Add(self.anglez, 0, wx.EXPAND | wx.ALL, 5) sizer.AddSpacer(5) - sizer.Add(btnapply, 0, wx.EXPAND | wx.ALL, 5) + sizer.Add(self.btnapply, 0, wx.EXPAND | wx.ALL, 5) sizer.AddSpacer(5) self.SetSizer(sizer) @@ -1607,10 +1608,21 @@ class ReorientImageDialog(wx.Dialog): def _bind_events(self): Publisher.subscribe(self._update_angles, 'Update reorient angles') + def _bind_events_wx(self): + self.btnapply.Bind(wx.EVT_BUTTON, self.apply_reorientation) + self.Bind(wx.EVT_CLOSE, self.OnClose) + def _update_angles(self, pubsub_evt): anglex, angley, anglez = pubsub_evt.data self.anglex.SetValue("%.2f" % np.rad2deg(anglex)) self.angley.SetValue("%.2f" % np.rad2deg(angley)) self.anglez.SetValue("%.2f" % np.rad2deg(anglez)) - print anglex, angley, anglez + def apply_reorientation(self, evt): + Publisher.sendMessage('Apply reorientation') + self.Close() + + def OnClose(self, evt): + Publisher.sendMessage('Disable style', const.SLICE_STATE_REORIENT) + Publisher.sendMessage('Enable style', const.STATE_DEFAULT) + self.Destroy() -- libgit2 0.21.2