Skip to content

ColoredAnnotatedCube

vtk-examples/Cxx/Visualization/ColoredAnnotatedCube


Description

This example demonstrates how to color the individual faces of an annotated cube.

This is based on a very nice example by Rodrigo Figueiredo in this discussion.

The process is:

  • Create the annotated cube actor using vtkAnnotatedCubeActor.
  • Select the names on the faces, text colors and, if needed, any rotations of the text.
  • Make the annotated cube transparent.
  • Create a cube actor with colored faces.
  • Combine the annotated cube actor and cube actor into a prop assembly using vtkPropAssembly. Since the annotated cube and the cube are the same size you get an assembly with colored cube faces and the requisite text.
  • Create a vtkOrientationMarkerWidget and set the set the orientation marker to be the prop assembly.

The function MakeAnnotatedCubeActor generates the annotated cube with different colored faces which is then added to a vtkOrientationMarkerWidget.

The colored annotated cube is then placed in the lower left of the view (default). Additionally, a vtkOrientationMarkerWidget containing an axes actor has been added to the lower right of the view.

Other languages

See (Python)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

ColoredAnnotatedCube.cxx

#include <vtkAnnotatedCubeActor.h>
#include <vtkAxesActor.h>
#include <vtkBandedPolyDataContourFilter.h>
#include <vtkCamera.h>
#include <vtkCaptionActor2D.h>
#include <vtkCellData.h>
#include <vtkColorSeries.h>
#include <vtkConeSource.h>
#include <vtkCubeSource.h>
#include <vtkElevationFilter.h>
#include <vtkLookupTable.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkPolyDataMapper.h>
#include <vtkPropAssembly.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkTextProperty.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>

#include <array>

namespace {
/**
 * Nake the annotated cube actor with different colored faces.
 *
 * @param colors: Used to set the colors of the cube faces.
 * @return The annotated cube actor.
 */
vtkSmartPointer<vtkPropAssembly> MakeAnnotatedCubeActor(vtkNamedColors* colors);

/**
 * Make an axes actor.
 *
 * @param scale: Sets the scale and direction of the axes.
 * @param xyzLabels: Labels for the axes.
 * @return The axes actor.
 */
vtkSmartPointer<vtkAxesActor>
MakeAxesActor(std::array<double, 3>& scale,
              std::array<std::string, 3>& xyzLabels);

} // namespace

