Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

809 lines
23 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkInteractorStyleFlight.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkInteractorStyleFlight.h"
#include "vtkCamera.h"
#include "vtkPerspectiveTransform.h"
#include "vtkRenderer.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkCommand.h"
#include "vtkWindows.h"
vtkCxxRevisionMacro(vtkInteractorStyleFlight, "$Revision: 1.30 $");
vtkStandardNewMacro(vtkInteractorStyleFlight);
class CPIDControl
{
public:
int m_iDeltaT;
int m_iDeltaTf;
double m_dPrevX;
double m_dKp;
double m_dKd;
double m_dKi;
double m_dXSum;
double m_dDelta;
double m_dVelSum;
int m_iVelCount;
double m_dVelAvg;
public:
CPIDControl(double dKp, double dKd, double dKi);
double PIDCalc(double dX,double dFinalX);
void SetCoefficients(double dKp, double dKd, double dKi);
};
CPIDControl::CPIDControl(double dKp, double dKd, double dKi)
{
m_dXSum = 0.0;
m_dPrevX = 0.0;
m_dDelta = 0.0;
m_iDeltaT = 0;
m_iDeltaTf = 0;
m_dVelSum = 0.0;
m_iVelCount = 0;
m_dVelAvg = 0.0;
this->SetCoefficients(dKp, dKd, dKi);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
double CPIDControl::PIDCalc(double dX, double dFinalX)
{
double dVal = dX - dFinalX;
m_dXSum = m_dXSum + dVal;
// Calculate the velocity
dVal = m_dPrevX - dX;
// Average the velocity
m_dVelSum += dVal;
m_iVelCount++;
if(m_iVelCount >= 10)
{
m_dVelAvg = m_dVelSum/(double)m_iVelCount;
m_iVelCount = 0;
m_dVelSum = 0.0;
}
m_dDelta = m_dKp*dX + m_dKd*m_dVelAvg + m_dKi*m_dXSum;
m_dPrevX = dX;
return m_dDelta;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void CPIDControl::SetCoefficients(double dKp, double dKd, double dKi)
{
m_dKp = dKp;
m_dKd = dKd;
m_dKi = dKi;
// should reset internal params here, but no need for this simple usage
}
//---------------------------------------------------------------------------
vtkInteractorStyleFlight::vtkInteractorStyleFlight()
{
this->KeysDown = 0;
this->UseTimers = 1;
this->DiagonalLength = 1.0;
this->MotionStepSize = 1.0/250.0;
this->MotionUserScale = 1.0; // +/- key adjustment
this->MotionAccelerationFactor = 10.0;
this->AngleStepSize = 1.0;
this->AngleAccelerationFactor = 5.0;
this->DisableMotion = 0;
this->RestoreUpVector = 1;
this->DefaultUpVector[0] = 0;
this->DefaultUpVector[1] = 0;
this->DefaultUpVector[2] = 1;
//
PID_Yaw = new CPIDControl(-0.05, 0.0, -0.0008);
PID_Pitch = new CPIDControl(-0.05, 0.0, -0.0008);
Transform = vtkPerspectiveTransform::New();
}
//---------------------------------------------------------------------------
vtkInteractorStyleFlight::~vtkInteractorStyleFlight()
{
Transform->Delete();
delete PID_Yaw;
delete PID_Pitch;
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::ForwardFly()
{
if (this->CurrentRenderer == NULL)
{
return;
}
vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
//
if (this->KeysDown)
{
this->FlyByKey(camera);
}
else
{
this->UpdateSteering(camera);
this->FlyByMouse(camera);
}
//
this->FinishCamera(camera);
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::ReverseFly()
{
// The code is the same, just the state variable that is tracked...
ForwardFly();
}
//----------------------------------------------------------------------------
void vtkInteractorStyleFlight::StartForwardFly()
{
if (this->State != VTKIS_NONE)
{
return;
}
this->StartState(VTKIS_FORWARDFLY);
}
//----------------------------------------------------------------------------
void vtkInteractorStyleFlight::EndForwardFly()
{
if (this->State != VTKIS_FORWARDFLY)
{
return;
}
this->StopState();
}
//----------------------------------------------------------------------------
void vtkInteractorStyleFlight::StartReverseFly()
{
if (this->State != VTKIS_NONE)
{
return;
}
this->StartState(VTKIS_REVERSEFLY);
}
//----------------------------------------------------------------------------
void vtkInteractorStyleFlight::EndReverseFly()
{
if (this->State != VTKIS_REVERSEFLY)
{
return;
}
this->StopState();
}
//---------------------------------------------------------------------------
// All actual motion is performed in the timer
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnTimer()
{
vtkRenderWindowInteractor *rwi = this->Interactor;
switch (this->State)
{
case VTKIS_FORWARDFLY:
this->ForwardFly();
if (this->UseTimers)
{
rwi->CreateTimer(VTKI_TIMER_UPDATE);
}
break;
case VTKIS_REVERSEFLY:
this->ReverseFly();
if (this->UseTimers)
{
rwi->CreateTimer(VTKI_TIMER_UPDATE);
}
break;
default:
break;
}
}
//---------------------------------------------------------------------------
// Mouse event handlers
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnMouseMove()
{
int x = this->Interactor->GetEventPosition()[0];
int y = this->Interactor->GetEventPosition()[1];
this->FindPokedRenderer(x, y);
vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
switch (this->State)
{
case VTKIS_FORWARDFLY:
case VTKIS_REVERSEFLY:
this->UpdateMouseSteering(cam);
this->InvokeEvent(vtkCommand::InteractionEvent, NULL);
break;
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnLeftButtonDown()
{
int x = this->Interactor->GetEventPosition()[0];
int y = this->Interactor->GetEventPosition()[1];
this->FindPokedRenderer(x, y);
if (this->CurrentRenderer == NULL)
{
return;
}
//
vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
switch (this->State)
{
case VTKIS_REVERSEFLY:
this->State = VTKIS_FORWARDFLY;
break;
default :
this->SetupMotionVars(cam);
this->StartForwardFly();
break;
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnLeftButtonUp()
{
switch (this->State)
{
case VTKIS_FORWARDFLY:
this->EndForwardFly();
break;
default :
break;
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnMiddleButtonDown()
{
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnMiddleButtonUp()
{
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnRightButtonDown()
{
int x = this->Interactor->GetEventPosition()[0];
int y = this->Interactor->GetEventPosition()[1];
this->FindPokedRenderer(x, y);
if (this->CurrentRenderer == NULL)
{
return;
}
//
vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
switch (this->State)
{
case VTKIS_FORWARDFLY:
this->State = VTKIS_REVERSEFLY;
break;
default :
this->SetupMotionVars(cam);
this->StartReverseFly();
break;
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnRightButtonUp()
{
switch (this->State)
{
case VTKIS_REVERSEFLY:
this->EndReverseFly();
break;
default :
break;
}
}
//---------------------------------------------------------------------------
// Keyboard event handlers
// Note, OnChar is a key press down and then up event
// Note, OnKeyDown/OnKeyUp are more sensitive for controlling motion
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnKeyDown()
{
// New Flight mode behaviour
// Note that we'll need #defines for ARROW key defs under non win32 OS
#ifdef _WIN32
switch (this->Interactor->GetKeyCode())
{
case VK_LEFT : this->KeysDown |=1; break;
case VK_RIGHT : this->KeysDown |=2; break;
case VK_UP : this->KeysDown |=4; break;
case VK_DOWN : this->KeysDown |=8; break;
case 'a':
case 'A' : this->KeysDown |=16; break;
case 'z':
case 'Z' : this->KeysDown |=32; break;
}
if ((this->KeysDown & (32+16)) == (32+16))
{
if (this->State==VTKIS_FORWARDFLY)
{
this->EndForwardFly();
}
if (this->State==VTKIS_REVERSEFLY)
{
this->EndReverseFly();
}
}
else if ((this->KeysDown & 32) == 32)
{
if (this->State==VTKIS_FORWARDFLY)
{
this->EndForwardFly();
}
this->StartReverseFly();
}
else if ((this->KeysDown & 16) == 16)
{
if (this->State==VTKIS_REVERSEFLY)
{
this->EndReverseFly();
}
this->StartForwardFly();
}
#else
// the following if statement is a dummy one to prevent keycode not used
// warnings under unix, (until the correct keycodes are supplied)
if (this->Interactor->GetKeyCode() == 0x7F)
{
vtkWarningMacro(<<"Dummy test to prevent compiler warning");
}
#endif
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnKeyUp()
{
#ifdef _WIN32
switch (this->Interactor->GetKeyCode())
{
case VK_LEFT : this->KeysDown &= ~1; break;
case VK_RIGHT : this->KeysDown &= ~2; break;
case VK_UP : this->KeysDown &= ~4; break;
case VK_DOWN : this->KeysDown &= ~8; break;
case 'a':
case 'A' : this->KeysDown &= ~16; break;
case 'z':
case 'Z' : this->KeysDown &= ~32; break;
}
switch (this->State)
{
case VTKIS_FORWARDFLY:
if ((this->KeysDown & 16) == 0)
{
this->EndForwardFly();
}
break;
case VTKIS_REVERSEFLY:
if ((this->KeysDown & 32) == 0)
{
this->EndReverseFly();
}
break;
}
#else
// the following if statement is a dummy one to prevent keycode not used
// warnings under unix, (until the correct keycodes are supplied)
if (this->Interactor->GetKeyCode() == 0x7F)
{
vtkWarningMacro(<<"Dummy test to prevent compiler warning");
}
#endif
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::OnChar()
{
switch (this->Interactor->GetKeyCode())
{
case '+' :
this->MotionUserScale *= 2.0;
break;
case '-' :
this->MotionUserScale *= 0.5;
break;
default:
this->Superclass::OnChar();
break;
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::JumpTo(double campos[3], double focpos[3])
{
if (this->CurrentRenderer == NULL)
{
return;
}
vtkCamera* cam = this->CurrentRenderer->GetActiveCamera();
cam->SetPosition(campos);
cam->SetFocalPoint(focpos);
FinishCamera(cam);
this->Interactor->Render();
}
void vtkInteractorStyleFlight::FinishCamera(vtkCamera* cam)
{
cam->OrthogonalizeViewUp();
if (this->RestoreUpVector)
{
double delta[3];
cam->GetViewUp(delta);
double weight = vtkMath::Dot(this->DefaultUpVector,delta);
// only correct up if we're close to it already...
if (weight>0.3) {
weight = 0.25*fabs(weight);
delta[0] = delta[0] + (this->DefaultUpVector[0]-delta[0])*weight;
delta[1] = delta[1] + (this->DefaultUpVector[1]-delta[1])*weight;
delta[2] = delta[2] + (this->DefaultUpVector[2]-delta[2])*weight;
cam->SetViewUp(delta);
}
}
if (this->AutoAdjustCameraClippingRange)
{
this->CurrentRenderer->ResetCameraClippingRange();
}
if (this->Interactor->GetLightFollowCamera())
{
this->CurrentRenderer->UpdateLightsGeometryToFollowCamera();
}
}
//---------------------------------------------------------------------------
// Use this mouse pos and last mouse pos to get the amount of motion
// Compute an "Ideal" focal point, The flight will sterr towards this ideal
// point, but will be damped in Yaw/Pitch by our PID Controllers.
// The damping and motion is done in the timer event.
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::UpdateMouseSteering(vtkCamera *cam)
{
int *thispos = this->Interactor->GetEventPosition();
int *lastpos = this->Interactor->GetLastEventPosition();
double aspeed = this->AngleStepSize*(this->Interactor->GetShiftKey() ?
this->AngleAccelerationFactor : 1.0);
//
// we want to steer by an amount proportional to window viewangle and size
// compute dx and dy increments relative to last mouse click
int *size = this->Interactor->GetSize();
double scalefactor = 5*cam->GetViewAngle()/(double)size[0];
double dx = - (thispos[0] - lastpos[0])*scalefactor*aspeed;
double dy = (thispos[1] - lastpos[1])*scalefactor*aspeed;
// Temporary until I get smooth flight working
this->DeltaPitch = dy;
this->DeltaYaw = dx;
/*
Not happy with smooth flight yet, please levae this code here
until I get around to experimenting : JB July 2002
// dx and dy need to be converted to a new 'ideal' camera focal point
// we maintain an actual FocalPoint and an IdealFocalPoint so that we can
// smooth the motion using our PID controllers (one for yaw, one for pitch).
cam->OrthogonalizeViewUp();
double LRaxis[3];
double *ViewUp = cam->GetViewUp();
double *Position = cam->GetPosition();
double *FocalPoint = cam->GetFocalPoint();
this->GetLRVector(LRaxis, cam);
//
this->Transform->Identity();
this->Transform->Translate(+Position[0],+Position[1],+Position[2]);
this->Transform->RotateWXYZ(dx, ViewUp);
this->Transform->RotateWXYZ(dy, LRaxis);
this->Transform->Translate(-Position[0],-Position[1],-Position[2]);
this->Transform->TransformPoint(this->IdealFocalPoint,this->IdealFocalPoint);
*/
}
#define D2R 0.01745329251994329576923690768 // degrees to radians
#define R2D 57.2957795130823208767981548141 // radians to degrees
// We know the ideal and actual focal points. We now want to reduce these
// to a 2D Yaw+Pitch form so that we can smooth the motion on each
void vtkInteractorStyleFlight::UpdateSteering(vtkCamera *vtkNotUsed(cam))
{
/*
Not happy with smooth flight yet, please levae this code here
until I get around to experimenting : JB July 2002
cam->OrthogonalizeViewUp();
double *Position = cam->GetPosition();
double *FocalPoint = cam->GetFocalPoint();
double vec1[3], vec2[3], norm1[3], norm2[3];
vec1[0] = FocalPoint[0]-Position[0];
vec1[1] = FocalPoint[1]-Position[1];
vec1[2] = FocalPoint[2]-Position[2];
vec2[0] = this->IdealFocalPoint[0]-Position[0];
vec2[1] = this->IdealFocalPoint[1]-Position[1];
vec2[2] = this->IdealFocalPoint[2]-Position[2];
// what's the azimuthal angle between the Ideal and actual focal points
// angle between planes given by Up/Focus and Up/IdealFocus
double *ViewUp = cam->GetViewUp();
vtkMath::Cross(vec1, ViewUp, norm1);
vtkMath::Cross(vec2, ViewUp, norm2);
vtkMath::Normalize(norm1);
vtkMath::Normalize(norm2);
//
double dot = vtkMath::Dot(norm1, norm2);
if (dot>1.0) {
dot = 1.0;
}
else if (dot<-1.0) {
dot =-1.0;
}
double yaw = R2D*acos(dot);
// we know the angle, but is it +ve or -ve (which side is new focal point)
double d1,d2;
d1 = vtkMath::Dot(norm1,this->IdealFocalPoint);
d2 = vtkMath::Dot(norm1,FocalPoint);
if (d1-d2>0) yaw = -yaw;
//
// what's the elevation angle between the Ideal and actual focal points
// angle between planes given by LR/Focus and LR/IdealFocus
double LRaxis[3];
this->GetLRVector(LRaxis, cam);
vtkMath::Cross(vec1, LRaxis, norm1);
vtkMath::Cross(vec2, LRaxis, norm2);
vtkMath::Normalize(norm1);
vtkMath::Normalize(norm2);
//
dot = vtkMath::Dot(norm1, norm2);
if (dot>1.0) {
dot = 1.0;
} else if (dot<-1.0) {
dot =-1.0;
}
double pitch = R2D*acos(dot);
d1 = vtkMath::Dot(norm1,this->IdealFocalPoint);
d2 = vtkMath::Dot(norm1,FocalPoint);
if (d1-d2>0) pitch = -pitch;
// use our motion dampers to reduce the yaw/pitch errors to zero gradually
// this->DeltaYaw = PID_Yaw->PIDCalc(yaw, 0);
// this->DeltaPitch = PID_Pitch->PIDCalc(pitch, 0);
this->DeltaPitch = 0.75*pitch + 0.25*lPitch;
lPitch = pitch;
this->DeltaYaw = 0.75*yaw + 0.25*lYaw;
lYaw = yaw;
*/
}
//---------------------------------------------------------------------------
// useful utility functions
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::SetupMotionVars(vtkCamera *cam)
{
lPitch = 0;
lYaw = 0;
cam->GetFocalPoint(IdealFocalPoint);
double bounds[6];
this->CurrentRenderer->ComputeVisiblePropBounds( bounds );
if ( !vtkMath::AreBoundsInitialized(bounds) )
{
this->DiagonalLength = 1.0;
}
else
{
this->DiagonalLength =
sqrt( (bounds[0] - bounds[1]) * (bounds[0] - bounds[1]) +
(bounds[2] - bounds[3]) * (bounds[2] - bounds[3]) +
(bounds[4] - bounds[5]) * (bounds[4] - bounds[5]) );
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::MotionAlongVector(double vector[3],
double amount, vtkCamera* cam)
{
double oldcampos[3], oldcamfoc[3];
cam->GetPosition(oldcampos);
cam->GetFocalPoint(oldcamfoc);
// move camera and focus along DirectionOfProjection
cam->SetPosition(
oldcampos[0] - amount * vector[0],
oldcampos[1] - amount * vector[1],
oldcampos[2] - amount * vector[2]);
cam->SetFocalPoint(
oldcamfoc[0] - amount * vector[0],
oldcamfoc[1] - amount * vector[1],
oldcamfoc[2] - amount * vector[2]);
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::GetLRVector(double vector[3], vtkCamera* cam)
{
vtkMatrix4x4 *vtm;
vtm = cam->GetViewTransformMatrix();
vector[0] = vtm->GetElement(0,0);
vector[1] = vtm->GetElement(0,1);
vector[2] = vtm->GetElement(0,2);
}
//---------------------------------------------------------------------------
// Perform the motion
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::FlyByMouse(vtkCamera* cam)
{
double a_vector[3];
double speed = this->DiagonalLength * this->MotionStepSize * this->MotionUserScale;
speed = speed * ( this->Interactor->GetShiftKey() ? this->MotionAccelerationFactor : 1.0);
if (this->DisableMotion)
{
speed = 0;
}
// Sidestep (convert steering angles to left right movement :
// only because I added this after doing the angles earlier
if (this->Interactor->GetControlKey())
{
if (this->DeltaYaw!=0.0)
{
this->GetLRVector(a_vector, cam);
this->MotionAlongVector(a_vector,-this->DeltaYaw*speed/2.0, cam);
}
if (this->DeltaPitch!=0.0)
{
cam->GetViewUp(a_vector);
this->MotionAlongVector(a_vector,-this->DeltaPitch*speed/2.0, cam);
}
}
else
{
cam->Yaw(this->DeltaYaw);
cam->Pitch(this->DeltaPitch);
this->DeltaYaw = 0;
this->DeltaPitch = 0;
// cam->SetFocalPoint(this->IdealFocalPoint);
}
//
if (!this->Interactor->GetControlKey())
{
cam->GetDirectionOfProjection(a_vector); // reversed (use -speed)
switch (this->State)
{
case VTKIS_FORWARDFLY:
this->MotionAlongVector(a_vector, -speed, cam);
break;
case VTKIS_REVERSEFLY:
this->MotionAlongVector(a_vector, speed, cam);
break;
}
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::FlyByKey(vtkCamera* cam)
{
double speed = this->DiagonalLength * this->MotionStepSize * this->MotionUserScale;
speed = speed * ( this->Interactor->GetShiftKey() ? this->MotionAccelerationFactor : 1.0);
if (this->DisableMotion)
{
speed = 0;
}
//
double aspeed = this->AngleStepSize* (this->Interactor->GetShiftKey() ? this->AngleAccelerationFactor : 1.0);
double a_vector[3];
// Left and right
if (this->Interactor->GetControlKey())
{ // Sidestep
this->GetLRVector(a_vector, cam);
if (this->KeysDown & 1)
{
this->MotionAlongVector(a_vector,-speed, cam);
}
if (this->KeysDown & 2)
{
this->MotionAlongVector(a_vector, speed, cam);
}
}
else
{
if (this->KeysDown & 1)
{
cam->Yaw( aspeed);
}
if (this->KeysDown & 2)
{
cam->Yaw(-aspeed);
}
}
// Up and Down
if (this->Interactor->GetControlKey())
{ // Sidestep
cam->GetViewUp(a_vector);
if (this->KeysDown & 4)
{
this->MotionAlongVector(a_vector,-speed, cam);
}
if (this->KeysDown & 8)
{
this->MotionAlongVector(a_vector, speed, cam);
}
}
else
{
if (this->KeysDown & 4)
{
cam->Pitch(-aspeed);
}
if (this->KeysDown & 8)
{
cam->Pitch( aspeed);
}
}
// forward and backward
cam->GetDirectionOfProjection(a_vector);
if (this->KeysDown & 16)
{
this->MotionAlongVector(a_vector, speed, cam);
}
if (this->KeysDown & 32)
{
this->MotionAlongVector(a_vector,-speed, cam);
}
}
//---------------------------------------------------------------------------
void vtkInteractorStyleFlight::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "MotionStepSize: "
<< this->MotionStepSize << "\n";
os << indent << "MotionAccelerationFactor: "
<< this->MotionAccelerationFactor << "\n";
os << indent << "AngleStepSize: "
<< this->AngleStepSize << "\n";
os << indent << "AngleAccelerationFactor: "
<< this->AngleAccelerationFactor << "\n";
os << indent << "MotionUserScale: "
<< this->MotionUserScale << "\n";
os << indent << "DisableMotion: "
<< this->DisableMotion << "\n";
os << indent << "RestoreUpVector: "
<< this->RestoreUpVector << "\n";
os << indent << "DefaultUpVector: "
<< this->DefaultUpVector[0] << " "
<< this->DefaultUpVector[1] << " "
<< this->DefaultUpVector[2] << "\n";
}