Program Listing for File IndexedFaceMesh.h

Return to documentation for file (Utils/IndexedFaceMesh.h)

#ifndef __INDEXEDFACEMESH_H__
#define __INDEXEDFACEMESH_H__

#include <vector>
#include <array>
#include "Common/Common.h"
#include <iterator>

namespace Utilities
{
    class IndexedFaceMesh
    {
    public:
        struct Edge
        {
            std::array<unsigned int, 2> m_face;
            std::array<unsigned int, 2> m_vert;
        };

    public:
        typedef std::vector<unsigned int> Faces;
        typedef std::vector<Vector3r> FaceNormals;
        typedef std::vector<Vector3r> VertexNormals;
        typedef std::vector<std::vector<unsigned int>> FacesEdges;
        typedef std::vector<Edge> Edges;
        typedef std::vector<std::vector<unsigned int>> VerticesEdges;
        typedef std::vector<std::vector<unsigned int>> VerticesFaces;
        typedef std::vector<unsigned int> UVIndices;
        typedef std::vector<Vector2r> UVs;

    protected:
        unsigned int m_numPoints;
        Faces m_indices;
        Edges m_edges;
        FacesEdges m_facesEdges;
        bool m_closed;
        UVIndices m_uvIndices;
        UVs m_uvs;
        VerticesFaces m_verticesFaces;
        VerticesEdges m_verticesEdges;
        const unsigned int m_verticesPerFace = 3u;
        FaceNormals m_normals;
        VertexNormals m_vertexNormals;
        bool m_flatShading;

    public:
        IndexedFaceMesh();
        IndexedFaceMesh(IndexedFaceMesh const& other);
        IndexedFaceMesh& operator=(IndexedFaceMesh const& other);
        ~IndexedFaceMesh();

        void release();
        bool isClosed() const;
        bool getFlatShading() const { return m_flatShading; }
        void setFlatShading(const bool v) { m_flatShading = v; }
        void initMesh(const unsigned int nPoints, const unsigned int nEdges, const unsigned int nFaces);
        void addFace(const unsigned int * const indices);
        void addFace(const int * const indices);
        void addUV(const Real u, const Real v);
        void addUVIndex(const unsigned int index);

        const Faces& getFaces() const { return m_indices; }
        Faces& getFaces(){ return m_indices; }
        const FaceNormals& getFaceNormals() const { return m_normals; }
        FaceNormals& getFaceNormals(){ return m_normals; }
        const VertexNormals& getVertexNormals() const { return m_vertexNormals; }
        VertexNormals& getVertexNormals(){ return m_vertexNormals; }
        Edges& getEdges() { return m_edges; }
        const Edges& getEdges() const { return m_edges; }
        const FacesEdges& getFacesEdges() const { return m_facesEdges; }
        const UVIndices& getUVIndices() const { return m_uvIndices; }
        const UVs& getUVs() const { return m_uvs; }
        const VerticesFaces& getVertexFaces() const { return m_verticesFaces; }
        const VerticesEdges& getVertexEdges() const { return m_verticesEdges; }


        unsigned int numVertices() const { return m_numPoints; }
        unsigned int numFaces() const { return (unsigned int)m_indices.size() / m_verticesPerFace; }
        unsigned int numEdges() const { return (unsigned int)m_edges.size(); }
        unsigned int numUVs() const { return (unsigned int)m_uvs.size(); }

        void copyUVs(const UVIndices& uvIndices, const UVs& uvs);

        void buildNeighbors();

        template<class PositionData>
        void updateNormals(const PositionData &pd, const unsigned int offset);

        template<class PositionData>
        void updateVertexNormals(const PositionData &pd);

        unsigned int getVerticesPerFace() const;
    };


    template<class PositionData>
    void IndexedFaceMesh::updateNormals(const PositionData &pd, const unsigned int offset)
    {
        m_normals.resize(numFaces());

        #pragma omp parallel default(shared)
        {
            #pragma omp for schedule(static)
            for (int i = 0; i < (int) numFaces(); i++)
            {
                // Get first three points of face
                const Vector3r &a = pd.getPosition(m_indices[m_verticesPerFace*i] + offset);
                const Vector3r &b = pd.getPosition(m_indices[m_verticesPerFace*i + 1] + offset);
                const Vector3r &c = pd.getPosition(m_indices[m_verticesPerFace*i + 2] + offset);

                // Create normal
                Vector3r v1 = b - a;
                Vector3r v2 = c - a;

                m_normals[i] = v1.cross(v2);
                m_normals[i].normalize();
                // fix normals of degenerate triangles that can become zero vectors
                if (m_normals[i].squaredNorm() < 1e-6f)
                    m_normals[i] = Vector3r::UnitX();
            }
        }
    }

    template<class PositionData>
    void IndexedFaceMesh::updateVertexNormals(const PositionData &pd)
    {
        m_vertexNormals.resize(numVertices());


        for (unsigned int i = 0; i < numVertices(); i++)
        {
            m_vertexNormals[i].setZero();
        }

        for (unsigned int i = 0u; i < numFaces(); i++)
        {
            const Vector3r &n = m_normals[i];
            m_vertexNormals[m_indices[m_verticesPerFace*i]] += n;
            m_vertexNormals[m_indices[m_verticesPerFace*i + 1]] += n;
            m_vertexNormals[m_indices[m_verticesPerFace*i + 2]] += n;
        }

        for (unsigned int i = 0; i < numVertices(); i++)
        {
            m_vertexNormals[i].normalize();
        }
    }

}

#endif