# PolyDataExtractNormals

VTKExamples/Cxx/PolyData/PolyDataExtractNormals

### Description

This demo looks for multiple types of normals in a polydata and generates them if they do not exist.

### Code

PolyDataExtractNormals.cxx

    #include <vtkVersion.h>
    #include <vtkCellData.h>
    #include <vtkDoubleArray.h>
    #include <vtkFloatArray.h>
    #include <vtkPoints.h>
    #include <vtkPolyData.h>
    #include <vtkPolyDataNormals.h>
    #include <vtkPointData.h>
    #include <vtkSmartPointer.h>
    #include <vtkSphereSource.h>
    #include <vtkXMLPolyDataReader.h>

    void TestPointNormals(vtkPolyData* polydata);
    void TestCellNormals(vtkPolyData* polydata);

    bool GetPointNormals(vtkPolyData* polydata);
    bool GetCellNormals(vtkPolyData* polydata);

    int main(int argc, char *argv[])
    {
      vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();

      // 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;

        vtkSmartPointer<vtkXMLPolyDataReader> reader = vtkSmartPointer<vtkXMLPolyDataReader>::New();
        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;
        vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
        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;
    }

    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
        vtkSmartPointer<vtkPolyDataNormals> normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
    #if VTK_MAJOR_VERSION <= 5
        normalGenerator->SetInput(polydata);
    #else
        normalGenerator->SetInputData(polydata);
    #endif
        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
        vtkSmartPointer<vtkPolyDataNormals> normalGenerator = vtkSmartPointer<vtkPolyDataNormals>::New();
    #if VTK_MAJOR_VERSION <= 5
        normalGenerator->SetInput(polydata);
    #else
        normalGenerator->SetInputData(polydata);
    #endif
        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 =
        vtkDoubleArray::SafeDownCast(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 =
        vtkFloatArray::SafeDownCast(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 =
        vtkDoubleArray::SafeDownCast(polydata->GetPointData()->GetNormals());

      if(normalsDouble)
      {
        std::cout << "There are " << normalsDouble->GetNumberOfComponents()
                  << " components in normalsDouble" << std::endl;
        return true;
      }

      ////////////////////////////////////////////////////////////////
      // Point normals
      vtkFloatArray* normalsFloat =
        vtkFloatArray::SafeDownCast(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 =
        vtkDoubleArray::SafeDownCast(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 =
        vtkFloatArray::SafeDownCast(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 =
        vtkDoubleArray::SafeDownCast(polydata->GetCellData()->GetNormals());

      if(normalsDouble)
      {
        std::cout << "There are " << normalsDouble->GetNumberOfComponents()
                  << " components in normalsDouble" << std::endl;
        return true;
      }

      ////////////////////////////////////////////////////////////////
      // Point normals
      vtkFloatArray* normalsFloat =
        vtkFloatArray::SafeDownCast(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;

    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 2.8)

    PROJECT(PolyDataExtractNormals)

    find_package(VTK REQUIRED)
    include(${VTK_USE_FILE})

    add_executable(PolyDataExtractNormals MACOSX_BUNDLE PolyDataExtractNormals.cxx )

    target_link_libraries(PolyDataExtractNormals ${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.