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