Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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)