Skip to content

ResampleAppendedPolyData

vtk-examples/Cxx/PolyData/ResampleAppendedPolyData


Description

The example populates a level terrain with randomly positioned and scaled objects selected from vtkPlatonicSolidSource.

The example proceeds as follows:

  1. Create a terrain using vtkPlaneSource.
  2. Generate objects using vtkPlatonicSolidSource, randomly selecting the type of solid.
  3. Randomly scale and place the object using std::random.
  4. Use vtkAppendPolyDatato to append the object to the terrain and other objects.
  5. Create a higher or lower resolution terrain.
  6. For each point in the new terrain, create a long line, through the point.
  7. Use vtkCellLocator::IntersectWithLine to find the intersection of the line and use its z value as the new terrain height.
  8. Display original and resampled terrain in side-by-side viewports.

Note

The example was motivated on this question on VTK's Discourse.

Note

Note that std::mt19937_64 gives different results for Microsoft Visual Studio and Linux gcc so it has been commented out and vtkMinimalStandardRandomSequence used instead.

Question

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

Code

ResampleAppendedPolyData.cxx

#include <vtkActor.h>
#include <vtkAppendPolyData.h>
#include <vtkCamera.h>
#include <vtkCellLocator.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkMinimalStandardRandomSequence.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlaneSource.h>
#include <vtkPlatonicSolidSource.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>

// #include <random>

