Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkBoundingShapeInteractor.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 
17 #include "../DataManagement/mitkBoundingShapeUtil.h"
19 #include <mitkDisplayInteractor.h>
20 #include <mitkInteractionConst.h>
24 #include <mitkMouseWheelEvent.h>
25 
26 #include <vtkCamera.h>
27 #include <vtkInteractorObserver.h>
28 #include <vtkInteractorStyle.h>
29 #include <vtkPointData.h>
30 #include <vtkRenderWindowInteractor.h>
31 #include <vtkSmartPointer.h>
32 
33 #include "usGetModuleContext.h"
34 #include "usModuleRegistry.h"
35 
36 // Properties to allow the user to interact with the base data
37 const char *selectedColorPropertyName = "Bounding Shape.Selected Color";
38 const char *deselectedColorPropertyName = "Bounding Shape.Deselected Color";
39 const char *activeHandleIdPropertyName = "Bounding Shape.Active Handle ID";
40 const char *boundingShapePropertyName = "Bounding Shape";
41 
42 namespace mitk
43 {
44  class BoundingShapeInteractor::Impl
45  {
46  public:
47  Impl() : ScrollEnabled(false), RotationEnabled(false)
48  {
49  Point3D initialPoint;
50  initialPoint.Fill(0.0);
51 
52  for (int i = 0; i < 6; ++i)
53  Handles.push_back(Handle(initialPoint, i, GetHandleIndices(i)));
54  }
55 
56  ~Impl() {}
57  bool ScrollEnabled;
58  Point3D InitialPickedWorldPoint;
59  Point3D LastPickedWorldPoint;
60  Point2D InitialPickedDisplayPoint;
61  std::vector<Handle> Handles;
62  Handle ActiveHandle;
63  Geometry3D::Pointer OriginalGeometry;
64  bool RotationEnabled;
65  std::map<us::ServiceReferenceU, mitk::EventConfig> DisplayInteractorConfigs;
66  };
67 }
68 
70 {
71 }
72 
74 {
75  this->RestoreNodeProperties();
76  delete m_Impl;
77 }
78 
80 {
81  // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually
82  // executing an action
83  CONNECT_CONDITION("isHoveringOverObject", CheckOverObject);
84  CONNECT_CONDITION("isHoveringOverHandles", CheckOverHandles);
85 
86  // **Function** in the statemachine patterns also referred to as **Actions**
87  CONNECT_FUNCTION("selectObject", SelectObject);
88  CONNECT_FUNCTION("deselectObject", DeselectObject);
89  CONNECT_FUNCTION("deselectHandles", DeselectHandles);
90  CONNECT_FUNCTION("initInteraction", InitInteraction);
91  CONNECT_FUNCTION("translateObject", TranslateObject);
92  CONNECT_FUNCTION("selectHandle", SelectHandle);
93  CONNECT_FUNCTION("scaleObject", ScaleObject);
94  // CONNECT_FUNCTION("rotateObject",RotateObject);
95 }
96 
97 // RotateObject(StateMachineAction*, InteractionEvent* interactionEvent)
98 // void mitk::BoundingShapeInteractor::RotateGeometry(mitk::ScalarType angle, int rotationaxis, mitk::BaseGeometry*
99 // geometry)
100 //{
101 // mitk::Vector3D rotationAxis = geometry->GetAxisVector(rotationaxis);
102 // float pointX = 0.0f;
103 // float pointY = 0.0f;
104 // float pointZ = 0.0f;
105 // mitk::Point3D pointOfRotation;
106 // pointOfRotation.Fill(0.0);
107 // this->GetDataNode()->GetFloatProperty(anchorPointX, pointX);
108 // this->GetDataNode()->GetFloatProperty(anchorPointY, pointY);
109 // this->GetDataNode()->GetFloatProperty(anchorPointZ, pointZ);
110 // pointOfRotation[0] = pointX;
111 // pointOfRotation[1] = pointY;
112 // pointOfRotation[2] = pointZ;
113 //
114 // mitk::RotationOperation* doOp = new mitk::RotationOperation(OpROTATE, pointOfRotation, rotationAxis, angle);
115 //
116 // geometry->ExecuteOperation(doOp);
117 // delete doOp;
118 //}
119 
120 void mitk::BoundingShapeInteractor::SetRotationEnabled(bool rotationEnabled)
121 {
122  m_Impl->RotationEnabled = rotationEnabled;
123 }
124 
126 {
127  mitk::DataNode::Pointer newInputNode = this->GetDataNode();
128 
129  if (newInputNode == nullptr)
130  return;
131 
132  // add color properties
134  dynamic_cast<mitk::ColorProperty *>(newInputNode->GetProperty(selectedColorPropertyName));
135  mitk::ColorProperty::Pointer deselectedColor =
136  dynamic_cast<mitk::ColorProperty *>(newInputNode->GetProperty(deselectedColorPropertyName));
137 
138  if (selectedColor.IsNull())
139  newInputNode->AddProperty(selectedColorPropertyName, mitk::ColorProperty::New(0.0, 1.0, 0.0));
140 
141  if (deselectedColor.IsNull())
142  newInputNode->AddProperty(deselectedColorPropertyName, mitk::ColorProperty::New(1.0, 1.0, 1.0));
143 
144  newInputNode->SetProperty(boundingShapePropertyName, mitk::BoolProperty::New(true));
145  newInputNode->AddProperty(activeHandleIdPropertyName, mitk::IntProperty::New(-1));
146  newInputNode->SetProperty("layer", mitk::IntProperty::New(101));
147  newInputNode->SetBoolProperty("fixedLayer", mitk::BoolProperty::New(true));
148  newInputNode->SetBoolProperty("pickable", true);
149 
150  mitk::ColorProperty::Pointer initialColor =
151  dynamic_cast<mitk::ColorProperty *>(newInputNode->GetProperty(deselectedColorPropertyName));
152  if (initialColor.IsNotNull())
153  {
154  newInputNode->SetColor(initialColor->GetColor());
155  }
156 
158 }
159 
160 void mitk::BoundingShapeInteractor::HandlePositionChanged(const InteractionEvent *interactionEvent, Point3D &center)
161 {
162  GeometryData::Pointer geometryData = dynamic_cast<GeometryData *>(this->GetDataNode()->GetData());
163  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
164  mitk::BaseGeometry::Pointer geometry = geometryData->GetGeometry(timeStep);
165 
166  std::vector<Point3D> cornerPoints = GetCornerPoints(geometry, true);
167  if (m_Impl->Handles.size() == 6)
168  {
169  // set handle positions
170  Point3D pointLeft = CalcAvgPoint(cornerPoints[5], cornerPoints[6]);
171  Point3D pointRight = CalcAvgPoint(cornerPoints[1], cornerPoints[2]);
172  Point3D pointTop = CalcAvgPoint(cornerPoints[0], cornerPoints[6]);
173  Point3D pointBottom = CalcAvgPoint(cornerPoints[7], cornerPoints[1]);
174  Point3D pointFront = CalcAvgPoint(cornerPoints[2], cornerPoints[7]);
175  Point3D pointBack = CalcAvgPoint(cornerPoints[4], cornerPoints[1]);
176 
177  m_Impl->Handles[0].SetPosition(pointLeft);
178  m_Impl->Handles[1].SetPosition(pointRight);
179  m_Impl->Handles[2].SetPosition(pointTop);
180  m_Impl->Handles[3].SetPosition(pointBottom);
181  m_Impl->Handles[4].SetPosition(pointFront);
182  m_Impl->Handles[5].SetPosition(pointBack);
183 
184  // calculate center based on half way of the distance between two opposing cornerpoints
185  center = CalcAvgPoint(cornerPoints[7], cornerPoints[0]);
186  }
187 }
188 
190 {
191  this->RestoreNodeProperties(); // if there is another node set, restore it's color
192 
193  if (node == nullptr)
194  return;
195  DataInteractor::SetDataNode(node); // calls DataNodeChanged internally
196  this->DataNodeChanged();
197 }
198 
199 bool mitk::BoundingShapeInteractor::CheckOverObject(const InteractionEvent *interactionEvent)
200 {
201  const InteractionPositionEvent *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
202  if (positionEvent == nullptr)
203  return false;
204 
205  GeometryData::Pointer geometryData = dynamic_cast<GeometryData *>(this->GetDataNode()->GetData());
206  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
207  BaseGeometry::Pointer geometry = geometryData->GetGeometry(timeStep);
208 
209  // calculates translation based on offset+extent not on the transformation matrix (because the cube is located in the
210  // center not in the origin)
211  vtkSmartPointer<vtkMatrix4x4> imageTransform = geometry->GetVtkTransform()->GetMatrix();
212  Point3D center = geometry->GetCenter();
213  auto translation = vtkSmartPointer<vtkTransform>::New();
214  auto transform = vtkSmartPointer<vtkTransform>::New();
215  translation->Translate(center[0] - imageTransform->GetElement(0, 3),
216  center[1] - imageTransform->GetElement(1, 3),
217  center[2] - imageTransform->GetElement(2, 3));
218  transform->SetMatrix(imageTransform);
219  transform->PostMultiply();
220  transform->Concatenate(translation);
221  transform->Update();
222 
223  mitk::Vector3D extent;
224  for (unsigned int i = 0; i < 3; ++i)
225  extent[i] = (geometry->GetExtent(i));
226 
227  Point3D currentWorldPosition;
228  Point2D currentDisplayPosition = positionEvent->GetPointerPositionOnScreen();
229  interactionEvent->GetSender()->DisplayToWorld(currentDisplayPosition, currentWorldPosition);
230 
231  ScalarType transformedPosition[4];
232  transformedPosition[0] = currentWorldPosition[0];
233  transformedPosition[1] = currentWorldPosition[1];
234  transformedPosition[2] = currentWorldPosition[2];
235  transformedPosition[3] = 1;
236  // transform point from world to object coordinates
237  transform->GetInverse()->TransformPoint(transformedPosition, transformedPosition);
238  // check if the world point is within bounds
239  bool isInside = (transformedPosition[0] >= (-extent[0] / 2.0)) && (transformedPosition[0] <= (extent[0] / 2.0)) &&
240  (transformedPosition[1] >= (-extent[1] / 2.0)) && (transformedPosition[1] <= (extent[1] / 2.0)) &&
241  (transformedPosition[2] >= (-extent[2] / 2.0)) && (transformedPosition[2] <= (extent[2] / 2.0));
242 
243  return isInside;
244 }
245 
246 bool mitk::BoundingShapeInteractor::CheckOverHandles(const InteractionEvent *interactionEvent)
247 {
248  Point3D boundingBoxCenter;
249  HandlePositionChanged(interactionEvent, boundingBoxCenter);
250  const InteractionPositionEvent *positionEvent = dynamic_cast<const InteractionPositionEvent *>(interactionEvent);
251  if (positionEvent == nullptr)
252  return false;
253 
254  Point2D displayCenterPoint;
255  // to do: change to actual time step (currently not necessary because geometry remains the same for each timestep
256  int timeStep = 0;
257 
258  GeometryData::Pointer geometryData = dynamic_cast<GeometryData *>(this->GetDataNode()->GetData());
259  BaseGeometry::Pointer geometry = geometryData->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep);
260  std::vector<Point3D> cornerPoints = GetCornerPoints(geometry, true);
261  interactionEvent->GetSender()->WorldToDisplay(boundingBoxCenter, displayCenterPoint);
262  double scale = interactionEvent->GetSender()->GetScaleFactorMMPerDisplayUnit(); // GetDisplaySizeInMM
263  mitk::DoubleProperty::Pointer handleSizeProperty =
264  dynamic_cast<mitk::DoubleProperty *>(this->GetDataNode()->GetProperty("Bounding Shape.Handle Size Factor"));
265 
266  ScalarType initialHandleSize;
267  if (handleSizeProperty != nullptr)
268  initialHandleSize = handleSizeProperty->GetValue();
269  else
270  initialHandleSize = 1.0 / 40.0;
271 
272  mitk::Point2D displaysize = interactionEvent->GetSender()->GetDisplaySizeInMM();
273  ScalarType handlesize = ((displaysize[0] + displaysize[1]) / 2.0) * initialHandleSize;
274  unsigned int handleNum = 0;
275 
276  for (auto &handle : m_Impl->Handles)
277  {
278  Point2D centerpoint;
279  interactionEvent->GetSender()->WorldToDisplay(handle.GetPosition(), centerpoint);
280  Point2D currentDisplayPosition = positionEvent->GetPointerPositionOnScreen();
281 
282  if ((currentDisplayPosition.EuclideanDistanceTo(centerpoint) < (handlesize / scale)) &&
283  (currentDisplayPosition.EuclideanDistanceTo(displayCenterPoint) >
284  (handlesize / scale))) // check if mouse is hovering over center point
285  {
286  handle.SetActive(true);
287  m_Impl->ActiveHandle = handle;
288  this->GetDataNode()->GetPropertyList()->SetProperty(activeHandleIdPropertyName,
289  mitk::IntProperty::New(handleNum++));
290  this->GetDataNode()->GetData()->Modified();
291  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
292  return true;
293  }
294  else
295  {
296  handleNum++;
297  handle.SetActive(false);
298  }
299  this->GetDataNode()->GetPropertyList()->SetProperty(activeHandleIdPropertyName, mitk::IntProperty::New(-1));
300  }
301 
302  return false;
303 }
304 
305 void mitk::BoundingShapeInteractor::SelectHandle(StateMachineAction *, InteractionEvent *interactionEvent)
306 {
307  this->DisableCrosshairNavigation();
308  DataNode::Pointer node = this->GetDataNode();
309 
310  if (node.IsNull())
311  return;
312 
313  mitk::ColorProperty::Pointer selectedColor =
314  dynamic_cast<mitk::ColorProperty *>(node->GetProperty(deselectedColorPropertyName));
315  if (selectedColor.IsNotNull())
316  {
317  this->GetDataNode()->GetPropertyList()->SetProperty("color", selectedColor);
318  }
319  this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date
320  this->GetDataNode()->GetData()->Modified();
321  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
322  return;
323 }
324 
325 void mitk::BoundingShapeInteractor::DeselectHandles(StateMachineAction *, InteractionEvent *interactionEvent)
326 {
327  this->DisableCrosshairNavigation();
328  DataNode::Pointer node = this->GetDataNode();
329 
330  if (node.IsNull())
331  return;
332 
333  this->GetDataNode()->GetPropertyList()->SetProperty(activeHandleIdPropertyName, mitk::IntProperty::New(-1));
334  this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date
335  this->GetDataNode()->GetData()->Modified();
336  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
337 
338  return;
339 }
340 
341 void mitk::BoundingShapeInteractor::SelectObject(StateMachineAction *, InteractionEvent *)
342 {
343  this->DisableCrosshairNavigation(); // disable crosshair interaction and scolling if user is hovering over the object
344  DataNode::Pointer node = this->GetDataNode();
345 
346  if (node.IsNull())
347  return;
348 
349  mitk::ColorProperty::Pointer selectedColor =
350  dynamic_cast<mitk::ColorProperty *>(node->GetProperty(selectedColorPropertyName));
351  if (selectedColor.IsNotNull())
352  {
353  node->GetPropertyList()->SetProperty("color", selectedColor);
354  }
355  this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date
356  this->GetDataNode()->GetData()->Modified();
358  return;
359 }
360 
361 void mitk::BoundingShapeInteractor::DeselectObject(StateMachineAction *, InteractionEvent *interactionEvent)
362 {
363  this->EnableCrosshairNavigation(); // enable crosshair interaction and scolling if user is hovering over the object
364 
365  DataNode::Pointer node = this->GetDataNode();
366 
367  if (node.IsNull())
368  return;
369 
370  mitk::ColorProperty::Pointer deselectedColor =
371  dynamic_cast<mitk::ColorProperty *>(node->GetProperty(deselectedColorPropertyName));
372  if (deselectedColor.IsNotNull())
373  {
374  node->GetPropertyList()->SetProperty("color", deselectedColor);
375  }
376 
377  this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date
378  this->GetDataNode()->GetData()->Modified();
379  interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
380  return;
381 }
382 
383 void mitk::BoundingShapeInteractor::InitInteraction(StateMachineAction *, InteractionEvent *interactionEvent)
384 {
385  InitMembers(interactionEvent);
386 }
387 
388 bool mitk::BoundingShapeInteractor::InitMembers(InteractionEvent *interactionEvent)
389 {
390  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
391  if (positionEvent == nullptr)
392  return false;
393 
394  // get initial position coordinates
395  m_Impl->InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
396  m_Impl->InitialPickedWorldPoint = positionEvent->GetPositionInWorld();
397  m_Impl->LastPickedWorldPoint = positionEvent->GetPositionInWorld();
398 
399  return true;
400 }
401 
402 void mitk::BoundingShapeInteractor::TranslateObject(StateMachineAction *, InteractionEvent *interactionEvent)
403 {
404  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
405  if (positionEvent == nullptr)
406  return;
407 
408  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
409  mitk::BaseGeometry::Pointer geometry =
410  this->GetDataNode()->GetData()->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep);
411  Vector3D spacing = geometry->GetSpacing();
412  Point3D currentPickedPoint;
413  interactionEvent->GetSender()->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint);
414  Vector3D interactionMove;
415 
416  // pixel aligned shifting of the bounding box
417  interactionMove[0] = std::round((currentPickedPoint[0] - m_Impl->LastPickedWorldPoint[0]) / spacing[0]) * spacing[0];
418  interactionMove[1] = std::round((currentPickedPoint[1] - m_Impl->LastPickedWorldPoint[1]) / spacing[1]) * spacing[1];
419  interactionMove[2] = std::round((currentPickedPoint[2] - m_Impl->LastPickedWorldPoint[2]) / spacing[2]) * spacing[2];
420 
421  if ((interactionMove[0] + interactionMove[1] + interactionMove[2]) !=
422  0.0) // only update current position if a movement occured
423  {
424  m_Impl->LastPickedWorldPoint = currentPickedPoint;
425 
426  geometry->SetOrigin(geometry->GetOrigin() + interactionMove);
427 
428  this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date
429  this->GetDataNode()->GetData()->Modified();
431  }
432  return;
433 }
434 
435 void mitk::BoundingShapeInteractor::ScaleObject(StateMachineAction *, InteractionEvent *interactionEvent)
436 {
437  InteractionPositionEvent *positionEvent = dynamic_cast<InteractionPositionEvent *>(interactionEvent);
438  if (positionEvent == nullptr)
439  return;
440 
441  GeometryData::Pointer geometryData = dynamic_cast<GeometryData *>(this->GetDataNode()->GetData());
442  Point3D handlePickedPoint = m_Impl->ActiveHandle.GetPosition();
443  Point3D currentPickedPoint;
444  interactionEvent->GetSender()->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint);
445  int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData());
446  mitk::BaseGeometry::Pointer geometry = geometryData->GetGeometry(timeStep);
447  Vector3D spacing = geometry->GetSpacing();
448 
449  // pixel aligned bounding box
450  Vector3D interactionMove;
451  interactionMove[0] = (currentPickedPoint[0] - m_Impl->LastPickedWorldPoint[0]);
452  interactionMove[1] = (currentPickedPoint[1] - m_Impl->LastPickedWorldPoint[1]);
453  interactionMove[2] = (currentPickedPoint[2] - m_Impl->LastPickedWorldPoint[2]);
454 
455  std::vector<int> faces = m_Impl->ActiveHandle.GetFaceIndices();
456  auto pointscontainer = mitk::BoundingBox::PointsContainer::New();
457 
458  // calculate cornerpoints from geometry plus visualization offset
459  std::vector<Point3D> cornerPoints = GetCornerPoints(geometry, true);
460  unsigned int num = 0;
461  for (auto point : cornerPoints)
462  {
463  pointscontainer->InsertElement(num++, point);
464  }
465 
466  // calculate center based on half way of the distance between two opposing cornerpoints
467  mitk::Point3D center = CalcAvgPoint(cornerPoints[7], cornerPoints[0]);
468 
469  Vector3D faceNormal;
470  faceNormal[0] = handlePickedPoint[0] - center[0];
471  faceNormal[1] = handlePickedPoint[1] - center[1];
472  faceNormal[2] = handlePickedPoint[2] - center[2];
473  Vector3D faceShift = ((faceNormal * interactionMove) / (faceNormal.GetNorm() * faceNormal.GetNorm())) * faceNormal;
474 
475  // calculate cornerpoints from geometry without visualization offset to update actual geometry
476  cornerPoints = GetCornerPoints(geometry, false);
477  num = 0;
478  for (auto point : cornerPoints)
479  {
480  pointscontainer->InsertElement(num++, point);
481  }
482 
483  bool positionChangeThreshold = true;
484  for (int numFaces = 0; numFaces < 8; numFaces++) // estimate the corresponding face and shift its assigned points
485  {
486  if ((numFaces != faces[0]) && (numFaces != faces[1]) && (numFaces != faces[2]) && (numFaces != faces[3]))
487  {
488  Point3D point = pointscontainer->GetElement(numFaces);
489  if (m_Impl->RotationEnabled) // apply if geometry is rotated at a pixel aligned shift is not possible
490  {
491  point[0] += faceShift[0];
492  point[1] += faceShift[1];
493  point[2] += faceShift[2];
494  }
495  else // shift pixelwise
496  {
497  point[0] += std::round(faceShift[0] / spacing[0]) * spacing[0];
498  point[1] += std::round(faceShift[1] / spacing[1]) * spacing[1];
499  point[2] += std::round(faceShift[2] / spacing[2]) * spacing[2];
500  }
501 
502  if (point == pointscontainer->GetElement(numFaces))
503  positionChangeThreshold = false;
504  else
505  m_Impl->LastPickedWorldPoint = point;
506 
507  pointscontainer->InsertElement(numFaces, point);
508  }
509  }
510 
511  if (positionChangeThreshold) // update only if bounding box is shifted at least by one pixel
512  {
513  auto inverse = mitk::AffineTransform3D::New();
514  geometry->GetIndexToWorldTransform()->GetInverse(inverse);
515  for (unsigned int pointid = 0; pointid < 8; pointid++)
516  {
517  pointscontainer->InsertElement(pointid, inverse->TransformPoint(pointscontainer->GetElement(pointid)));
518  }
519 
520  auto bbox = mitk::BoundingBox::New();
521  bbox->SetPoints(pointscontainer);
522  bbox->ComputeBoundingBox();
523  mitk::Point3D BBmin = bbox->GetMinimum();
524  mitk::Point3D BBmax = bbox->GetMaximum();
525  if (std::abs(BBmin[0] - BBmax[0]) > 0.01 && std::abs(BBmin[1] - BBmax[1]) > 0.01 &&
526  std::abs(BBmin[2] - BBmax[2]) > 0.01) // TODO: check if the extent is greater than zero
527  {
528  geometry->SetBounds(bbox->GetBounds());
529  geometry->Modified();
530  this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date
531  this->GetDataNode()->GetData()->Modified();
533  }
534  }
535  return;
536 }
537 
539 {
540  mitk::DataNode::Pointer inputNode = this->GetDataNode();
541  if (inputNode.IsNull())
542  return;
543 
545  if (color.IsNotNull())
546  {
547  inputNode->GetPropertyList()->SetProperty("color", color);
548  }
549  inputNode->SetProperty("layer", mitk::IntProperty::New(99));
550  inputNode->SetProperty(boundingShapePropertyName, mitk::BoolProperty::New(false));
551  inputNode->GetPropertyList()->DeleteProperty(activeHandleIdPropertyName);
552 
553  EnableCrosshairNavigation();
554  // update rendering
556 }
557 
558 void mitk::BoundingShapeInteractor::EnableCrosshairNavigation()
559 {
560  // enable the crosshair navigation
561  // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools
562  // in new interaction framework
563  for (std::map<us::ServiceReferenceU, mitk::EventConfig>::iterator it = m_Impl->DisplayInteractorConfigs.begin();
564  it != m_Impl->DisplayInteractorConfigs.end();
565  ++it)
566  {
567  if (it->first)
568  {
569  mitk::DisplayInteractor *displayInteractor = static_cast<mitk::DisplayInteractor *>(
571  if (displayInteractor != nullptr)
572  {
573  // here the regular configuration is loaded again
574  displayInteractor->SetEventConfig(it->second);
575  // MITK_INFO << "restore config";
576  }
577  }
578  }
579  m_Impl->DisplayInteractorConfigs.clear();
580  m_Impl->ScrollEnabled = true;
581 }
582 
583 void mitk::BoundingShapeInteractor::DisableCrosshairNavigation()
584 {
585  // dont deactivate twice, else we will clutter the config list ...
586  if (m_Impl->ScrollEnabled == false)
587  return;
588 
589  // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts
590  // with tools
591  // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction
592  // will still be enabled
593  m_Impl->DisplayInteractorConfigs.clear();
594  std::vector<us::ServiceReference<mitk::InteractionEventObserver>> listEventObserver =
596  for (std::vector<us::ServiceReference<mitk::InteractionEventObserver>>::iterator it = listEventObserver.begin();
597  it != listEventObserver.end();
598  ++it)
599  {
600  mitk::DisplayInteractor *displayInteractor =
602  if (displayInteractor != nullptr)
603  {
604  // remember the original configuration
605  m_Impl->DisplayInteractorConfigs.insert(std::make_pair(*it, displayInteractor->GetEventConfig()));
606  // here the alternative configuration is loaded
607  displayInteractor->SetEventConfig("DisplayConfigMITKNoCrosshair.xml");
608  // MITK_INFO << "change config";
609  }
610  }
611 
612  m_Impl->ScrollEnabled = false;
613 }
Point< ScalarType, 2 > Point2D
Definition: mitkPoint.h:98
bool InitMembers(InteractionEvent *interactionEvent)
Initializes member variables.
const char * boundingShapePropertyName
Base class to implement InteractionEventObservers.
itk::SmartPointer< Self > Pointer
virtual bool CheckOverObject(const InteractionEvent *)
Checks if the mouse pointer is over the object.
Observer that manages the interaction with the display.
double ScalarType
virtual void DataNodeChanged() override
Called when a DataNode has been set/changed.
static Pointer New()
const char * activeHandleIdPropertyName
DataCollection - Class to facilitate loading/accessing structured data.
EventConfig GetEventConfig() const
Returns the current configuration.
Constants for most interaction classes, due to the generic StateMachines.
std::vector< mitk::Point3D > GetCornerPoints(mitk::BaseGeometry::Pointer geometry, bool visualizationOffset)
helper function for calculating corner points of the bounding object from a given geometry ...
virtual void DeselectObject(StateMachineAction *, InteractionEvent *)
Called if the mouse pointer leaves the area of the object.
void * GetService(const ServiceReferenceBase &reference)
std::vector< int > GetHandleIndices(int index)
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)
static Pointer New()
The ColorProperty class RGB color property.
virtual void RestoreNodeProperties()
Restore default properties of bounding box and handles.
itk::SmartPointer< Self > Pointer
const char * selectedColorPropertyName
Vector< ScalarType, 3 > Vector3D
Definition: mitkVector.h:134
virtual void TranslateObject(StateMachineAction *, InteractionEvent *)
Performs a translation of the object relative to the mouse movement.
virtual void DeselectHandles(StateMachineAction *, InteractionEvent *interactionEvent)
Deselects all Handles at the end of interaction.
static RenderingManager * GetInstance()
virtual bool CheckOverHandles(const InteractionEvent *interactionEvent)
Checks if the mouse pointer is over one of the assigned handles.
virtual void ConnectActionsAndFunctions() override
Point< ScalarType, 3 > Point3D
Definition: mitkPoint.h:99
std::vector< ServiceReferenceU > GetServiceReferences(const std::string &clazz, const std::string &filter=std::string())
virtual void SetDataNode(DataNode *dataNode) override
#define CONNECT_CONDITION(a, f)
static Pointer New()
const float selectedColor[]
virtual ~BoundingShapeInteractor()
void SetRotationEnabled(bool rotationEnabled)
#define CONNECT_FUNCTION(a, f)
void HandlePositionChanged(const InteractionEvent *interactionEvent, Point3D &center)
virtual void SelectHandle(StateMachineAction *, InteractionEvent *)
Called if the mouse pointer is over one of the handles indicated by a color change.
virtual void ScaleObject(StateMachineAction *, InteractionEvent *)
Performs a object shape change by influencing the scaling of the initial bounding box...
const char * deselectedColorPropertyName
BoundingShapeInteractor()
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
virtual void InitInteraction(StateMachineAction *, InteractionEvent *interactionEvent)
Performs a rotation of the object relative to the mouse movement.
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
mitk::Point3D CalcAvgPoint(mitk::Point3D a, mitk::Point3D b)
helper function for calculating the average of two points
bool SetEventConfig(const std::string &filename, const us::Module *module=nullptr)
Loads a configuration from an XML resource.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.