MovableAxes
Repository source: 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.
Other languages
See (PythonicAPI)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
MovableAxes.cxx
#include <vtkActor.h>
#include <vtkAssembly.h>
#include <vtkAssemblyPath.h>
#include <vtkAxesActor.h>
#include <vtkCallbackCommand.h>
#include <vtkCommand.h>
#include <vtkConeSource.h>
#include <vtkFollower.h>
#include <vtkInteractorStyleTrackballActor.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkTextActor.h>
#include <vtkVectorText.h>
namespace {
//----------------------------------------------------------------------------
class vtkPositionCallback : public vtkCallbackCommand
{
public:
static vtkPositionCallback* New()
{
return new vtkPositionCallback;
}
void Execute(vtkObject* vtkNotUsed(caller), unsigned long vtkNotUsed(event),
void* vtkNotUsed(callData))
{
this->Axes->InitPathTraversal();
vtkAssemblyPath* path = nullptr;
int count = 0;
vtkFollower* followers[3] = {this->XLabel, this->YLabel, this->ZLabel};
int followerId = 0;
while ((path = this->Axes->GetNextPath()) != nullptr)
{
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(nullptr);
}
}
}
}
vtkPositionCallback()
: XLabel(nullptr), YLabel(nullptr), ZLabel(nullptr), Axes(nullptr)
{
}
vtkFollower* XLabel;
vtkFollower* YLabel;
vtkFollower* ZLabel;
vtkAssembly* Axes;
};
} // namespace
int main(int, char*[])
{
vtkNew<vtkNamedColors> colors;
vtkNew<vtkConeSource> coneSource;
coneSource->Update();
// vtkPolyData* cone = coneSource->GetOutput();
// create a mapper
vtkNew<vtkPolyDataMapper> coneMapper;
coneMapper->SetInputConnection(coneSource->GetOutputPort());
// create an actor
vtkNew<vtkActor> coneActor;
coneActor->SetMapper(coneMapper);
coneActor->GetProperty()->SetColor(colors->GetColor3d("Gold").GetData());
// a renderer and render window
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
renderWindow->SetWindowName("MovableAxes");
// an interactor
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
// Add the actors to the scene.
renderer->AddActor(coneActor);
renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());
// 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.
vtkNew<vtkAxesActor> axes;
// Get a copy of the axes' constituent 3D actors and put them into a
// vtkAssembly so they can be manipulated as one prop.
vtkNew<vtkPropCollection> collection;
axes->GetActors(collection);
collection->InitTraversal();
vtkNew<vtkAssembly> movableAxes;
for (int i = 0; i < collection->GetNumberOfItems(); ++i)
{
movableAxes->AddPart(static_cast<vtkProp3D*>(collection->GetNextProp()));
}
renderer->AddActor(movableAxes);
// Create our own labels that will follow and face the camera.
vtkNew<vtkFollower> xLabel;
vtkNew<vtkVectorText> xText;
vtkNew<vtkPolyDataMapper> xTextMapper;
xText->SetText("X");
xTextMapper->SetInputConnection(xText->GetOutputPort());
xLabel->SetMapper(xTextMapper);
xLabel->SetScale(0.3);
xLabel->SetCamera(renderer->GetActiveCamera());
xLabel->SetPosition((static_cast<vtkProp3D*>(collection->GetItemAsObject(3))
->GetCenter())); // XAxisTip
xLabel->PickableOff();
renderer->AddActor(xLabel);
vtkNew<vtkFollower> yLabel;
vtkNew<vtkVectorText> yText;
vtkNew<vtkPolyDataMapper> yTextMapper;
yText->SetText("Y");
yTextMapper->SetInputConnection(yText->GetOutputPort());
yLabel->SetMapper(yTextMapper);
yLabel->SetScale(0.3);
yLabel->SetCamera(renderer->GetActiveCamera());
yLabel->SetPosition((static_cast<vtkProp3D*>(collection->GetItemAsObject(4))
->GetCenter())); // YAxisTip
yLabel->PickableOff();
renderer->AddActor(yLabel);
vtkNew<vtkFollower> zLabel;
vtkNew<vtkVectorText> zText;
vtkNew<vtkPolyDataMapper> zTextMapper;
zText->SetText("Z");
zTextMapper->SetInputConnection(zText->GetOutputPort());
zLabel->SetMapper(zTextMapper);
zLabel->SetScale(0.3);
zLabel->SetCamera(renderer->GetActiveCamera());
zLabel->SetPosition((static_cast<vtkProp3D*>(collection->GetItemAsObject(5))
->GetCenter())); // ZAxisTip
zLabel->PickableOff();
renderer->AddActor(zLabel);
// Custom callback to set the positions of the labels.
vtkNew<vtkPositionCallback> callback;
callback->XLabel = xLabel;
callback->YLabel = yLabel;
callback->ZLabel = zLabel;
callback->Axes = movableAxes;
renderer->ResetCamera();
renderWindow->Render();
vtkNew<vtkInteractorStyleTrackballActor> style;
renderWindowInteractor->SetInteractorStyle(style);
style->AddObserver(vtkCommand::InteractionEvent, callback);
// Begin mouse interaction.
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MovableAxes)
find_package(VTK COMPONENTS
CommonColor
CommonCore
FiltersSources
InteractionStyle
RenderingAnnotation
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "MovableAxes: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(MovableAxes MACOSX_BUNDLE MovableAxes.cxx )
target_link_libraries(MovableAxes PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS MovableAxes
MODULES ${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
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.