VTK/VTK 6 Migration/Replacement of SetInput

From KitwarePublic
< VTK
Jump to navigationJump to search

Replacement of SetInput() with SetInputData() and SetInputConnection()

VTK 6 introduces a number of backwards-incompatible changes. The reasons behind these changes are described in more detail here. One of these changes is the replacement of SetInput() with SetInputData() and SetInputConnection(). In VTK 4, pipeline objects were connected as follows:

<source lang="cpp"> someFilter->SetInput(someReader->GetOutput()); </source>

In VTK 5, this was changed to:

<source lang="cpp"> someFilter->SetInputConnection(someReader->GetOutputPort()); </source>

However, the SetInput() and related methods were preserved for backwards compatibility. This method and all related functions, such as SetSource, were removed in VTK 6. The main reason behind this is that it is impossible to preserve this method while decoupling data objects from pipeline objects (see here for details). In VTK 5, SetInput() was implemented under the hood using SetInputConnection() but this required access to the algorithm and its output port given a data object. In VTK 6, since the data object no longer has a reference to the algorithm that produced it, it is not possible to establish a pipeline connection given only a data object.

In order to make it easy to assign a stand-alone data object as an input to an algorithm, we introduced a set of convenience functions in VTK 6. Below is an example:

<source lang="cpp"> someFilter->SetInputData(aDataObject); </source>

Note that even though the following will compile, it will NOT create a pipeline connection and should not be used in place of SetInputConnection().

<source lang="cpp"> someFilter->SetInputData(someReader->GetOutput()); </source>

Another advantage of decoupling data objects from pipeline objects is that developers no longer need to create shallow copies of inputs in order to use internal filters. Previously, this was required for an algorithm to function properly:

<source lang="cpp"> void MyFilter::RequestData(…) {

  vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
  vtkDataObject* copy = input->NewInstance();
  copy->ShallowCopy(input);
  this->InternalFilter->SetInput(copy);
  this->InternalFilter->Update();
  …

} </source>

This can now be replaced with the following without any unexpected side effects:

<source lang="cpp"> void MyFilter::RequestData(…) {

  vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
  this->InternalFilter->SetInputData(input);
  this->InternalFilter->Update();
  …

} </source>

Another advantage is that this change removes some circular references from the pipeline making it unnecessary to use the garbage collector. This should have a noticeable impact on the performance of VTK when using large pipelines.

This change will probably have the biggest impact on the VTK community. At the same time, it is the easiest to fix. Here is a rule of thumb:

  • If you want to establish a pipeline connection, use SetInputConnection
  • If you want to process a stand-alone dataset, use SetInputData

Here are some specific examples. Note that even though we use SetInput() in all of these examples, similar methods such as SetSource() should follow the same pattern. Look for SetSourceConnection() or SetSourceData() for example. Furthermore, we ignore the port number in these examples but most should work with a port number.

Example 1

<source lang="cpp"> anotherFilter->SetInput(aFilter->GetOutput()); </source>

should become

<source lang="cpp"> anotherFilter->SetInputConnection(aFilter->GetOutputPort()); </source>

Example 2

<source lang="cpp"> vtkDataObject* output = aFilter->GetOutput(); anotherFilter->SetInput(output); </source>

should become

<source lang="cpp"> anotherFilter->SetInputConnection(aFilter->GetOutputPort()); </source>

Example 3

<source lang="cpp"> vtkPolyData *pd = vtkPolyData::New(); aFilter->SetInput(pd); </source>

should become

<source lang="cpp"> vtkPolyData *pd = vtkPolyData::New(); aFilter->SetInputData(pd); </source>

Example 4

<source lang="cpp"> vtkDataObject* output = aFilter->GetOutput(); aFilter->Update(); anotherFilter->SetInput(output); </source>

This is ambiguous. If aFilter or any other source/filter upstream in never modified after this point, the following is valid:

<source lang="cpp"> vtkDataObject* output = aFilter->GetOutput(); aFilter->Update(); anotherFilter->SetInputData(output); </source>

Otherwise, SetInputConnection() should be used. Remember that SetInputData() does not establish a pipeline connection and therefore updating anotherFilter can never cause any other filter to update. Here, anotherFilter will always process output after the manual update of aFilter.

Example 5

<source lang="cpp"> void myfunction(vtkDataObject* dobj) {

 vtkAFilter* aFilter = vtkAFilter::New();
 aFilter->SetInput(dobj);
 aFilter->Update();
 // …

} </source>

This example is also ambiguous. You need to trace it up to find the origin of dobj. If this is the common use:

<source lang="cpp"> myfunction(aFilter->GetOutput()); </source>

you will have to refactor myfunction to take an algorithm and an output port. For example:

<source lang="cpp"> void myfunction(vtkAlgorithm* alg, int port) {

 vtkAFilter* aFilter = vtkAFilter::New();
 aFilter->SetInputConnection(alg->GetOutputPort(port));
 aFilter->Update();
 // …

}

myfunction(aFilter, 0); </source>

If this is the common use:

<source lang="cpp"> vtkPolyData* pd = vtkPolyData::New(); // fill pd myfunction(pd); </source>

then replacing SetInput() with SetInputData() would work.

Example 6

<source lang="cpp"> class foo {

 vtkDataObject* DataObject;
 void Process()
   {
   vtkAFilter* aFilter = vtkAFilter::New();
   aFilter->SetInput(this->DataObject);
   aFilter->Update();
   // …
   }

}; </source>

This is almost identical to the previous example. Refer to that one for the suggested solution.