int main(int, char*[])
{
  // Define adjustable paramaters.
  constexpr double xMin = -10.0;
  constexpr double xMax = 10.0;
  constexpr double yMin = -10.0;
  constexpr double yMax = 10.0;
  constexpr int xResolution = 100;
  constexpr int yResolution = 100;
  constexpr double scaleMin = 0.2;
  constexpr double scaleMax = 1.5;
  constexpr int numberOfObjects = 200;
  constexpr int probeResolution = 200.0;

  // Generate terrain.
  vtkNew<vtkPlaneSource> terrain;
  terrain->SetOrigin(xMin, yMin, 0.0);
  terrain->SetPoint2(xMin, yMax, 0.0);
  terrain->SetPoint1(xMax, yMin, 0.0);
  terrain->SetXResolution(xResolution);
  terrain->SetYResolution(yResolution);
  terrain->Update();

  // Generate objects and append them to terrain.
  vtkNew<vtkAppendPolyData> append;
  append->AddInputConnection(terrain->GetOutputPort());

  // Commented out since it gives different results for VS and gcc.
  // std::mt19937_64 mt(4355412); // Standard mersenne twister engine
  // std::uniform_int_distribution<> solid(0, 4);
  // std::uniform_real_distribution<> scale(scaleMin, scaleMax);
  // std::uniform_real_distribution<> position(xMin + 1.0, xMax - 1.0);

  vtkNew<vtkMinimalStandardRandomSequence> randomSequence;
  randomSequence->SetSeed(4355412);

  for (auto i = 0; i < numberOfObjects; ++i)
  {
    int solid = static_cast<int>(randomSequence->GetRangeValue(0, 4));
    randomSequence->Next();
    double s = randomSequence->GetRangeValue(scaleMin, scaleMax);
    randomSequence->Next();
    double x, y;
    x = randomSequence->GetRangeValue(xMin + 1.0, xMax - 1.0);
    randomSequence->Next();
    y = randomSequence->GetRangeValue(yMin + 1.0, yMax - 1.0);
    randomSequence->Next();

    // Generate an object.
    vtkNew<vtkPlatonicSolidSource> platonic;
    // platonic->SetSolidType(solid(mt));
    platonic->SetSolidType(solid);

    // Translate and scale.
    vtkNew<vtkTransform> transform;
    // double s = scale(mt);
    // transform->Translate(position(mt), position(mt), 0.0);
    transform->Translate(x, y, 0.0);
    transform->Scale(s, s, s);
    vtkNew<vtkTransformPolyDataFilter> transformPD;
    transformPD->SetTransform(transform);
    transformPD->SetInputConnection(platonic->GetOutputPort());
    transformPD->Update();

    vtkNew<vtkPolyData> pd;
    pd->DeepCopy(transformPD->GetOutput());
    append->AddInputData(pd);
  }
  append->Update();

  // Resample terrian.
  vtkNew<vtkCellLocator> cellLocator;
  cellLocator->SetDataSet(append->GetOutput());
  cellLocator->BuildLocator();

  // Generate a probe plane.
  vtkNew<vtkPlaneSource> probeTerrain;
  probeTerrain->SetOrigin(terrain->GetOrigin());
  probeTerrain->SetPoint2(terrain->GetPoint2());
  probeTerrain->SetPoint1(terrain->GetPoint1());
  probeTerrain->SetXResolution(probeResolution);
  probeTerrain->SetYResolution(probeResolution);
  probeTerrain->Update();

  vtkPoints* probePoints = probeTerrain->GetOutput()->GetPoints();
  for (auto i = 0; i < probeTerrain->GetOutput()->GetNumberOfPoints(); ++i)
  {
    int subId;
    double t, xyz[3], pcoords[3];
    double rayStart[3], rayEnd[3];
    probePoints->GetPoint(i, rayStart);
    rayStart[2] += 100000.0;
    probePoints->GetPoint(i, rayEnd);
    rayEnd[2] -= 100000.0;

    if (cellLocator->IntersectWithLine(rayStart, rayEnd, 0.0001, t, xyz,
                                       pcoords, subId))
    {
      // The new elevation is in xyz[2].
      double pt[3];
      probePoints->GetPoint(i, pt);
      probePoints->SetPoint(i, pt[0], pt[1], xyz[2]);
    }
  }
  probeTerrain->GetOutput()->GetPointData()->SetNormals(nullptr);

  // Visualize
  vtkNew<vtkNamedColors> colors;

  // Two viewports, left for original and right for resampled.
  vtkNew<vtkPolyDataMapper> originalMapper;
  originalMapper->SetInputConnection(append->GetOutputPort());
  originalMapper->SetInputData(append->GetOutput());
  originalMapper->ScalarVisibilityOff();

  vtkNew<vtkActor> originalActor;
  originalActor->SetMapper(originalMapper);
  originalActor->GetProperty()->SetRepresentationToWireframe();
  originalActor->GetProperty()->SetColor(
      colors->GetColor3d("Seashell").GetData());

  vtkNew<vtkPolyDataMapper> resampledMapper;
  resampledMapper->SetInputConnection(append->GetOutputPort());
  resampledMapper->SetInputData(probeTerrain->GetOutput());
  resampledMapper->ScalarVisibilityOff();

  vtkNew<vtkActor> resampledActor;
  resampledActor->SetMapper(resampledMapper);
  resampledActor->GetProperty()->SetRepresentationToWireframe();
  resampledActor->GetProperty()->SetColor(
      colors->GetColor3d("Seashell").GetData());

  double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};
  vtkNew<vtkRenderer> rightRenderer;
  rightRenderer->SetViewport(rightViewport);
  rightRenderer->UseHiddenLineRemovalOn();
  rightRenderer->AddActor(resampledActor);
  rightRenderer->SetBackground(colors->GetColor3d("DarkSlateGray").GetData());

  double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
  vtkNew<vtkRenderer> leftRenderer;
  leftRenderer->SetViewport(leftViewport);
  leftRenderer->UseHiddenLineRemovalOn();
  leftRenderer->AddActor(originalActor);
  leftRenderer->SetBackground(colors->GetColor3d("DarkSlateGray").GetData());
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->AddRenderer(rightRenderer);
  renderWindow->AddRenderer(leftRenderer);
  renderWindow->SetSize(1024, 512);

  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);
  renderWindow->SetWindowName("ResampleAppendedPolyData");

  vtkNew<vtkInteractorStyleTrackballCamera> style;
  renderWindowInteractor->SetInteractorStyle(style);

  renderWindow->Render();
  vtkCamera* camera;
  camera = leftRenderer->GetActiveCamera();
  camera->SetFocalPoint(0.0, 0.0, 0.0);
  camera->SetPosition(1.0, 0.0, 0.0);
  camera->SetViewUp(0.0, 0.0, 1.0);
  camera->Azimuth(30.0);
  camera->Elevation(45.0);

  leftRenderer->ResetCamera();
  rightRenderer->SetActiveCamera(camera);
  renderWindow->Render();

  renderWindowInteractor->Start();
  return EXIT_SUCCESS;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(ResampleAppendedPolyData)

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

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

Download and Build ResampleAppendedPolyData

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

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

./ResampleAppendedPolyData

WINDOWS USERS

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