You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmRender/nmVTKPivotCameraInteractorS...

296 lines
9.0 KiB
C++

#include "nmVTKPivotCameraInteractorStyle.h"
#include "nmVTKCameraController.h"
#include <vtkCamera.h>
#include <vtkMath.h>
#include <vtkObjectFactory.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <cmath>
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();
}