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
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.