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