# EllipticalButton

VTKExamples/Cxx/Interaction/EllipticalButton

### Description

This example creates a 3D button using vtkEllipsoidalButton. Interaction is done by assigning the button to a vtkProp3DButtonRepresentation. Then a callback for a vtkButtonWidget controls the color of the button and the displayed geometry. Click on the button to see the color of both the button and geometry change.

Warning

There is a bug in vtkEllipticalButtonSource. If CircumferentialResolution is odd, improper geometry is created.

Warning

Values close to 1.0 for RadialRatio can cause shading artifacts at the corners of the button.

### Code

EllipticalButton.cxx

    #include <vtkEllipticalButtonSource.h>
    #include <vtkSmartPointer.h>

    #include <vtkSuperquadricSource.h>

    #include <vtkImageReader2Factory.h>
    #include <vtkImageReader2.h>
    #include <vtkImageData.h>

    #include <vtkTexture.h>
    #include <vtkPolyDataMapper.h>
    #include <vtkActor.h>
    #include <vtkProperty.h>
    #include <vtkRenderer.h>
    #include <vtkRenderWindow.h>
    #include <vtkRenderWindowInteractor.h>

    #include <vtkProp3DButtonRepresentation.h>
    #include <vtkButtonWidget.h>
    #include <vtkCoordinate.h>
    #include <vtkCommand.h>

    #include <vtkNamedColors.h>

    // Callback for the interaction
    namespace
    {
    class vtkButtonCallback : public vtkCommand
    {
    public:
      static vtkButtonCallback *New()
        { return new vtkButtonCallback; }
      virtual void Execute(vtkObject *caller, unsigned long, void*)
      {
          vtkButtonWidget *buttonWidget =
            reinterpret_cast<vtkButtonWidget*>(caller);
          vtkProp3DButtonRepresentation *rep =
            reinterpret_cast<vtkProp3DButtonRepresentation *>
            (buttonWidget->GetRepresentation());
          int state = rep->GetState();
          this->Actor->GetProperty()->SetColor(reinterpret_cast<vtkActor *>(rep->GetButtonProp(state))->GetProperty()->GetColor());
          std::cout << "State: " << state << "\n";
      }
      vtkButtonCallback():Actor(0) {}
      vtkActor *Actor;
    };
    }

    static vtkSmartPointer<vtkActor> CreateButtonActor(const char *textureFile);

    int main (int argc, char *argv[])
    {
      if (argc < 2)
      {
        std::cout << "Usage: " << argv[0] << " imageFilename" << std::endl;
        return EXIT_FAILURE;
      }

      vtkSmartPointer<vtkNamedColors> color =
        vtkSmartPointer<vtkNamedColors>::New();

      vtkSmartPointer<vtkSuperquadricSource> source =
        vtkSmartPointer<vtkSuperquadricSource>::New();
      source->SetPhiResolution(64);
      source->SetThetaResolution(64);
      source->SetThetaRoundness(1.5);
      source->SetThickness(1.5);
      source->SetSize(2);
      source->Update();

      vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      mapper->SetInputConnection(source->GetOutputPort());

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

      vtkSmartPointer<vtkRenderer> renderer =
        vtkSmartPointer<vtkRenderer>::New();
      renderer->AddActor(actor);
      renderer->SetBackground(color->GetColor3d("Burlywood").GetData());

      vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
      renderWindow->SetSize(200, 200);
      renderWindow->AddRenderer(renderer);

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

      // Create the widget and its representation
      vtkSmartPointer<vtkActor> buttonActor1 = CreateButtonActor(argv[1]);
      buttonActor1->GetProperty()->SetColor(color->GetColor3d("Tomato").GetData());
      vtkSmartPointer<vtkActor> buttonActor2 = CreateButtonActor(argv[1]);
      buttonActor2->GetProperty()->SetColor(color->GetColor3d("Banana").GetData());

      vtkSmartPointer<vtkProp3DButtonRepresentation> buttonRepresentation =
        vtkSmartPointer<vtkProp3DButtonRepresentation>::New();
      buttonRepresentation->SetNumberOfStates(2);
      buttonRepresentation->SetButtonProp(0, buttonActor1);
      buttonRepresentation->SetButtonProp(1, buttonActor2);
      buttonRepresentation->FollowCameraOn();

      vtkSmartPointer<vtkButtonCallback> callback =
        vtkSmartPointer<vtkButtonCallback>::New();
      callback->Actor = actor;
      actor->GetProperty()->SetColor(reinterpret_cast<vtkActor *>(buttonRepresentation->GetButtonProp(0))->GetProperty()->GetColor());

      renderWindowInteractor->Initialize();

      vtkSmartPointer<vtkButtonWidget> buttonWidget =
        vtkSmartPointer<vtkButtonWidget>::New();
      buttonWidget->SetInteractor(renderWindowInteractor);
      buttonWidget->SetRepresentation(buttonRepresentation);
      buttonWidget->AddObserver(vtkCommand::StateChangedEvent,callback);
      buttonWidget->SetEnabled(1);

      renderer->ResetCamera();
      renderer->Render();

      renderWindowInteractor->Start();

      return EXIT_SUCCESS;
    }
    vtkSmartPointer<vtkActor> CreateButtonActor(const char *textureFile)
    {
      vtkSmartPointer<vtkImageReader2Factory> readerFactory =
        vtkSmartPointer<vtkImageReader2Factory>::New();
      vtkSmartPointer<vtkImageReader2> imageReader =
        readerFactory->CreateImageReader2(textureFile);
      imageReader->SetFileName(textureFile);
      imageReader->Update();

      // Aspect ratio of image
      int dims[3];
      imageReader->GetOutput()->GetDimensions(dims);
      double aspect = static_cast<double>(dims[0])/ static_cast<double>(dims[1]);

      vtkSmartPointer<vtkTexture> texture =
        vtkSmartPointer<vtkTexture>::New();
      texture->SetInputConnection(imageReader->GetOutputPort());

      vtkSmartPointer<vtkEllipticalButtonSource> ellipticalButtonSource
        = vtkSmartPointer<vtkEllipticalButtonSource>::New();
      ellipticalButtonSource->SetCircumferentialResolution(50);
      ellipticalButtonSource->SetShoulderResolution(10);
      ellipticalButtonSource->SetTextureResolution(10);
      ellipticalButtonSource->SetRadialRatio(1.05);
      ellipticalButtonSource->SetShoulderTextureCoordinate(0.0, 0.0);
      ellipticalButtonSource->SetTextureDimensions(dims[0], dims[1]);
      ellipticalButtonSource->SetTextureStyleToProportional();
      ellipticalButtonSource->TwoSidedOn();
      ellipticalButtonSource->SetWidth(aspect);
      ellipticalButtonSource->SetHeight(1.0);
      ellipticalButtonSource->SetDepth(.15);
      ellipticalButtonSource->SetCenter(2, 2, 0);

      ellipticalButtonSource->SetOutputPointsPrecision(vtkAlgorithm::SINGLE_PRECISION);

      vtkSmartPointer<vtkPolyDataMapper> buttonMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      buttonMapper->SetInputConnection(ellipticalButtonSource->GetOutputPort());

      vtkSmartPointer<vtkActor> buttonActor =
        vtkSmartPointer<vtkActor>::New();
      buttonActor->SetMapper(buttonMapper);
      buttonActor->SetTexture(texture);

      return buttonActor;
    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 3.3 FATAL_ERROR)

    project(EllipticalButton)

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

### Download and Build EllipticalButton

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

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

    ./EllipticalButton

WINDOWS USERS

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