Skip to content

AlgorithmFilter

Repository source: AlgorithmFilter

Description

This example demonstrates how to create a filter that accepts a custom class and returns a custom class. To test that it is working, the class vtkTest simply stores a double named 'Value' that is instantiated to the value of 4.5. Example.cxx instantiates a vtkTest and sets its value to 5.6. The filter adds 1.0 to this value, so the vtkTest that is the output of the vtkTestAlgorithmFilter should contain the value 6.6.

You will need the following in your CMakeLists.txt file:

find_package(VTK
 COMPONENTS
    CommonCore
    CommonDataModel
    CommonExecutionModel
    FiltersSources
    InfovisCore
)

Question

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

Code

AlgorithmFilter.cxx

#include <vtkNew.h>

#include "vtkTest.h"
#include "vtkTestAlgorithmFilter.h"

int main(int, char*[])
{
  vtkNew<vtkTest> inputTest;
  inputTest->SetValue(5.6);
  std::cout << "Input value: " << inputTest->GetValue() << std::endl;

  vtkNew<vtkTestAlgorithmFilter> filter;
  filter->SetInput(inputTest);
  filter->Update();

  vtkTest* outputTest = filter->GetOutput();
  std::cout << "Output value: " << outputTest->GetValue() << std::endl;
  std::cout << "Input value is still: " << inputTest->GetValue() << std::endl;

  return EXIT_SUCCESS;
}

vtkTestAlgorithmFilter.cxx

#include "vtkTestAlgorithmFilter.h"
#include "vtkTest.h"

#include <vtkCommand.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkObjectFactory.h>
#include <vtkStreamingDemandDrivenPipeline.h>

vtkStandardNewMacro(vtkTestAlgorithmFilter);

//----------------------------------------------------------------------------
vtkTestAlgorithmFilter::vtkTestAlgorithmFilter()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
}

//----------------------------------------------------------------------------
vtkTestAlgorithmFilter::~vtkTestAlgorithmFilter()
{
}

//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//----------------------------------------------------------------------------
vtkTest* vtkTestAlgorithmFilter::GetOutput()
{
  return this->GetOutput(0);
}

//----------------------------------------------------------------------------
vtkTest* vtkTestAlgorithmFilter::GetOutput(int port)
{
  return dynamic_cast<vtkTest*>(this->GetOutputDataObject(port));
}

//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::SetOutput(vtkDataObject* d)
{
  this->GetExecutive()->SetOutputData(0, d);
}

//----------------------------------------------------------------------------
vtkDataObject* vtkTestAlgorithmFilter::GetInput()
{
  return this->GetInput(0);
}

//----------------------------------------------------------------------------
vtkDataObject* vtkTestAlgorithmFilter::GetInput(int port)
{
  return this->GetExecutive()->GetInputData(port, 0);
}

//----------------------------------------------------------------------------
vtkTest* vtkTestAlgorithmFilter::GetLabelHierarchyInput(int port)
{
  return dynamic_cast<vtkTest*>(this->GetInput(port));
}

