vtkRenderWindow::Render() is extremely slow when using vtkDelaunay2D filter

I’ve subclassed vtkAbstractPolyDataReader to “GmtGridReader” that reads an x,y grid of elevations. I pass the output of the reader through a vtkDelaunay2D filter before displaying it. However when I read and filter the data and try to render it, vtkRenderWindow::Render() blocks for more than seven minutes, displaying a white background, then finally displaying the surface against a black background. Without seeing details of my reader code yet, can someone see an error in this main() code, i.e. does the pipeline look correct? Am I doing something that is very inefficient?
My dataset consists of 1613850 points, running on Intel I5 7200U dual-core CPU with Intel Corporation HD Graphics 620. Seven minutes seems extremely slow!

   vtkSmartPointer<GmtGridReader> reader =
     vtkSmartPointer<GmtGridReader>::New();
   
   reader->SetFileName ( filePath.c_str() );
   std::cout << "reader->Update()" << std::endl;
   reader->Update();
 
  vtkSmartPointer<vtkDelaunay2D> delaunay =
    vtkSmartPointer<vtkDelaunay2D>::New();
 
  delaunay->SetInputConnection(reader->GetOutputPort());
 
   // Create mapper
   std::cout << "create mapper" << std::endl;
   vtkSmartPointer<vtkPolyDataMapper> mapper =
      vtkSmartPointer<vtkPolyDataMapper>::New();
 
   std::cout << "mapper->SetInputConnection()" << std::endl;
   mapper->SetInputConnection(delaunay->GetOutputPort());
 
   // Create actor
   std::cout << "create actor" << std::endl;   
   vtkSmartPointer<vtkActor> actor =
      vtkSmartPointer<vtkActor>::New();
 
   // Assign mapper to actor
   std::cout << "assign mapper to actor" << std::endl;      
   actor->SetMapper(mapper);
 
   // Create renderer
   std::cout << "create renderer" << std::endl;         
   vtkSmartPointer<vtkRenderer> renderer =
      vtkSmartPointer<vtkRenderer>::New();
 
   // Create renderWindow
   std::cout << "create renderWindow" << std::endl;            
   vtkSmartPointer<vtkRenderWindow> renderWindow =
      vtkSmartPointer<vtkRenderWindow>::New();
 
   // Add renderer to the renderWindow
   std::cout << "add renderer to renderWindow" << std::endl;               
   renderWindow->AddRenderer(renderer);
 
   // Create renderWindowInteractor
   std::cout << "create renderWindowInteractor" << std::endl;                  
   vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
      vtkSmartPointer<vtkRenderWindowInteractor>::New();
 
   std::cout << "renderWindowInteractor->SetRenderWindow()" << std::endl;                     
   renderWindowInteractor->SetRenderWindow(renderWindow);
 
   // Add actor to the renderer
   std::cout << "rendererr->AddActor()" << std::endl;                        
   renderer->AddActor(actor);
   
   // renderer->SetBackground(.2, .3, .4);
   renderer->SetBackground(0., 0., 0.);   
 
   std::cout << "renderWindow->Render()" << std::endl;                        
   renderWindow->Render();
   std::cout << "renderWindowInteractor->Start()" << std::endl;
   renderWindowInteractor->Start();

If x and y is on a grid (e.g., data from a surface scanner) then you should not need Delaunay triangulation at all, but you pre-create all the triangles in advance (maybe you can even use a vtkStructuredGrid).

1 Like

@lassoan - thank you. I have now implemented this and it is fast

1 Like

Great! Would you mind posting a code snippet that worked for you? (just to make things a bit simpler for the next person who comes across this question)

1 Like

Here’s a code snippet from my “GmtGridReader” polydata reader, showing the adding of vertexes (points) and triangular cells to the output:

class GmtGridReader : vtkAbstractPolyDataReader {
 
  [... stuff here ...]
 
  /// Override base class method
  int RequestData(vtkInformation* request, 
                  vtkInformationVector** inputVector,
                  vtkInformationVector* outputVector) override;
 
 
  /// Holds surface vertexes
  vtkSmartPointer<vtkPoints> gridPoints_;
 
  /// Holds surface triangles
  vtkSmartPointer<vtkCellArray> gridPolygons_;  
 
}
 
int GmtGridReader::RequestData(vtkInformation* request,
                               vtkInformationVector** inputVector,
                               vtkInformationVector* outputVector) {
 
 
  
  vtkInformation* outInfo = outputVector->GetInformationObject(0);
 
  vtkPolyData* polyOutput = vtkPolyData::SafeDownCast(output);
 
 
  // Load vertexes read from grid file   
  for (unsigned row = 0; row < gmtGrid_->header->n_rows; row++) {
    for (unsigned col = 0; col < gmtGrid_->header->n_columns; col++) {
 
      // Get index into z-value
      unsigned dataIndex = GMT_Get_Index(gmtApi, gmtGrid_->header, 
                                         row, col);
      // Set x,y,z of this vertex. Note that each inserted point has
      // has an associated “slot” Id; first inserted point has Id=0,
      // second point has Id=1, etc...
      gridPoints_->InsertNextPoint(row, col,
                                   gmtGrid_->data[dataIndex]);
    }
  }
 
 
  // Set triangle vertices
  unsigned nRows = gmtGrid_->header->n_rows;
  unsigned nCols = gmtGrid_->header->n_columns;
 
  // This holds 3 vertexes for each triangular cell. Note that 
  // each vertex was assigned an Id equal to the order in which 
  // that vertex was added with InsertNextPoint(), above. As we 
  // build triangular cells, we refer to the Id of each vertex.
  vtkIdType triangleVertexId[3];
 
  // Triangles must stay within row and column bounds, so stop making
  // triangles at nRows-1 and nCols-1
  for (unsigned row = 0; row < nRows-1; row++) {
    for (unsigned col = 0; col < nCols-1; col++) {
 
      // First triangle
      triangleVertexId[0] = gridOffset(nRows, nCols, row, col);
      triangleVertexId[1] = gridOffset(nRows, nCols, row, col+1);
      triangleVertexId[2] = gridOffset(nRows, nCols, row+1, col+1);      
      gridPolygons_->InsertNextCell(3, triangleVertexId);
      
      // Second triangle
      triangleVertexId[0] = gridOffset(nRows, nCols, row, col);
      triangleVertexId[1] = gridOffset(nRows, nCols, row+1, col+1);
      triangleVertexId[2] = gridOffset(nRows, nCols, row+1, col);      
      gridPolygons_->InsertNextCell(3, triangleVertexId);
    }
  }
 
  // Set output vertexes
  polyOutput->SetPoints(gridPoints_);
 
  // Set output triangles
  polyOutput->SetPolys(gridPolygons_);