Subversion Repositories gelsvn

Rev

Rev 489 | Rev 506 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#ifndef __HMESH_MANIFOLD_H__
#define __HMESH_MANIFOLD_H__

#include "entities.h"
#include "EntityVector.h"

namespace CGLA
{
    // forward declaration
    class Vec3f;
}

namespace Geometry
{
    // forward declaration
    class TriMesh;
    class IndexedFaceSet;
}

namespace HMesh
{
    // forward declarations
    class VertexHandle;
    class HalfEdgeHandle;
    class FaceHandle;

    class Manifold
    {
    public:
        /// Default constructor
        Manifold();

        /** \brief Build a manifold. 
            The arguments are the number of vertices, no_vertices, the vector of vertices, vertvec, the number of faces, no_faces. 
            facevecis an array where each entry indicates the number of vertices in that face. 
            The array indices contains all the corresponding vertex indices in one concatenated list. */
                template<typename float_type, typename int_type>
        void build( int_type no_vertices,
                    const float_type* vertvec,
                    int_type no_faces,
                    const int_type* facevec,
                    const int_type* indices,
                    const int* touch = NULL);
                
        /// Build a manifold from a TriMesh
        void build(const Geometry::TriMesh& mesh);

        /** \brief Collapse the halfedge h.
                    The argument h is the halfedge being removed. The vertex v=h->opp->vert is the one being removed while h->vert survives.
                    The final argument indicates whether the surviving vertex should have the average position of the former vertices.
                    By default false meaning that the surviving vertex retains it position.
                    This function is not guaranteed to keep the mesh sane unless, collapse_precond has returned true !! */
        void collapse_halfedge(HalfEdgeHandle h, bool avg_vertices = false);

                /** \brief Split a face.
                    The face, f, is split by creating an edge with endpoints v0 and v1 (the next two arguments). 
            The vertices of the old face between v0 and v1 (in counter clockwise order) continue to belong to f. 
            The vertices between v1 and v0 belong to the new face. A handle to the new face is returned. */
        FaceHandle split_face_by_edge(FaceHandle f, VertexHandle v0, VertexHandle v1);
                
        /** \brief Split a polygon, f, by inserting a vertex at the barycenter.                 
                        This function is less likely to create flipped triangles than the split_face_triangulate function. 
            On the other hand, it introduces more vertices and probably makes the triangles more acute.
                        A handle to the inserted vertex is returned. */
        VertexHandle split_face_by_vertex(FaceHandle f);

        /** \brief Insert a new vertex on halfedge h.
            The new halfedge is insterted as the previous edge to h.
            An iterator to the inserted vertex is returned. */
        VertexHandle split_edge(HalfEdgeHandle h);

                /** \brief Merges two faces into a single polygon. 
            The first face is f. The second face is adjacent to f along the halfedge h. 
            This function returns true if the merging was possible and false otherwise. 
            Currently merge only fails if the mesh is already illegal. Thus it should, in fact, never fail. */
        bool merge_faces(FaceHandle f, HalfEdgeHandle h);

        /// \brief Close hole given by the invalid face of halfedgehandle h. 
        void close_hole(HalfEdgeHandle h);

        /** \brief Test for legal HalfEdge collapse.
            The argument h is the halfedge we want to collapse. 
            If this function does not return true, it is illegal to collapse h. 
            The reason is that the collapse would violate the manifold property of the mesh.
            The test is as follows:
            1.  For the two vertices adjacent to the edge, we generate a list of all their neighbouring vertices. 
                We then generate a  list of the vertices that occur in both these lists. 
                That is, we find all vertices connected by edges to both endpoints of the edge and store these in a list.
            2.  For both faces incident on the edge, check whether they are triangular. 
                If this is the case, the face will be removed, and it is ok that the the third vertex is connected to both endpoints. 
                Thus the third vertex in such a face is removed from the list generated in 1.
            3.  If the list is now empty, all is well. 
                Otherwise, there would be a vertex in the new mesh with two edges connecting it to the same vertex. Return false.
            4.  TETRAHEDRON TEST:
                If the valency of both vertices is three, and the incident faces are triangles, we also disallow the operation. 
                Reason: A vertex valency of two and two triangles incident on the adjacent vertices makes the construction collapse.
            5.  VALENCY 4 TEST:
                If a triangle is adjacent to the edge being collapsed, it disappears.
                This means the valency of the remaining edge vertex is decreased by one.
                A valency three vertex reduced to a valency two vertex is considered illegal.
            6.  PREVENT MERGING HOLES:
                Collapsing an edge with boundary endpoints and valid faces results in the creation where two holes meet.
                A non manifold situation.       */
        bool collapse_halfedge_test(HalfEdgeHandle h);

                /** \brief Verify Manifold Integrity
            Performs a series of tests to check that this is a valid manifold.
                        This function is not rigorously constructed but seems to catch all problems so far. 
            The function returns true if the mesh is valid and false otherwise. */
        bool is_valid();

        /// Calculate the bounding box of the manifold
        void bbox(CGLA::Vec3f& pmin, CGLA::Vec3f& pmax);
        /// Calculate the bounding sphere of the manifold
        void bsphere(CGLA::Vec3f& c, float& r);

        /// Get a vertex handle to vertex represented by idx
        VertexHandle vertex_handle(VIDX idx);
        /// Get a halfedge handle to vertex represented by idx
        HalfEdgeHandle halfedge_handle(HIDX hidx);
        /// Get a face to vertex represented by idx
        FaceHandle face_handle(FIDX idx);

        VertexHandle vertices_begin();
        HalfEdgeHandle halfedges_begin();
        FaceHandle faces_begin();
        VertexHandle vertices_end();
        HalfEdgeHandle halfedges_end();
        FaceHandle faces_end();

        /// Get number of vertices 
        size_t no_vertices() const;
        /// Get number of halfedges
        size_t no_halfedges() const;
        /// Get number of faces
        size_t no_faces() const;

        /// Store index in touched attribute of vertex
        void enumerate_vertices();
        /// Store index in touched attribute of halfedge
        void enumerate_halfedges();
        /// Store index in touched attribute of face
        void enumerate_faces();

        /// Clear the mesh
        void clear();
        /// Clean up unused space in vectors - WARNING! Invalidates existing handles!
        void cleanup();
    private:
        EntityVector<Vertex> vertices;
        EntityVector<HalfEdge> halfedges;
        EntityVector<Face> faces;

        // Only handles can access and modify the data directly  
        friend class VertexHandle;
        friend class HalfEdgeHandle;
        friend class FaceHandle;

        VertexHandle add_vertex(const Vertex& v);
        FaceHandle add_face(const Face& f);
        HalfEdgeHandle add_halfedge(const HalfEdge& h);

        void remove_vertex(VertexHandle v);
        void remove_halfedge(HalfEdgeHandle h);
        void remove_face(FaceHandle f);

        /// Auxiliary function called from collapse
        void remove_face_if_degenerate(HalfEdgeHandle h);
    };

    inline Manifold::Manifold(){}

    inline size_t Manifold::no_vertices() const{ return vertices.size(); }
    inline size_t Manifold::no_halfedges() const{ return halfedges.size(); }
    inline size_t Manifold::no_faces() const{ return faces.size(); }
}


#endif __HMESH_MANIFOLD_H__