本文主要实现了一个点集转化为一个折线,再由这个折线通过delaunary2D转化为二维点面(这里是我的理解,不一定准确),再通过面计算点集的所有法向量。
注意:这里我出现了一个误区,原本一直想计算折线上点的法向量,后来发型,线上点的法向量应该是没法计算的,因为法向量是有方向的,而基于线上点,是没法确定垂直于这个线的法向量方向的。只有基于面,才能计算点的法向量。
其他内容都在代码和代码注释中!
int main()
{
vtkSmartPointer<vtkPoints> centerPoints = readFileToGetPoints("/Mine/QTTestCodes/VTKTest1/centerline.txt");
vtkIdType pointCount = centerPoints->GetNumberOfPoints();
vtkSmartPointer<vtkPolyLine> polyline = vtkSmartPointer<vtkPolyLine>::New();
polyline->GetPointIds()->SetNumberOfIds(pointCount);
for (int i = 0; i < pointCount; i++) {
polyline->GetPointIds()->SetId(i, i);
}
// 将点数据生成折线数据
vtkSmartPointer<vtkUnstructuredGrid> centerLineGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
centerLineGrid->SetPoints(centerPoints);
centerLineGrid->InsertNextCell(polyline->GetCellType(), polyline->GetPointIds());
// 也可以用下面这种方式生成一个PolyData类型的折线
// vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
// cells->InsertNextCell(polyline);
// vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
// polyData->SetPoints(centerPoints);
// polyData->SetLines(cells);
// delaunary2D,三角刨分?我理解是 将点/线 数据生成 “面” 数据。
vtkSmartPointer<vtkDelaunay2D> delaunay2D = vtkSmartPointer<vtkDelaunay2D>::New();
delaunay2D->SetInputData(centerLineGrid);
// vtkGeometryFilter将数据转换为几何数据,输出类型为vtkPolyData
vtkSmartPointer<vtkGeometryFilter> filter = vtkSmartPointer<vtkGeometryFilter>::New();
filter->SetInputConnection(delaunay2D->GetOutputPort());
// 法向量计算
vtkSmartPointer<vtkPolyDataNormals> normFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
normFilter->SetInputConnection(filter->GetOutputPort());
normFilter->SetComputePointNormals(1);//开启点法向量计算
normFilter->SetComputeCellNormals(0); //关闭单元法向量计算
normFilter->SetAutoOrientNormals(1);
normFilter->SetSplitting(1);
normFilter->SetConsistency(1);
normFilter->Update();
// 提取法向量数据
vtkPointData *pointData = normFilter->GetOutput()->GetPointData();
// pointData->GetArray("Normals")->GetTuple(0);
// pointData->GetNormals();
vtkSmartPointer<vtkMaskPoints> mask = vtkSmartPointer<vtkMaskPoints>::New();
mask->SetInputData(normFilter->GetOutput());
mask->SetMaximumNumberOfPoints(300); // 对所有点中点随机300个点,进行处理。这就是将法向量展示为箭头
mask->RandomModeOn();
mask->Update();
// 这里统计下法向量为0,0,0的个数,为什么回出现法向量为0,0,0,我理解是由于上面delaunary2D算法将点/线数据生成2维数据时,
// 有一部分点不在生成后的2维数据表面了,这导致一部分点的法向量为0,
// 如果用delaunary2D算法生成3为数据,那会导致更多的点不在表面,会有更多点的法向量为0,这里仅是我的理解,不清楚是否正确
// vtkDataArray *nArr2 =mask->GetOutput()->GetPointData()->GetNormals();
// int zeroNormalCount = 0;
// for (int i = 0; i < nArr2->GetNumberOfTuples(); i++) {
// double *p = nArr2->GetTuple(i);
// cout << "GetNormals:" << p[0] << "," << p[1] << "," << p[2] << ",\n" <<endl;
// if (p[0] == 0 && p[1] == 0 && p[2] == 0) {
// zeroNormalCount++;
// }
// }
vtkSmartPointer<vtkArrowSource> arrow = vtkSmartPointer<vtkArrowSource>::New();
arrow->Update(); //一定要更新 否则数据没有添加进来,程序会报错
vtkSmartPointer<vtkGlyph3D> glyph = vtkSmartPointer<vtkGlyph3D>::New();
glyph->SetInputData(mask->GetOutput());
glyph->SetSourceData(arrow->GetOutput());//每一点用箭头代替
glyph->SetVectorModeToUseNormal();//设置向量显示模式和法向量一致
glyph->SetScaleFactor(0.1); //设置伸缩比例
glyph->Update();
vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
mapper->SetInputData(centerLineGrid);
vtkSmartPointer<vtkPolyDataMapper> normMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
normMapper->SetInputData(normFilter->GetOutput());
vtkSmartPointer<vtkPolyDataMapper> glyphMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
glyphMapper->SetInputData(glyph->GetOutput());
// glyphMapper->SetInputConnection(glyph->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkActor> normActor = vtkSmartPointer<vtkActor>::New();
normActor->SetMapper(normMapper);
vtkSmartPointer<vtkActor> glyphActor = vtkSmartPointer<vtkActor>::New();
glyphActor->SetMapper(glyphMapper);
glyphActor->GetProperty()->SetColor(1, 0, 0);
double origView[4] = { 0, 0, 0.33, 1 };
double normView[4] = { 0.33, 0, 0.66, 1 };
double glyphView[4] = { 0.66, 0, 1, 1 };
vtkSmartPointer<vtkRenderer> origRender = vtkSmartPointer<vtkRenderer>::New();
origRender->SetViewport(origView);
origRender->AddActor(actor);
origRender->SetBackground(1, 0, 0);
vtkSmartPointer<vtkRenderer> normRender = vtkSmartPointer<vtkRenderer>::New();
normRender->SetViewport(normView);
normRender->AddActor(normActor);
normRender->SetBackground(0, 1, 0);
vtkSmartPointer<vtkRenderer> glyphRender = vtkSmartPointer<vtkRenderer>::New();
glyphRender->SetViewport(glyphView);
glyphRender->AddActor(glyphActor);
glyphRender->AddActor(normActor);
glyphRender->SetBackground(0, 0, 1);
vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(origRender);
rw->AddRenderer(normRender);
rw->AddRenderer(glyphRender);
rw->SetWindowName("Calculating Point Norm & Cell Norm");
rw->SetSize(960, 320);
rw->Render();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
rwi->Initialize();
rwi->Start();
return 0;
}
法向量计算参考自这个文章,