MoveAGlyph

VTKExamples/Cxx/Interaction/MoveAGlyph


Description

This example allows the user to reposition a glyph. It does this by faking the interactor into thinking that a new actor (MoveActor) is the object to be interacted with. We use the array generated by glyph3D->GeneratePointIdsOn() to determine the point associated with the glyph that the user selected. A "ghost" actor of the selected glyph is generated (because all of the glyphs are part of the same actor, so they would all move together). This actor is moved, and its final position is used to update the point in the original data set.

Code

MoveAGlyph.cxx

#include <vtkSmartPointer.h>
#include <vtkCellPicker.h>
#include <vtkSphereSource.h>
#include <vtkGlyph3D.h>
#include <vtkPointData.h>
#include <vtkIdTypeArray.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkRendererCollection.h>
#include <vtkProperty.h>
#include <vtkPlanes.h>
#include <vtkObjectFactory.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkPointSource.h>
#include <vtkInteractorStyleTrackballActor.h>
#include <vtkAreaPicker.h>
#include <vtkExtractGeometry.h>
#include <vtkDataSetMapper.h>
#include <vtkUnstructuredGrid.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkIdFilter.h>

// Define interaction style
class InteractorStyleMoveGlyph : public vtkInteractorStyleTrackballActor
{
public:
  static InteractorStyleMoveGlyph* New();
  vtkTypeMacro(InteractorStyleMoveGlyph,vtkInteractorStyleTrackballActor);

  InteractorStyleMoveGlyph()
  {
    this->MoveSphereSource = vtkSmartPointer<vtkSphereSource>::New();
    this->MoveSphereSource->SetRadius(.1);
    this->MoveSphereSource->Update();

    this->MoveMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    this->MoveMapper->SetInputConnection(this->MoveSphereSource->GetOutputPort());

    this->MoveActor = vtkSmartPointer<vtkActor>::New();
    this->MoveActor->SetMapper(this->MoveMapper);
    //this->MoveActor->VisibilityOff();

    this->Move = false;
  }

  void OnMouseMove() override
  {
    if(!this->Move)
    {
      return;
    }

    vtkInteractorStyleTrackballActor::OnMouseMove();

  }

  void OnMiddleButtonUp() override
  {
    // Forward events
    vtkInteractorStyleTrackballActor::OnMiddleButtonUp();
    this->Move = false;
    this->MoveActor->VisibilityOff();

    this->Data->GetPoints()->SetPoint(this->SelectedPoint, this->MoveActor->GetPosition());
    this->Data->Modified();
    this->GetCurrentRenderer()->Render();
    this->GetCurrentRenderer()->GetRenderWindow()->Render();
  }
  void OnMiddleButtonDown() override
  {
    // Forward events
    vtkInteractorStyleTrackballActor::OnMiddleButtonDown();
    this->MoveActor->VisibilityOn();
    if(static_cast<vtkCellPicker*>(this->InteractionPicker)->GetPointId() >= 0)
    {
      vtkIdType id = dynamic_cast<vtkIdTypeArray*>(this->GlyphData->GetPointData()->GetArray("InputPointIds"))
        ->GetValue(static_cast<vtkCellPicker*>(this->InteractionPicker)->GetPointId());
      std::cout << "Id: " << id << std::endl;
      this->Move = true;
      this->SelectedPoint = id;

      double p[3];
      this->Data->GetPoint(id, p);
      std::cout << "p: " << p[0] << " " << p[1] << " " << p[2] << std::endl;
      this->MoveActor->SetPosition(p);
    }

    this->GetCurrentRenderer()->AddActor(this->MoveActor);
    this->InteractionProp = this->MoveActor;

  }
  vtkPolyData* Data;
  vtkPolyData* GlyphData;

  vtkSmartPointer<vtkPolyDataMapper> MoveMapper;
  vtkSmartPointer<vtkActor> MoveActor;
  vtkSmartPointer<vtkSphereSource> MoveSphereSource;

  bool Move;
  vtkIdType SelectedPoint;
};
vtkStandardNewMacro(InteractorStyleMoveGlyph);

int main (int, char *[])
{
  vtkSmartPointer<vtkPoints> points =
    vtkSmartPointer<vtkPoints>::New();
  points->InsertNextPoint(0,0,0);
  points->InsertNextPoint(1,0,0);
  points->InsertNextPoint(2,0,0);

  vtkSmartPointer<vtkPolyData> input =
    vtkSmartPointer<vtkPolyData>::New();
  input->SetPoints(points);

  vtkSmartPointer<vtkSphereSource> glyphSource =
    vtkSmartPointer<vtkSphereSource>::New();
  glyphSource->SetRadius(.1);
  glyphSource->Update();

  vtkSmartPointer<vtkGlyph3D> glyph3D =
    vtkSmartPointer<vtkGlyph3D>::New();
  glyph3D->GeneratePointIdsOn();
  glyph3D->SetSourceConnection(glyphSource->GetOutputPort());
  glyph3D->SetInputData(input);
  glyph3D->SetScaleModeToDataScalingOff();
  glyph3D->Update();

  // Create a mapper and actor
  vtkSmartPointer<vtkPolyDataMapper> mapper =
    vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputConnection(glyph3D->GetOutputPort());

  vtkSmartPointer<vtkActor> actor =
    vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);

  // Visualize
  vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();
  vtkSmartPointer<vtkRenderWindow> renderWindow =
    vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);

  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);

  renderer->AddActor(actor);
  //renderer->SetBackground(1,1,1); // Background color white

  renderWindow->Render();

  vtkSmartPointer<InteractorStyleMoveGlyph> style =
    vtkSmartPointer<InteractorStyleMoveGlyph>::New();
  renderWindowInteractor->SetInteractorStyle( style );
  style->Data = input;
  style->GlyphData = glyph3D->GetOutput();

  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.3 FATAL_ERROR)

project(MoveAGlyph)

find_package(VTK COMPONENTS 
  vtkCommonCore
  vtkCommonDataModel
  vtkFiltersCore
  vtkFiltersExtraction
  vtkFiltersGeneral
  vtkFiltersGeometry
  vtkFiltersSources
  vtkInteractionStyle
  vtkRenderingContextOpenGL2
  vtkRenderingCore
  vtkRenderingFreeType
  vtkRenderingGL2PSOpenGL2
  vtkRenderingOpenGL2 QUIET)
if (NOT VTK_FOUND)
  message("Skipping MoveAGlyph: ${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(MoveAGlyph MACOSX_BUNDLE MoveAGlyph.cxx )
  target_link_libraries(MoveAGlyph PRIVATE ${VTK_LIBRARIES})
else ()
  # include all components
  add_executable(MoveAGlyph MACOSX_BUNDLE MoveAGlyph.cxx )
  target_link_libraries(MoveAGlyph PRIVATE ${VTK_LIBRARIES})
  # vtk_module_autoinit is needed
  vtk_module_autoinit(
    TARGETS MoveAGlyph
    MODULES ${VTK_LIBRARIES}
    )
endif () 

Download and Build MoveAGlyph

Click here to download MoveAGlyph and its CMakeLists.txt file. Once the tarball MoveAGlyph.tar has been downloaded and extracted,

cd MoveAGlyph/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:

./MoveAGlyph

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.