Rotate a cube and move it.
Replay the event by shortcut key in the following simple example.
We will start by decomposing the matrix into a rotation matrix and a translation matrix, then perform linear interpolation, and finally calculate a new matrix based on the number of steps.
main.cpp
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkTransform.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkAxesActor.h>
#include <vtkLine.h>
#include <vtkPlane.h>
#include <vtkSTLWriter.h>
#include <vtkPointLocator.h>
#include <vtkProperty.h>
#include <vtkSphereSource.h>
#include <vtkCubeSource.h>
#include <vtkAxesActor.h>
#include "point.hpp"
#include "CustomIteractorStyle.h"
using namespace std;
int main()
{
vtkSPtrNew( source, vtkCubeSource );
source->Update();
vtkSPtrNew( mapper, vtkPolyDataMapper );
mapper->SetInputData( source->GetOutput() );
vtkSPtrNew( actor, vtkActor );
actor->SetMapper( mapper );
vtkSPtrNew( moveTrans, vtkTransform );
moveTrans->Translate( -1, 0, 0 );
moveTrans->Update();
vtkSPtrNew( moveTrans1, vtkTransform );
moveTrans1->Translate( 0, 2, 0 );
moveTrans1->Update();
vtkSPtrNew( finalMoveTrans, vtkTransform );
finalMoveTrans->Concatenate( moveTrans1 );
finalMoveTrans->Concatenate( moveTrans );
finalMoveTrans->Update();
vtkSPtrNew( rotateTrans, vtkTransform );
rotateTrans->RotateY( 30 );
rotateTrans->RotateZ( 40 );
rotateTrans->Update();
vtkSPtrNew( scaleTrans, vtkTransform );
scaleTrans->Scale( 3, 1, 1 );
scaleTrans->Scale( 1, 2, 1 );
scaleTrans->Update();
vtkSPtrNew( scaleTransInv, vtkTransform );
scaleTransInv->DeepCopy( scaleTrans );
scaleTransInv->Inverse();
vtkSPtrNew( finalTrans, vtkTransform );
// world system's move matrix
// finalTrans->Concatenate( finalMoveTrans );
// finalTrans->Concatenate( scaleTrans );
// finalTrans->Concatenate( rotateTrans );
// move on local trans direction.
finalTrans->Concatenate( rotateTrans );
finalTrans->Concatenate( finalMoveTrans );
finalTrans->Update();
actor->SetUserTransform( finalTrans );
vtkSPtrNew( axesActor, vtkAxesActor );
axesActor->AxisLabelsOff();
vtkSPtrNew( renderer, vtkRenderer );
renderer->AddActor( actor );
renderer->AddActor( axesActor );
renderer->SetBackground( 0, 0, 0 );
vtkSPtrNew( renderWindow, vtkRenderWindow );
renderWindow->AddRenderer( renderer );
vtkSPtrNew( iStyle, CustomIteractorStyle );
iStyle->Setm_Actor( actor );
iStyle->Setm_RenderWindow( renderWindow );
vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
renderWindowInteractor->SetInteractorStyle( iStyle );
renderWindowInteractor->SetRenderWindow( renderWindow );
renderer->ResetCamera();
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}
CustomIteractorStyle.h
#pragma once
#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>
#include <vtkRenderWindow.h>
#include "point.hpp"
#define CPP_SET_MACRO(name,type) \
void Set##name(type _arg) \
{ \
if (this->name != _arg) \
{ \
this->name = _arg; \
} \
}
#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();
class CustomIteractorStyle: public vtkInteractorStyleTrackballCamera
{
public:
static CustomIteractorStyle *New(){ return new CustomIteractorStyle(); }
virtual void OnKeyDown();
CPP_SET_MACRO( m_Actor, vtkSPtr<vtkActor> )
CPP_SET_MACRO( m_RenderWindow, vtkSPtr<vtkRenderWindow> )
protected:
CustomIteractorStyle();
~CustomIteractorStyle() override;
void DecomposeActorTrans();
void PlayFrame(int stepIndex);
vtkSPtr<vtkRenderer> m_Renderer;
vtkSPtr<vtkActor> m_Actor;
vtkSPtr<vtkRenderWindow> m_RenderWindow;
int m_StepCount, m_StepIndex;
double m_AngleStep, m_XYZ[3];
Point m_MoveStep;
};
CustomIteractorStyle.cpp
#include "CustomIteractorStyle.h"
#include "point.hpp"
#include <string>
#include <vtkCamera.h>
#include <vtkTransform.h>
#include <vtkLinearTransform.h>
void CustomIteractorStyle::OnKeyDown()
{
std::string str = Interactor->GetKeySym();
std::cout << "key: " << str << std::endl;
if( str == "Up" )
{
DecomposeActorTrans();
}
else if(str == "Down"){
PlayFrame( m_StepIndex );
m_StepIndex = (m_StepIndex+1)%m_StepCount;
}
}
CustomIteractorStyle::CustomIteractorStyle()
{
m_Actor = nullptr;
m_StepCount = 11;
m_StepIndex = 0;
}
CustomIteractorStyle::~CustomIteractorStyle()
{
m_Actor = nullptr;
}
void CustomIteractorStyle::DecomposeActorTrans()
{
vtkSmartPointer<vtkTransform> userTrans = (vtkTransform*)( m_Actor->GetUserTransform() );
double wxyz[4];
userTrans->GetOrientationWXYZ( wxyz );
m_AngleStep = wxyz[0] / (m_StepCount - 1.0);
m_XYZ[0] = wxyz[1];
m_XYZ[1] = wxyz[2];
m_XYZ[2] = wxyz[3];
Point origin( 0, 0, 0 );
Point newOrigin;
userTrans->TransformPoint( origin.point, newOrigin.point );
Point vec = newOrigin - origin;
m_MoveStep = vec / (double(m_StepCount - 1.0));
}
void CustomIteractorStyle::PlayFrame(int stepIndex)
{
vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
vtkSmartPointer<vtkTransform> rotateTrans = vtkSmartPointer<vtkTransform>::New();
rotateTrans->RotateWXYZ( stepIndex*m_AngleStep, m_XYZ[0], m_XYZ[1], m_XYZ[2] );
rotateTrans->Update();
vtkSmartPointer<vtkTransform> moveTrans = vtkSmartPointer<vtkTransform>::New();
moveTrans->Translate( (m_MoveStep*stepIndex).point );
moveTrans->Update();
trans->Concatenate( moveTrans ); // direction refer to world coordinate system axis.
trans->Concatenate( rotateTrans );
trans->Update();
m_Actor->SetUserTransform( trans );
m_RenderWindow->Render();
}
Result: