How to have multiple polylines in polydata?

I am starting from this example and I want to extend it to put multiple lines in a single polydata. My attempt is below. It results in an empty render window, whereas I expect some lines to be visible. What am I doing wrong and how to fix it?

#include <vtkActor.h>
#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkDoubleArray.h>
#include <vtkNamedColors.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkPolyLine.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>

int
main(int, char *[])
{
  constexpr unsigned numberOfPoints = 12;
  constexpr unsigned numberOfContours = 7;

  auto cells = vtkSmartPointer<vtkCellArray>::New();
  auto points = vtkSmartPointer<vtkPoints>::New();
  points->Allocate(numberOfPoints * numberOfContours);
  vtkIdType cpNumber = 0;

  for (unsigned k = 0; k < numberOfContours; k++)
  {
    double point[3];
    auto   polyLine = vtkSmartPointer<vtkPolyLine>::New();
    polyLine->GetPointIds()->SetNumberOfIds(numberOfPoints);
    for (vtkIdType i = 0; i < numberOfPoints; i++)
    {
      point[0] = i;
      point[1] = numberOfPoints - i;
      point[2] = k;

      points->SetPoint(cpNumber, point);
      polyLine->GetPointIds()->SetId(i, cpNumber);
      ++cpNumber;
    }
    cells->InsertNextCell(polyLine);
  }

  // Create a polydata to store everything in
  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();

  // Add the points to the dataset
  polyData->SetPoints(points);

  // Add the lines to the dataset
  polyData->SetLines(cells);

  // Setup actor and mapper
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputData(polyData);

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

  vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(colors->GetColor3d("Tomato").GetData());

  // Setup render window, renderer, and interactor
  vtkSmartPointer<vtkRenderer>     renderer = vtkSmartPointer<vtkRenderer>::New();
  vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->SetWindowName("PolyLine");
  renderWindow->AddRenderer(renderer);
  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);
  renderer->AddActor(actor);
  renderer->SetBackground(colors->GetColor3d("DarkOliveGreen").GetData());

  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}

Hello,

This is how I did in a project in my current job :

struct Something....
{
....
    vtkSmartPointer<vtkPoints> Points;
    vtkSmartPointer<vtkCellArray> Lines; // stores the lines between points
    vtkSmartPointer<vtkPolyData> PolyData;
....
};

PolyData->SetPoints(Points.GetPointer());
PolyData->SetLines(Lines.GetPointer());

// Reset the vtkPoints and vtkCellArray objects and the sum of the lengths
// of the lines between the points associated with the interval.
interval.Points->Reset();
interval.Lines->Reset();

// Insert multi line points into interval.Points

for(vtkIdType i = 0; i < interval.Points->GetNumberOfPoints() - 1; i++)
{
    vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
    line->GetPointIds()->SetId(0, i);
    line->GetPointIds()->SetId(1, i + 1);
    interval.Lines->InsertNextCell(line);
} 

Hope that helps !

Thanks for the reply, but what is interval and how is it defined?

Ignore it (remove it, I copied parts from a project so it’s not a clean example, interval is a struct something instance).

In short, you will need a vtkPoints and a vtkCellArray, set them to a vtkPolyData like in the example above.

Add your points to the vtkPoints object in the right order, than create simple lines that will define a (having 2 extremities hence the 0 and 1 values that you can see in SetId and which IDs are vtkPoints’s points IDs).

Let me know, if you want an example of how to color the lines with an array (float for example) and a lookup table.

The example I started from works correctly with a single line of 5 points. I need N lines with M points each. I don’t care about color.

It turns out I was missing points->SetNumberOfPoints(...);. Just points->Allocate(...); is not enough :frowning:

I never used vtkPolyLine, so I will continue with what I know :

Store ALL your points in a vtkPoints object (M * N points I guess) and call

YourPolyData->SetPoints(YourVTKPointsObject);

We assume that calling YourVTKPointsObject->GetNumberOfPoints(); will return M*N

Create a vtkCellArray object “YourVTKLines” in which you will create your N Lines and call this :

YourPolyData->SetLines(YourVTKLines);

Then iterate on YourVTKPointsObject’s points to create the N Lines points and set their points (define them) - I didn’t really understand what are you trying to do, but hope that helps anyway !

1 Like

I was doing that, except that I was missing YourVTKPointsObject->SetNumberOfPoints(M*N). Here is a code which works:

#include <vtkActor.h>
#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkDoubleArray.h>
#include <vtkNamedColors.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkPolyLine.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>

int
main(int, char *[])
{
  constexpr unsigned numberOfPoints = 12;
  constexpr unsigned numberOfContours = 7;

  auto cells = vtkSmartPointer<vtkCellArray>::New();
  auto points = vtkSmartPointer<vtkPoints>::New();
  points->SetNumberOfPoints(numberOfPoints * numberOfContours);
  vtkIdType cpNumber = 0;

  for (unsigned k = 0; k < numberOfContours; k++)
  {
    double point[3];
    auto   polyLine = vtkSmartPointer<vtkPolyLine>::New();
    polyLine->GetPointIds()->SetNumberOfIds(numberOfPoints);
    for (vtkIdType i = 0; i < numberOfPoints; i++)
    {
      point[0] = i;
      point[1] = numberOfPoints - i;
      point[2] = k;

      points->SetPoint(cpNumber, point);
      polyLine->GetPointIds()->SetId(i, cpNumber);
      ++cpNumber;
    }
    cells->InsertNextCell(polyLine);
  }

  // Create a polydata to store everything in
  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();

  // Add the points to the dataset
  polyData->SetPoints(points);

  // Add the lines to the dataset
  polyData->SetLines(cells);

  // Setup actor and mapper
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputData(polyData);

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

  vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(colors->GetColor3d("Tomato").GetData());

  // Setup render window, renderer, and interactor
  vtkSmartPointer<vtkRenderer>     renderer = vtkSmartPointer<vtkRenderer>::New();
  vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->SetWindowName("PolyLine");
  renderWindow->AddRenderer(renderer);
  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);
  renderer->AddActor(actor);
  renderer->SetBackground(colors->GetColor3d("DarkOliveGreen").GetData());

  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}