Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkNavigationDataSliceVisualization.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
17 
18 #include "mitkBaseRenderer.h"
19 
21  m_Renderer(NULL),
22  m_ViewDirection(Axial)
23 {
24  m_TipOffset[0] = 0.0f;
25  m_TipOffset[1] = 0.0f;
26  m_TipOffset[2] = 0.0f;
27 
28  m_ToolTrajectory[0] = 0;
29  m_ToolTrajectory[1] = 0;
30  m_ToolTrajectory[2] = -1;
31 
32  m_WorldVerticalVector[0] = 0.0;
33  m_WorldVerticalVector[1] = 1.0;
34  m_WorldVerticalVector[2] = 0.0;
35 }
36 
38 {
39  if (Equal(direction.GetNorm(), 0.0))
40  {
41  MITK_WARN << "Ignoring invalid direction of projection: " << direction;
42  return;
43  }
44 
45  if (m_ToolTrajectory != direction)
46  {
47  m_ToolTrajectory = direction;
48  this->SetViewDirection(Oblique);
49  this->Modified();
50  }
51 }
52 
54 {
55  // check if renderer was set
56  if (m_Renderer.IsNull())
57  {
58  itkExceptionMacro(<< "Renderer was not properly set");
59  }
60 
61  /* update outputs with tracking data from tools */
62  unsigned int numberOfInputs = this->GetNumberOfInputs();
63  if (numberOfInputs == 0)
64  {
65  return;
66  }
67  for (unsigned int i = 0; i < numberOfInputs ; ++i)
68  {
69  NavigationData* output = this->GetOutput(i);
70  assert(output);
71  const NavigationData* input = this->GetInput(i);
72  assert(input);
73 
74  if (!input->IsDataValid())
75  continue;
76 
77  output->Graft(input); // First, copy all information from input to output
78  }
79 
80  // Nothing left to do if we don't have an input with valid data
81  if (numberOfInputs == 0 || !this->GetInput()->IsDataValid())
82  return;
83 
84  // get position from NavigationData to move the slice to this position
85  Point3D slicePosition = this->GetInput()->GetPosition();
86 
87  {
88  NavigationData::OrientationType orientation = this->GetInput()->GetOrientation();
89 
90  Vector3D transformedTipOffset;
91  transformedTipOffset.SetVnlVector(orientation.rotate(m_TipOffset.GetVnlVector()));
92 
93  slicePosition += transformedTipOffset;
94 
95  mitk::SliceNavigationController::Pointer snc = m_Renderer->GetSliceNavigationController();
96 
97  if (Axial == m_ViewDirection)
98  {
99  snc->SetViewDirection(mitk::SliceNavigationController::Axial);
100  snc->SelectSliceByPoint(slicePosition);
101  }
102  else if (Sagittal == m_ViewDirection)
103  {
104  snc->SetViewDirection(mitk::SliceNavigationController::Sagittal);
105  snc->SelectSliceByPoint(slicePosition);
106  }
107  else if (Frontal == m_ViewDirection)
108  {
109  snc->SetViewDirection(mitk::SliceNavigationController::Frontal);
110  snc->SelectSliceByPoint(slicePosition);
111  }
112  else if (AxialOblique == m_ViewDirection || SagittalOblique == m_ViewDirection)
113  {
114  const int slicingPlaneXAxis = AxialOblique == m_ViewDirection ? 0 : 2;
115 
116  // The column 0 is the slicing plane's x-axis, column 1 is the slicing plane's y-axis
117  const mitk::Geometry2D::TransformType::MatrixType &m =
118  m_Renderer->GetCurrentWorldGeometry2D()->GetIndexToWorldTransform()->GetMatrix();
119 
120  // Rotate the tool trajectory vector into world coordinate frame (assuming
121  // NavigationData has passed through a NavigationDataTransformFilter to
122  // convert it into world coordinate frame)
123  Vector3D slicingPlaneYAxisVector;
124  slicingPlaneYAxisVector.SetVnlVector(orientation.rotate(m_ToolTrajectory.GetVnlVector()));
125 
126  // Project the tool trajectory onto the plane normal to x-axis of this
127  // oblique slicing. This defines the y-axis ("up") of the oblique slicing
128  // plane
129  slicingPlaneYAxisVector[slicingPlaneXAxis] = 0.0;
130 
131  // Do nothing for ambigous/undefined cases:
132  // - the R-L component of the x-axis is zero (for AxialOblique)
133  // - the S-I component of the x-axis is zero (for SagittalOblique)
134  // - the A-P component of the y-axis is zero
135  if ( m(slicingPlaneXAxis,0) == 0.0 ||
136  m(1,1) == 0.0 ||
137  (slicingPlaneXAxis != 0 && slicingPlaneYAxisVector[0] == 0.0) ||
138  (slicingPlaneXAxis != 1 && slicingPlaneYAxisVector[1] == 0.0) ||
139  (slicingPlaneXAxis != 2 && slicingPlaneYAxisVector[2] == 0.0) )
140  {
141  return;
142  }
143 
144  // Maintain the A-P orientation of the slice's y-axis regardless of what
145  // direction the tool trajectory points
147  if ( (m(1,1) > 0) != (slicingPlaneYAxisVector[1] > 0) )
148  {
149  slicingPlaneYAxisVector *= -1;
150  }
151 
152  Vector3D slicingPlaneXAxisVector;
153  slicingPlaneXAxisVector.Fill(0.0);
154  // For AxialOblique: maintain the Left/Right direction of the slice's x-axis
155  // For SagittalOblique: maintain the Superior/Inferior direction of the slice's x-axis
157  slicingPlaneXAxisVector[slicingPlaneXAxis] = m(slicingPlaneXAxis,0) > 0 ? 1.0 : -1.0;
158 
159  Point3D origin;
160  FillVector3D(origin, 0.0, 0.0, 0.0);
161  snc->ReorientSlices(origin, slicingPlaneXAxisVector, slicingPlaneYAxisVector);
162  snc->SelectSliceByPoint(slicePosition);
163  }
164  else if (Oblique == m_ViewDirection)
165  {
166  Vector3D slicingPlaneNormalVector;
167  slicingPlaneNormalVector.SetVnlVector(orientation.rotate(m_ToolTrajectory.GetVnlVector()));
168 
169  // The second column of the Index-to-World matrix is the positive y-axis
170  // of the current slicing plane in world coordinates.
171  const mitk::Geometry2D::TransformType::MatrixType &m =
172  m_Renderer->GetCurrentWorldGeometry2D()->GetIndexToWorldTransform()->GetMatrix();
173  mitk::Vector3D currentSlicingPlaneUpVector;
174  mitk::FillVector3D(currentSlicingPlaneUpVector, m[0][1], m[1][1], m[2][1]);
175  mitk::Vector3D worldUpVector = m_WorldVerticalVector;
176  if (angle(worldUpVector.GetVnlVector(), currentSlicingPlaneUpVector.GetVnlVector()) > vnl_math::pi_over_2 )
177  {
178  worldUpVector *= -1;
179  }
180 
182  Point3D origin;
183  FillVector3D(origin, 0.0, 0.0, 0.0);
184  slicingPlane->InitializePlane(origin, slicingPlaneNormalVector);
185 
186  // Now that we have the direction of WorldVerticalVector chosen to be the
187  // most "up" direction, project it onto the slicing plane to define the
188  // up vector (y-axis) of the reoriented slices
189  mitk::Vector3D slicingPlaneUpVector;
190  if ( slicingPlane->Project(worldUpVector, slicingPlaneUpVector) )
191  {
192  // slicingPlaneUpVector CROSS slicingPlaneNormalVector -> slicingPlaneRightVector
193  // Math is done in double precision as much as possible to get more
194  // orthogonal right and up vectors which fixes a VNL SVD error when
195  // the WorldGeometry matrix is later inverted
196  itk::Vector<double,3> slicingPlaneUpVector_double;
197  FillVector3D(slicingPlaneUpVector_double,
198  slicingPlaneUpVector[0], slicingPlaneUpVector[1], slicingPlaneUpVector[2]);
199  itk::Vector<double,3> slicingPlaneNormalVector_double;
200  FillVector3D(slicingPlaneNormalVector_double,
201  slicingPlaneNormalVector[0], slicingPlaneNormalVector[1], slicingPlaneNormalVector[2]);
202  itk::Vector<double,3> slicingPlaneRightVector_double = itk::CrossProduct(slicingPlaneUpVector_double,
203  slicingPlaneNormalVector_double);
204 
205  mitk::Vector3D slicingPlaneRightVector;
206  mitk::FillVector3D(slicingPlaneRightVector,
207  slicingPlaneRightVector_double[0], slicingPlaneRightVector_double[1], slicingPlaneRightVector_double[2]);
208  mitk::FillVector3D(slicingPlaneUpVector,
209  slicingPlaneUpVector_double[0], slicingPlaneUpVector_double[1], slicingPlaneUpVector_double[2]);
210 
211  snc->ReorientSlices(origin, slicingPlaneRightVector, slicingPlaneUpVector);
212  snc->SelectSliceByPoint(slicePosition);
213  }
214  }
215  else
216  {
217  MITK_ERROR << "Unsupported ViewDirection: " << m_ViewDirection;
218  }
219 
220  m_Renderer->RequestUpdate();
221  }
222 }
223 
NavigationDataToNavigationDataFilter is the base class of all filters that receive NavigationDatas as...
#define MITK_ERROR
Definition: mitkLogMacros.h:24
Navigation Data.
DataCollection - Class to facilitate loading/accessing structured data.
virtual void SetToolTrajectory(Vector3D direction)
Set/get the tool trajectory used to define the cutting plane normal direction.
mitk::Quaternion OrientationType
Type that holds the orientation part of the tracking data.
void FillVector3D(Tout &out, mitk::ScalarType x, mitk::ScalarType y, mitk::ScalarType z)
Definition: mitkArray.h:110
#define MITK_WARN
Definition: mitkLogMacros.h:23
virtual bool IsDataValid() const
returns true if the object contains valid data
virtual void Graft(const DataObject *data) override
Graft the data and information from one NavigationData to another.
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.
static Pointer New()