2017-11-18 238 views
1

我正在用C++编写一个VTK程序来处理有限元分析结果。为了显示等值面,我尝试了vtkContourFilter,但是在这个过滤器之后我什么也没有得到。为什么我的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 

回答

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; 
+0

非常感谢!所以通常使用什么SetFieldData()? – landings

+1

根据文档,'SetFieldData()'用于为此数据对象_分配一个常规字段数据,因此您也可以使用此函数,但在此情况下,您未指定数据集上值的关联(请参阅有关更多信息,请参阅vtkDataObject :: FieldAssociations的文档)。简而言之,您仍然可以使用'SetFieldData()',但在这种情况下,您需要调用'isoFilter-> SetInputArrayToProcess(0,0,0,vtkDataObject :: FIELD_ASSOCIATION_NONE,“Stress”)'告诉'vtkContourFilter'在哪里获取数据数组。 –

+1

为了完成,我需要说'vtkContourFilter'获取默认情况下的一个数据数组,它表示与点相关的标量值(你可以看到[构造函数])(https://github.com/Kitware/VTK/blob/master/vilk/Core/vtkContourFilter.cxx)''vtkContourFilter'知道它是如何完成的) –