diff --git a/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp b/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp index 715854ca22..27958f7987 100644 --- a/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp +++ b/Modules/DataTypesExt/mitkAffineDataInteractor3D.cpp @@ -1,329 +1,356 @@ /*=================================================================== 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 "mitkInteractionConst.h" #include "mitkInteractionPositionEvent.h" #include "mitkRotationOperation.h" #include "mitkSurface.h" #include #include #include #include #include +#include + mitk::AffineDataInteractor3D::AffineDataInteractor3D() { m_OriginalGeometry = Geometry3D::New(); // Initialize vector arithmetic m_ObjectNormal[0] = 0.0; m_ObjectNormal[1] = 0.0; m_ObjectNormal[2] = 1.0; } mitk::AffineDataInteractor3D::~AffineDataInteractor3D() { } 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); } void mitk::AffineDataInteractor3D::DataNodeChanged() { } bool mitk::AffineDataInteractor3D::CheckOverObject(const InteractionEvent* interactionEvent) { const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; - Point3D currentPickedPoint; - if(interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint) == this->GetDataNode().GetPointer()) + 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; node->SetColor(1.0, 0.0, 0.0); // Colorize surface / wireframe dependend on distance from picked point this->ColorizeSurface(interactionEvent->GetSender(), 0.0); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::AffineDataInteractor3D::DeselectObject(StateMachineAction*, InteractionEvent* interactionEvent) { DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return false; node->SetColor( 1.0, 1.0, 1.0 ); // Colorize surface / wireframe as inactive this->ColorizeSurface(interactionEvent->GetSender(), -1.0); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::AffineDataInteractor3D::InitTranslate(StateMachineAction*, InteractionEvent* interactionEvent) { InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; - m_InitialPickedPoint = positionEvent->GetPositionInWorld(); 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); if(positionEvent == NULL) return false; - m_InitialPickedPoint = positionEvent->GetPositionInWorld(); 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; - Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); + 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] = currentPickedPoint[0] - m_InitialPickedPoint[0]; - interactionMove[1] = currentPickedPoint[1] - m_InitialPickedPoint[1]; - interactionMove[2] = currentPickedPoint[2] - m_InitialPickedPoint[2]; + 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(); - Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); + 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] = currentPickedPoint[0] - m_InitialPickedPoint[0]; - interactionMove[1] = currentPickedPoint[1] - m_InitialPickedPoint[1]; - interactionMove[2] = currentPickedPoint[2] - m_InitialPickedPoint[2]; + 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; } bool mitk::AffineDataInteractor3D::ColorizeSurface(BaseRenderer::Pointer renderer, double scalar) { BaseData::Pointer data = this->GetDataNode()->GetData(); if(data.IsNull()) { MITK_ERROR << "AffineInteractor3D: No data object present!"; return false; } // Get the timestep to also support 3D+t int timeStep = 0; if (renderer.IsNotNull()) timeStep = renderer->GetTimeStep(data); // If data is an mitk::Surface, extract it Surface::Pointer surface = dynamic_cast< Surface* >(data.GetPointer()); vtkPolyData* polyData = NULL; if (surface.IsNotNull()) polyData = surface->GetVtkPolyData(timeStep); if (polyData == NULL) { MITK_ERROR << "AffineInteractor3D: No poly data present!"; return false; } vtkPointData* pointData = polyData->GetPointData(); if (pointData == NULL) { MITK_ERROR << "AffineInteractor3D: No point data present!"; return false; } vtkDataArray* scalars = pointData->GetScalars(); if (scalars == NULL) { MITK_ERROR << "AffineInteractor3D: No scalars for point data present!"; return false; } for (vtkIdType i = 0; i < pointData->GetNumberOfTuples(); ++i) { scalars->SetComponent(i, 0, scalar); } polyData->Modified(); pointData->Update(); return true; } diff --git a/Modules/DataTypesExt/mitkAffineDataInteractor3D.h b/Modules/DataTypesExt/mitkAffineDataInteractor3D.h index 48d2b6c385..38a7cac017 100644 --- a/Modules/DataTypesExt/mitkAffineDataInteractor3D.h +++ b/Modules/DataTypesExt/mitkAffineDataInteractor3D.h @@ -1,82 +1,82 @@ /*=================================================================== 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 "mitkBaseRenderer.h" #include "mitkDataInteractor.h" #include "MitkDataTypesExtExports.h" #include "mitkGeometry3D.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) 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*); private: bool ColorizeSurface(BaseRenderer::Pointer renderer, double scalar = 0.0); - Point3D m_InitialPickedPoint; + double m_InitialPickedWorldPoint[4]; Point2D m_InitialPickedDisplayPoint; //Point3D m_CurrentPickedPoint; //Point2D m_CurrentPickedDisplayPoint; Geometry3D::Pointer m_OriginalGeometry; Vector3D m_ObjectNormal; }; } #endif diff --git a/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.cpp b/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.cpp index 54bbefb4e3..d688a0ea5a 100644 --- a/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.cpp +++ b/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.cpp @@ -1,302 +1,318 @@ /*=================================================================== 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 "mitkSurfaceDeformationDataInteractor3D.h" #include "mitkMouseWheelEvent.h" #include #include +#include mitk::SurfaceDeformationDataInteractor3D::SurfaceDeformationDataInteractor3D() :m_GaussSigma(30.0) { m_OriginalPolyData = vtkPolyData::New(); // Initialize vector arithmetic m_ObjectNormal[0] = 0.0; m_ObjectNormal[1] = 0.0; m_ObjectNormal[2] = 1.0; } mitk::SurfaceDeformationDataInteractor3D::~SurfaceDeformationDataInteractor3D() { m_OriginalPolyData->Delete(); } void mitk::SurfaceDeformationDataInteractor3D::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("initDeformation",InitDeformation); CONNECT_FUNCTION("deformObject",DeformObject); CONNECT_FUNCTION("scaleRadius", ScaleRadius); } void mitk::SurfaceDeformationDataInteractor3D::DataNodeChanged() { if(this->GetDataNode().IsNotNull()) { m_Surface = dynamic_cast(this->GetDataNode()->GetData()); if (m_Surface == NULL) MITK_ERROR << "SurfaceDeformationDataInteractor3D::DataNodeChanged(): DataNode has to contain a surface."; } else m_Surface = NULL; } bool mitk::SurfaceDeformationDataInteractor3D::CheckOverObject(const InteractionEvent* interactionEvent) { const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); Point3D currentPickedPoint; if(interactionEvent->GetSender()->PickObject(currentPickedDisplayPoint, currentPickedPoint) == this->GetDataNode().GetPointer()) { // Colorized surface at current picked position m_SurfaceColorizationCenter = currentPickedPoint; return true; } return false; } bool mitk::SurfaceDeformationDataInteractor3D::SelectObject(StateMachineAction*, InteractionEvent* interactionEvent) { const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData* polyData = m_Surface->GetVtkPolyData(timeStep); this->GetDataNode()->SetColor(1.0, 0.0, 0.0); // Colorize surface / wireframe dependend on distance from picked point this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_GAUSS); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::SurfaceDeformationDataInteractor3D::DeselectObject(StateMachineAction*, InteractionEvent* interactionEvent) { const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData* polyData = m_Surface->GetVtkPolyData(timeStep); this->GetDataNode()->SetColor(1.0, 1.0, 1.0); // Colorize surface / wireframe as inactive this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_CONSTANT, -1.0); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::SurfaceDeformationDataInteractor3D::InitDeformation(StateMachineAction*, InteractionEvent* interactionEvent) { const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData* polyData = m_Surface->GetVtkPolyData(timeStep); // Store current picked point - interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), m_InitialPickedPoint); + mitk::Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); + interactionEvent->GetSender()->PickObject(currentPickedDisplayPoint, m_InitialPickedPoint); + + vtkInteractorObserver::ComputeDisplayToWorld( + interactionEvent->GetSender()->GetVtkRenderer(), + currentPickedDisplayPoint[0], + currentPickedDisplayPoint[1], + 0.0, //m_InitialInteractionPickedPoint[2], + m_InitialPickedWorldPoint); // Make deep copy of vtkPolyData interacted on m_OriginalPolyData->DeepCopy(polyData); return true; } bool mitk::SurfaceDeformationDataInteractor3D::DeformObject (StateMachineAction*, InteractionEvent* interactionEvent) { const InteractionPositionEvent* positionEvent = dynamic_cast(interactionEvent); if(positionEvent == NULL) return false; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData* polyData = m_Surface->GetVtkPolyData(timeStep); BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetGeometry(timeStep); - Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); + double currentWorldPoint[4]; + mitk::Point2D currentDisplayPoint = positionEvent->GetPointerPositionOnScreen(); + vtkInteractorObserver::ComputeDisplayToWorld( + interactionEvent->GetSender()->GetVtkRenderer(), + currentDisplayPoint[0], + currentDisplayPoint[1], + 0.0, //m_InitialInteractionPickedPoint[2], + currentWorldPoint); // Calculate mouse move in 3D space Vector3D interactionMove; - interactionMove[0] = currentPickedPoint[0] - m_InitialPickedPoint[0]; - interactionMove[1] = currentPickedPoint[1] - m_InitialPickedPoint[1]; - interactionMove[2] = currentPickedPoint[2] - m_InitialPickedPoint[2]; + interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; + interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; + interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; // Transform mouse move into geometry space this->GetDataNode()->GetData()->UpdateOutputInformation();// make sure that the Geometry is up-to-date Vector3D interactionMoveIndex; geometry->WorldToIndex(interactionMove, interactionMoveIndex); // Get picked point and transform into local coordinates Point3D pickedPoint; geometry->WorldToIndex(m_InitialPickedPoint, pickedPoint); Vector3D v1 = pickedPoint.GetVectorFromOrigin(); 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 v2 = m_ObjectNormal * (interactionMoveIndex * m_ObjectNormal); vtkPoints* originalPoints = m_OriginalPolyData->GetPoints(); vtkPoints* deformedPoints = polyData->GetPoints(); double denom = m_GaussSigma * m_GaussSigma * 2; double point[3]; for (vtkIdType i = 0; i < deformedPoints->GetNumberOfPoints(); ++i) { // Get original point double* originalPoint = originalPoints->GetPoint( i ); Vector3D v0; v0[0] = originalPoint[0]; v0[1] = originalPoint[1]; v0[2] = originalPoint[2]; // Calculate distance of this point from line through picked point double d = itk::CrossProduct(m_ObjectNormal, (v1 - v0)).GetNorm(); Vector3D t = v2 * exp(- d * d / denom); point[0] = originalPoint[0] + t[0]; point[1] = originalPoint[1] + t[1]; point[2] = originalPoint[2] + t[2]; deformedPoints->SetPoint(i, point); } // Make sure that surface is colorized at initial picked position as long as we are in deformation state m_SurfaceColorizationCenter = m_InitialPickedPoint; polyData->Modified(); m_Surface->Modified(); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::SurfaceDeformationDataInteractor3D::ScaleRadius(StateMachineAction*, InteractionEvent* interactionEvent) { const MouseWheelEvent* wheelEvent = dynamic_cast(interactionEvent); if(wheelEvent == NULL) return false; m_GaussSigma += (double) (wheelEvent->GetWheelDelta()) / 20; if ( m_GaussSigma < 10.0 ) { m_GaussSigma = 10.0; } else if ( m_GaussSigma > 128.0 ) { m_GaussSigma = 128.0; } int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData* polyData = m_Surface->GetVtkPolyData(timeStep); // Colorize surface / wireframe dependend on sigma and distance from picked point this->ColorizeSurface( polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_GAUSS ); interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); return true; } bool mitk::SurfaceDeformationDataInteractor3D::ColorizeSurface(vtkPolyData* polyData, int timeStep, const Point3D &pickedPoint, int mode, double scalar) { if (polyData == NULL) return false; vtkPoints* points = polyData->GetPoints(); vtkPointData* pointData = polyData->GetPointData(); if ( pointData == NULL ) return false; vtkDataArray* scalars = pointData->GetScalars(); if (scalars == NULL) return false; if (mode == COLORIZATION_GAUSS) { // Get picked point and transform into local coordinates Point3D localPickedPoint; BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetGeometry(timeStep); geometry->WorldToIndex( pickedPoint, localPickedPoint ); Vector3D v1 = localPickedPoint.GetVectorFromOrigin(); 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); } double denom = m_GaussSigma * m_GaussSigma * 2; for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i) { // Get original point double* point = points->GetPoint(i); Vector3D v0; v0[0] = point[0]; v0[1] = point[1]; v0[2] = point[2]; // Calculate distance of this point from line through picked point double d = itk::CrossProduct(m_ObjectNormal, (v1 - v0)).GetNorm(); double t = exp(- d * d / denom); scalars->SetComponent(i, 0, t); } } else if (mode == COLORIZATION_CONSTANT) { for (vtkIdType i = 0; i < pointData->GetNumberOfTuples(); ++i) { scalars->SetComponent(i, 0, scalar); } } polyData->Modified(); pointData->Update(); return true; } diff --git a/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.h b/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.h index e1c803dd08..76d42f2ff0 100644 --- a/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.h +++ b/Modules/DataTypesExt/mitkSurfaceDeformationDataInteractor3D.h @@ -1,85 +1,86 @@ /*=================================================================== 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 mitkSurfaceDeformationDataInteractor3D_h_ #define mitkSurfaceDeformationDataInteractor3D_h_ #include "mitkDataInteractor.h" #include "MitkDataTypesExtExports.h" #include "mitkSurface.h" namespace mitk { /** * \brief SurfaceDeformation interaction with objects in 3D windows. * * \ingroup Interaction */ // Inherit from DataInteratcor, this provides functionality of a state machine and configurable inputs. class MitkDataTypesExt_EXPORT SurfaceDeformationDataInteractor3D: public DataInteractor { public: mitkClassMacro(SurfaceDeformationDataInteractor3D, DataInteractor); itkFactorylessNewMacro(Self) itkCloneMacro(Self) protected: SurfaceDeformationDataInteractor3D(); virtual ~SurfaceDeformationDataInteractor3D(); /** * 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 InitDeformation (StateMachineAction*, InteractionEvent*); virtual bool DeformObject (StateMachineAction*, InteractionEvent*); virtual bool ScaleRadius (StateMachineAction*, InteractionEvent*); enum { COLORIZATION_GAUSS, COLORIZATION_CONSTANT }; private: bool ColorizeSurface(vtkPolyData* polyData, int timeStep, const Point3D& pickedPoint, int mode, double scalar = 0.0); + double m_InitialPickedWorldPoint[4]; Point3D m_InitialPickedPoint; Point3D m_SurfaceColorizationCenter; Surface* m_Surface; vtkPolyData* m_OriginalPolyData; double m_GaussSigma; Vector3D m_ObjectNormal; }; } #endif