Table of Contents

Pipelines

Sources and readers make data, filters change it, mappers draw it: VTK's pipeline, in C# as in C++.

A pipeline runs on demand A pipeline runs on demand

Sources

// a source makes data: here a sphere's triangles
using var sphere = new vtkSphereSource();
sphere.SetRadius(2);
sphere.SetThetaResolution(16);
sphere.SetPhiResolution(8);
sphere.Update();
using var polyData = sphere.GetOutput();
long points = polyData.GetNumberOfPoints();
long triangles = polyData.GetNumberOfPolys();

Counts and ids are long: VTK's vtkIdType, 64 bits on every platform.

Connecting filters

A filter's input is another algorithm's output port. Nothing runs until Update() (or a render) asks for output; then each algorithm runs if it or something before it changed since its last run:

// a filter's input is another's output port: sphere -> elevation -> shrink
using var sphere = new vtkSphereSource();
using var elevation = new vtkElevationFilter();
using var spherePort = sphere.GetOutputPort();
elevation.SetInputConnection(spherePort);
using var shrink = new vtkShrinkFilter();
using var elevationPort = elevation.GetOutputPort();
shrink.SetInputConnection(elevationPort);

// nothing has run yet: Update on the last one runs all three
shrink.Update();
using var shrunk = shrink.GetOutput(); // a vtkUnstructuredGrid
long before = shrunk.GetNumberOfCells();

// a changed parameter marks the sphere modified: the next Update runs it and what follows
sphere.SetThetaResolution(32);
shrink.Update();
long after = shrunk.GetNumberOfCells();

GetOutput() gives the same data object after each run, updated in place.

Data no algorithm made goes in with SetInputData:

// data no algorithm made (built in C#, read earlier): SetInputData instead of a port
using var normals = new vtkPolyDataNormals();
normals.SetInputData(polyData);
normals.Update();
using var withNormals = normals.GetOutput();
using var pointData = withNormals.GetPointData();
using var normalArray = pointData.GetNormals();

Drawing

// a mapper turns data into graphics, an actor places it with its look, a renderer holds actors
using var mapper = new vtkPolyDataMapper();
using var port = sphere.GetOutputPort();
mapper.SetInputConnection(port);
using var actor = new vtkActor();
actor.SetMapper(mapper);
actor.SetPosition(0, 0, 1);
using (var look = actor.GetProperty())
{
  look.SetColor(1.0, 0.5, 0.0); // orange
  look.SetOpacity(0.5);
}

using var renderer = new vtkRenderer();
renderer.AddActor(actor);
renderer.SetBackground(1, 1, 1);

The renderer draws once a render window holds it: Rendering and hosting.

From C++

C++ C#
vtkNew<vtkSphereSource> sphere; using var sphere = new vtkSphereSource();
auto sphere = vtkSmartPointer<vtkSphereSource>::New(); the same, or vtkSphereSource.New()
sphere->SetRadius(2); sphere.SetRadius(2);
filter->SetInputConnection(sphere->GetOutputPort()); using var port = sphere.GetOutputPort();
filter.SetInputConnection(port);
vtkPolyData* output = filter->GetOutput(); using var output = filter.GetOutput();
double* bounds = output->GetBounds(); double[] bounds = output.GetBounds();
actor->GetProperty()->SetColor(1, 0, 0); using (var look = actor.GetProperty()) look.SetColor(1, 0, 0);
vtkPolyData::SafeDownCast(object) vtkPolyData.SafeDownCast(object): null if it isn't one

Each returned object is a new proxy holding a reference: using drops it at once, otherwise the finalizer does. Chained calls (actor.GetProperty().SetColor(...)) leave theirs to the finalizer: fine for data, not for rendering objects, see Object lifetimes.