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 pd =
vtkSmartPointer::New();
pd->SetPolys( polys );
pd->SetPoints( points );
vtkSmartPointer mapper =
vtkSmartPointer::New();
mapper->SetInputData( pd );
vtkSmartPointer surfaceActor =
vtkSmartPointer::New();
surfaceActor->SetMapper( mapper );
vtkSmartPointer pdNormals =
vtkSmartPointer::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 sphere =
vtkSmartPointer::New();
vtkSmartPointer mapper =
vtkSmartPointer::New();
mapper->SetInputConnection( sphere->GetOutputPort() );
vtkSmartPointer surfaceActor =
vtkSmartPointer::New();
surfaceActor->SetMapper( mapper );
vtkSmartPointer pdNormals =
vtkSmartPointer::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;
}
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 cone =
vtkSmartPointer::New();
cone->SetResolution( 6 );
vtkSmartPointer transform =
vtkSmartPointer::New();
transform->RotateY( 180 ); // make vertex outside
vtkSmartPointer transformF =
vtkSmartPointer::New();
transformF->SetInputConnection( cone->GetOutputPort() );
transformF->SetTransform( transform );
vtkSmartPointer glyph =
vtkSmartPointer::New();
glyph->SetInputConnection( pdNormals->GetOutputPort() );
glyph->SetSourceConnection( transformF->GetOutputPort() ); // source => transform => graph3D
glyph->SetVectorModeToUseNormal();
glyph->SetScaleModeToScaleByVector();
glyph->SetScaleFactor( 0.1 );
vtkSmartPointer spikeMapper =
vtkSmartPointer::New();
spikeMapper->SetInputConnection( glyph->GetOutputPort() );
vtkSmartPointer spikeActor = vtkSmartPointer::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都没法设置图片居中吗?