Commit 3f79dd82d0bbdf493074ba34557dd45ec40d1c16
1 parent
b41e19ac
Exists in
rotvol
Almost done
Showing
4 changed files
with
56 additions
and
59 deletions
Show diff stats
invesalius/control.py
@@ -84,6 +84,8 @@ class Controller(): | @@ -84,6 +84,8 @@ class Controller(): | ||
84 | 84 | ||
85 | Publisher.subscribe(self.ShowBooleanOpDialog, 'Show boolean dialog') | 85 | Publisher.subscribe(self.ShowBooleanOpDialog, 'Show boolean dialog') |
86 | 86 | ||
87 | + Publisher.subscribe(self.ApplyReorientation, 'Apply reorientation') | ||
88 | + | ||
87 | 89 | ||
88 | def OnCancelImport(self, pubsub_evt): | 90 | def OnCancelImport(self, pubsub_evt): |
89 | #self.cancel_import = True | 91 | #self.cancel_import = True |
@@ -631,3 +633,6 @@ class Controller(): | @@ -631,3 +633,6 @@ class Controller(): | ||
631 | def ShowBooleanOpDialog(self, pubsub_evt): | 633 | def ShowBooleanOpDialog(self, pubsub_evt): |
632 | dlg = dialogs.MaskBooleanDialog(prj.Project().mask_dict) | 634 | dlg = dialogs.MaskBooleanDialog(prj.Project().mask_dict) |
633 | dlg.Show() | 635 | dlg.Show() |
636 | + | ||
637 | + def ApplyReorientation(self, pubsub_evt): | ||
638 | + self.Slice.apply_reorientation() |
invesalius/data/slice_.py
@@ -94,7 +94,6 @@ class Slice(object): | @@ -94,7 +94,6 @@ class Slice(object): | ||
94 | self.n_border = const.PROJECTION_BORDER_SIZE | 94 | self.n_border = const.PROJECTION_BORDER_SIZE |
95 | 95 | ||
96 | self._spacing = (1.0, 1.0, 1.0) | 96 | self._spacing = (1.0, 1.0, 1.0) |
97 | - self.rotations = [0, 0, 0] | ||
98 | self.center = [0, 0, 0] | 97 | self.center = [0, 0, 0] |
99 | 98 | ||
100 | self.q_orientation = np.array((1, 0, 0, 0)) | 99 | self.q_orientation = np.array((1, 0, 0, 0)) |
@@ -580,10 +579,8 @@ class Slice(object): | @@ -580,10 +579,8 @@ class Slice(object): | ||
580 | if self._type_projection == const.PROJECTION_NORMAL: | 579 | if self._type_projection == const.PROJECTION_NORMAL: |
581 | number_slices = 1 | 580 | number_slices = 1 |
582 | 581 | ||
583 | - if np.any(self.rotations): | 582 | + if np.any(self.q_orientation[1::]): |
584 | cx, cy, cz = self.center | 583 | cx, cy, cz = self.center |
585 | - rx, ry, rz = self.rotations | ||
586 | - sx, sy, sz = self.spacing | ||
587 | T0 = transformations.translation_matrix((-cz, -cy, -cx)) | 584 | T0 = transformations.translation_matrix((-cz, -cy, -cx)) |
588 | # Rx = transformations.rotation_matrix(rx, (0, 0, 1)) | 585 | # Rx = transformations.rotation_matrix(rx, (0, 0, 1)) |
589 | # Ry = transformations.rotation_matrix(ry, (0, 1, 0)) | 586 | # Ry = transformations.rotation_matrix(ry, (0, 1, 0)) |
@@ -597,7 +594,7 @@ class Slice(object): | @@ -597,7 +594,7 @@ class Slice(object): | ||
597 | 594 | ||
598 | if orientation == 'AXIAL': | 595 | if orientation == 'AXIAL': |
599 | tmp_array = np.array(self.matrix[slice_number:slice_number + number_slices]) | 596 | tmp_array = np.array(self.matrix[slice_number:slice_number + number_slices]) |
600 | - if np.any(self.rotations): | 597 | + if np.any(self.q_orientation[1::]): |
601 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 2, self.matrix.min(), tmp_array) | 598 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 2, self.matrix.min(), tmp_array) |
602 | if self._type_projection == const.PROJECTION_NORMAL: | 599 | if self._type_projection == const.PROJECTION_NORMAL: |
603 | n_image = tmp_array.squeeze() | 600 | n_image = tmp_array.squeeze() |
@@ -644,7 +641,7 @@ class Slice(object): | @@ -644,7 +641,7 @@ class Slice(object): | ||
644 | 641 | ||
645 | elif orientation == 'CORONAL': | 642 | elif orientation == 'CORONAL': |
646 | tmp_array = np.array(self.matrix[:, slice_number: slice_number + number_slices, :]) | 643 | tmp_array = np.array(self.matrix[:, slice_number: slice_number + number_slices, :]) |
647 | - if np.any(self.rotations): | 644 | + if np.any(self.q_orientation[1::]): |
648 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) | 645 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) |
649 | 646 | ||
650 | if self._type_projection == const.PROJECTION_NORMAL: | 647 | if self._type_projection == const.PROJECTION_NORMAL: |
@@ -694,7 +691,7 @@ class Slice(object): | @@ -694,7 +691,7 @@ class Slice(object): | ||
694 | n_image = np.array(self.matrix[:, slice_number, :]) | 691 | n_image = np.array(self.matrix[:, slice_number, :]) |
695 | elif orientation == 'SAGITAL': | 692 | elif orientation == 'SAGITAL': |
696 | tmp_array = np.array(self.matrix[:, :, slice_number: slice_number + number_slices]) | 693 | tmp_array = np.array(self.matrix[:, :, slice_number: slice_number + number_slices]) |
697 | - if np.any(self.rotations): | 694 | + if np.any(self.q_orientation[1::]): |
698 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) | 695 | transforms.apply_view_matrix_transform(self.matrix, self.spacing, M, slice_number, orientation, 1, self.matrix.min(), tmp_array) |
699 | 696 | ||
700 | if self._type_projection == const.PROJECTION_NORMAL: | 697 | if self._type_projection == const.PROJECTION_NORMAL: |
@@ -1365,6 +1362,30 @@ class Slice(object): | @@ -1365,6 +1362,30 @@ class Slice(object): | ||
1365 | self.buffer_slices[o].discard_vtk_mask() | 1362 | self.buffer_slices[o].discard_vtk_mask() |
1366 | Publisher.sendMessage('Reload actual slice') | 1363 | Publisher.sendMessage('Reload actual slice') |
1367 | 1364 | ||
1365 | + def apply_reorientation(self): | ||
1366 | + temp_file = tempfile.mktemp() | ||
1367 | + mcopy = np.memmap(temp_file, shape=self.matrix.shape, dtype=self.matrix.dtype, mode='w+') | ||
1368 | + mcopy[:] = self.matrix | ||
1369 | + | ||
1370 | + cx, cy, cz = self.center | ||
1371 | + T0 = transformations.translation_matrix((-cz, -cy, -cx)) | ||
1372 | + R = transformations.quaternion_matrix(self.q_orientation) | ||
1373 | + T1 = transformations.translation_matrix((cz, cy, cx)) | ||
1374 | + M = transformations.concatenate_matrices(T1, R.T, T0) | ||
1375 | + | ||
1376 | + transforms.apply_view_matrix_transform(mcopy, self.spacing, M, 0, 'AXIAL', 2, mcopy.min(), self.matrix) | ||
1377 | + | ||
1378 | + del mcopy | ||
1379 | + os.remove(temp_file) | ||
1380 | + | ||
1381 | + self.q_orientation = np.array((1, 0, 0, 0)) | ||
1382 | + self.center = [(s * d/2.0) for (d, s) in zip(self.matrix.shape[::-1], self.spacing)] | ||
1383 | + | ||
1384 | + self.__clean_current_mask(None) | ||
1385 | + self.current_mask.matrix[:] = 0 | ||
1386 | + | ||
1387 | + Publisher.sendMessage('Reload actual slice') | ||
1388 | + | ||
1368 | def __undo_edition(self, pub_evt): | 1389 | def __undo_edition(self, pub_evt): |
1369 | buffer_slices = self.buffer_slices | 1390 | buffer_slices = self.buffer_slices |
1370 | actual_slices = {"AXIAL": buffer_slices["AXIAL"].index, | 1391 | actual_slices = {"AXIAL": buffer_slices["AXIAL"].index, |
invesalius/data/styles.py
@@ -1426,7 +1426,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1426,7 +1426,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1426 | 1426 | ||
1427 | self.picker = vtk.vtkWorldPointPicker() | 1427 | self.picker = vtk.vtkWorldPointPicker() |
1428 | 1428 | ||
1429 | - # self.AddObserver("KeyPressEvent", self.OnKeyPress) | ||
1430 | self.AddObserver("LeftButtonPressEvent",self.OnLeftClick) | 1429 | self.AddObserver("LeftButtonPressEvent",self.OnLeftClick) |
1431 | self.AddObserver("LeftButtonReleaseEvent", self.OnLeftRelease) | 1430 | self.AddObserver("LeftButtonReleaseEvent", self.OnLeftRelease) |
1432 | self.AddObserver("MouseMoveEvent", self.OnMouseMove) | 1431 | self.AddObserver("MouseMoveEvent", self.OnMouseMove) |
@@ -1435,37 +1434,19 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1435,37 +1434,19 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1435 | self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnDblClick) | 1434 | self.viewer.interactor.Bind(wx.EVT_LEFT_DCLICK, self.OnDblClick) |
1436 | 1435 | ||
1437 | def SetUp(self): | 1436 | def SetUp(self): |
1438 | - self.viewer.slice_.current_mask.is_shown = False | ||
1439 | self.draw_lines() | 1437 | self.draw_lines() |
1438 | + Publisher.sendMessage('Show mask', (self.viewer.slice_.current_mask.index, False)) | ||
1440 | Publisher.sendMessage('Reload actual slice') | 1439 | Publisher.sendMessage('Reload actual slice') |
1441 | 1440 | ||
1442 | def CleanUp(self): | 1441 | def CleanUp(self): |
1443 | for actor in self.actors: | 1442 | for actor in self.actors: |
1444 | self.viewer.slice_data.renderer.RemoveActor(actor) | 1443 | self.viewer.slice_data.renderer.RemoveActor(actor) |
1445 | 1444 | ||
1446 | - def OnKeyPress(self, evt, obj): | ||
1447 | - key = self.viewer.interactor.GetKeyCode() | ||
1448 | - if key == '+': | ||
1449 | - delta = 1 | ||
1450 | - elif key == '-': | ||
1451 | - delta = -1 | ||
1452 | - else: | ||
1453 | - return | ||
1454 | - | ||
1455 | - rx, ry, rz = self.viewer.slice_.rotations | ||
1456 | - orientation = self.viewer.orientation | ||
1457 | - if orientation == 'AXIAL': | ||
1458 | - rz += np.deg2rad(delta) | ||
1459 | - elif orientation == 'CORONAL': | ||
1460 | - ry += np.deg2rad(delta) | ||
1461 | - elif orientation == 'SAGITAL': | ||
1462 | - rx += np.deg2rad(delta) | ||
1463 | - | ||
1464 | - self.viewer.slice_.rotations = (rx, ry, rz) | 1445 | + self.viewer.slice_.rotations = [0, 0, 0] |
1446 | + self.viewer.slice_.q_orientation = np.array((1, 0, 0, 0)) | ||
1465 | self._discard_buffers() | 1447 | self._discard_buffers() |
1466 | - | ||
1467 | - self.viewer.slice_.current_mask.clear_history() | ||
1468 | - Publisher.sendMessage('Reload actual slice') | 1448 | + Publisher.sendMessage('Show mask', (self.viewer.slice_.current_mask.index, True)) |
1449 | + Publisher.sendMessage('Reload actual slice %s' % self.viewer.orientation) | ||
1469 | 1450 | ||
1470 | def OnLeftClick(self, obj, evt): | 1451 | def OnLeftClick(self, obj, evt): |
1471 | if self._over_center: | 1452 | if self._over_center: |
@@ -1480,16 +1461,9 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1480,16 +1461,9 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1480 | self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) | 1461 | self.picker.Pick(x, y, 0, self.viewer.slice_data.renderer) |
1481 | x, y, z = self.picker.GetPickPosition() | 1462 | x, y, z = self.picker.GetPickPosition() |
1482 | 1463 | ||
1483 | - # if self.viewer.orientation == 'AXIAL': | ||
1484 | - # self.p0 = np.array((y-cy, x-cx)) | ||
1485 | - # elif self.viewer.orientation == 'CORONAL': | ||
1486 | - # self.p0 = np.array((z-cz, x-cx)) | ||
1487 | - # elif self.viewer.orientation == 'SAGITAL': | ||
1488 | - # self.p0 = np.array((z-cz, y-cy)) | ||
1489 | self.p0 = self.get_image_point_coord(x, y, z) | 1464 | self.p0 = self.get_image_point_coord(x, y, z) |
1490 | self.to_rot = True | 1465 | self.to_rot = True |
1491 | 1466 | ||
1492 | - | ||
1493 | def OnLeftRelease(self, obj, evt): | 1467 | def OnLeftRelease(self, obj, evt): |
1494 | self.dragging = False | 1468 | self.dragging = False |
1495 | 1469 | ||
@@ -1501,7 +1475,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1501,7 +1475,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1501 | """ | 1475 | """ |
1502 | This event is responsible to reorient image, set mouse cursors | 1476 | This event is responsible to reorient image, set mouse cursors |
1503 | """ | 1477 | """ |
1504 | - | ||
1505 | if self.dragging: | 1478 | if self.dragging: |
1506 | self._move_center_rot() | 1479 | self._move_center_rot() |
1507 | elif self.to_rot: | 1480 | elif self.to_rot: |
@@ -1599,19 +1572,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1599,19 +1572,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1599 | 1572 | ||
1600 | self.viewer.slice_.q_orientation = transformations.quaternion_multiply(self.viewer.slice_.q_orientation, transformations.quaternion_about_axis(angle, axis)) | 1573 | self.viewer.slice_.q_orientation = transformations.quaternion_multiply(self.viewer.slice_.q_orientation, transformations.quaternion_about_axis(angle, axis)) |
1601 | 1574 | ||
1602 | - # print axis, angle, self.viewer.slice_.q_orientation | ||
1603 | - print axis, angle | ||
1604 | - | ||
1605 | - if self.viewer.orientation == 'AXIAL': | ||
1606 | - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | ||
1607 | - self.viewer.slice_.rotations[2] = angle | ||
1608 | - elif self.viewer.orientation == 'CORONAL': | ||
1609 | - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | ||
1610 | - self.viewer.slice_.rotations[1] = angle | ||
1611 | - elif self.viewer.orientation == 'SAGITAL': | ||
1612 | - # angle = np.arctan2(p0[0] , p0[1]) - np.arctan2(p1[0], p1[1]) | ||
1613 | - self.viewer.slice_.rotations[0] = angle | ||
1614 | - | ||
1615 | az, ay, ax = transformations.euler_from_quaternion(self.viewer.slice_.q_orientation) | 1575 | az, ay, ax = transformations.euler_from_quaternion(self.viewer.slice_.q_orientation) |
1616 | Publisher.sendMessage('Update reorient angles', (ax, ay, az)) | 1576 | Publisher.sendMessage('Update reorient angles', (ax, ay, az)) |
1617 | 1577 | ||
@@ -1677,7 +1637,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | @@ -1677,7 +1637,6 @@ class ReorientImageInteractorStyle(DefaultInteractorStyle): | ||
1677 | self.line1 = self._create_line(0, 0.5, 1, 0.5, color1) | 1637 | self.line1 = self._create_line(0, 0.5, 1, 0.5, color1) |
1678 | self.line2 = self._create_line(0.5, 0, 0.5, 1, color2) | 1638 | self.line2 = self._create_line(0.5, 0, 0.5, 1, color2) |
1679 | 1639 | ||
1680 | - | ||
1681 | def _discard_buffers(self): | 1640 | def _discard_buffers(self): |
1682 | for buffer_ in self.viewer.slice_.buffer_slices.values(): | 1641 | for buffer_ in self.viewer.slice_.buffer_slices.values(): |
1683 | buffer_.discard_vtk_image() | 1642 | buffer_.discard_vtk_image() |
invesalius/gui/dialogs.py
@@ -1576,13 +1576,14 @@ class ReorientImageDialog(wx.Dialog): | @@ -1576,13 +1576,14 @@ class ReorientImageDialog(wx.Dialog): | ||
1576 | 1576 | ||
1577 | self._init_gui() | 1577 | self._init_gui() |
1578 | self._bind_events() | 1578 | self._bind_events() |
1579 | + self._bind_events_wx() | ||
1579 | 1580 | ||
1580 | def _init_gui(self): | 1581 | def _init_gui(self): |
1581 | - self.anglex = wx.TextCtrl(self, -1, "0.0") | ||
1582 | - self.angley = wx.TextCtrl(self, -1, "0.0") | ||
1583 | - self.anglez = wx.TextCtrl(self, -1, "0.0") | 1582 | + self.anglex = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) |
1583 | + self.angley = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) | ||
1584 | + self.anglez = wx.TextCtrl(self, -1, "0.0", style=wx.TE_READONLY) | ||
1584 | 1585 | ||
1585 | - btnapply = wx.Button(self, -1, _("Apply")) | 1586 | + self.btnapply = wx.Button(self, -1, _("Apply")) |
1586 | 1587 | ||
1587 | sizer = wx.BoxSizer(wx.HORIZONTAL) | 1588 | sizer = wx.BoxSizer(wx.HORIZONTAL) |
1588 | 1589 | ||
@@ -1598,7 +1599,7 @@ class ReorientImageDialog(wx.Dialog): | @@ -1598,7 +1599,7 @@ class ReorientImageDialog(wx.Dialog): | ||
1598 | sizer.Add(self.anglez, 0, wx.EXPAND | wx.ALL, 5) | 1599 | sizer.Add(self.anglez, 0, wx.EXPAND | wx.ALL, 5) |
1599 | sizer.AddSpacer(5) | 1600 | sizer.AddSpacer(5) |
1600 | 1601 | ||
1601 | - sizer.Add(btnapply, 0, wx.EXPAND | wx.ALL, 5) | 1602 | + sizer.Add(self.btnapply, 0, wx.EXPAND | wx.ALL, 5) |
1602 | sizer.AddSpacer(5) | 1603 | sizer.AddSpacer(5) |
1603 | 1604 | ||
1604 | self.SetSizer(sizer) | 1605 | self.SetSizer(sizer) |
@@ -1607,10 +1608,21 @@ class ReorientImageDialog(wx.Dialog): | @@ -1607,10 +1608,21 @@ class ReorientImageDialog(wx.Dialog): | ||
1607 | def _bind_events(self): | 1608 | def _bind_events(self): |
1608 | Publisher.subscribe(self._update_angles, 'Update reorient angles') | 1609 | Publisher.subscribe(self._update_angles, 'Update reorient angles') |
1609 | 1610 | ||
1611 | + def _bind_events_wx(self): | ||
1612 | + self.btnapply.Bind(wx.EVT_BUTTON, self.apply_reorientation) | ||
1613 | + self.Bind(wx.EVT_CLOSE, self.OnClose) | ||
1614 | + | ||
1610 | def _update_angles(self, pubsub_evt): | 1615 | def _update_angles(self, pubsub_evt): |
1611 | anglex, angley, anglez = pubsub_evt.data | 1616 | anglex, angley, anglez = pubsub_evt.data |
1612 | self.anglex.SetValue("%.2f" % np.rad2deg(anglex)) | 1617 | self.anglex.SetValue("%.2f" % np.rad2deg(anglex)) |
1613 | self.angley.SetValue("%.2f" % np.rad2deg(angley)) | 1618 | self.angley.SetValue("%.2f" % np.rad2deg(angley)) |
1614 | self.anglez.SetValue("%.2f" % np.rad2deg(anglez)) | 1619 | self.anglez.SetValue("%.2f" % np.rad2deg(anglez)) |
1615 | 1620 | ||
1616 | - print anglex, angley, anglez | 1621 | + def apply_reorientation(self, evt): |
1622 | + Publisher.sendMessage('Apply reorientation') | ||
1623 | + self.Close() | ||
1624 | + | ||
1625 | + def OnClose(self, evt): | ||
1626 | + Publisher.sendMessage('Disable style', const.SLICE_STATE_REORIENT) | ||
1627 | + Publisher.sendMessage('Enable style', const.STATE_DEFAULT) | ||
1628 | + self.Destroy() |