int main(int, char*[])
{
  // Basic stuff setup
  // Set up the renderer, window, and interactor.
  vtkNew<vtkNamedColors> colors;

  vtkNew<vtkRenderer> ren;
  vtkNew<vtkRenderWindow> renWin;
  renWin->AddRenderer(ren);
  renWin->SetSize(640, 480);
  vtkNew<vtkRenderWindowInteractor> iRen;
  iRen->SetRenderWindow(renWin);

  // Create a cone with an elliptical base whose major axis is in the
  // X-direction.
  vtkNew<vtkConeSource> coneSource;
  coneSource->SetCenter(0.0, 0.0, 0.0);
  coneSource->SetRadius(5.0);
  coneSource->SetHeight(15.0);
  coneSource->SetDirection(0, 1, 0);
  coneSource->SetResolution(60);
  coneSource->Update();

  vtkNew<vtkTransform> transform;
  transform->Scale(1.0, 1.0, 0.75);

  vtkNew<vtkTransformPolyDataFilter> transF;
  transF->SetInputConnection(coneSource->GetOutputPort());
  transF->SetTransform(transform);

  double bounds[6];
  transF->GetOutput()->GetBounds(bounds);

  vtkNew<vtkElevationFilter> elevation;
  elevation->SetInputConnection(transF->GetOutputPort());
  elevation->SetLowPoint(0, bounds[2], 0);
  elevation->SetHighPoint(0, bounds[3], 0);

  vtkNew<vtkBandedPolyDataContourFilter> bandedContours;
  bandedContours->SetInputConnection(elevation->GetOutputPort());
  bandedContours->SetScalarModeToValue();
  bandedContours->GenerateContourEdgesOn();
  bandedContours->GenerateValues(11, elevation->GetScalarRange());

  // Make a lookup table using a color series.
  vtkNew<vtkColorSeries> colorSeries;
  colorSeries->SetColorScheme(vtkColorSeries::BREWER_DIVERGING_SPECTRAL_11);

  vtkNew<vtkLookupTable> lut;
  colorSeries->BuildLookupTable(lut, vtkColorSeries::ORDINAL);

  vtkNew<vtkPolyDataMapper> coneMapper;
  coneMapper->SetInputConnection(bandedContours->GetOutputPort());
  coneMapper->SetScalarRange(elevation->GetScalarRange());
  coneMapper->SetLookupTable(lut);

  vtkNew<vtkActor> coneActor;
  coneActor->SetMapper(coneMapper);

  // Contouring
  vtkNew<vtkPolyDataMapper> contourLineMapper;
  contourLineMapper->SetInputData(bandedContours->GetContourEdgesOutput());
  contourLineMapper->SetScalarRange(elevation->GetScalarRange());
  contourLineMapper->SetResolveCoincidentTopologyToPolygonOffset();

  vtkNew<vtkActor> contourLineActor;
  contourLineActor->SetMapper(contourLineMapper);
  contourLineActor->GetProperty()->SetColor(
      colors->GetColor3d("DimGray").GetData());

  // Set up the Orientation Marker Widget.
  auto prop_assembly = MakeAnnotatedCubeActor(colors);
  vtkNew<vtkOrientationMarkerWidget> om1;
  om1->SetOrientationMarker(prop_assembly);
  om1->SetInteractor(iRen);
  om1->SetDefaultRenderer(ren);
  om1->On();
  om1->InteractiveOn();

  std::array<std::string, 3> xyzLabels{{"X", "Y", "Z"}};
  std::array<double, 3> scale{{1.0, 1.0, 1.0}};
  auto axes = MakeAxesActor(scale, xyzLabels);

  vtkNew<vtkOrientationMarkerWidget> om2;
  om2->SetOrientationMarker(axes);
  // Position lower right in the viewport.
  om2->SetViewport(0.8, 0, 1.0, 0.2);
  om2->SetInteractor(iRen);
  om2->EnabledOn();
  om2->InteractiveOn();

  ren->AddActor(coneActor);
  ren->AddActor(contourLineActor);
  ren->SetBackground2(colors->GetColor3d("RoyalBlue").GetData());
  ren->SetBackground(colors->GetColor3d("MistyRose").GetData());
  ren->GradientBackgroundOn();
  ren->GetActiveCamera()->Azimuth(45);
  ren->GetActiveCamera()->Pitch(-22.5);
  ren->ResetCamera();

  renWin->SetSize(600, 600);
  renWin->Render();
  renWin->SetWindowName("ColoredAnnotatedCube");
  renWin->Render();
  iRen->Start();

  return EXIT_SUCCESS;
}

