Commit 3f79dd82d0bbdf493074ba34557dd45ec40d1c16

Authored by Thiago Franco de Moraes
1 parent b41e19ac
Exists in rotvol

Almost done

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()