Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
mitkAffineBaseDataInteractor3D.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 <mitkScaleOperation.h>
19 #include <mitkSurface.h>
20 
22 #include <vtkCamera.h>
23 #include <vtkInteractorObserver.h>
24 #include <vtkInteractorStyle.h>
25 #include <vtkPointData.h>
26 #include <vtkPolyData.h>
27 #include <vtkRenderWindowInteractor.h>
28 
29 // Properties to allow the user to interact with the base data
30 const char *translationStepSizePropertyName = "AffineBaseDataInteractor3D.Translation Step Size";
31 const char *selectedColorPropertyName = "AffineBaseDataInteractor3D.Selected Color";
32 const char *deselectedColorPropertyName = "AffineBaseDataInteractor3D.Deselected Color";
33 const char *priorPropertyName = "AffineBaseDataInteractor3D.Prior Color";
34 const char *rotationStepSizePropertyName = "AffineBaseDataInteractor3D.Rotation Step Size";
35 const char *scaleStepSizePropertyName = "AffineBaseDataInteractor3D.Scale Step Size";
36 const char *anchorPointX = "AffineBaseDataInteractor3D.Anchor Point X";
37 const char *anchorPointY = "AffineBaseDataInteractor3D.Anchor Point Y";
38 const char *anchorPointZ = "AffineBaseDataInteractor3D.Anchor Point Z";
39 
41 {
42  m_OriginalGeometry = mitk::Geometry3D::New();
43 }
44 
46 {
47  this->RestoreNodeProperties();
48 }
49 
51 {
52  // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually
53  // executing an action
54  CONNECT_CONDITION("isOverObject", CheckOverObject);
55 
56  // **Function** in the statmachine patterns also referred to as **Actions**
57  CONNECT_FUNCTION("selectObject", SelectObject);
58  CONNECT_FUNCTION("deselectObject", DeselectObject);
59  CONNECT_FUNCTION("initTranslate", InitTranslate);
60  CONNECT_FUNCTION("initRotate", InitRotate);
61  CONNECT_FUNCTION("translateObject", TranslateObject);
62  CONNECT_FUNCTION("rotateObject", RotateObject);
63  CONNECT_FUNCTION("scaleObject", ScaleObject);
64 
65  CONNECT_FUNCTION("translateUpKey", TranslateUpKey);
66  CONNECT_FUNCTION("translateDownKey", TranslateDownKey);
67  CONNECT_FUNCTION("translateLeftKey", TranslateLeftKey);
68  CONNECT_FUNCTION("translateRightKey", TranslateRightKey);
69  CONNECT_FUNCTION("translateUpModifierKey", TranslateUpModifierKey);
70  CONNECT_FUNCTION("translateDownModifierKey", TranslateDownModifierKey);
71 
72  CONNECT_FUNCTION("scaleDownKey", ScaleDownKey);
73  CONNECT_FUNCTION("scaleUpKey", ScaleUpKey);
74 
75  CONNECT_FUNCTION("rotateUpKey", RotateUpKey);
76  CONNECT_FUNCTION("rotateDownKey", RotateDownKey);
77  CONNECT_FUNCTION("rotateLeftKey", RotateLeftKey);
78  CONNECT_FUNCTION("rotateRightKey", RotateRightKey);
79  CONNECT_FUNCTION("rotateUpModifierKey", RotateUpModifierKey);
80  CONNECT_FUNCTION("rotateDownModifierKey", RotateDownModifierKey);
81 }
82 
84 {
85  float stepSize = 1.0f;
87  mitk::Vector3D movementVector;
88  movementVector.Fill(0.0);
89  movementVector.SetElement(2, stepSize);
90  this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent));
91 }
92 
94  mitk::InteractionEvent *interactionEvent)
95 {
96  float stepSize = 1.0f;
98  mitk::Vector3D movementVector;
99  movementVector.Fill(0.0);
100  movementVector.SetElement(2, -stepSize);
101  this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent));
102 }
103 
105  mitk::InteractionEvent *interactionEvent)
106 {
107  float stepSize = 1.0f;
109  mitk::Vector3D movementVector;
110  movementVector.Fill(0.0);
111  movementVector.SetElement(0, -stepSize);
112  this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent));
113 }
114 
116  mitk::InteractionEvent *interactionEvent)
117 {
118  float stepSize = 1.0f;
120  mitk::Vector3D movementVector;
121  movementVector.Fill(0.0);
122  movementVector.SetElement(0, stepSize);
123  this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent));
124 }
125 
127  mitk::InteractionEvent *interactionEvent)
128 {
129  float stepSize = 1.0f;
131  mitk::Vector3D movementVector;
132  movementVector.Fill(0.0);
133  movementVector.SetElement(1, stepSize);
134  this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent));
135 }
136 
138  mitk::InteractionEvent *interactionEvent)
139 {
140  float stepSize = 1.0f;
142  mitk::Vector3D movementVector;
143  movementVector.Fill(0.0);
144  movementVector.SetElement(1, -stepSize);
145  this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent));
146 }
147 
149 {
150  float stepSize = 1.0f;
152  this->RotateGeometry(-stepSize, 0, this->GetUpdatedTimeGeometry(interactionEvent));
153 }
154 
156  mitk::InteractionEvent *interactionEvent)
157 {
158  float stepSize = 1.0f;
160  this->RotateGeometry(stepSize, 0, this->GetUpdatedTimeGeometry(interactionEvent));
161  return;
162 }
163 
165  mitk::InteractionEvent *interactionEvent)
166 {
167  float stepSize = 1.0f;
169  this->RotateGeometry(-stepSize, 2, this->GetUpdatedTimeGeometry(interactionEvent));
170 }
171 
173  mitk::InteractionEvent *interactionEvent)
174 {
175  float stepSize = 1.0f;
177  this->RotateGeometry(stepSize, 2, this->GetUpdatedTimeGeometry(interactionEvent));
178 }
179 
181  mitk::InteractionEvent *interactionEvent)
182 {
183  float stepSize = 1.0f;
185  this->RotateGeometry(stepSize, 1, this->GetUpdatedTimeGeometry(interactionEvent));
186 }
187 
189  mitk::InteractionEvent *interactionEvent)
190 {
191  float stepSize = 1.0f;
193  this->RotateGeometry(-stepSize, 1, this->GetUpdatedTimeGeometry(interactionEvent));
194 }
195 
197 {
198  float stepSize = 0.1f;
200  mitk::Point3D newScale;
201  newScale.Fill(stepSize);
202  this->ScaleGeometry(newScale, this->GetUpdatedTimeGeometry(interactionEvent));
203 }
204 
206  mitk::InteractionEvent *interactionEvent)
207 {
208  float stepSize = 0.1f;
210  mitk::Point3D newScale;
211  newScale.Fill(-stepSize);
212  this->ScaleGeometry(newScale, this->GetUpdatedTimeGeometry(interactionEvent));
213 }
214 
216 {
217  mitk::Point3D anchorPoint;
218  float pointX = 0.0f;
219  float pointY = 0.0f;
220  float pointZ = 0.0f;
221  anchorPoint.Fill(0.0);
222  this->GetDataNode()->GetFloatProperty(anchorPointX, pointX);
223  this->GetDataNode()->GetFloatProperty(anchorPointY, pointY);
224  this->GetDataNode()->GetFloatProperty(anchorPointZ, pointZ);
225  anchorPoint[0] = pointX;
226  anchorPoint[1] = pointY;
227  anchorPoint[2] = pointZ;
228 
229  auto *doOp = new mitk::ScaleOperation(OpSCALE, newScale, anchorPoint);
230  geometry->ExecuteOperation(doOp);
231 
233 }
234 
236  int rotationaxis,
237  mitk::BaseGeometry *geometry)
238 {
239  mitk::Vector3D rotationAxis = geometry->GetAxisVector(rotationaxis);
240  float pointX = 0.0f;
241  float pointY = 0.0f;
242  float pointZ = 0.0f;
243  mitk::Point3D pointOfRotation;
244  pointOfRotation.Fill(0.0);
245  this->GetDataNode()->GetFloatProperty(anchorPointX, pointX);
246  this->GetDataNode()->GetFloatProperty(anchorPointY, pointY);
247  this->GetDataNode()->GetFloatProperty(anchorPointZ, pointZ);
248  pointOfRotation[0] = pointX;
249  pointOfRotation[1] = pointY;
250  pointOfRotation[2] = pointZ;
251 
252  auto *doOp = new mitk::RotationOperation(OpROTATE, pointOfRotation, rotationAxis, angle);
253 
254  geometry->ExecuteOperation(doOp);
255  delete doOp;
257 }
258 
260 {
261  geometry->Translate(translate);
262  this->GetDataNode()->Modified();
264 }
265 
267 {
268  // Get the correct time geometry to support 3D + t
269  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
271  if (geometry == nullptr)
272  MITK_ERROR << "Geometry is nullptr. Cannot modify it.";
273  return geometry;
274 }
275 
277 {
278  mitk::DataNode::Pointer newInputNode = this->GetDataNode();
279  if (newInputNode.IsNotNull())
280  {
281  // add default properties
282  newInputNode->AddProperty(selectedColorPropertyName, mitk::ColorProperty::New(0.0, 1.0, 0.0));
283  newInputNode->AddProperty(deselectedColorPropertyName, mitk::ColorProperty::New(0.0, 0.0, 1.0));
284  newInputNode->AddProperty(translationStepSizePropertyName, mitk::FloatProperty::New(1.0f));
285  newInputNode->AddProperty(rotationStepSizePropertyName, mitk::FloatProperty::New(1.0f));
286  newInputNode->AddProperty(scaleStepSizePropertyName, mitk::FloatProperty::New(0.1f));
287 
288  // save the previous color of the node, in order to restore it after the interactor is destroyed
289  mitk::ColorProperty::Pointer priorColor = dynamic_cast<mitk::ColorProperty *>(newInputNode->GetProperty("color"));
290  if (priorColor.IsNotNull())
291  {
293  tmpCopyOfPriorColor->SetColor(priorColor->GetColor());
294  newInputNode->AddProperty(priorPropertyName, tmpCopyOfPriorColor);
295  }
296  newInputNode->SetColor(0.0, 0.0, 1.0);
297  }
299 }
300 
302 {
303  this->RestoreNodeProperties(); // if there was another node set, restore it's color
305 }
306 
308 {
309  const auto *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
310  if (positionEvent == nullptr)
311  return false;
312 
313  Point3D currentWorldPoint;
314  if (interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), currentWorldPoint) ==
315  this->GetDataNode())
316  return true;
317 
318  return false;
319 }
320 
322 {
323  DataNode::Pointer node = this->GetDataNode();
324 
325  if (node.IsNull())
326  return;
327 
329  dynamic_cast<mitk::ColorProperty *>(node->GetProperty(selectedColorPropertyName));
330  if (selectedColor.IsNotNull())
331  {
332  node->GetPropertyList()->SetProperty("color", selectedColor);
333  }
335 
336  return;
337 }
338 
340 {
341  DataNode::Pointer node = this->GetDataNode();
342 
343  if (node.IsNull())
344  return;
345 
347  dynamic_cast<mitk::ColorProperty *>(node->GetProperty(deselectedColorPropertyName));
348  if (selectedColor.IsNotNull())
349  {
350  node->GetPropertyList()->SetProperty("color", selectedColor);
351  }
352 
354 
355  return;
356 }
357 
359 {
360  InitMembers(interactionEvent);
361 }
362 
364 {
365  InitMembers(interactionEvent);
366 }
367 
369 {
370  auto *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
371  if (positionEvent == nullptr)
372  return false;
373 
374  m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
375  m_InitialPickedWorldPoint = positionEvent->GetPositionInWorld();
376 
377  // Get the timestep to also support 3D+t
378  int timeStep = 0;
379  if ((interactionEvent->GetSender()) != nullptr)
380  timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
381 
382  // Make deep copy of current Geometry3D of the plane
383  this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date
384  m_OriginalGeometry =
385  static_cast<Geometry3D *>(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer());
386  return true;
387 }
388 
390 {
391  auto *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
392  if (positionEvent == nullptr)
393  return;
394 
395  Point3D currentPickedPoint = positionEvent->GetPositionInWorld();
396 
397  Vector3D interactionMove;
398  interactionMove[0] = currentPickedPoint[0] - m_InitialPickedWorldPoint[0];
399  interactionMove[1] = currentPickedPoint[1] - m_InitialPickedWorldPoint[1];
400  interactionMove[2] = currentPickedPoint[2] - m_InitialPickedWorldPoint[2];
401 
402  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
403 
404  mitk::BaseGeometry::Pointer geometry =
406  geometry->SetOrigin(m_OriginalGeometry->GetOrigin());
407 
408  this->TranslateGeometry(interactionMove, this->GetUpdatedTimeGeometry(interactionEvent));
409 
410  return;
411 }
412 
414 {
415  auto *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
416  if (positionEvent == nullptr)
417  return;
418 
419  Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
420  Point3D currentWorldPoint = positionEvent->GetPositionInWorld();
421 
422  vtkCamera *camera = nullptr;
423  vtkRenderer *currentVtkRenderer = nullptr;
424 
425  if ((interactionEvent->GetSender()) != nullptr)
426  {
427  camera = interactionEvent->GetSender()->GetVtkRenderer()->GetActiveCamera();
428  currentVtkRenderer = interactionEvent->GetSender()->GetVtkRenderer();
429  }
430  if (camera && currentVtkRenderer)
431  {
432  double vpn[3];
433  camera->GetViewPlaneNormal(vpn);
434 
435  Vector3D viewPlaneNormal;
436  viewPlaneNormal[0] = vpn[0];
437  viewPlaneNormal[1] = vpn[1];
438  viewPlaneNormal[2] = vpn[2];
439 
440  Vector3D interactionMove;
441  interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0];
442  interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1];
443  interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2];
444 
445  if (interactionMove[0] == 0 && interactionMove[1] == 0 && interactionMove[2] == 0)
446  return;
447 
448  Vector3D rotationAxis = itk::CrossProduct(viewPlaneNormal, interactionMove);
449  rotationAxis.Normalize();
450 
451  int *size = currentVtkRenderer->GetSize();
452  double l2 = (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) *
453  (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) +
454  (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]) *
455  (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]);
456 
457  double rotationAngle = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1]));
458 
459  // Use center of data bounding box as center of rotation
460  Point3D rotationCenter = m_OriginalGeometry->GetCenter();
461 
462  int timeStep = 0;
463  if ((interactionEvent->GetSender()) != nullptr)
464  timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
465 
466  // Reset current Geometry3D to original state (pre-interaction) and
467  // apply rotation
468  RotationOperation op(OpROTATE, rotationCenter, rotationAxis, rotationAngle);
469  Geometry3D::Pointer newGeometry = static_cast<Geometry3D *>(m_OriginalGeometry->Clone().GetPointer());
470  newGeometry->ExecuteOperation(&op);
471  mitk::TimeGeometry::Pointer timeGeometry = this->GetDataNode()->GetData()->GetTimeGeometry();
472  if (timeGeometry.IsNotNull())
473  timeGeometry->SetTimeStepGeometry(newGeometry, timeStep);
474 
476  }
477 }
478 
480 {
481  return;
482 }
483 
485 {
486  mitk::DataNode::Pointer inputNode = this->GetDataNode();
487  if (inputNode.IsNull())
488  return;
489  mitk::ColorProperty::Pointer color = dynamic_cast<mitk::ColorProperty *>(inputNode->GetProperty(priorPropertyName));
490  if (color.IsNotNull())
491  {
492  inputNode->GetPropertyList()->SetProperty("color", color);
493  }
494 
495  inputNode->GetPropertyList()->DeleteProperty(selectedColorPropertyName);
496  inputNode->GetPropertyList()->DeleteProperty(deselectedColorPropertyName);
497  inputNode->GetPropertyList()->DeleteProperty(priorPropertyName);
498  inputNode->GetPropertyList()->DeleteProperty(translationStepSizePropertyName);
499  inputNode->GetPropertyList()->DeleteProperty(rotationStepSizePropertyName);
500  inputNode->GetPropertyList()->DeleteProperty(scaleStepSizePropertyName);
501 
502  // update rendering
504 }
virtual void ScaleDownKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent)
Super class for all position events.
Standard implementation of BaseGeometry.
void ScaleGeometry(mitk::Point3D newScale, mitk::BaseGeometry *geometry)
const char * priorPropertyName
Vector3D GetAxisVector(unsigned int direction) const
Get vector along bounding-box in the specified direction in mm.
virtual void SelectObject(StateMachineAction *, InteractionEvent *)
vtkRenderer * GetVtkRenderer() const
#define MITK_ERROR
Definition: mitkLogMacros.h:20
double ScalarType
static Pointer New()
bool GetFloatProperty(const char *propertyKey, float &floatValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for float properties (instances of FloatProperty)
void TranslateGeometry(mitk::Vector3D translate, mitk::BaseGeometry *geometry)
const char * selectedColorPropertyName
void RotateGeometry(mitk::ScalarType angle, int rotationaxis, mitk::BaseGeometry *geometry)
Pointer Clone() const
static Pointer New()
const char * rotationStepSizePropertyName
Constants for most interaction classes, due to the generic StateMachines.
virtual void TranslateDownModifierKey(StateMachineAction *, InteractionEvent *interactionEvent)
virtual void RotateRightKey(StateMachineAction *, InteractionEvent *interactionEvent)
virtual void RotateUpKey(StateMachineAction *, InteractionEvent *interactionEvent)
const char * scaleStepSizePropertyName
void Translate(const Vector3D &vector)
Translate the origin by a vector.
DataNode * GetDataNode() const
const char * anchorPointX
const char * anchorPointZ
BaseRenderer * GetSender() const
virtual void RotateObject(StateMachineAction *, InteractionEvent *)
virtual void TranslateLeftKey(StateMachineAction *, InteractionEvent *interactionEvent)
The ColorProperty class RGB color property.
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
Definition: mitkBaseData.h:61
virtual void RotateLeftKey(StateMachineAction *, InteractionEvent *interactionEvent)
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
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 DeselectObject(StateMachineAction *, InteractionEvent *)
virtual void InitRotate(StateMachineAction *, InteractionEvent *)
virtual void TranslateRightKey(StateMachineAction *, InteractionEvent *interactionEvent)
virtual bool CheckOverObject(const InteractionEvent *)
const char * translationStepSizePropertyName
const char * anchorPointY
virtual void TranslateObject(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 void TranslateUpKey(StateMachineAction *, InteractionEvent *interactionEvent)
mitk::BaseGeometry * GetUpdatedTimeGeometry(mitk::InteractionEvent *interactionEvent)
virtual DataNode * PickObject(const Point2D &, Point3D &) const
Determines the object (mitk::DataNode) closest to the current position by means of picking...
virtual void InitTranslate(StateMachineAction *, InteractionEvent *)
static Pointer New()
bool InitMembers(InteractionEvent *interactionEvent)
InitMembers convinience method to avoid code duplication between InitRotate() and InitTranslate()...
virtual void TranslateUpModifierKey(StateMachineAction *, InteractionEvent *interactionEvent)
virtual void RotateDownModifierKey(StateMachineAction *, InteractionEvent *interactionEvent)
virtual void SetDataNode(DataNode *dataNode)
#define CONNECT_CONDITION(a, f)
virtual void ScaleObject(StateMachineAction *, InteractionEvent *)
const mitk::TimeGeometry * GetUpdatedTimeGeometry()
Return the TimeGeometry of the data.
The ScaleOperation is an operation to scale any mitk::BaseGeometry.
virtual BaseGeometry::Pointer GetGeometryForTimeStep(TimeStepType timeStep) const =0
Returns the geometry which corresponds to the given time step.
const float selectedColor[]
const char * deselectedColorPropertyName
#define CONNECT_FUNCTION(a, f)
virtual void ScaleUpKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent)
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
virtual void TranslateDownKey(StateMachineAction *, InteractionEvent *interactionEvent)
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
BaseGeometry Describes the geometry of a data object.
void ExecuteOperation(Operation *operation) override
executes affine operations (translate, rotate, scale)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:64
virtual void RotateDownKey(StateMachineAction *, InteractionEvent *interactionEvent)
virtual void RotateUpModifierKey(StateMachineAction *, InteractionEvent *interactionEvent)