namespace {
vtkSmartPointer<vtkPropAssembly> MakeAnnotatedCubeActor(vtkNamedColors* colors)
{
  // Annotated Cube setup.
  vtkNew<vtkAnnotatedCubeActor> annotated_cube;
  annotated_cube->SetFaceTextScale(0.366667);

  // Anatomic labeling
  annotated_cube->SetXPlusFaceText("X+");
  annotated_cube->SetXMinusFaceText("X-");
  annotated_cube->SetYPlusFaceText("Y+");
  annotated_cube->SetYMinusFaceText("Y-");
  annotated_cube->SetZPlusFaceText("Z+");
  annotated_cube->SetZMinusFaceText("Z-");

  // Change the vector text colors.
  annotated_cube->GetTextEdgesProperty()->SetColor(
      colors->GetColor3d("Black").GetData());
  annotated_cube->GetTextEdgesProperty()->SetLineWidth(1);

  annotated_cube->GetXPlusFaceProperty()->SetColor(
      colors->GetColor3d("Turquoise").GetData());
  annotated_cube->GetXMinusFaceProperty()->SetColor(
      colors->GetColor3d("Turquoise").GetData());
  annotated_cube->GetYPlusFaceProperty()->SetColor(
      colors->GetColor3d("Mint").GetData());
  annotated_cube->GetYMinusFaceProperty()->SetColor(
      colors->GetColor3d("Mint").GetData());
  annotated_cube->GetZPlusFaceProperty()->SetColor(
      colors->GetColor3d("Tomato").GetData());
  annotated_cube->GetZMinusFaceProperty()->SetColor(
      colors->GetColor3d("Tomato").GetData());
  annotated_cube->SetXFaceTextRotation(90);
  annotated_cube->SetYFaceTextRotation(180);
  annotated_cube->SetZFaceTextRotation(-90);
  // Make the annotated cube transparent.
  annotated_cube->GetCubeProperty()->SetOpacity(0);

  // Colored faces cube setup.
  vtkNew<vtkCubeSource> cube_source;
  cube_source->Update();

  vtkNew<vtkUnsignedCharArray> face_colors;
  face_colors->SetNumberOfComponents(3);
  auto face_x_plus = colors->GetColor3ub("Red").GetData();
  auto face_x_minus = colors->GetColor3ub("Green").GetData();
  auto face_y_plus = colors->GetColor3ub("Blue").GetData();
  auto face_y_minus = colors->GetColor3ub("Yellow").GetData();
  auto face_z_plus = colors->GetColor3ub("Cyan").GetData();
  auto face_z_minus = colors->GetColor3ub("Magenta").GetData();
  face_colors->InsertNextTypedTuple(face_x_minus);
  face_colors->InsertNextTypedTuple(face_x_plus);
  face_colors->InsertNextTypedTuple(face_y_minus);
  face_colors->InsertNextTypedTuple(face_y_plus);
  face_colors->InsertNextTypedTuple(face_z_minus);
  face_colors->InsertNextTypedTuple(face_z_plus);

  cube_source->GetOutput()->GetCellData()->SetScalars(face_colors);
  cube_source->Update();

  vtkNew<vtkPolyDataMapper> cube_mapper;
  cube_mapper->SetInputData(cube_source->GetOutput());
  cube_mapper->Update();

  vtkNew<vtkActor> cube_actor;
  cube_actor->SetMapper(cube_mapper);

  // Assemble the colored cube and annotated cube texts into a composite prop.
  vtkNew<vtkPropAssembly> prop_assembly;
  prop_assembly->AddPart(annotated_cube);
  prop_assembly->AddPart(cube_actor);
  return prop_assembly;
}

vtkSmartPointer<vtkAxesActor>
MakeAxesActor(std::array<double, 3>& scale,
              std::array<std::string, 3>& xyzLabels)
{
  vtkNew<vtkAxesActor> axes;
  axes->SetScale(scale[0], scale[1], scale[2]);
  axes->SetShaftTypeToCylinder();
  axes->SetXAxisLabelText(xyzLabels[0].c_str());
  axes->SetYAxisLabelText(xyzLabels[1].c_str());
  axes->SetZAxisLabelText(xyzLabels[2].c_str());
  axes->SetCylinderRadius(0.5 * axes->GetCylinderRadius());
  axes->SetConeRadius(1.025 * axes->GetConeRadius());
  axes->SetSphereRadius(1.5 * axes->GetSphereRadius());
  vtkTextProperty* tprop =
      axes->GetXAxisCaptionActor2D()->GetCaptionTextProperty();
  tprop->ItalicOn();
  tprop->ShadowOn();
  tprop->SetFontFamilyToTimes();
  // Use the same text properties on the other two axes.
  axes->GetYAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy(tprop);
  axes->GetZAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy(tprop);
  return axes;
}

} // namespace

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(ColoredAnnotatedCube)

find_package(VTK COMPONENTS 
  CommonColor
  CommonCore
  CommonDataModel
  CommonTransforms
  FiltersCore
  FiltersGeneral
  FiltersModeling
  FiltersSources
  InteractionStyle
  InteractionWidgets
  RenderingAnnotation
  RenderingContextOpenGL2
  RenderingCore
  RenderingFreeType
  RenderingGL2PSOpenGL2
  RenderingOpenGL2
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "ColoredAnnotatedCube: 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(ColoredAnnotatedCube MACOSX_BUNDLE ColoredAnnotatedCube.cxx )
  target_link_libraries(ColoredAnnotatedCube PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS ColoredAnnotatedCube
  MODULES ${VTK_LIBRARIES}
)

Download and Build ColoredAnnotatedCube

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

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

./ColoredAnnotatedCube

WINDOWS USERS

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