PolyDataExtractNormals
vtk-examples/Cxx/PolyData/PolyDataExtractNormals
Description¶
This demo looks for multiple types of normals in a polydata and generates them if they do not exist.
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
PolyDataExtractNormals.cxx
#include <vtkCellData.h>
#include <vtkDoubleArray.h>
#include <vtkFloatArray.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include <vtkPolyDataNormals.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>
#include <iostream>
#include <string>
namespace {
void TestPointNormals(vtkPolyData* polydata);
void TestCellNormals(vtkPolyData* polydata);
bool GetPointNormals(vtkPolyData* polydata);
bool GetCellNormals(vtkPolyData* polydata);
} // namespace
int main(int argc, char* argv[])
{
vtkNew<vtkPolyData> polydata;
// If a file is provided, read it. Else, create a sphere.
if (argc == 2)
{
// Read File
std::string filename = argv[1]; // first command line argument
std::cout << "Reading file " << filename << "..." << std::endl;
vtkNew<vtkXMLPolyDataReader> reader;
std::cout << "Reading " << filename << std::endl;
reader->SetFileName(filename.c_str());
reader->Update();
polydata->DeepCopy(reader->GetOutput());
}
else
{
std::cout << "Creating a sphere..." << std::endl;
vtkNew<vtkSphereSource> sphereSource;
sphereSource->Update();
std::cout << "In main: " << sphereSource->GetOutput()->GetNumberOfPoints()
<< std::endl;
polydata->DeepCopy(sphereSource->GetOutput());
}
std::cout << "PolyData address: " << polydata << std::endl;
TestPointNormals(polydata);
TestCellNormals(polydata);
return EXIT_SUCCESS;
}
namespace {
void TestPointNormals(vtkPolyData* polydata)
{
std::cout << "In TestPointNormals: " << polydata->GetNumberOfPoints()
<< std::endl;
// Try to read normals directly
bool hasPointNormals = GetPointNormals(polydata);
if (!hasPointNormals)
{
std::cout << "No point normals were found. Computing normals..."
<< std::endl;
// Generate normals
vtkNew<vtkPolyDataNormals> normalGenerator;
normalGenerator->SetInputData(polydata);
normalGenerator->ComputePointNormalsOn();
normalGenerator->ComputeCellNormalsOff();
normalGenerator->Update();
/*
// Optional settings
normalGenerator->SetFeatureAngle(0.1);
normalGenerator->SetSplitting(1);
normalGenerator->SetConsistency(0);
normalGenerator->SetAutoOrientNormals(0);
normalGenerator->SetComputePointNormals(1);
normalGenerator->SetComputeCellNormals(0);
normalGenerator->SetFlipNormals(0);
normalGenerator->SetNonManifoldTraversal(1);
*/
polydata = normalGenerator->GetOutput();
// Try to read normals again
hasPointNormals = GetPointNormals(polydata);
std::cout << "On the second try, has point normals? " << hasPointNormals
<< std::endl;
}
else
{
std::cout << "Point normals were found!" << std::endl;
}
}
void TestCellNormals(vtkPolyData* polydata)
{
// Try to read normals directly
bool hasCellNormals = GetCellNormals(polydata);
if (!hasCellNormals)
{
std::cout << "No cell normals were found. Computing normals..."
<< std::endl;
// Generate normals
vtkNew<vtkPolyDataNormals> normalGenerator;
normalGenerator->SetInputData(polydata);
normalGenerator->ComputePointNormalsOff();
normalGenerator->ComputeCellNormalsOn();
normalGenerator->Update();
/*
// Optional settings
normalGenerator->SetFeatureAngle(0.1);
normalGenerator->SetSplitting(1);
normalGenerator->SetConsistency(0);
normalGenerator->SetAutoOrientNormals(0);
normalGenerator->SetComputePointNormals(1);
normalGenerator->SetComputeCellNormals(0);
normalGenerator->SetFlipNormals(0);
normalGenerator->SetNonManifoldTraversal(1);
*/
polydata = normalGenerator->GetOutput();
// Try to read normals again
hasCellNormals = GetCellNormals(polydata);
std::cout << "On the second try, has cell normals? " << hasCellNormals
<< std::endl;
}
else
{
std::cout << "Cell normals were found!" << std::endl;
}
}
bool GetPointNormals(vtkPolyData* polydata)
{
std::cout << "In GetPointNormals: " << polydata->GetNumberOfPoints()
<< std::endl;
std::cout << "Looking for point normals..." << std::endl;
// Count points
vtkIdType numPoints = polydata->GetNumberOfPoints();
std::cout << "There are " << numPoints << " points." << std::endl;
// Count triangles
vtkIdType numPolys = polydata->GetNumberOfPolys();
std::cout << "There are " << numPolys << " polys." << std::endl;
////////////////////////////////////////////////////////////////
// Double normals in an array
vtkDoubleArray* normalDataDouble = dynamic_cast<vtkDoubleArray*>(
polydata->GetPointData()->GetArray("Normals"));
if (normalDataDouble)
{
int nc = normalDataDouble->GetNumberOfTuples();
std::cout << "There are " << nc << " components in normalDataDouble"
<< std::endl;
return true;
}
////////////////////////////////////////////////////////////////
// Double normals in an array
vtkFloatArray* normalDataFloat = dynamic_cast<vtkFloatArray*>(
polydata->GetPointData()->GetArray("Normals"));
if (normalDataFloat)
{
int nc = normalDataFloat->GetNumberOfTuples();
std::cout << "There are " << nc << " components in normalDataFloat"
<< std::endl;
return true;
}
////////////////////////////////////////////////////////////////
// Point normals
vtkDoubleArray* normalsDouble =
dynamic_cast<vtkDoubleArray*>(polydata->GetPointData()->GetNormals());
if (normalsDouble)
{
std::cout << "There are " << normalsDouble->GetNumberOfComponents()
<< " components in normalsDouble" << std::endl;
return true;
}
////////////////////////////////////////////////////////////////
// Point normals
vtkFloatArray* normalsFloat =
dynamic_cast<vtkFloatArray*>(polydata->GetPointData()->GetNormals());
if (normalsFloat)
{
std::cout << "There are " << normalsFloat->GetNumberOfComponents()
<< " components in normalsFloat" << std::endl;
return true;
}
/////////////////////////////////////////////////////////////////////
// Generic type point normals
vtkDataArray* normalsGeneric =
polydata->GetPointData()->GetNormals(); // works
if (normalsGeneric)
{
std::cout << "There are " << normalsGeneric->GetNumberOfTuples()
<< " normals in normalsGeneric" << std::endl;
double testDouble[3];
normalsGeneric->GetTuple(0, testDouble);
std::cout << "Double: " << testDouble[0] << " " << testDouble[1] << " "
<< testDouble[2] << std::endl;
// Can't do this:
/*
float testFloat[3];
normalsGeneric->GetTuple(0, testFloat);
std::cout << "Float: " << testFloat[0] << " "
<< testFloat[1] << " " << testFloat[2] << std::endl;
*/
return true;
}
// If the function has not yet quit, there were none of these types of normals
std::cout << "Normals not found!" << std::endl;
return false;
}
bool GetCellNormals(vtkPolyData* polydata)
{
std::cout << "Looking for cell normals..." << std::endl;
// Count points
vtkIdType numCells = polydata->GetNumberOfCells();
std::cout << "There are " << numCells << " cells." << std::endl;
// Count triangles
vtkIdType numPolys = polydata->GetNumberOfPolys();
std::cout << "There are " << numPolys << " polys." << std::endl;
////////////////////////////////////////////////////////////////
// Double normals in an array
vtkDoubleArray* normalDataDouble = dynamic_cast<vtkDoubleArray*>(
polydata->GetCellData()->GetArray("Normals"));
if (normalDataDouble)
{
int nc = normalDataDouble->GetNumberOfTuples();
std::cout << "There are " << nc << " components in normalDataDouble"
<< std::endl;
return true;
}
////////////////////////////////////////////////////////////////
// Double normals in an array
vtkFloatArray* normalDataFloat = dynamic_cast<vtkFloatArray*>(
polydata->GetCellData()->GetArray("Normals"));
if (normalDataFloat)
{
int nc = normalDataFloat->GetNumberOfTuples();
std::cout << "There are " << nc << " components in normalDataFloat"
<< std::endl;
return true;
}
////////////////////////////////////////////////////////////////
// Point normals
vtkDoubleArray* normalsDouble =
dynamic_cast<vtkDoubleArray*>(polydata->GetCellData()->GetNormals());
if (normalsDouble)
{
std::cout << "There are " << normalsDouble->GetNumberOfComponents()
<< " components in normalsDouble" << std::endl;
return true;
}
////////////////////////////////////////////////////////////////
// Point normals
vtkFloatArray* normalsFloat =
dynamic_cast<vtkFloatArray*>(polydata->GetCellData()->GetNormals());
if (normalsFloat)
{
std::cout << "There are " << normalsFloat->GetNumberOfComponents()
<< " components in normalsFloat" << std::endl;
return true;
}
/////////////////////////////////////////////////////////////////////
// Generic type point normals
vtkDataArray* normalsGeneric = polydata->GetCellData()->GetNormals(); // works
if (normalsGeneric)
{
std::cout << "There are " << normalsGeneric->GetNumberOfTuples()
<< " normals in normalsGeneric" << std::endl;
double testDouble[3];
normalsGeneric->GetTuple(0, testDouble);
std::cout << "Double: " << testDouble[0] << " " << testDouble[1] << " "
<< testDouble[2] << std::endl;
// Can't do this:
/*
float testFloat[3];
normalsGeneric->GetTuple(0, testFloat);
std::cout << "Float: " << testFloat[0] << " "
<< testFloat[1] << " " << testFloat[2] << std::endl;
*/
return true;
}
// If the function has not yet quit, there were none of these types of normals
std::cout << "Normals not found!" << std::endl;
return false;
}
} // namespace
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(PolyDataExtractNormals)
find_package(VTK COMPONENTS
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "PolyDataExtractNormals: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(PolyDataExtractNormals MACOSX_BUNDLE PolyDataExtractNormals.cxx )
target_link_libraries(PolyDataExtractNormals PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS PolyDataExtractNormals
MODULES ${VTK_LIBRARIES}
)
Download and Build PolyDataExtractNormals¶
Click here to download PolyDataExtractNormals and its CMakeLists.txt file. Once the tarball PolyDataExtractNormals.tar has been downloaded and extracted,
cd PolyDataExtractNormals/build
If VTK is installed:
cmake ..
If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:
cmake -DVTK_DIR:PATH=/home/me/vtk_build ..
Build the project:
make
and run it:
./PolyDataExtractNormals
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.