Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkClippingPlaneInteractor3D.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 <mitkInteractionConst.h>
21 #include <mitkRotationOperation.h>
22 #include <mitkSurface.h>
23 
24 #include <vtkCamera.h>
25 #include <vtkInteractorObserver.h>
26 #include <vtkInteractorStyle.h>
27 #include <vtkPointData.h>
28 #include <vtkPolyData.h>
29 #include <vtkRenderWindowInteractor.h>
30 
32 {
33  m_OriginalGeometry = Geometry3D::New();
34 
35  // Initialize vector arithmetic
36  m_ObjectNormal[0] = 0.0;
37  m_ObjectNormal[1] = 0.0;
38  m_ObjectNormal[2] = 1.0;
39 }
40 
42 {
43 }
44 
46 {
47  // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually
48  // executing an action
49  CONNECT_CONDITION("isOverObject", CheckOverObject);
50 
51  // **Function** in the statmachine patterns also referred to as **Actions**
52  CONNECT_FUNCTION("selectObject", SelectObject);
53  CONNECT_FUNCTION("deselectObject", DeselectObject);
54  CONNECT_FUNCTION("initTranslate", InitTranslate);
55  CONNECT_FUNCTION("initRotate", InitRotate);
56  CONNECT_FUNCTION("translateObject", TranslateObject);
57  CONNECT_FUNCTION("rotateObject", RotateObject);
58 }
59 
61 {
62 }
63 
65 {
66  const InteractionPositionEvent *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
67  if (positionEvent == NULL)
68  return false;
69 
70  Point3D currentWorldPoint;
71  if (interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), currentWorldPoint) ==
72  this->GetDataNode())
73  return true;
74 
75  return false;
76 }
77 
79 {
80  DataNode::Pointer node = this->GetDataNode();
81 
82  if (node.IsNull())
83  return;
84 
85  node->SetColor(1.0, 0.0, 0.0);
86 
87  // Colorize surface / wireframe dependend on distance from picked point
88  this->ColorizeSurface(interactionEvent->GetSender(), 0.0);
89 
90  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
91 }
92 
94 {
95  DataNode::Pointer node = this->GetDataNode();
96 
97  if (node.IsNull())
98  return;
99 
100  node->SetColor(1.0, 1.0, 1.0);
101 
102  // Colorize surface / wireframe as inactive
103  this->ColorizeSurface(interactionEvent->GetSender(), -1.0);
104 
105  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
106 }
107 
109 {
110  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
111  if (positionEvent == NULL)
112  return;
113 
114  m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
115 
116  vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(),
117  m_InitialPickedDisplayPoint[0],
118  m_InitialPickedDisplayPoint[1],
119  0.0, // m_InitialInteractionPickedPoint[2],
120  m_InitialPickedWorldPoint);
121 
122  // Get the timestep to also support 3D+t
123  int timeStep = 0;
124  if ((interactionEvent->GetSender()) != NULL)
125  timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
126 
127  // Make deep copy of current Geometry3D of the plane
128  this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date
129  m_OriginalGeometry =
130  static_cast<Geometry3D *>(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer());
131 }
132 
134 {
135  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
136  if (positionEvent == NULL)
137  return;
138 
139  m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
140 
141  vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(),
142  m_InitialPickedDisplayPoint[0],
143  m_InitialPickedDisplayPoint[1],
144  0.0, // m_InitialInteractionPickedPoint[2],
145  m_InitialPickedWorldPoint);
146 
147  // Get the timestep to also support 3D+t
148  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
149 
150  // Make deep copy of current Geometry3D of the plane
151  this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date
152  m_OriginalGeometry =
153  static_cast<Geometry3D *>(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer());
154 }
155 
157 {
158  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
159  if (positionEvent == NULL)
160  return;
161 
162  double currentWorldPoint[4];
163  mitk::Point2D currentDisplayPoint = positionEvent->GetPointerPositionOnScreen();
164  vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(),
165  currentDisplayPoint[0],
166  currentDisplayPoint[1],
167  0.0, // m_InitialInteractionPickedPoint[2],
168  currentWorldPoint);
169 
170  Vector3D interactionMove;
171  interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0];
172  interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1];
173  interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2];
174 
175  Point3D origin = m_OriginalGeometry->GetOrigin();
176 
177  // Get the timestep to also support 3D+t
178  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
179 
180  // If data is an mitk::Surface, extract it
181  Surface::Pointer surface = dynamic_cast<Surface *>(this->GetDataNode()->GetData());
182  vtkPolyData *polyData = NULL;
183  if (surface.IsNotNull())
184  {
185  polyData = surface->GetVtkPolyData(timeStep);
186 
187  // Extract surface normal from surface (if existent, otherwise use default)
188  vtkPointData *pointData = polyData->GetPointData();
189  if (pointData != NULL)
190  {
191  vtkDataArray *normal = polyData->GetPointData()->GetVectors("planeNormal");
192  if (normal != NULL)
193  {
194  m_ObjectNormal[0] = normal->GetComponent(0, 0);
195  m_ObjectNormal[1] = normal->GetComponent(0, 1);
196  m_ObjectNormal[2] = normal->GetComponent(0, 2);
197  }
198  }
199  }
200 
201  Vector3D transformedObjectNormal;
202  this->GetDataNode()->GetData()->GetGeometry(timeStep)->IndexToWorld(m_ObjectNormal, transformedObjectNormal);
203 
204  this->GetDataNode()->GetData()->GetGeometry(timeStep)->SetOrigin(
205  origin + transformedObjectNormal * (interactionMove * transformedObjectNormal));
206 
207  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
208 }
209 
211 {
212  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
213  if (positionEvent == NULL)
214  return;
215 
216  double currentWorldPoint[4];
217  Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
218  vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(),
219  currentPickedDisplayPoint[0],
220  currentPickedDisplayPoint[1],
221  0.0, // m_InitialInteractionPickedPoint[2],
222  currentWorldPoint);
223 
224  vtkCamera *camera = NULL;
225  vtkRenderer *currentVtkRenderer = NULL;
226 
227  if ((interactionEvent->GetSender()) != NULL)
228  {
229  vtkRenderWindow *renderWindow = interactionEvent->GetSender()->GetRenderWindow();
230  if (renderWindow != NULL)
231  {
232  vtkRenderWindowInteractor *renderWindowInteractor = renderWindow->GetInteractor();
233  if (renderWindowInteractor != NULL)
234  {
235  currentVtkRenderer = renderWindowInteractor->GetInteractorStyle()->GetCurrentRenderer();
236  if (currentVtkRenderer != NULL)
237  camera = currentVtkRenderer->GetActiveCamera();
238  }
239  }
240  }
241  if (camera)
242  {
243  double vpn[3];
244  camera->GetViewPlaneNormal(vpn);
245 
246  Vector3D viewPlaneNormal;
247  viewPlaneNormal[0] = vpn[0];
248  viewPlaneNormal[1] = vpn[1];
249  viewPlaneNormal[2] = vpn[2];
250 
251  Vector3D interactionMove;
252  interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0];
253  interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1];
254  interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2];
255 
256  if (interactionMove[0] == 0 && interactionMove[1] == 0 && interactionMove[2] == 0)
257  return;
258 
259  Vector3D rotationAxis = itk::CrossProduct(viewPlaneNormal, interactionMove);
260  rotationAxis.Normalize();
261 
262  int *size = currentVtkRenderer->GetSize();
263  double l2 = (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) *
264  (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) +
265  (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]) *
266  (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]);
267 
268  double rotationAngle = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1]));
269 
270  // Use center of data bounding box as center of rotation
271  Point3D rotationCenter = m_OriginalGeometry->GetCenter();
272 
273  int timeStep = 0;
274  if ((interactionEvent->GetSender()) != NULL)
275  timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
276 
277  // Reset current Geometry3D to original state (pre-interaction) and
278  // apply rotation
279  RotationOperation op(OpROTATE, rotationCenter, rotationAxis, rotationAngle);
280  Geometry3D::Pointer newGeometry = static_cast<Geometry3D *>(m_OriginalGeometry->Clone().GetPointer());
281  newGeometry->ExecuteOperation(&op);
282  mitk::TimeGeometry::Pointer timeGeometry = this->GetDataNode()->GetData()->GetTimeGeometry();
283  if (timeGeometry.IsNotNull())
284  timeGeometry->SetTimeStepGeometry(newGeometry, timeStep);
285 
286  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
287  }
288 }
289 
290 void mitk::ClippingPlaneInteractor3D::ColorizeSurface(BaseRenderer::Pointer renderer, double scalar)
291 {
292  BaseData::Pointer data = this->GetDataNode()->GetData();
293  if (data.IsNull())
294  {
295  MITK_ERROR << "ClippingPlaneInteractor3D: No data object present!";
296  return;
297  }
298 
299  // Get the timestep to also support 3D+t
300  int timeStep = 0;
301  if (renderer.IsNotNull())
302  timeStep = renderer->GetTimeStep(data);
303 
304  // If data is an mitk::Surface, extract it
305  Surface::Pointer surface = dynamic_cast<Surface *>(data.GetPointer());
306  vtkPolyData *polyData = NULL;
307  if (surface.IsNotNull())
308  polyData = surface->GetVtkPolyData(timeStep);
309 
310  if (polyData == NULL)
311  {
312  MITK_ERROR << "ClippingPlaneInteractor3D: No poly data present!";
313  return;
314  }
315 
316  vtkPointData *pointData = polyData->GetPointData();
317  if (pointData == NULL)
318  {
319  MITK_ERROR << "ClippingPlaneInteractor3D: No point data present!";
320  return;
321  }
322 
323  vtkDataArray *scalars = pointData->GetScalars();
324  if (scalars == NULL)
325  {
326  MITK_ERROR << "ClippingPlaneInteractor3D: No scalars for point data present!";
327  return;
328  }
329 
330  for (vtkIdType i = 0; i < pointData->GetNumberOfTuples(); ++i)
331  {
332  scalars->SetComponent(i, 0, scalar);
333  }
334 
335  polyData->Modified();
336  pointData->Update();
337 }
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:32
Super class for all position events.
Standard implementation of BaseGeometry.
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 InitRotate(StateMachineAction *, InteractionEvent *)
itk::SmartPointer< Self > Pointer
Definition: mitkSurface.h:37
static Pointer New()
Constants for most interaction classes, due to the generic StateMachines.
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 RotateObject(StateMachineAction *, InteractionEvent *)
virtual void InitTranslate(StateMachineAction *, InteractionEvent *)
virtual mitk::RenderingManager * GetRenderingManager() const
Setter for the RenderingManager that handles this instance of BaseRenderer.
virtual void TranslateObject(StateMachineAction *, InteractionEvent *)
Performs a translation of the object relative to the mouse movement.
Represents an action, that is executed after a certain event (in statemachine-mechanism) TODO: implem...
virtual bool CheckOverObject(const InteractionEvent *)
virtual void SelectObject(StateMachineAction *, InteractionEvent *)
virtual unsigned int GetTimeStep() const
virtual void DeselectObject(StateMachineAction *, InteractionEvent *)
#define CONNECT_CONDITION(a, f)
virtual void TranslateObject(StateMachineAction *, InteractionEvent *)
#define CONNECT_FUNCTION(a, f)
vtkRenderer * GetVtkRenderer() const
Operation, that holds everything necessary for an rotation operation on mitk::BaseData.
vtkRenderWindow * GetRenderWindow() const
Access the RenderWindow into which this renderer renders.
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)