vtk 点转线,线转面,并求法向量

474 阅读3分钟

本文主要实现了一个点集转化为一个折线,再由这个折线通过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;
}

blog.csdn.net/shenziheng1…

法向量计算参考自这个文章,