# 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
      vtkSmartPointer<vtkPositionCallback> callback =
        vtkSmartPointer<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();

      return EXIT_SUCCESS;
    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 3.3 FATAL_ERROR)

    project(MovableAxes)

    find_package(VTK COMPONENTS
      vtkCommonCore
      vtkFiltersSources
      vtkInteractionStyle
      vtkRenderingAnnotation
      vtkRenderingCore
      vtkRenderingFreeType
      vtkRenderingOpenGL2 QUIET)
    if (NOT VTK_FOUND)
      message("Skipping MovableAxes: ${VTK_NOT_FOUND_MESSAGE}")
      return ()
    endif()
    message (STATUS "VTK_VERSION: ${VTK_VERSION}")
    if (VTK_VERSION VERSION_LESS "8.90.0")
      # old system
      include(${VTK_USE_FILE})
      add_executable(MovableAxes MACOSX_BUNDLE MovableAxes.cxx )
      target_link_libraries(MovableAxes PRIVATE ${VTK_LIBRARIES})
    else ()
      # include all components
      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}
        )
    endif ()

### 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.