Subversion Repositories gelsvn

Rev

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

#ifndef __MANIFOLD_H
#define __MANIFOLD_H

#include <vector>
#include <list>
#include <map>

#include "Vertex.h"
#include "HalfEdge.h"
#include "Face.h"

namespace HMesh
{
        class VertexCirculator;
        class FaceCirculator;

        /** \brief A Data structure representing an open or closed manifold.
                        Manifold keeps lists of the entities making up a halfedge mesh
                        and provides basic functions for creating new faces, halfedges
                        and vertices. There are also primitive operations for editing 
                        such as edge collapse. */
        struct Manifold
        {
                std::list<Vertex> vertex_db;
                std::list<Face> face_db;
                std::list<HalfEdge> halfedge_db;

                /** Remove a face if it contains only two edges.
                                This is an auxiliary function called from collapse_halfedge. */
                void remove_face_if_degenerate(HalfEdgeIter);

                /** Empty copy constructor.
                                Copying a manifold will not work, since faces, vertices, and
                                halfedges contain iterators pointing to other faces, vertices,
                                and halfedges. These pointers would need to be changed if the 
                                mesh were copied. In other words, we would need to walk the
                                entire mesh. This may be required but it should not be an 
                                operation that is easily invoked by calling the copy constructor.
                                Hence, this operator is made private.           */
                Manifold(const Manifold&) {}

                /** Empty assignment operator.
                                The assignment operator is private for the same reason that the
                                copy constructor is private. */
                const Manifold& operator=(const Manifold&) {return *this;}

                public:
        
                /// Construct an empty manifold.
                Manifold() {}

        /** Return the bounding box of the manifold. The arguments pmin and pmax
                                will contain the extreme corners of the box when the function returns.
                 */
                void get_bbox(CGLA::Vec3f& pmin, CGLA::Vec3f& pmax);

                /** Get a bounding sphere. When the function returns c contains the 
                                centre and r the radius. */ 
    void get_bsphere(CGLA::Vec3f& c, float& r);

                /// Clear the manifold - removing all data.
                void clear()
                {
                        vertex_db.clear();
                        face_db.clear();
                        halfedge_db.clear();
                }

                /// Return the number of faces.
                size_t no_faces() const {return face_db.size();}

                /// Return the number of halfedges.
                size_t no_halfedges() const {return halfedge_db.size();}

                /// Return the number of vertices
                size_t no_vertices() const {return vertex_db.size();}

                /** Create a new vertex. 
                                The argument is the position of the vertex, and the 
                                function returns an iterator pointing to the vertex. */
                VertexIter create_vertex(const CGLA::Vec3f& pos)
                {
                        vertex_db.push_back(Vertex(pos));
                        return --vertex_db.end();
                }

                /** Create a new face. 
                                An iterator to the face is returned. */
                FaceIter create_face()
                {
                        face_db.push_back(Face());
                        return --face_db.end();
                }

        /** Create a new halfedge. An iterator to the halfedge is returned. */
                HalfEdgeIter create_halfedge()
                {
                        halfedge_db.push_back(HalfEdge());
                        return --halfedge_db.end();
                }

                /// Erase halfedge h. Assumes it is safe to do so. Use with care.
                void erase_halfedge(HalfEdgeIter h)
                {
                        halfedge_db.erase(h);
                }

                /// Erase vertex v. Assumes it is safe to do so. Use with care.
                void erase_vertex(VertexIter v)
                {
                        vertex_db.erase(v);
                }
        
                /// Erase face f. Assumes it is safe to do so. Use with care.
                void erase_face(FaceIter f)
                {
                        face_db.erase(f);
                }

                /// Return iterator pointing to the first halfedge.
                HalfEdgeIter halfedges_begin() { return halfedge_db.begin();}

                /// Return iterator pointing to beyond the last halfedge.
                HalfEdgeIter halfedges_end() { return halfedge_db.end(); }
        
