#include "nmVTKPivotCameraInteractorStyle.h" #include "nmVTKCameraController.h" #include #include #include #include #include #include vtkStandardNewMacro(nmVTKPivotCameraInteractorStyle); namespace { const double ROTATION_ANGLE_EPSILON = 1.0e-12; bool isFiniteVector3(const double dVector[3]) { return dVector != nullptr && vtkMath::IsFinite(dVector[0]) && vtkMath::IsFinite(dVector[1]) && vtkMath::IsFinite(dVector[2]); } bool rotateVector(const double dInput[3], const double dAxis[3], double dAngleDegrees, double dOutput[3]) { if(!isFiniteVector3(dInput) || !isFiniteVector3(dAxis) || !vtkMath::IsFinite(dAngleDegrees) || dOutput == nullptr) { return false; } if(std::fabs(dAngleDegrees) <= ROTATION_ANGLE_EPSILON) { dOutput[0] = dInput[0]; dOutput[1] = dInput[1]; dOutput[2] = dInput[2]; return true; } double dUnitAxis[3] = { dAxis[0], dAxis[1], dAxis[2] }; if(vtkMath::Normalize(dUnitAxis) <= 0.0) { return false; } const double dAngleRadians = vtkMath::RadiansFromDegrees(dAngleDegrees); const double dCosine = std::cos(dAngleRadians); const double dSine = std::sin(dAngleRadians); const double dProjection = vtkMath::Dot(dUnitAxis, dInput); double dCross[3]; vtkMath::Cross(dUnitAxis, dInput, dCross); for(int nComponent = 0; nComponent < 3; ++nComponent) { dOutput[nComponent] = dInput[nComponent] * dCosine + dCross[nComponent] * dSine + dUnitAxis[nComponent] * dProjection * (1.0 - dCosine); } return isFiniteVector3(dOutput); } bool rotateCameraFrame(double dPosition[3], double dFocalPoint[3], double dViewUp[3], const double dCenter[3], const double dAxis[3], double dAngleDegrees) { if(!isFiniteVector3(dPosition) || !isFiniteVector3(dFocalPoint) || !isFiniteVector3(dViewUp) || !isFiniteVector3(dCenter)) { return false; } double dRelativePosition[3]; double dRelativeFocalPoint[3]; for(int nComponent = 0; nComponent < 3; ++nComponent) { dRelativePosition[nComponent] = dPosition[nComponent] - dCenter[nComponent]; dRelativeFocalPoint[nComponent] = dFocalPoint[nComponent] - dCenter[nComponent]; } double dRotatedPosition[3]; double dRotatedFocalPoint[3]; double dRotatedViewUp[3]; if(!rotateVector(dRelativePosition, dAxis, dAngleDegrees, dRotatedPosition) || !rotateVector(dRelativeFocalPoint, dAxis, dAngleDegrees, dRotatedFocalPoint) || !rotateVector(dViewUp, dAxis, dAngleDegrees, dRotatedViewUp)) { return false; } for(int nComponent = 0; nComponent < 3; ++nComponent) { dPosition[nComponent] = dCenter[nComponent] + dRotatedPosition[nComponent]; dFocalPoint[nComponent] = dCenter[nComponent] + dRotatedFocalPoint[nComponent]; dViewUp[nComponent] = dRotatedViewUp[nComponent]; } return isFiniteVector3(dPosition) && isFiniteVector3(dFocalPoint) && isFiniteVector3(dViewUp); } } nmVTKPivotCameraInteractorStyle::nmVTKPivotCameraInteractorStyle() : m_pCameraController(nullptr) { } nmVTKPivotCameraInteractorStyle::~nmVTKPivotCameraInteractorStyle() { m_pCameraController = nullptr; } void nmVTKPivotCameraInteractorStyle::setCameraController( nmVTKCameraController* pController) { m_pCameraController = pController; } nmVTKCameraController* nmVTKPivotCameraInteractorStyle::getCameraController() const { return m_pCameraController; } void nmVTKPivotCameraInteractorStyle::Rotate() { double dCenter[3]; if(!getCurrentRotationCenter(dCenter)) { vtkInteractorStyleTrackballCamera::Rotate(); return; } if(this->CurrentRenderer == nullptr || this->Interactor == nullptr) { return; } vtkCamera* pCamera = this->CurrentRenderer->GetActiveCamera(); int* pRendererSize = this->CurrentRenderer->GetSize(); int* pEventPosition = this->Interactor->GetEventPosition(); int* pLastEventPosition = this->Interactor->GetLastEventPosition(); if(pCamera == nullptr || pRendererSize == nullptr || pRendererSize[0] <= 0 || pRendererSize[1] <= 0 || pEventPosition == nullptr || pLastEventPosition == nullptr) { return; } const double dAzimuth = (pEventPosition[0] - pLastEventPosition[0]) * (-20.0 / pRendererSize[0]) * this->MotionFactor; const double dElevation = (pEventPosition[1] - pLastEventPosition[1]) * (-20.0 / pRendererSize[1]) * this->MotionFactor; double dPosition[3]; double dFocalPoint[3]; double dViewUp[3]; pCamera->GetPosition(dPosition); pCamera->GetFocalPoint(dFocalPoint); pCamera->GetViewUp(dViewUp); if(!rotateCameraFrame(dPosition, dFocalPoint, dViewUp, dCenter, dViewUp, dAzimuth)) { return; } // vtkCamera::Elevation 使用 (-DirectionOfProjection) x ViewUp。 double dNegativeDirection[3] = { dPosition[0] - dFocalPoint[0], dPosition[1] - dFocalPoint[1], dPosition[2] - dFocalPoint[2] }; double dElevationAxis[3]; vtkMath::Cross(dNegativeDirection, dViewUp, dElevationAxis); if(!rotateCameraFrame(dPosition, dFocalPoint, dViewUp, dCenter, dElevationAxis, dElevation)) { return; } finishCameraMotion(dPosition, dFocalPoint, dViewUp); } void nmVTKPivotCameraInteractorStyle::Spin() { double dCenter[3]; if(!getCurrentRotationCenter(dCenter)) { vtkInteractorStyleTrackballCamera::Spin(); return; } if(this->CurrentRenderer == nullptr || this->Interactor == nullptr) { return; } vtkCamera* pCamera = this->CurrentRenderer->GetActiveCamera(); int* pEventPosition = this->Interactor->GetEventPosition(); int* pLastEventPosition = this->Interactor->GetLastEventPosition(); if(pCamera == nullptr || pEventPosition == nullptr || pLastEventPosition == nullptr) { return; } this->CurrentRenderer->SetWorldPoint( dCenter[0], dCenter[1], dCenter[2], 1.0); this->CurrentRenderer->WorldToDisplay(); const double* pDisplayCenter = this->CurrentRenderer->GetDisplayPoint(); if(!isFiniteVector3(pDisplayCenter)) { return; } const double dNewAngle = std::atan2( pEventPosition[1] - pDisplayCenter[1], pEventPosition[0] - pDisplayCenter[0]); const double dOldAngle = std::atan2( pLastEventPosition[1] - pDisplayCenter[1], pLastEventPosition[0] - pDisplayCenter[0]); double dSpinAngle = vtkMath::DegreesFromRadians( dNewAngle - dOldAngle); if(dSpinAngle > 180.0) { dSpinAngle -= 360.0; } else if(dSpinAngle < -180.0) { dSpinAngle += 360.0; } double dPosition[3]; double dFocalPoint[3]; double dViewUp[3]; pCamera->GetPosition(dPosition); pCamera->GetFocalPoint(dFocalPoint); pCamera->GetViewUp(dViewUp); double dDirectionOfProjection[3] = { dFocalPoint[0] - dPosition[0], dFocalPoint[1] - dPosition[1], dFocalPoint[2] - dPosition[2] }; if(!rotateCameraFrame(dPosition, dFocalPoint, dViewUp, dCenter, dDirectionOfProjection, dSpinAngle)) { return; } finishCameraMotion(dPosition, dFocalPoint, dViewUp); } bool nmVTKPivotCameraInteractorStyle::getCurrentRotationCenter( double dCenter[3]) const { return dCenter != nullptr && m_pCameraController != nullptr && this->CurrentRenderer != nullptr && m_pCameraController->getRenderer() == this->CurrentRenderer && m_pCameraController->getRotationCenter(dCenter); } void nmVTKPivotCameraInteractorStyle::finishCameraMotion( const double dPosition[3], const double dFocalPoint[3], const double dViewUp[3]) { if(this->CurrentRenderer == nullptr || this->Interactor == nullptr || !isFiniteVector3(dPosition) || !isFiniteVector3(dFocalPoint) || !isFiniteVector3(dViewUp)) { return; } vtkCamera* pCamera = this->CurrentRenderer->GetActiveCamera(); if(pCamera == nullptr) { return; } pCamera->SetPosition(dPosition); pCamera->SetFocalPoint(dFocalPoint); pCamera->SetViewUp(dViewUp); pCamera->OrthogonalizeViewUp(); if(this->AutoAdjustCameraClippingRange != 0) { this->CurrentRenderer->ResetCameraClippingRange(); } if(this->Interactor->GetLightFollowCamera() != 0) { this->CurrentRenderer->UpdateLightsGeometryToFollowCamera(); } this->Interactor->Render(); }