VTKvtkPolyDataNormals 计算法向量

Posted theArcticOcean

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTKvtkPolyDataNormals 计算法向量相关的知识,希望对你有一定的参考价值。

vtkPolyDataNormals可以用于计算poly data中points和cell的法向量,方便处理一些数据集。
下面的例子显示了vtkPolyDataNormals作用在正方体和球体的效果。

注:为了不影响阅读体验,此文仅展示关键代码,所有例子的完整代码和输出可以浏览:【VTK】vtkPolyDataNormals example

正方体

人为构造6个面的正方体,每一个cell是一个正方形。使用points和polys构造polydata,之后使用vtkPolyDataNormals 处理polydata。由此我们能够得到point的在mesh上的的normal和cell的normal。

int main(int argc, char *argv[])

// ...
    vtkSmartPointer<vtkPolyData> pd =
            vtkSmartPointer<vtkPolyData>::New();
    pd->SetPolys( polys );
    pd->SetPoints( points );
    vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData( pd );

    vtkSmartPointer<vtkActor> surfaceActor =
        vtkSmartPointer<vtkActor>::New();
    surfaceActor->SetMapper( mapper );

    vtkSmartPointer<vtkPolyDataNormals> pdNormals =
            vtkSmartPointer<vtkPolyDataNormals>::New();
    pdNormals->SetInputData( surfaceActor->GetMapper()->GetInput() );
    pdNormals->ComputeCellNormalsOn();
    pdNormals->Update();

    vtkPointData* ptData = pdNormals->GetOutput()->GetPointData();
    vtkDataArray* ptNormals = pdNormals->GetOutput()->GetPointData()->GetNormals();

    cout << "For points in every cell: \\n";
    cout << ptNormals->GetNumberOfTuples() << endl;
    for( int i = 0; i < ptNormals->GetNumberOfTuples(); ++i )
    
        double value[3];
        ptNormals->GetTuple( i, value );
        printf( "Value: (%lf, %lf, %lf)\\n", value[0], value[1], value[2] );
    

    cout << "For cells: \\n";
    if( pdNormals->GetOutput()->GetCellData() && pdNormals->GetOutput()->GetCellData()->GetNormals() )
    
        vtkDataArray* cellNormals = pdNormals->GetOutput()->GetCellData()->GetNormals();
        cout << cellNormals->GetNumberOfTuples() << endl;
        for( int i = 0; i < cellNormals->GetNumberOfTuples(); ++i )
        
            double value[3];
            cellNormals->GetTuple( i, value );
            printf( "Value: (%lf, %lf, %lf)\\n", value[0], value[1], value[2] );
        
    
//...

output:

For points in every cell: 
24
Value: (0.000000, 1.000000, 0.000000)
Value: (0.000000, 1.000000, 0.000000)
Value: (0.000000, 1.000000, 0.000000)
Value: (0.000000, 1.000000, 0.000000)
Value: (0.000000, -1.000000, 0.000000)
Value: (0.000000, -1.000000, 0.000000)
//...
Value: (-1.000000, 0.000000, 0.000000)
Value: (-1.000000, 0.000000, 0.000000)
Value: (0.000000, 0.000000, 1.000000)

For cells:
6
Value: (0.000000, 1.000000, 0.000000)
Value: (0.000000, -1.000000, 0.000000)
Value: (1.000000, 0.000000, 0.000000)
Value: (0.000000, 0.000000, -1.000000)
Value: (-1.000000, 0.000000, 0.000000)
Value: (0.000000, 0.000000, 1.000000)

关于计算point的normal,本例子的输出中有24条,这是因为同一个点在不同的cell上可能具有不同的normal,观察本文最后的动态图有助于理解。
后面的cell normal有6条输出就很好理解了,因为这是一个6面体。

球类

以sphere为例,进行同样的操作。