                /// Return iterator pointing to the first vertex.
                VertexIter vertices_begin() { return vertex_db.begin();}

                /// Return iterator pointing to beyond the last vertex.
                VertexIter vertices_end() { return vertex_db.end(); }

                /// Return iterator pointing to the first face.
                FaceIter faces_begin() { return face_db.begin();        }

                /// Return iterator pointing to beyond the last face.
                FaceIter faces_end() { return face_db.end(); }

                /** \brief HalfEdge collapse precondition. 

                                The first argument, v, is the vertex we want to remove. The
                                second, h, is a halfedge pointing away from that vertex.

                                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: It introduces a vertex of valency two
                                and if the final two polygons incident on the vertices 
                                that are adjacent to the edge being collapsed are triangles, then
                                the construction will collapse

                                5. VALENCY 4 TEST:
                                If a face adjacent to the edge being collapsed is a triangle,
                                it will disappear, and the valency of the final vertex beloning to
                                this edge will be reduced by one. Hence this valency should be at
                                least 4. A valency three vertex will be reduced to a valency two
                                vertex which is considered illegal.

                                6. PREVENT MERGING HOLES:
                                We do not want to collapse an edge if its end points are boundary
                                vertices, but its two adjacent faces are not NULL faces, because
                                in that case we create a vertex where two holes meet. A non manifold
                                situation.      */
                bool collapse_precond(VertexIter v, HalfEdgeIter h);
                
                /** Collapse the halfedge h.

                                The first argument, v, is the vertex that is being removed. The
                                second, h, is a halfedge pointing away from that vertex.

                                The final argument is a boolean indicating whether the vertex
                                that survives the collapse should have a position which is the
                                average of its own position and the vertex that is removed.
                                By default false.

                                This function is not guaranteed to keep the mesh sane unless,
                                collapse_precond has returned true.
                */
                void collapse_halfedge(VertexIter v, HalfEdgeIter h, bool=false);

                /** Split a face.
                    The face, f, is split by connecting two
                                vertices 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. An iterator to the new face is 
                                returned. */
                FaceIter split_face(FaceIter f, VertexIter v0, VertexIter v1);

                /** 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. */
                VertexIter Manifold::split_edge(HalfEdgeIter h);

                /** Triangulate a polygonal face by repeatedly calling split_face. 
                                Triangulate iteratively splits triangles off a polygon. The first 
                                triangle split off is the one connecting f->last->vert and
                                f->last->next->next->vert.
                */
                void triangulate(FaceIter f);

                /** Triangulate a polygon, f, by inserting a vertex at the barycenter.
                                All vertices in f are connected to the new vertex.                              
                                The word "safe" means that it is less likely to create flipped
                                triangles than the normal triangulate. On the other hand, it 
                                introduces more vertices and probably makes the triangles more
                                acute. This function simply calls face_insert_point.

                                The inserted vertex is returned.
                */
                VertexIter safe_triangulate(FaceIter f);

                /** Insert a new vertex, v, in a face, f.
                                This operation splits an N-gon into N triangles.
                                In the current implementation the original face is erased. 
                                This means that the iterator is not valid after the function
                                returns. 
                */
                void face_insert_point(FaceIter f, VertexIter v);

                /** 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(FaceIter f, HalfEdgeIter h);

                /** Flip an edge h. Returns false if flipping cannot be performed.
                                This is either because one of the two adjacent faces is not
                                a triangle, or because either end point has valency three or
                                because the vertices that will be connected already are. */
                bool flip(HalfEdgeIter h);

                /** 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();

                /** Give each vertex a unique id corresponding to its iterator 
                                position */
                void enumerate_vertices();

                /** Give each halfedge a unique id corresponding to its iterator 
                                position */
                void enumerate_halfedges();

                /** Give each face a unique id corresponding to its iterator 
                                position */
                void enumerate_faces();
                
        };


}
#endif