The post is related to The Example About vtkPolyDataNormals.
If you want to use vtkPolyDataNormals to compute the normals of points, it’s better to set variable Splitting false.
#include <vtkVersion.h>
#include <vtkSmartPointer.h>
#include <vtkSurfaceReconstructionFilter.h>
#include <vtkProgrammableSource.h>
#include <vtkContourFilter.h>
#include <vtkReverseSense.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkPolyData.h>
#include <vtkCamera.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkUnstructuredGrid.h>
#include <vtkDataSetMapper.h>
#include <vtkPolyDataNormals.h>
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkConeSource.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkGlyph3D.h>
int main(int argc, char *argv[])
{
setbuf( stdout, nullptr );
// There are first four points which z = 0: {0, 0, 0}, {0, 0, 1}, {1, 0, 1}, {1, 0, 0}
// They form a plane
// Other points have same scene.
double coords[8][3] = { {0, 0, 0}, {0, 0, 1}, {1, 0, 1}, {1, 0, 0},
{0, 1, 0}, {0, 1, 1}, {1, 1, 1}, {1, 1, 0} };
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
for( int i = 0; i < 8; ++i )
{
points->InsertPoint( i, coords[i] );
}
vtkSmartPointer<vtkCellArray> polys =
vtkSmartPointer<vtkCellArray>::New();
vtkIdType pts[6][4]={ {0,1,2,3}, {4,5,6,7}, {0,1,5,4},
{1,2,6,5}, {2,3,7,6}, {3,0,4,7} };
for( int i = 0; i < 6; ++i )
{
polys->InsertNextCell( 4, pts[i] );
}
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->SetSplitting( false );
pdNormals->ComputeCellNormalsOff();
pdNormals->Update();
vtkPointData* ptData = pdNormals->GetOutput()->GetPointData();
vtkDataArray* ptNormals = pdNormals->GetOutput()->GetPointData()->GetNormals();
printf( "For points in every cell: \n" );
printf( "GetNumberOfTuples: %d\n", ptNormals->GetNumberOfTuples() );
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] );
}
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 );
// Create the RenderWindow, Renderer and both Actors
vtkSmartPointer<vtkRenderer> ren =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renWin =
vtkSmartPointer<vtkRenderWindow>::New();
renWin->AddRenderer(ren);
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
iren->SetRenderWindow(renWin);
// Add the actors to the renderer, set the background and size
ren->AddActor( surfaceActor );
ren->AddActor( spikeActor );
ren->SetBackground(.2, .3, .4);
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}
Output:
GetNumberOfTuples: 8
Value: (0.577350, 0.577350, 0.577350)
Value: (0.577350, 0.577350, -0.577350)
Value: (-0.577350, 0.577350, -0.577350)
Value: (-0.577350, 0.577350, 0.577350)
Value: (0.577350, -0.577350, 0.577350)
Value: (0.577350, -0.577350, -0.577350)
Value: (-0.577350, -0.577350, -0.577350)
Value: (-0.577350, -0.577350, 0.577350)
The vtkPolyDataNormals object will split edge and add points if don’t set Splitting false. The number of points of new polyData from vtkPolyDataNormals become 24.
vtkSmartPointer<vtkPolyDataNormals> pdNormals =
vtkSmartPointer<vtkPolyDataNormals>::New();
pdNormals->SetInputData( pd );
pdNormals->ComputeCellNormalsOff();
pdNormals->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData( pdNormals->GetOutput() );
auto newPts = pdNormals->GetOutput()->GetPoints();
printf( "GetNumberOfPoints: %d\n", newPts->GetNumberOfPoints() );
vtkSmartPointer<vtkActor> surfaceActor =
vtkSmartPointer<vtkActor>::New();
surfaceActor->SetMapper( mapper );
vtkPointData* ptData = pdNormals->GetOutput()->GetPointData();
vtkDataArray* ptNormals = pdNormals->GetOutput()->GetPointData()->GetNormals();
printf( "GetNumberOfTuples: %d\n", ptNormals->GetNumberOfTuples() );
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] );
}
Output:
GetNumberOfPoints: 24
GetNumberOfTuples: 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: (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)
Value: (0.000000, 0.000000, -1.000000)
Value: (-1.000000, 0.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)
Value: (1.000000, 0.000000, 0.000000)
Value: (0.000000, 0.000000, -1.000000)
Value: (0.000000, 0.000000, -1.000000)
Value: (-1.000000, 0.000000, 0.000000)
Value: (-1.000000, 0.000000, 0.000000)
Value: (0.000000, 0.000000, 1.000000)