//----------------------------------------------------------------------------
int vtkTestAlgorithmFilter::ProcessRequest(vtkInformation* request,
                                           vtkInformationVector** inputVector,
                                           vtkInformationVector* outputVector)
{
  // Create an output object of the correct type.
  if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA_OBJECT()))
  {
    return this->RequestDataObject(request, inputVector, outputVector);
  }
  // generate the data
  if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
  {
    return this->RequestData(request, inputVector, outputVector);
  }

  if (request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()))
  {
    return this->RequestUpdateExtent(request, inputVector, outputVector);
  }

  // execute information
  if (request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
  {
    return this->RequestInformation(request, inputVector, outputVector);
  }

  return this->Superclass::ProcessRequest(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int vtkTestAlgorithmFilter::FillOutputPortInformation(int vtkNotUsed(port),
                                                      vtkInformation* info)
{
  // now add our info
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTest");
  return 1;
}

//----------------------------------------------------------------------------
int vtkTestAlgorithmFilter::FillInputPortInformation(int vtkNotUsed(port),
                                                     vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTest");
  return 1;
}

int vtkTestAlgorithmFilter::RequestDataObject(
    vtkInformation* vtkNotUsed(request),
    vtkInformationVector** vtkNotUsed(inputVector),
    vtkInformationVector* outputVector)
{
  // RequestDataObject (RDO) is an earlier pipeline pass.
  // During RDO, each filter is supposed to produce an empty data object of the
  // proper type

  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  vtkTest* output =
      dynamic_cast<vtkTest*>(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!output)
  {
    output = vtkTest::New();
    outInfo->Set(vtkDataObject::DATA_OBJECT(), output);
    output->FastDelete();

    this->GetOutputPortInformation(0)->Set(vtkDataObject::DATA_EXTENT_TYPE(),
                                           output->GetExtentType());
  }

  return 1;
}

//----------------------------------------------------------------------------
int vtkTestAlgorithmFilter::RequestInformation(
    vtkInformation* vtkNotUsed(request),
    vtkInformationVector** vtkNotUsed(inputVector),
    vtkInformationVector* vtkNotUsed(outputVector))
{
  // do nothing let subclasses handle it
  return 1;
}

//----------------------------------------------------------------------------
int vtkTestAlgorithmFilter::RequestUpdateExtent(
    vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector,
    vtkInformationVector* vtkNotUsed(outputVector))
{
  int numInputPorts = this->GetNumberOfInputPorts();
  for (int i = 0; i < numInputPorts; i++)
  {
    int numInputConnections = this->GetNumberOfInputConnections(i);
    for (int j = 0; j < numInputConnections; j++)
    {
      vtkInformation* inputInfo = inputVector[i]->GetInformationObject(j);
      inputInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
    }
  }
  return 1;
}

//----------------------------------------------------------------------------
// This is the superclasses style of Execute method.  Convert it into
// an imaging style Execute method.
int vtkTestAlgorithmFilter::RequestData(vtkInformation* vtkNotUsed(request),
                                        vtkInformationVector** inputVector,
                                        vtkInformationVector* outputVector)
{
  // Later on RequestData (RD) happens.
  // During RD each filter examines any inputs it has, then fills in that empty
  // data object with real data.

  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  vtkTest* output =
      dynamic_cast<vtkTest*>(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  vtkTest* input =
      dynamic_cast<vtkTest*>(inInfo->Get(vtkDataObject::DATA_OBJECT()));
  output->ShallowCopy(input);
  output->SetValue(output->GetValue() + 1.0);

  return 1;
}

//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::SetInput(vtkDataObject* input)
{
  this->SetInput(0, input);
}

//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::SetInput(int index, vtkDataObject* input)
{
  if (input)
  {
    this->SetInputDataObject(index, input);
  }
  else
  {
    // Setting a NULL input removes the connection.
    this->SetInputDataObject(index, 0);
  }
}

//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::AddInput(vtkDataObject* input)
{
  this->AddInput(0, input);
}

//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::AddInput(int index, vtkDataObject* input)
{
  if (input)
  {
    this->AddInputDataObject(index, input);
  }
}

vtkTest.cxx

#include "vtkTest.h"

#include <vtkObjectFactory.h>

vtkStandardNewMacro(vtkTest);

vtkTest::vtkTest()
{
  this->Value = 0.0;
}

vtkTest::~vtkTest()
{
}

void vtkTest::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

void vtkTest::ShallowCopy(vtkDataObject* t)
{
  vtkTest* m = dynamic_cast<vtkTest*>(t);
  this->Value = m->GetValue();
}

vtkTest.h

#ifndef __vtkTest_h
#define __vtkTest_h

#include <vtkDataObject.h>

class vtkTest : public vtkDataObject
{
public:
  static vtkTest* New();
  vtkTypeMacro(vtkTest, vtkDataObject);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  void ShallowCopy(vtkDataObject* t) override;

  vtkGetMacro(Value, double);
  vtkSetMacro(Value, double);

protected:
  vtkTest();
  ~vtkTest();

private:
  vtkTest(const vtkTest&);        // Not implemented.
  void operator=(const vtkTest&); // Not implemented.

  double Value;
};

#endif

vtkTestAlgorithmFilter.h

#ifndef __vtkTestAlgorithmFilter_h
#define __vtkTestAlgorithmFilter_h

#include <vtkAlgorithm.h>

class vtkDataSet;
class vtkTest;

class vtkTestAlgorithmFilter : public vtkAlgorithm
{
public:
  static vtkTestAlgorithmFilter* New();
  vtkTypeMacro(vtkTestAlgorithmFilter, vtkAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  // Description:
  // Get the output data object for a port on this algorithm.
  vtkTest* GetOutput();
  vtkTest* GetOutput(int);
  virtual void SetOutput(vtkDataObject* d);

  // Description:
  // see vtkAlgorithm for details
  virtual int ProcessRequest(vtkInformation*, vtkInformationVector**,
                             vtkInformationVector*) override;

  // this method is not recommended for use, but lots of old style filters use
  // it
  vtkDataObject* GetInput();
  vtkDataObject* GetInput(int port);
  vtkTest* GetLabelHierarchyInput(int port);

  // Description:
  // Set an input of this algorithm. You should not override these
  // methods because they are not the only way to connect a pipeline.
  // Note that these methods support old-style pipeline connections.
  // When writing new code you should use the more general
  // vtkAlgorithm::SetInputConnection().  These methods transform the
  // input index to the input port index, not an index of a connection
  // within a single port.
  void SetInput(vtkDataObject*);
  void SetInput(int, vtkDataObject*);

  // Description:
  // Add an input of this algorithm.  Note that these methods support
  // old-style pipeline connections.  When writing new code you should
  // use the more general vtkAlgorithm::AddInputConnection().  See
  // SetInput() for details.
  void AddInput(vtkDataObject*);
  void AddInput(int, vtkDataObject*);

protected:
  vtkTestAlgorithmFilter();
  ~vtkTestAlgorithmFilter();

  // Description:
  // This is called by the superclass.
  // This is the method you should override.
  virtual int RequestDataObject(vtkInformation* request,
                                vtkInformationVector** inputVector,
                                vtkInformationVector* outputVector);

  // convenience method
  virtual int RequestInformation(vtkInformation* request,
                                 vtkInformationVector** inputVector,
                                 vtkInformationVector* outputVector);

  // Description:
  // This is called by the superclass.
  // This is the method you should override.
  virtual int RequestData(vtkInformation* request,
                          vtkInformationVector** inputVector,
                          vtkInformationVector* outputVector);

  // Description:
  // This is called by the superclass.
  // This is the method you should override.
  virtual int RequestUpdateExtent(vtkInformation*, vtkInformationVector**,
                                  vtkInformationVector*);

  virtual int FillOutputPortInformation(int port,
                                        vtkInformation* info) override;
  virtual int FillInputPortInformation(int port, vtkInformation* info) override;

private:
  vtkTestAlgorithmFilter(const vtkTestAlgorithmFilter&); // Not implemented.
  void operator=(const vtkTestAlgorithmFilter&);         // Not implemented.
};

#endif

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(AlgorithmFilter)

find_package(VTK COMPONENTS 
  CommonCore
)

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

Download and Build AlgorithmFilter

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

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

./AlgorithmFilter

WINDOWS USERS

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