int main(int argc, char *argv[])

    vtkSmartPointer<vtkSphereSource> sphere =
            vtkSmartPointer<vtkSphereSource>::New();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection( sphere->GetOutputPort() );

    vtkSmartPointer<vtkActor> surfaceActor =
        vtkSmartPointer<vtkActor>::New();
    surfaceActor->SetMapper( mapper );

    vtkSmartPointer<vtkPolyDataNormals> pdNormals =
            vtkSmartPointer<vtkPolyDataNormals>::New();
    pdNormals->SetInputConnection( sphere->GetOutputPort() );
    pdNormals->ComputeCellNormalsOn();
    pdNormals->Update();

    vtkPointData* ptData = pdNormals->GetOutput()->GetPointData();
    if( ptData )
    
        vtkDataArray* ptNormals = pdNormals->GetOutput()->GetPointData()->GetNormals();
        if( ptNormals )
        
            cout << "For points in every cell: \\n";
            cout << ptNormals->GetNumberOfTuples() << endl;
            for( int i = 0; i < ptNormals->GetNumberOfTuples(); ++i )
            
                double value[3];
                ptNormals->GetTuple( i, value );
                printf( "Value: (%lf, %lf, %lf)\\n", value[0], value[1], value[2] );
            
        
    

    cout << "For cells: \\n";
    if( pdNormals->GetOutput()->GetCellData() && pdNormals->GetOutput()->GetCellData()->GetNormals() )
    
        vtkDataArray* cellNormals = pdNormals->GetOutput()->GetCellData()->GetNormals();
        cout << cellNormals->GetNumberOfTuples() << endl;
        for( int i = 0; i < cellNormals->GetNumberOfTuples(); ++i )
        
            double value[3];
            cellNormals->GetTuple( i, value );
            printf( "Value: (%lf, %lf, %lf)\\n", value[0], value[1], value[2] );
        
    
// ...
    return EXIT_SUCCESS;

output:

For points in every cell:
66
Value: (0.000000, 0.000000, 1.000000)
Value: (0.000000, 0.000000, -1.000000)
Value: (0.471163, 0.052265, 0.880496)
Value: (0.779360, 0.017869, 0.626322)
// ...
Value: (0.887900, -0.367780, -0.276354)
For cells:
96
Value: (0.221582, 0.091782, 0.970813)
Value: (0.091782, 0.221582, 0.970813)
// ...
Value: (0.603683, -0.250054, -0.756994)
Value: (0.603683, -0.250054, -0.756994)

计算points的normal,使用圆锥显示出来。
这里需要使用到vtkGlyph3D,将cone和每一个normal进行绑定。
详细的使用如下:

int main(int argc, char *argv[])

//...
    vtkSmartPointer<vtkConeSource> cone =
            vtkSmartPointer<vtkConeSource>::New();
    cone->SetResolution( 6 );
    vtkSmartPointer<vtkTransform> transform =
            vtkSmartPointer<vtkTransform>::New();
    transform->RotateY( 180 ); // make vertex outside
    vtkSmartPointer<vtkTransformPolyDataFilter> transformF =
            vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    transformF->SetInputConnection( cone->GetOutputPort() );
    transformF->SetTransform( transform );

    vtkSmartPointer<vtkGlyph3D> glyph =
            vtkSmartPointer<vtkGlyph3D>::New();
    glyph->SetInputConnection( pdNormals->GetOutputPort() );
    glyph->SetSourceConnection( transformF->GetOutputPort() ); // source => transform => graph3D
    glyph->SetVectorModeToUseNormal();
    glyph->SetScaleModeToScaleByVector();
    glyph->SetScaleFactor( 0.1 );

    vtkSmartPointer<vtkPolyDataMapper> spikeMapper =
            vtkSmartPointer<vtkPolyDataMapper>::New();
    spikeMapper->SetInputConnection( glyph->GetOutputPort() );

    vtkSmartPointer<vtkActor> spikeActor = vtkSmartPointer<vtkActor>::New();
    spikeActor->SetMapper( spikeMapper );
    spikeActor->GetProperty()->SetColor( 0.0, 0.79, 0.34 );

    // Add the actors to the renderer, set the background and size
    ren->AddActor( spikeActor );
// ...


(我们可以使用key W、S进行网格和平面模式的切换)

吐槽:CSDN Markdown都没法设置图片居中吗?

以上是关于VTKvtkPolyDataNormals 计算法向量的主要内容,如果未能解决你的问题,请参考以下文章

如何计算Flink集群规模:信封背计算法

红包计算的方法(通过2倍指数法进行计算,通过线性切割法计算)

求VHDL的查表法计算16位CRC-CCITT 。

CASS精品教程CASS9.1土方量的计算方法汇总

CASS精品教程CASS9.1土方量的计算方法汇总

用指数记数法赋值和计算