diff --git a/Modules/DataTypesExt/Resources/Interactions/AffineInteraction3D.xml b/Modules/DataTypesExt/Resources/Interactions/AffineInteraction3D.xml new file mode 100644 index 0000000000..5b0ddf80b5 --- /dev/null +++ b/Modules/DataTypesExt/Resources/Interactions/AffineInteraction3D.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Modules/DataTypesExt/Resources/Interactions/AffineRotationConfig.xml b/Modules/DataTypesExt/Resources/Interactions/AffineRotationConfig.xml new file mode 100644 index 0000000000..fb9c6fe6d1 --- /dev/null +++ b/Modules/DataTypesExt/Resources/Interactions/AffineRotationConfig.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Modules/DataTypesExt/Resources/Interactions/AffineTranslationConfig.xml b/Modules/DataTypesExt/Resources/Interactions/AffineTranslationConfig.xml new file mode 100644 index 0000000000..4040972f11 --- /dev/null +++ b/Modules/DataTypesExt/Resources/Interactions/AffineTranslationConfig.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Modules/DataTypesExt/files.cmake b/Modules/DataTypesExt/files.cmake index c3e5085e70..d84459eb02 100644 --- a/Modules/DataTypesExt/files.cmake +++ b/Modules/DataTypesExt/files.cmake @@ -1,44 +1,44 @@ set(CPP_FILES + mitkAffineDataInteractor3D.cpp mitkApplyDiffImageOperation.cpp mitkBoundingObject.cpp mitkBoundingObjectGroup.cpp mitkCellOperation.cpp mitkClippingPlaneInteractor3D.cpp mitkColorSequence.cpp mitkColorSequenceCycleH.cpp mitkColorSequenceRainbow.cpp mitkCompressedImageContainer.cpp mitkCone.cpp mitkCuboid.cpp mitkCylinder.cpp mitkDataStorageSelection.cpp mitkEllipsoid.cpp mitkGridRepresentationProperty.cpp mitkGridVolumeMapperProperty.cpp mitkLabeledImageLookupTable.cpp mitkLabeledImageVolumeCalculator.cpp mitkLineOperation.cpp mitkLookupTableSource.cpp mitkMesh.cpp mitkMultiStepper.cpp mitkOrganTypeProperty.cpp mitkPlane.cpp mitkSurfaceDeformationDataInteractor3D.cpp mitkUnstructuredGrid.cpp mitkUnstructuredGridSource.cpp mitkVideoSource.cpp Internal/mitkColorConversions.cpp ) set(RESOURCE_FILES - #Interactions/AffineInteraction3D.xml - #Interactions/AffineTranslationConfig.xml - #Interactions/AffineRotationConfig.xml - #Interactions/AffineDeformationConfig.xml + Interactions/AffineInteraction3D.xml + Interactions/AffineTranslationConfig.xml + Interactions/AffineRotationConfig.xml Interactions/ClippingPlaneInteraction3D.xml Interactions/ClippingPlaneTranslationConfig.xml Interactions/ClippingPlaneRotationConfig.xml Interactions/ClippingPlaneDeformationConfig.xml ) diff --git a/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp b/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp new file mode 100644 index 0000000000..0b1206a7cf --- /dev/null +++ b/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp @@ -0,0 +1,544 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkAffineDataInteractor3D.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +const char* translationStepSizePropertyName = "AffineDataInteractor3D.Translation Step Size"; +const char* selectedColorPropertyName = "AffineDataInteractor3D.Selected Color"; +const char* deselectedColorPropertyName = "AffineDataInteractor3D.Deselected Color"; +const char* priorPropertyName = "AffineDataInteractor3D.Prior Color"; +const char* rotationStepSizePropertyName = "AffineDataInteractor3D.Rotation Step Size"; +const char* scaleStepSizePropertyName = "AffineDataInteractor3D.Scale Step Size"; + +mitk::AffineDataInteractor3D::AffineDataInteractor3D() +{ + m_OriginalGeometry = mitk::Geometry3D::New(); + + // Initialize vector arithmetic + m_ObjectNormal[0] = 0.0; + m_ObjectNormal[1] = 0.0; + m_ObjectNormal[2] = 1.0; +} + +mitk::AffineDataInteractor3D::~AffineDataInteractor3D() +{ + this->RestoreNodeProperties(); +} + +void mitk::AffineDataInteractor3D::ConnectActionsAndFunctions() +{ + // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually executing an action + CONNECT_CONDITION("isOverObject", CheckOverObject); + + // **Function** in the statmachine patterns also referred to as **Actions** + CONNECT_FUNCTION("selectObject",SelectObject); + CONNECT_FUNCTION("deselectObject",DeselectObject); + CONNECT_FUNCTION("initTranslate",InitTranslate); + CONNECT_FUNCTION("initRotate",InitRotate); + CONNECT_FUNCTION("translateObject",TranslateObject); + CONNECT_FUNCTION("rotateObject",RotateObject); + + CONNECT_FUNCTION("translateUpKey",TranslateUpKey); + CONNECT_FUNCTION("translateDownKey",TranslateDownKey); + CONNECT_FUNCTION("translateLeftKey",TranslateLeftKey); + CONNECT_FUNCTION("translateRightKey",TranslateRightKey); + CONNECT_FUNCTION("translateUpModifierKey",TranslateUpModifierKey); + CONNECT_FUNCTION("translateDownModifierKey",TranslateDownModifierKey); + + CONNECT_FUNCTION("scaleDownKey",ScaleDownKey); + CONNECT_FUNCTION("scaleUpKey",ScaleUpKey); + + CONNECT_FUNCTION("rotateUpKey",RotateUpKey); + CONNECT_FUNCTION("rotateDownKey",RotateDownKey); + CONNECT_FUNCTION("rotateLeftKey",RotateLeftKey); + CONNECT_FUNCTION("rotateRightKey",RotateRightKey); + CONNECT_FUNCTION("rotateUpModifierKey",RotateUpModifierKey); + CONNECT_FUNCTION("rotateDownModifierKey",RotateDownModifierKey); +} + +bool mitk::AffineDataInteractor3D::TranslateUpKey(StateMachineAction*, InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); + mitk::Vector3D movementVector; + movementVector.Fill(0.0); + movementVector.SetElement(2, stepSize); + this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::TranslateDownKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); + mitk::Vector3D movementVector; + movementVector.Fill(0.0); + movementVector.SetElement(2, -stepSize); + this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::TranslateLeftKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); + mitk::Vector3D movementVector; + movementVector.Fill(0.0); + movementVector.SetElement(0, -stepSize); + this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::TranslateRightKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); + mitk::Vector3D movementVector; + movementVector.Fill(0.0); + movementVector.SetElement(0, stepSize); + this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::TranslateUpModifierKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); + mitk::Vector3D movementVector; + movementVector.Fill(0.0); + movementVector.SetElement(1, stepSize); + this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::TranslateDownModifierKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); + mitk::Vector3D movementVector; + movementVector.Fill(0.0); + movementVector.SetElement(1, -stepSize); + this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::RotateUpKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); + this->RotateGeometry(-stepSize, 0, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::RotateDownKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); + this->RotateGeometry(stepSize, 0, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::RotateLeftKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); + this->RotateGeometry(-stepSize, 2, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::RotateRightKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); + this->RotateGeometry(stepSize, 2, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::RotateUpModifierKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); + this->RotateGeometry(stepSize, 1, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::RotateDownModifierKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 1.0f; + this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); + this->RotateGeometry(-stepSize, 1, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::ScaleUpKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 0.1f; + this->GetDataNode()->GetFloatProperty(scaleStepSizePropertyName, stepSize); + mitk::Point3D newScale; + newScale.Fill(stepSize); + this->ScaleGeometry(newScale, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +bool mitk::AffineDataInteractor3D::ScaleDownKey(mitk::StateMachineAction*, mitk::InteractionEvent* interactionEvent) +{ + float stepSize = 0.1f; + this->GetDataNode()->GetFloatProperty(scaleStepSizePropertyName, stepSize); + mitk::Point3D newScale; + newScale.Fill(-stepSize); + this->ScaleGeometry(newScale, this->GetUpdatedTimeGeometry(interactionEvent)); + return true; +} + +void mitk::AffineDataInteractor3D::ScaleGeometry(mitk::Point3D newScale, mitk::BaseGeometry* geometry) +{ + PointOperation* doOp = new mitk::PointOperation(OpSCALE, newScale, 0); + geometry->ExecuteOperation(doOp); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void mitk::AffineDataInteractor3D::RotateGeometry(mitk::ScalarType angle, int rotationaxis, mitk::BaseGeometry* geometry) +{ + mitk::Vector3D rotationAxis = geometry->GetAxisVector(rotationaxis); + mitk::Point3D center = geometry->GetCenter(); + + mitk::RotationOperation* doOp = new mitk::RotationOperation(OpROTATE, center, rotationAxis, angle); + + geometry->ExecuteOperation(doOp); + delete doOp; + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void mitk::AffineDataInteractor3D::TranslateGeometry(mitk::Vector3D translate, mitk::BaseGeometry* geometry) +{ + geometry->Translate(translate); + this->GetDataNode()->Modified(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +mitk::BaseGeometry* mitk::AffineDataInteractor3D::GetUpdatedTimeGeometry(mitk::InteractionEvent* interactionEvent) +{ + //Get the correct time geometry to support 3D + t + int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); + BaseGeometry* geometry = this->GetDataNode()->GetData()->GetUpdatedTimeGeometry()->GetGeometryForTimeStep( timeStep ); + if(geometry == NULL) + MITK_ERROR << "Geometry is NULL. Cannot modify it."; + return geometry; +} + +void mitk::AffineDataInteractor3D::DataNodeChanged() +{ + mitk::DataNode::Pointer newInputNode = this->GetDataNode(); + //add default properties + newInputNode->AddProperty( selectedColorPropertyName, mitk::ColorProperty::New(0.0,1.0,0.0) ); + newInputNode->AddProperty( deselectedColorPropertyName, mitk::ColorProperty::New(0.0,0.0,1.0) ); + newInputNode->AddProperty( translationStepSizePropertyName, mitk::FloatProperty::New(1.0f) ); + newInputNode->AddProperty( rotationStepSizePropertyName, mitk::FloatProperty::New(1.0f) ); + newInputNode->AddProperty( scaleStepSizePropertyName, mitk::FloatProperty::New(0.1f) ); + + //save the previous color of the node, in order to restore it after the interactor is destroyed + mitk::ColorProperty::Pointer priorColor = dynamic_cast(newInputNode->GetProperty("color")); + if ( priorColor.IsNotNull() ) + { + mitk::ColorProperty::Pointer tmpCopyOfPriorColor = mitk::ColorProperty::New(); + tmpCopyOfPriorColor->SetColor( priorColor->GetColor() ); + newInputNode->AddProperty( priorPropertyName, tmpCopyOfPriorColor ); + } + newInputNode->SetColor(0.0,0.0,1.0); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void mitk::AffineDataInteractor3D::SetDataNode(mitk::DataInteractor::NodeType node) +{ + this->RestoreNodeProperties(); //if there was another node set, restore it's color + DataInteractor::SetDataNode(node); +} + +bool mitk::AffineDataInteractor3D::CheckOverObject(const InteractionEvent* interactionEvent) +{ + const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); + if(positionEvent == NULL) + return false; + + Point3D currentWorldPoint; + if(interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), currentWorldPoint) == this->GetDataNode().GetPointer()) + return true; + + return false; +} + +bool mitk::AffineDataInteractor3D::SelectObject(StateMachineAction*, InteractionEvent* interactionEvent) +{ + DataNode::Pointer node = this->GetDataNode(); + + if (node.IsNull()) + return false; + + mitk::ColorProperty::Pointer selectedColor = dynamic_cast(node->GetProperty(selectedColorPropertyName)); + if ( selectedColor.IsNotNull() ) + { + node->GetPropertyList()->SetProperty("color", selectedColor); + } + interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + + return true; +} + +bool mitk::AffineDataInteractor3D::DeselectObject(StateMachineAction*, InteractionEvent* interactionEvent) +{ + DataNode::Pointer node = this->GetDataNode(); + + if (node.IsNull()) + return false; + + mitk::ColorProperty::Pointer selectedColor = dynamic_cast(node->GetProperty(deselectedColorPropertyName)); + if ( selectedColor.IsNotNull() ) + { + node->GetPropertyList()->SetProperty("color", selectedColor); + } + + interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + + return true; +} + +bool mitk::AffineDataInteractor3D::InitTranslate(StateMachineAction*, InteractionEvent* interactionEvent) +{ + InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); + if(positionEvent == NULL) + return false; + + m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); + + vtkInteractorObserver::ComputeDisplayToWorld( + interactionEvent->GetSender()->GetVtkRenderer(), + m_InitialPickedDisplayPoint[0], + m_InitialPickedDisplayPoint[1], + 0.0, //m_InitialInteractionPickedPoint[2], + m_InitialPickedWorldPoint ); + + // Get the timestep to also support 3D+t + int timeStep = 0; + if ((interactionEvent->GetSender()) != NULL) + timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); + + // Make deep copy of current Geometry3D of the plane + this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date + m_OriginalGeometry = static_cast(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer()); + + return true; +} + +bool mitk::AffineDataInteractor3D::InitRotate(StateMachineAction*, InteractionEvent* interactionEvent) +{ + InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); + + m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); + + vtkInteractorObserver::ComputeDisplayToWorld( + interactionEvent->GetSender()->GetVtkRenderer(), + m_InitialPickedDisplayPoint[0], + m_InitialPickedDisplayPoint[1], + 0.0, //m_InitialInteractionPickedPoint[2], + m_InitialPickedWorldPoint ); + + // Get the timestep to also support 3D+t + int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); + + // Make deep copy of current Geometry3D of the plane + this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date + m_OriginalGeometry = static_cast(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer()); + + return true; +} + +bool mitk::AffineDataInteractor3D::TranslateObject (StateMachineAction*, InteractionEvent* interactionEvent) +{ + InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); + if(positionEvent == NULL) + return false; + + double currentWorldPoint[4]; + mitk::Point2D currentDisplayPoint = positionEvent->GetPointerPositionOnScreen(); + vtkInteractorObserver::ComputeDisplayToWorld( + interactionEvent->GetSender()->GetVtkRenderer(), + currentDisplayPoint[0], + currentDisplayPoint[1], + 0.0, //m_InitialInteractionPickedPoint[2], + currentWorldPoint); + + Vector3D interactionMove; + interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; + interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; + interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; + + Point3D origin = m_OriginalGeometry->GetOrigin(); + + // Get the timestep to also support 3D+t + int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); + + // If data is an mitk::Surface, extract it + Surface::Pointer surface = dynamic_cast< Surface* >(this->GetDataNode()->GetData()); + vtkPolyData* polyData = NULL; + if (surface.IsNotNull()) + { + polyData = surface->GetVtkPolyData( timeStep ); + + // Extract surface normal from surface (if existent, otherwise use default) + vtkPointData* pointData = polyData->GetPointData(); + if (pointData != NULL) + { + vtkDataArray* normal = polyData->GetPointData()->GetVectors("planeNormal"); + if (normal != NULL) + { + m_ObjectNormal[0] = normal->GetComponent( 0, 0 ); + m_ObjectNormal[1] = normal->GetComponent( 0, 1 ); + m_ObjectNormal[2] = normal->GetComponent( 0, 2 ); + } + } + } + + Vector3D transformedObjectNormal; + this->GetDataNode()->GetData()->GetGeometry( timeStep )->IndexToWorld(m_ObjectNormal, transformedObjectNormal); + + this->GetDataNode()->GetData()->GetGeometry( timeStep )->SetOrigin(origin + transformedObjectNormal * (interactionMove * transformedObjectNormal)); + + interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + + return true; +} + +bool mitk::AffineDataInteractor3D::RotateObject (StateMachineAction*, InteractionEvent* interactionEvent) +{ + InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); + if(positionEvent == NULL) + return false; + + double currentWorldPoint[4]; + Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); + vtkInteractorObserver::ComputeDisplayToWorld( + interactionEvent->GetSender()->GetVtkRenderer(), + currentPickedDisplayPoint[0], + currentPickedDisplayPoint[1], + 0.0, //m_InitialInteractionPickedPoint[2], + currentWorldPoint); + + vtkCamera* camera = NULL; + vtkRenderer* currentVtkRenderer = NULL; + + if ((interactionEvent->GetSender()) != NULL) + { + vtkRenderWindow* renderWindow = interactionEvent->GetSender()->GetRenderWindow(); + if (renderWindow != NULL) + { + vtkRenderWindowInteractor* renderWindowInteractor = renderWindow->GetInteractor(); + if ( renderWindowInteractor != NULL ) + { + currentVtkRenderer = renderWindowInteractor->GetInteractorStyle()->GetCurrentRenderer(); + if (currentVtkRenderer != NULL) + camera = currentVtkRenderer->GetActiveCamera(); + } + } + } + if ( camera ) + { + double vpn[3]; + camera->GetViewPlaneNormal( vpn ); + + Vector3D viewPlaneNormal; + viewPlaneNormal[0] = vpn[0]; + viewPlaneNormal[1] = vpn[1]; + viewPlaneNormal[2] = vpn[2]; + + Vector3D interactionMove; + interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; + interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; + interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; + + if (interactionMove[0] == 0 && interactionMove[1] == 0 && interactionMove[2] == 0) + return true; + + Vector3D rotationAxis = itk::CrossProduct(viewPlaneNormal, interactionMove); + rotationAxis.Normalize(); + + int* size = currentVtkRenderer->GetSize(); + double l2 = + (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) * + (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) + + (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]) * + (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]); + + double rotationAngle = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1])); + + // Use center of data bounding box as center of rotation + Point3D rotationCenter = m_OriginalGeometry->GetCenter(); + + int timeStep = 0; + if ((interactionEvent->GetSender()) != NULL) + timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); + + // Reset current Geometry3D to original state (pre-interaction) and + // apply rotation + RotationOperation op( OpROTATE, rotationCenter, rotationAxis, rotationAngle ); + Geometry3D::Pointer newGeometry = static_cast(m_OriginalGeometry->Clone().GetPointer()); + newGeometry->ExecuteOperation( &op ); + mitk::TimeGeometry::Pointer timeGeometry = this->GetDataNode()->GetData()->GetTimeGeometry(); + if (timeGeometry.IsNotNull()) + timeGeometry->SetTimeStepGeometry(newGeometry, timeStep); + + interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + + return true; + } + else + return false; +} + +void mitk::AffineDataInteractor3D::RestoreNodeProperties() +{ + mitk::DataNode::Pointer inputNode = this->GetDataNode(); + if(inputNode.IsNull()) + return; + mitk::ColorProperty::Pointer color = dynamic_cast(inputNode->GetProperty(priorPropertyName)); + if ( color.IsNotNull() ) + { + inputNode->GetPropertyList()->SetProperty("color", color); + } + + inputNode->GetPropertyList()->DeleteProperty(selectedColorPropertyName); + inputNode->GetPropertyList()->DeleteProperty(deselectedColorPropertyName); + inputNode->GetPropertyList()->DeleteProperty(priorPropertyName); + inputNode->GetPropertyList()->DeleteProperty(translationStepSizePropertyName); + inputNode->GetPropertyList()->DeleteProperty(rotationStepSizePropertyName); + inputNode->GetPropertyList()->DeleteProperty(scaleStepSizePropertyName); + + //update rendering + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} diff --git a/Modules/DataTypesExt/mitkAffineDataInteractor3D.h b/Modules/DataTypesExt/mitkAffineDataInteractor3D.h new file mode 100644 index 0000000000..20a24a42a7 --- /dev/null +++ b/Modules/DataTypesExt/mitkAffineDataInteractor3D.h @@ -0,0 +1,101 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkAffineDataInteractor3D_h_ +#define mitkAffineDataInteractor3D_h_ + +#include +#include +#include "MitkDataTypesExtExports.h" + +namespace mitk +{ +/** + * \brief Affine interaction with objects in 3D windows. + * + * \ingroup Interaction + */ +// Inherit from DataInteratcor, this provides functionality of a state machine and configurable inputs. +class MitkDataTypesExt_EXPORT AffineDataInteractor3D: public DataInteractor +{ + +public: + mitkClassMacro(AffineDataInteractor3D, DataInteractor); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + virtual void SetDataNode(NodeType node); + void TranslateGeometry(mitk::Vector3D translate, mitk::BaseGeometry* geometry); + void RotateGeometry(mitk::ScalarType angle, int rotationaxis, mitk::BaseGeometry* geometry); + void ScaleGeometry(mitk::Point3D newScale, mitk::BaseGeometry* geometry); + mitk::BaseGeometry *GetUpdatedTimeGeometry(mitk::InteractionEvent *interactionEvent); +protected: + AffineDataInteractor3D(); + virtual ~AffineDataInteractor3D(); + /** + * Here actions strings from the loaded state machine pattern are mapped to functions of + * the DataInteractor. These functions are called when an action from the state machine pattern is executed. + */ + virtual void ConnectActionsAndFunctions(); + /** + * This function is called when a DataNode has been set/changed. + */ + virtual void DataNodeChanged(); + + + /** + * Initializes the movement, stores starting position. + */ + virtual bool CheckOverObject (const InteractionEvent*); + virtual bool SelectObject (StateMachineAction*, InteractionEvent*); + virtual bool DeselectObject (StateMachineAction*, InteractionEvent*); + virtual bool InitTranslate (StateMachineAction*, InteractionEvent*); + virtual bool InitRotate (StateMachineAction*, InteractionEvent*); + virtual bool TranslateObject (StateMachineAction*, InteractionEvent*); + virtual bool RotateObject (StateMachineAction*, InteractionEvent*); + virtual bool TranslateUpKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool TranslateDownKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool TranslateLeftKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool TranslateRightKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool TranslateUpModifierKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool TranslateDownModifierKey(StateMachineAction*, InteractionEvent* interactionEvent); + + virtual bool RotateUpKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool RotateDownKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool RotateLeftKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool RotateRightKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool RotateUpModifierKey(StateMachineAction*, InteractionEvent* interactionEvent); + virtual bool RotateDownModifierKey(StateMachineAction*, InteractionEvent* interactionEvent); + + virtual bool ScaleDownKey(mitk::StateMachineAction *, mitk::InteractionEvent* interactionEvent); + virtual bool ScaleUpKey(mitk::StateMachineAction *, mitk::InteractionEvent* interactionEvent); + + + virtual void RestoreNodeProperties(); + +private: + + double m_InitialPickedWorldPoint[4]; + Point2D m_InitialPickedDisplayPoint; + + Geometry3D::Pointer m_OriginalGeometry; + + Vector3D m_ObjectNormal; + +}; + +} +#endif