Medical Imaging Interaction Toolkit  2018.4.99-b585543d
Medical Imaging Interaction Toolkit
mitkSurfaceDeformationDataInteractor3D.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 (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
15 #include "mitkMouseWheelEvent.h"
16 
17 #include <vtkInteractorObserver.h>
18 #include <vtkPointData.h>
19 #include <vtkPolyData.h>
20 
22 {
23  m_OriginalPolyData = vtkPolyData::New();
24 
25  // Initialize vector arithmetic
26  m_ObjectNormal[0] = 0.0;
27  m_ObjectNormal[1] = 0.0;
28  m_ObjectNormal[2] = 1.0;
29 }
30 
32 {
33  m_OriginalPolyData->Delete();
34 }
35 
37 {
38  // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before
39  // actually executing an action
40  CONNECT_CONDITION("isOverObject", CheckOverObject);
41 
42  // **Function** in the statmachine patterns also referred to as **Actions**
43  CONNECT_FUNCTION("selectObject", SelectObject);
44  CONNECT_FUNCTION("deselectObject", DeselectObject);
45  CONNECT_FUNCTION("initDeformation", InitDeformation);
46  CONNECT_FUNCTION("deformObject", DeformObject);
47  CONNECT_FUNCTION("scaleRadius", ScaleRadius);
48 }
49 
51 {
52  if (this->GetDataNode() != nullptr)
53  {
54  m_Surface = dynamic_cast<Surface *>(this->GetDataNode()->GetData());
55 
56  if (m_Surface == nullptr)
57  MITK_ERROR << "SurfaceDeformationDataInteractor3D::DataNodeChanged(): DataNode has to contain a surface.";
58  }
59  else
60  m_Surface = nullptr;
61 }
62 
64 {
65  const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
66  if (positionEvent == nullptr)
67  return false;
68 
69  Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
70  Point3D currentPickedPoint;
71 
72  if (interactionEvent->GetSender()->PickObject(currentPickedDisplayPoint, currentPickedPoint) == this->GetDataNode())
73  {
74  // Colorized surface at current picked position
75  m_SurfaceColorizationCenter = currentPickedPoint;
76  return true;
77  }
78  return false;
79 }
80 
82 {
83  const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
84  if (positionEvent == nullptr)
85  return;
86 
87  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
88  vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep);
89 
90  this->GetDataNode()->SetColor(1.0, 0.0, 0.0);
91 
92  // Colorize surface / wireframe dependend on distance from picked point
93  this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_GAUSS);
94 
96 }
97 
99 {
100  const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
101  if (positionEvent == nullptr)
102  return;
103 
104  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
105  vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep);
106 
107  this->GetDataNode()->SetColor(1.0, 1.0, 1.0);
108 
109  // Colorize surface / wireframe as inactive
110  this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_CONSTANT, -1.0);
111 
113 }
114 
116 {
117  const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
118  if (positionEvent == nullptr)
119  return;
120 
121  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
122  vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep);
123 
124  // Store current picked point
125  mitk::Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
126  interactionEvent->GetSender()->PickObject(currentPickedDisplayPoint, m_InitialPickedPoint);
127 
128  vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(),
129  currentPickedDisplayPoint[0],
130  currentPickedDisplayPoint[1],
131  0.0, // m_InitialInteractionPickedPoint[2],
132  m_InitialPickedWorldPoint);
133 
134  // Make deep copy of vtkPolyData interacted on
135  m_OriginalPolyData->DeepCopy(polyData);
136 }
137 
139 {
140  const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
141  if (positionEvent == nullptr)
142  return;
143 
144  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
145  vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep);
146  BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetGeometry(timeStep);
147 
148  double currentWorldPoint[4];
149  mitk::Point2D currentDisplayPoint = positionEvent->GetPointerPositionOnScreen();
150  vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(),
151  currentDisplayPoint[0],
152  currentDisplayPoint[1],
153  0.0, // m_InitialInteractionPickedPoint[2],
154  currentWorldPoint);
155 
156  // Calculate mouse move in 3D space
157  Vector3D interactionMove;
158  interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0];
159  interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1];
160  interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2];
161 
162  // Transform mouse move into geometry space
163  this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date
164  Vector3D interactionMoveIndex;
165  geometry->WorldToIndex(interactionMove, interactionMoveIndex);
166 
167  // Get picked point and transform into local coordinates
168  Point3D pickedPoint;
169  geometry->WorldToIndex(m_InitialPickedPoint, pickedPoint);
170 
171  Vector3D v1 = pickedPoint.GetVectorFromOrigin();
172 
173  vtkDataArray *normal = polyData->GetPointData()->GetVectors("planeNormal");
174  if (normal != nullptr)
175  {
176  m_ObjectNormal[0] = normal->GetComponent(0, 0);
177  m_ObjectNormal[1] = normal->GetComponent(0, 1);
178  m_ObjectNormal[2] = normal->GetComponent(0, 2);
179  }
180 
181  Vector3D v2 = m_ObjectNormal * (interactionMoveIndex * m_ObjectNormal);
182 
183  vtkPoints *originalPoints = m_OriginalPolyData->GetPoints();
184  vtkPoints *deformedPoints = polyData->GetPoints();
185 
186  double denom = m_GaussSigma * m_GaussSigma * 2;
187  double point[3];
188  for (vtkIdType i = 0; i < deformedPoints->GetNumberOfPoints(); ++i)
189  {
190  // Get original point
191  double *originalPoint = originalPoints->GetPoint(i);
192 
193  Vector3D v0;
194  v0[0] = originalPoint[0];
195  v0[1] = originalPoint[1];
196  v0[2] = originalPoint[2];
197 
198  // Calculate distance of this point from line through picked point
199  double d = itk::CrossProduct(m_ObjectNormal, (v1 - v0)).GetNorm();
200 
201  Vector3D t = v2 * exp(-d * d / denom);
202 
203  point[0] = originalPoint[0] + t[0];
204  point[1] = originalPoint[1] + t[1];
205  point[2] = originalPoint[2] + t[2];
206  deformedPoints->SetPoint(i, point);
207  }
208 
209  // Make sure that surface is colorized at initial picked position as long as we are in deformation state
210  m_SurfaceColorizationCenter = m_InitialPickedPoint;
211 
212  polyData->Modified();
213  m_Surface->Modified();
214 
216 }
217 
219 {
220  const auto *wheelEvent = dynamic_cast<const MouseWheelEvent *>(interactionEvent);
221  if (wheelEvent == nullptr)
222  return;
223 
224  m_GaussSigma += (double)(wheelEvent->GetWheelDelta()) / 20;
225  if (m_GaussSigma < 10.0)
226  {
227  m_GaussSigma = 10.0;
228  }
229  else if (m_GaussSigma > 128.0)
230  {
231  m_GaussSigma = 128.0;
232  }
233 
234  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
235  vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep);
236 
237  // Colorize surface / wireframe dependend on sigma and distance from picked point
238  this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_GAUSS);
239 
241 }
242 
243 void mitk::SurfaceDeformationDataInteractor3D::ColorizeSurface(
244  vtkPolyData *polyData, int timeStep, const Point3D &pickedPoint, int mode, double scalar)
245 {
246  if (polyData == nullptr)
247  return;
248 
249  vtkPoints *points = polyData->GetPoints();
250  vtkPointData *pointData = polyData->GetPointData();
251  if (pointData == nullptr)
252  return;
253 
254  vtkDataArray *scalars = pointData->GetScalars();
255  if (scalars == nullptr)
256  return;
257 
258  if (mode == COLORIZATION_GAUSS)
259  {
260  // Get picked point and transform into local coordinates
261  Point3D localPickedPoint;
262  BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetGeometry(timeStep);
263  geometry->WorldToIndex(pickedPoint, localPickedPoint);
264 
265  Vector3D v1 = localPickedPoint.GetVectorFromOrigin();
266 
267  vtkDataArray *normal = polyData->GetPointData()->GetVectors("planeNormal");
268  if (normal != nullptr)
269  {
270  m_ObjectNormal[0] = normal->GetComponent(0, 0);
271  m_ObjectNormal[1] = normal->GetComponent(0, 1);
272  m_ObjectNormal[2] = normal->GetComponent(0, 2);
273  }
274 
275  double denom = m_GaussSigma * m_GaussSigma * 2;
276  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
277  {
278  // Get original point
279  double *point = points->GetPoint(i);
280  Vector3D v0;
281  v0[0] = point[0];
282  v0[1] = point[1];
283  v0[2] = point[2];
284 
285  // Calculate distance of this point from line through picked point
286  double d = itk::CrossProduct(m_ObjectNormal, (v1 - v0)).GetNorm();
287  double t = exp(-d * d / denom);
288 
289  scalars->SetComponent(i, 0, t);
290  }
291  }
292  else if (mode == COLORIZATION_CONSTANT)
293  {
294  for (vtkIdType i = 0; i < pointData->GetNumberOfTuples(); ++i)
295  {
296  scalars->SetComponent(i, 0, scalar);
297  }
298  }
299  polyData->Modified();
300  pointData->Update();
301 }
virtual void ScaleRadius(StateMachineAction *, InteractionEvent *)
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:28
virtual void SelectObject(StateMachineAction *, InteractionEvent *)
Super class for all position events.
virtual void DeselectObject(StateMachineAction *, InteractionEvent *)
virtual vtkPolyData * GetVtkPolyData(unsigned int t=0) const
vtkRenderer * GetVtkRenderer() const
#define MITK_ERROR
Definition: mitkLogMacros.h:20
DataNode * GetDataNode() const
BaseRenderer * GetSender() const
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
virtual void DeformObject(StateMachineAction *, InteractionEvent *)
static RenderingManager * GetInstance()
Represents an action, that is executed after a certain event (in statemachine-mechanism) TODO: implem...
virtual unsigned int GetTimeStep() const
virtual void InitDeformation(StateMachineAction *, InteractionEvent *)
void SetColor(const mitk::Color &color, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="color")
Convenience method for setting color properties (instances of ColorProperty)
void UpdateOutputInformation() override
Update the information for this BaseData (the geometry in particular) so that it can be used as an ou...
virtual DataNode * PickObject(const Point2D &, Point3D &) const
Determines the object (mitk::DataNode) closest to the current position by means of picking...
#define CONNECT_CONDITION(a, f)
static Point3D originalPoint
#define CONNECT_FUNCTION(a, f)
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:138
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)