Filter類定義了RequestData()函數,當Filter調用Update()後,響應RequestData()函數。
VTK管線機制
VTK
中通過管線機制來實現組合各種算法處理數據。每一種算法是一個Filter
,多個Filter
連接一起形成了VTK管線
。每個Filter可以分爲兩個組成部分:一個是算法部分,繼承自vtkAlgorithm
,主要負責處理輸入的數據和信息;另一個是執行對象,繼承自vtkExecutive
,負責通知算法對象何時運行以及傳遞需要處理的數據和信息。
Filter
類繼承自vtkAlgorithm
及其 子類,實例化時,其內部會生成一個默認的vtkExecutive
對象,用於管理執行管線。
數據和信息通過端口在Filter
中傳遞,根據數據流的方向,分爲輸入端口和輸出端口。Filter
之間通過端口(Port
)建立連接。
VTK
中定義了一個vtkInformation
類,用於存儲和傳遞管線執行過程中的信息、請求和數據,實現執行管線的連接和控制。
vtkInformation
是實現VTK
執行管線的一個非常重要的類。它是一個Map
容器,採用Key-Value
的映射方法,通過索引(Key
)的類型來決定其對應的數據,用於存儲管線中的各種信息和數據。
vtkInformation
類中 索引Key
的類型爲vtkInformationKey
的子類,VTK
定義了大量的索引類型,這些類都繼承自vtkInformationKey
。
基本步驟
定義管線接口
vtkTestAlgorithmFilter::vtkTestAlgorithmFilter()
{
//兩個輸入,一個輸出
this->SetNumberOfInputPorts( 2 );
this->SetNumberOfOutputPorts( 1 );
}
vtkAlgorithm::FillInputPortInformation()
設置輸入端口信息;每個輸出端口對應一個輸出端口信息對象,使用vtkAlgorithm::FillOutputPortInformation()
設置輸出端口信息。由於直接繼承自vtkPolyDataAlgorithm
類,只需重寫FillOutputPortInformation
。
int vtkTestAlgorithmFilter::FillInputPortInformation(
int port, vtkInformation* info)
{
if ( port == 0)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
}
else if (port == 1)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
//info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
}
return 1;
}
定義用戶接口
Filter
需要定義多個用戶接口來設置參數,以調節Filter
執行效果。對於每個Filter
,需要覆蓋基類的PrintSelf()
函數。
實現管線請求
參見vtkPolyDataAlgorithm中的ProcessRequest()
,如果直接繼承自vtkPolyDataAlgorithm
,不用實現。
實現算法核心部分
REQUEST_DATA()
是執行Filter的主要函數。
int vtkTestAlgorithmFilter::RequestData(
vtkInformation* vtkNotUsed(request),
vtkInformationVector **inputVector,
vtkInformationVector* outputVector )
示例
vtkTestAlgorithmFilter.h
#ifndef __vtkTestAlgorithmFilter_h
#define __vtkTestAlgorithmFilter_h
#include <vtkPolyDataAlgorithm.h>
class vtkDataSet;
class vtkPolyData;
class vtkTestAlgorithmFilter : public vtkPolyDataAlgorithm
{
public:
static vtkTestAlgorithmFilter *New();
vtkTypeMacro(vtkTestAlgorithmFilter, vtkPolyDataAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent) override;
protected:
vtkTestAlgorithmFilter();
~vtkTestAlgorithmFilter();
// Description:
// This is called by the superclass.
// This is the method you should override.
virtual int RequestData(
vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector );
virtual int FillInputPortInformation( int port, vtkInformation* info ) override;
};
#endif
vtkTestAlgorithmFilter.cxx
#include "vtkTestAlgorithmFilter.h"
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkFeatureEdges.h>
#include <vtkStripper.h>
#include <vtkCleanPolyData.h>
#include <vtkAppendPolyData.h>
vtkStandardNewMacro(vtkTestAlgorithmFilter);
//----------------------------------------------------------------------------
vtkTestAlgorithmFilter::vtkTestAlgorithmFilter()
{
//
this->SetNumberOfInputPorts( 2 );
this->SetNumberOfOutputPorts( 1 );
}
//----------------------------------------------------------------------------
vtkTestAlgorithmFilter::~vtkTestAlgorithmFilter()
{
}
//----------------------------------------------------------------------------
void vtkTestAlgorithmFilter::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
//----------------------------------------------------------------------------
int vtkTestAlgorithmFilter::FillInputPortInformation(
int port, vtkInformation* info)
{
if ( port == 0)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
}
else if (port == 1)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
//info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 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 *inInfoOne = inputVector[0]->GetInformationObject(0);
vtkInformation *inInfoTwo = inputVector[1]->GetInformationObject(0);
vtkInformation *outInfo = outputVector->GetInformationObject(0);
vtkPolyData *sourceOne = vtkPolyData::SafeDownCast(inInfoOne->Get(vtkDataObject::DATA_OBJECT()));
vtkPolyData *sourceTwo = vtkPolyData::SafeDownCast(inInfoTwo->Get(vtkDataObject::DATA_OBJECT()));;
vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT()));
//獲取三角網邊界點集
vtkSmartPointer<vtkFeatureEdges> fEdgesOne = vtkSmartPointer<vtkFeatureEdges>::New();
fEdgesOne->SetInputData(sourceOne);
fEdgesOne->BoundaryEdgesOn();
fEdgesOne->FeatureEdgesOff();
fEdgesOne->ManifoldEdgesOff();
fEdgesOne->NonManifoldEdgesOff();
fEdgesOne->Update();
//使點集有序
vtkSmartPointer<vtkStripper> stripperOne = vtkSmartPointer<vtkStripper>::New();
stripperOne->SetInputConnection(fEdgesOne->GetOutputPort());
vtkSmartPointer<vtkCleanPolyData> cleanPolyDataOne =
vtkSmartPointer<vtkCleanPolyData>::New();
cleanPolyDataOne->SetInputConnection(stripperOne->GetOutputPort());
cleanPolyDataOne->Update();
vtkPoints *pt = nullptr;
double* p;
unsigned int num1, num2;
pt = cleanPolyDataOne->GetOutput()->GetPoints();
num1 = pt->GetNumberOfPoints();
//拷貝到邊界點集中
vtkSmartPointer<vtkPoints> boundary1 = vtkSmartPointer<vtkPoints>::New();
for (unsigned int i = 0; i < num1; ++i) {
p = pt->GetPoint(i);
boundary1->InsertNextPoint(p);
}
vtkSmartPointer<vtkFeatureEdges> fEdgesTwo = vtkSmartPointer<vtkFeatureEdges>::New();
fEdgesTwo->SetInputData(sourceTwo);
fEdgesTwo->BoundaryEdgesOn();
fEdgesTwo->FeatureEdgesOff();
fEdgesTwo->ManifoldEdgesOff();
fEdgesTwo->NonManifoldEdgesOff();
fEdgesTwo->Update();
vtkSmartPointer<vtkStripper> stripperTwo = vtkSmartPointer<vtkStripper>::New();
stripperTwo->SetInputConnection(fEdgesTwo->GetOutputPort());
vtkSmartPointer<vtkCleanPolyData> cleanPolyDataTwo = vtkSmartPointer<vtkCleanPolyData>::New();
cleanPolyDataTwo->SetInputConnection(stripperTwo->GetOutputPort());
cleanPolyDataTwo->Update();
pt = cleanPolyDataTwo->GetOutput()->GetPoints();
num2 = pt->GetNumberOfPoints();
//將第二個邊界點集拷貝到邊界點集中
vtkSmartPointer<vtkPoints> boundary2 = vtkSmartPointer<vtkPoints>::New();
for (unsigned int i = 0; i < num1; ++i) {
p = pt->GetPoint(i);
boundary2->InsertNextPoint(p);
}
/*
* 由上下兩個邊界環生成三角網
* 原則:按照最短對角線原則
* 方法:上下兩個邊界環,依次組成四邊形,比較對角線的大小,生成三角形
*/
vtkPoints *boundary = vtkPoints::New();
for (unsigned int i = 0; i < num1; ++i) {
p = boundary1->GetPoint(i);
boundary->InsertNextPoint(p);
}
for (unsigned int i = 0; i < num2; ++i) {
p = boundary2->GetPoint(i);
boundary->InsertNextPoint(p);
}
vtkIdType pts[3]; //保存三角形三個頂點的索引
vtkCellArray* triangles = vtkCellArray::New();
vtkPolyData* Mesh = vtkPolyData::New();
triangles->Allocate(triangles->EstimateSize(2 * (num1 + num2), 3));
Mesh->SetPoints(boundary);
Mesh->SetPolys(triangles);
double d0 = 0.0, d1 = 0.0; //保存四邊形兩條對角線的長度
double p1[3], p2[3], p3[3], p4[3]; //四邊形的四個頂點
unsigned int n1 = 0, n2 = 0; //上下邊界環當前遍歷的位置
unsigned int start1 = 0, start2 = 0;//上下邊界環遍歷的起始位置
start1 = 0;// 設置第一條邊界環遍歷的起始位置 start1=0
boundary1->GetPoint(0, p1);
//尋找第二條邊的起始位置 start2 (距離最近的點)
d1 = VTK_DOUBLE_MAX;
for (unsigned int i = 0; i < num2; ++i) {
boundary2->GetPoint(i, p2);
d0 = vtkMath::Distance2BetweenPoints(p1, p2);
if (d0 < d1) {
d1 = d0;
start2 = i;
}
}
n2 = start2;
bool flag = false;
do {
// 組成四邊形的四個點
// p1,p2 一條邊界環的點
// p3,p4 另一條邊界環的點
boundary1->GetPoint(n1, p1);
boundary1->GetPoint((n1 + 1) % num1, p2);
boundary2->GetPoint(n2, p3);
boundary2->GetPoint((n2 + 1) % num2, p4);
d0 = vtkMath::Distance2BetweenPoints(p1, p4);
d1 = vtkMath::Distance2BetweenPoints(p2, p3);
pts[0] = n1%num1;
pts[1] = n2%num2 + num1;
if (d0 <= d1) {
pts[2] = (n2 + 1) % num2 + num1;
n2 = (n2 + 1) % num2;
}
else {
pts[2] = (n1 + 1) % num1;
n1 = (n1 + 1) % num1;
}
triangles->InsertNextCell(3, pts);
flag = !((n1%num1 == start1 || (n1 + 1) % num1 == start1) && (n2%num2 == start2 || (n2 + 1) % num2 == start2));
} while (flag);
//最後兩個三角形的情況
if ((n1 + 1) % num1 == start1 && (n2 + 1) % num2 == start2) {
boundary1->GetPoint(n1, p1);
boundary1->GetPoint((n1 + 1) % num1, p2);
boundary2->GetPoint(n2, p3);
boundary2->GetPoint((n2 + 1) % num2, p4);
d0 = vtkMath::Distance2BetweenPoints(p1, p4);
d1 = vtkMath::Distance2BetweenPoints(p2, p3);
if (d0 <= d1) {
pts[0] = n1%num1;
pts[1] = n2%num2 + num1;
pts[2] = (n2 + 1) % num2 + num1;
triangles->InsertNextCell(3, pts);
pts[0] = n1%num1;
pts[1] = (n2 + 1) % num2 + num1;
pts[2] = (n1 + 1) % num1;
triangles->InsertNextCell(3, pts);
}
else {
pts[0] = n1%num1;
pts[1] = n2%num2 + num1;
pts[2] = (n1 + 1) % num1;
triangles->InsertNextCell(3, pts);
pts[0] = (n1 + 1) % num1;
pts[1] = (n2 + 1) % num2 + num1;
pts[2] = n2%num2 + num1;
triangles->InsertNextCell(3, pts);
}
}
else { // 最後一個三角形的情況
if (n1 == 0) {
pts[0] = n1%num1;
pts[1] = n2%num2 + num1;
pts[2] = (n2 + 1) % num2 + num1;
}
else {
pts[0] = n1%num1;
pts[1] = n2%num2 + num1;
pts[2] = (n1 + 1) % num1;
}
triangles->InsertNextCell(3, pts);
}
Mesh->BuildLinks();
// combine two poly data
// 上下三角網和側面三角網組合,生成封閉的體
vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter->AddInputData(sourceOne);
appendFilter->AddInputData(sourceTwo);
appendFilter->AddInputData(Mesh);
appendFilter->Update();
output->SetPoints(appendFilter->GetOutput()->GetPoints());
output->SetPolys(appendFilter->GetOutput()->GetPolys());
Mesh->Delete();
return 1;
}
Delaunay2D.cxx
#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkNamedColors.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkDelaunay2D.h>
#include <vtkVertexGlyphFilter.h>
#include "vtkTestAlgorithmFilter.h"
int main(int, char *[])
{
/*
* 模擬生成第一個三角網
* 1. 隨機生成點集
* 2. 獲取生成三角網的邊界環點集(有序)
*/
vtkSmartPointer<vtkPoints> ps1 =vtkSmartPointer<vtkPoints>::New();
unsigned int GridSize = 10;
for(unsigned int x = 0; x < GridSize; x++)
{
for(unsigned int y = 0; y < GridSize; y++)
{
ps1->InsertNextPoint(x, y, vtkMath::Random(-.25, .25));
}
}
vtkSmartPointer<vtkPolyData> polydata1 =vtkSmartPointer<vtkPolyData>::New();
polydata1->SetPoints(ps1);
vtkSmartPointer<vtkDelaunay2D> delaunay1 =vtkSmartPointer<vtkDelaunay2D>::New();
delaunay1->SetInputData(polydata1);
delaunay1->Update();
vtkSmartPointer<vtkPoints> pts2 = vtkSmartPointer<vtkPoints>::New();
GridSize = 9;
for (unsigned int x =1; x < GridSize; x++)
{
for (unsigned int y =1; y < GridSize; y++)
{
pts2->InsertNextPoint(x+ vtkMath::Random(-.25, 1.25), y+
vtkMath::Random(-.25, 1.25), vtkMath::Random(1.5, 1.75));
}
}
vtkSmartPointer<vtkPolyData> polydata2 = vtkSmartPointer<vtkPolyData>::New();
polydata2->SetPoints(pts2);
vtkSmartPointer<vtkDelaunay2D> delaunay2 = vtkSmartPointer<vtkDelaunay2D>::New();
delaunay2->SetInputData(polydata2);
delaunay2->Update();
// Visualize
vtkSmartPointer<vtkTestAlgorithmFilter>testAlgorithm
= vtkSmartPointer<vtkTestAlgorithmFilter>::New();
testAlgorithm->SetInputData(0,delaunay1->GetOutput()); //
testAlgorithm->SetInputData(1, delaunay2->GetOutput());
testAlgorithm->Update();
vtkSmartPointer<vtkNamedColors> colors =vtkSmartPointer<vtkNamedColors>::New();
vtkSmartPointer<vtkPolyDataMapper> meshMapper =vtkSmartPointer<vtkPolyDataMapper>::New();
meshMapper->SetInputConnection(testAlgorithm->GetOutputPort());
vtkSmartPointer<vtkActor> meshActor =vtkSmartPointer<vtkActor>::New();
meshActor->SetMapper(meshMapper);
meshActor->GetProperty()->SetColor(colors->GetColor3d("Banana").GetData());
meshActor->GetProperty()->EdgeVisibilityOn();
vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter =vtkSmartPointer<vtkVertexGlyphFilter>::New();
glyphFilter->SetInputData(testAlgorithm->GetOutput());
vtkSmartPointer<vtkPolyDataMapper> pointMapper =vtkSmartPointer<vtkPolyDataMapper>::New();
pointMapper->SetInputConnection(glyphFilter->GetOutputPort());
vtkSmartPointer<vtkActor> pointActor =vtkSmartPointer<vtkActor>::New();
pointActor->GetProperty()->SetColor(colors->GetColor3d("Tomato").GetData());
pointActor->GetProperty()->SetPointSize(5);
pointActor->SetMapper(pointMapper);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(meshActor);
renderer->AddActor(pointActor);
renderer->SetBackground(colors->GetColor3d("Mint").GetData());
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}