17 #include "../DataManagement/mitkBoundingShapeUtil.h"
26 #include <vtkCamera.h>
27 #include <vtkInteractorObserver.h>
28 #include <vtkInteractorStyle.h>
29 #include <vtkPointData.h>
30 #include <vtkRenderWindowInteractor.h>
31 #include <vtkSmartPointer.h>
44 class BoundingShapeInteractor::Impl
47 Impl() : ScrollEnabled(
false), RotationEnabled(
false)
50 initialPoint.Fill(0.0);
52 for (
int i = 0; i < 6; ++i)
58 Point3D InitialPickedWorldPoint;
60 Point2D InitialPickedDisplayPoint;
61 std::vector<Handle> Handles;
65 std::map<us::ServiceReferenceU, mitk::EventConfig> DisplayInteractorConfigs;
122 m_Impl->RotationEnabled = rotationEnabled;
129 if (newInputNode ==
nullptr)
138 if (selectedColor.IsNull())
141 if (deselectedColor.IsNull())
148 newInputNode->SetBoolProperty(
"pickable",
true);
152 if (initialColor.IsNotNull())
154 newInputNode->SetColor(initialColor->GetColor());
163 int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->
GetData());
167 if (
m_Impl->Handles.size() == 6)
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);
185 center =
CalcAvgPoint(cornerPoints[7], cornerPoints[0]);
201 const InteractionPositionEvent *positionEvent =
dynamic_cast<const InteractionPositionEvent *
>(interactionEvent);
202 if (positionEvent ==
nullptr)
206 int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->
GetData());
211 vtkSmartPointer<vtkMatrix4x4> imageTransform = geometry->GetVtkTransform()->GetMatrix();
212 Point3D center = geometry->GetCenter();
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);
224 for (
unsigned int i = 0; i < 3; ++i)
225 extent[i] = (geometry->GetExtent(i));
228 Point2D currentDisplayPosition = positionEvent->GetPointerPositionOnScreen();
229 interactionEvent->GetSender()->DisplayToWorld(currentDisplayPosition, currentWorldPosition);
232 transformedPosition[0] = currentWorldPosition[0];
233 transformedPosition[1] = currentWorldPosition[1];
234 transformedPosition[2] = currentWorldPosition[2];
235 transformedPosition[3] = 1;
237 transform->GetInverse()->TransformPoint(transformedPosition, transformedPosition);
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));
250 const InteractionPositionEvent *positionEvent =
dynamic_cast<const InteractionPositionEvent *
>(interactionEvent);
251 if (positionEvent ==
nullptr)
259 BaseGeometry::Pointer geometry = geometryData->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep);
261 interactionEvent->GetSender()->WorldToDisplay(boundingBoxCenter, displayCenterPoint);
262 double scale = interactionEvent->GetSender()->GetScaleFactorMMPerDisplayUnit();
264 dynamic_cast<mitk::DoubleProperty *
>(this->GetDataNode()->GetProperty(
"Bounding Shape.Handle Size Factor"));
267 if (handleSizeProperty !=
nullptr)
268 initialHandleSize = handleSizeProperty->GetValue();
270 initialHandleSize = 1.0 / 40.0;
272 mitk::Point2D displaysize = interactionEvent->GetSender()->GetDisplaySizeInMM();
273 ScalarType handlesize = ((displaysize[0] + displaysize[1]) / 2.0) * initialHandleSize;
274 unsigned int handleNum = 0;
276 for (
auto &handle :
m_Impl->Handles)
279 interactionEvent->GetSender()->WorldToDisplay(handle.GetPosition(), centerpoint);
280 Point2D currentDisplayPosition = positionEvent->GetPointerPositionOnScreen();
282 if ((currentDisplayPosition.EuclideanDistanceTo(centerpoint) < (handlesize / scale)) &&
283 (currentDisplayPosition.EuclideanDistanceTo(displayCenterPoint) >
284 (handlesize / scale)))
286 handle.SetActive(
true);
287 m_Impl->ActiveHandle = handle;
290 this->GetDataNode()->GetData()->Modified();
291 interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
297 handle.SetActive(
false);
307 this->DisableCrosshairNavigation();
315 if (selectedColor.IsNotNull())
317 this->GetDataNode()->GetPropertyList()->SetProperty(
"color", selectedColor);
319 this->GetDataNode()->GetData()->UpdateOutputInformation();
320 this->GetDataNode()->GetData()->Modified();
321 interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
327 this->DisableCrosshairNavigation();
334 this->GetDataNode()->GetData()->UpdateOutputInformation();
335 this->GetDataNode()->GetData()->Modified();
336 interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
343 this->DisableCrosshairNavigation();
351 if (selectedColor.IsNotNull())
353 node->GetPropertyList()->SetProperty(
"color", selectedColor);
355 this->GetDataNode()->GetData()->UpdateOutputInformation();
356 this->GetDataNode()->GetData()->Modified();
363 this->EnableCrosshairNavigation();
372 if (deselectedColor.IsNotNull())
374 node->GetPropertyList()->SetProperty(
"color", deselectedColor);
377 this->GetDataNode()->GetData()->UpdateOutputInformation();
378 this->GetDataNode()->GetData()->Modified();
379 interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll();
390 InteractionPositionEvent *positionEvent =
dynamic_cast<InteractionPositionEvent *
>(interactionEvent);
391 if (positionEvent ==
nullptr)
395 m_Impl->InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen();
396 m_Impl->InitialPickedWorldPoint = positionEvent->GetPositionInWorld();
397 m_Impl->LastPickedWorldPoint = positionEvent->GetPositionInWorld();
404 InteractionPositionEvent *positionEvent =
dynamic_cast<InteractionPositionEvent *
>(interactionEvent);
405 if (positionEvent ==
nullptr)
408 int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->
GetData());
410 this->GetDataNode()->GetData()->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep);
411 Vector3D spacing = geometry->GetSpacing();
413 interactionEvent->GetSender()->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint);
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];
421 if ((interactionMove[0] + interactionMove[1] + interactionMove[2]) !=
424 m_Impl->LastPickedWorldPoint = currentPickedPoint;
426 geometry->SetOrigin(geometry->GetOrigin() + interactionMove);
428 this->GetDataNode()->GetData()->UpdateOutputInformation();
429 this->GetDataNode()->GetData()->Modified();
437 InteractionPositionEvent *positionEvent =
dynamic_cast<InteractionPositionEvent *
>(interactionEvent);
438 if (positionEvent ==
nullptr)
442 Point3D handlePickedPoint =
m_Impl->ActiveHandle.GetPosition();
444 interactionEvent->GetSender()->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint);
445 int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->
GetData());
447 Vector3D spacing = geometry->GetSpacing();
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]);
455 std::vector<int> faces =
m_Impl->ActiveHandle.GetFaceIndices();
460 unsigned int num = 0;
461 for (
auto point : cornerPoints)
463 pointscontainer->InsertElement(num++, point);
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;
478 for (
auto point : cornerPoints)
480 pointscontainer->InsertElement(num++, point);
483 bool positionChangeThreshold =
true;
484 for (
int numFaces = 0; numFaces < 8; numFaces++)
486 if ((numFaces != faces[0]) && (numFaces != faces[1]) && (numFaces != faces[2]) && (numFaces != faces[3]))
488 Point3D point = pointscontainer->GetElement(numFaces);
489 if (
m_Impl->RotationEnabled)
491 point[0] += faceShift[0];
492 point[1] += faceShift[1];
493 point[2] += faceShift[2];
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];
502 if (point == pointscontainer->GetElement(numFaces))
503 positionChangeThreshold =
false;
505 m_Impl->LastPickedWorldPoint = point;
507 pointscontainer->InsertElement(numFaces, point);
511 if (positionChangeThreshold)
514 geometry->GetIndexToWorldTransform()->GetInverse(inverse);
515 for (
unsigned int pointid = 0; pointid < 8; pointid++)
517 pointscontainer->InsertElement(pointid, inverse->TransformPoint(pointscontainer->GetElement(pointid)));
521 bbox->SetPoints(pointscontainer);
522 bbox->ComputeBoundingBox();
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)
528 geometry->SetBounds(bbox->GetBounds());
529 geometry->Modified();
530 this->GetDataNode()->GetData()->UpdateOutputInformation();
531 this->GetDataNode()->GetData()->Modified();
541 if (inputNode.IsNull())
545 if (color.IsNotNull())
547 inputNode->GetPropertyList()->SetProperty(
"color", color);
553 EnableCrosshairNavigation();
558 void mitk::BoundingShapeInteractor::EnableCrosshairNavigation()
563 for (std::map<us::ServiceReferenceU, mitk::EventConfig>::iterator it =
m_Impl->DisplayInteractorConfigs.begin();
564 it !=
m_Impl->DisplayInteractorConfigs.end();
571 if (displayInteractor !=
nullptr)
579 m_Impl->DisplayInteractorConfigs.clear();
580 m_Impl->ScrollEnabled =
true;
583 void mitk::BoundingShapeInteractor::DisableCrosshairNavigation()
586 if (
m_Impl->ScrollEnabled ==
false)
593 m_Impl->DisplayInteractorConfigs.clear();
594 std::vector<us::ServiceReference<mitk::InteractionEventObserver>> listEventObserver =
597 it != listEventObserver.end();
602 if (displayInteractor !=
nullptr)
605 m_Impl->DisplayInteractorConfigs.insert(std::make_pair(*it, displayInteractor->
GetEventConfig()));
607 displayInteractor->
SetEventConfig(
"DisplayConfigMITKNoCrosshair.xml");
612 m_Impl->ScrollEnabled =
false;
Point< ScalarType, 2 > Point2D
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.
virtual void DataNodeChanged() override
Called when a DataNode has been set/changed.
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)
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
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
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)
const float selectedColor[]
virtual ~BoundingShapeInteractor()
void SetRotationEnabled(bool rotationEnabled)
#define CONNECT_FUNCTION(a, f)
void HandlePositionChanged(const InteractionEvent *interactionEvent, Point3D ¢er)
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.