为什么我的 vtkContourFilter 没有输出

Why does my vtkContourFilter have no output?

本文关键字:输出 vtkContourFilter 我的 为什么      更新时间:2023-10-16

我正在编写一个带有C++的VTK程序来处理有限元分析结果。为了显示等值面,我正在尝试 vtkContourFilter,但在此过滤器之后我什么也得不到。

所以我写了一个简单的版本:一个自定义阅读器生成一个 2 单元的非结构化网格,然后一个 vtkContourFilter 提取等值面。我的标量数据是点数据。

我打算获得等值面,但仍然得到零输出。我想知道我错过了什么。

我的程序:

#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPoints.h>
#include <vtkPointData.h>
#include <vtkCellArray.h>
#include <vtkIdList.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkUnstructuredGridReader.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkClipDataSet.h>
#include <vtkPlane.h>
#include <vtkContourFilter.h>
#include <iostream>
using namespace std;
// This is a fake reader that outputs an unstructured mesh
class VTKIOLEGACY_EXPORT FakeUnstructuredGridReader : public vtkUnstructuredGridReader {
public:
    static FakeUnstructuredGridReader* New() { return new FakeUnstructuredGridReader(); }
    vtkTypeMacro(FakeUnstructuredGridReader, vtkUnstructuredGridReader);
    void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE {}
protected:
    FakeUnstructuredGridReader() { this->SetNumberOfInputPorts(0); }// No input ports
    // This method passes a 2-cell unstructured grid with 1 set of scalar point data
    int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector) VTK_OVERRIDE {
        static const double rawPoints[15] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1 };
        static const vtkIdType rawIndices[8] = { 0, 1, 2, 3, 1, 2, 3, 4};
        static const double rawScalar[5] = { 5, 10, 20, 15, 50 };
        static const char* scalarName = "Stress";
        // Build Points
        auto points = vtkSmartPointer<vtkPoints>::New();
        for (int i = 0; i < 15; i += 3)
            points->InsertNextPoint(rawPoints + i);
        // Build Cells
        auto cells = vtkSmartPointer<vtkCellArray>::New();
        // Build Cell 1
        auto indices1 = vtkSmartPointer<vtkIdList>::New();
        for (int i = 0; i < 4; ++i)
            indices1->InsertNextId(rawIndices[i]);      
        cells->InsertNextCell(indices1);
        // Build Cell 2
        auto indices2 = vtkSmartPointer<vtkIdList>::New();
        for (int i = 0; i < 4; ++i)
            indices2->InsertNextId(rawIndices[i + 4]);
        cells->InsertNextCell(indices2);
        // Scalar Data
        auto dataArray = vtkSmartPointer<vtkDoubleArray>::New();
        dataArray->SetName(scalarName);
        dataArray->SetNumberOfComponents(1);
        for (int i = 0; i < 5; ++i)
            dataArray->InsertNextValue(rawScalar[i]);
        // Point Data
        auto pointData = vtkSmartPointer<vtkPointData>::New();
        pointData->AddArray(dataArray);
        // Pass Data
        vtkInformation* outInfo = outputVector->GetInformationObject(0);
        vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
        output->SetPoints(points);
        output->SetCells(VTK_TETRA, cells);
        output->SetFieldData(pointData);
        return 1;
    }
};

int main() {
    // Reader
    auto fakeReader = vtkSmartPointer<FakeUnstructuredGridReader>::New();
    // Isosurface Filter
    auto isoFilter = vtkSmartPointer<vtkContourFilter>::New();
    isoFilter->SetInputConnection(fakeReader->GetOutputPort());
    isoFilter->GenerateValues(8, 0.0, 50.0);
    isoFilter->Update();
    cout << fakeReader->GetOutput()->GetNumberOfPoints() << endl;
    cout << fakeReader->GetOutput()->GetNumberOfCells() << endl;
    cout << fakeReader->GetOutput()->GetFieldData()->GetNumberOfArrays() << endl;
    cout << isoFilter->GetOutput()->GetNumberOfPoints() << endl;
    cout << isoFilter->GetOutput()->GetNumberOfCells() << endl;
    cout << isoFilter->GetOutput()->GetFieldData()->GetNumberOfArrays() << endl;
    system("pause");
    return 0;
}

其输出:

5
2
1
0
0
1

在函数RequestData()中,您首先需要将标量值与数据集的点相关联,output->GetPointData()->AddArray(dataArray)然后使用 output->GetPointData()->SetActiveScalars(scalarName) 激活标量字段,以便 vtkContourFilter 能够选择它来计算轮廓。您可以通过执行 output->GetPointData()->SetScalars(dataArray) 来执行这两项操作。请注意,使用此解决方案,您不再需要分配pointData变量。

因此,简而言之,您可以更改:

int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector) VTK_OVERRIDE {
  /* body of the function here */
  // old version
  // output->SetFieldData(pointData);
  // new version
  output->GetPointData()->SetScalars(dataArray);
  return 1;
}

您可能需要相应地修改打印。

// old version:
// cout << fakeReader->GetOutput()->GetFieldData()->GetNumberOfArrays() << endl;
// new version:
cout << fakeReader->GetOutput()->GetPointData()->GetNumberOfArrays() << endl;
// old version
// cout << isoFilter->GetOutput()->GetFieldData()->GetNumberOfArrays() << endl;
// new version
cout << isoFilter->GetOutput()->GetPointData()->GetNumberOfArrays() << endl;