MovableAxes
VTKExamples/Cxx/Visualization/MovableAxes
Description
With vtkAxesActor, a hybrid object with 3D axes and 2D label props, it is not possible to move the labels along with the axes with vtkInteractorStyleTrackballActor. Here we create new axes labels using a different 3D prop: vtkFollower, and update their positions with a custom callback command.
Code
MovableAxes.cxx
#include <vtkActor.h>
#include <vtkAssembly.h>
#include <vtkAssemblyPath.h>
#include <vtkAxesActor.h>
#include <vtkCommand.h>
#include <vtkConeSource.h>
#include <vtkFollower.h>
#include <vtkPolyDataMapper.h>
#include <vtkProp3DCollection.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleTrackballActor.h>
#include <vtkSmartPointer.h>
#include <vtkTextActor.h>
#include <vtkVectorText.h>
//----------------------------------------------------------------------------
class vtkPositionCallback : public vtkCommand
{
public:
static vtkPositionCallback *New()
{ return new vtkPositionCallback; }
void Execute( vtkObject* vtkNotUsed(caller), unsigned long vtkNotUsed(event),
void *vtkNotUsed( callData ) )
{
this->Axes->InitPathTraversal();
vtkAssemblyPath *path = 0;
int count = 0;
vtkFollower* followers[3] = { this->XLabel, this->YLabel, this->ZLabel };
int followerId = 0;
while( (path = this->Axes->GetNextPath()) != NULL )
{
if( count++ > 2 )
{
vtkProp3D *prop3D = static_cast<vtkProp3D *>(path->GetLastNode()->GetViewProp());
if ( prop3D )
{
prop3D->PokeMatrix(path->GetLastNode()->GetMatrix());
followers[followerId]->SetPosition(prop3D->GetCenter());
followerId++;
prop3D->PokeMatrix(NULL);
}
}
}
}
vtkPositionCallback(): XLabel( 0 ), YLabel( 0 ),ZLabel( 0 ),Axes(0){}
vtkFollower *XLabel;
vtkFollower *YLabel;
vtkFollower *ZLabel;
vtkAssembly* Axes;
};
int main (int, char *[])
{
vtkSmartPointer<vtkConeSource> coneSource =
vtkSmartPointer<vtkConeSource>::New();
coneSource->Update();
// vtkPolyData* cone = coneSource->GetOutput();
//create a mapper
vtkSmartPointer<vtkPolyDataMapper> coneMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
coneMapper->SetInputConnection(coneSource->GetOutputPort());
// create an actor
vtkSmartPointer<vtkActor> coneActor =
vtkSmartPointer<vtkActor>::New();
coneActor->SetMapper(coneMapper);
coneActor->GetProperty()->SetColor(1,1,0);
// a renderer and render window
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
// an interactor
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
// add the actors to the scene
renderer->AddActor(coneActor);
renderer->SetBackground(0.5,0.5,0.5);
// vtkAxesActor is currently not designed to work with vtkInteractorStyleTrackballActor
// since it is a hybrid object containing both vtkProp3D's and vtkActor2D's, the latter
// of which does not have a 3D position that can be manipulated
vtkSmartPointer<vtkAxesActor> axes =
vtkSmartPointer<vtkAxesActor>::New();
// get a copy of the axes' constituent 3D actors and put them into a vtkAssembly
// so they can be manipulated as one prop
vtkSmartPointer<vtkPropCollection> collection =
vtkSmartPointer<vtkPropCollection>::New();
axes->GetActors(collection);
collection->InitTraversal();
vtkSmartPointer<vtkAssembly> movableAxes =
vtkSmartPointer<vtkAssembly>::New();
for( int i = 0; i < collection->GetNumberOfItems(); ++i )
{
movableAxes->AddPart((vtkProp3D*)collection->GetNextProp());
}
renderer->AddActor(movableAxes);
// create our own labels that will follow and face the camera
vtkSmartPointer<vtkFollower> xLabel =
vtkSmartPointer<vtkFollower>::New();
vtkSmartPointer<vtkVectorText> xText =
vtkSmartPointer<vtkVectorText>::New();
vtkSmartPointer<vtkPolyDataMapper> xTextMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
xText->SetText( "X" );
xTextMapper->SetInputConnection( xText->GetOutputPort() );
xLabel->SetMapper( xTextMapper );
xLabel->SetScale( 0.3 );
xLabel->SetCamera(renderer->GetActiveCamera());
xLabel->SetPosition(((vtkProp3D*)collection->GetItemAsObject( 3 ))->GetCenter()); // XAxisTip
xLabel->PickableOff();
renderer->AddActor( xLabel );
vtkSmartPointer<vtkFollower> yLabel =
vtkSmartPointer<vtkFollower>::New();
vtkSmartPointer<vtkVectorText> yText =
vtkSmartPointer<vtkVectorText>::New();
vtkSmartPointer<vtkPolyDataMapper> yTextMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
yText->SetText( "Y" );
yTextMapper->SetInputConnection( yText->GetOutputPort() );
yLabel->SetMapper( yTextMapper );
yLabel->SetScale( 0.3 );
yLabel->SetCamera(renderer->GetActiveCamera());
yLabel->SetPosition(((vtkProp3D*)collection->GetItemAsObject( 4 ))->GetCenter()); // YAxisTip
yLabel->PickableOff();
renderer->AddActor( yLabel );
vtkSmartPointer<vtkFollower> zLabel =
vtkSmartPointer<vtkFollower>::New();
vtkSmartPointer<vtkVectorText> zText =
vtkSmartPointer<vtkVectorText>::New();
vtkSmartPointer<vtkPolyDataMapper> zTextMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
zText->SetText( "Z" );
zTextMapper->SetInputConnection( zText->GetOutputPort() );
zLabel->SetMapper( zTextMapper );
zLabel->SetScale( 0.3 );
zLabel->SetCamera(renderer->GetActiveCamera());
zLabel->SetPosition(((vtkProp3D*)collection->GetItemAsObject( 5 ))->GetCenter()); // ZAxisTip
zLabel->PickableOff();
renderer->AddActor( zLabel );
// custom callback to set the positions of the labels
vtkPositionCallback* callback = vtkPositionCallback::New();
callback->XLabel = xLabel;
callback->YLabel = yLabel;
callback->ZLabel = zLabel;
callback->Axes = movableAxes;
renderer->ResetCamera();
renderWindow->Render();
vtkSmartPointer<vtkInteractorStyleTrackballActor> style =
vtkSmartPointer<vtkInteractorStyleTrackballActor>::New();
renderWindowInteractor->SetInteractorStyle( style );
style->AddObserver( vtkCommand::InteractionEvent, callback );
// begin mouse interaction
renderWindowInteractor->Start();
callback->Delete();
return EXIT_SUCCESS;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
PROJECT(MovableAxes)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(MovableAxes MACOSX_BUNDLE MovableAxes.cxx)
target_link_libraries(MovableAxes ${VTK_LIBRARIES})
Download and Build MovableAxes
Click here to download MovableAxes and its CMakeLists.txt file. Once the tarball MovableAxes.tar has been downloaded and extracted,
cd MovableAxes/build
If VTK is installed:
cmake ..
If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:
cmake -DVTK_DIR:PATH=/home/me/vtk_build ..
Build the project:
make
and run it:
./MovableAxes
WINDOWS USERS PLEASE NOTE: Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.