Subversion Repositories gelsvn

Rev

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

#include "Manifold.h"

#include <iostream>
#include <iterator>
#include <vector>
#include <map>

#include <CGLA/Vec3f.h>
#include <Geometry/TriMesh.h>

#include "VertexHandle.h"
#include "FaceHandle.h"
#include "HalfEdgeHandle.h"

#include "VertexCirculator.h"
#include "FaceCirculator.h"

namespace HMesh
{
    using std::vector;
    using std::back_insert_iterator;
    using std::map;
    using std::cout;
    using std::endl;

    using Geometry::TriMesh;
    using namespace CGLA;

    // brief code used for manifold and edge creation
    namespace
    {
        class EdgeKey
        {
        public:
            EdgeKey(size_t va, size_t vb)
            {
                if(va < vb){
                    v0 = va;
                    v1 = vb;
                }
                else{
                    v0 = vb;
                    v1 = va;
                }
            }

            bool operator<(const EdgeKey& k2) const
            {
                if(v0 < k2.v0){
                    return true;
                }
                else if(v0 > k2.v0){
                    return false;
                }
                else{
                    return v1 < k2.v1;
                }
            }
        private:
            int v0;
            int v1;         
        };

        struct Edge
        {
            HIDX h0;
            HIDX h1;
            size_t count;
            Edge() : h0(NULL_HALFEDGE_IDX), h1(NULL_HALFEDGE_IDX), count(0){}
        };
    }

    // build functions
    void Manifold::build(const TriMesh& mesh)
    {
        // A vector of 3's - used to tell build how many indices each face consists of
        vector<int> faces(mesh.geometry.no_faces(), 3);

        build(  static_cast<int>(mesh.geometry.no_vertices()),
                reinterpret_cast<const float*>(&mesh.geometry.vertex(0)),
                static_cast<int>(faces.size()),
                &faces[0],
                reinterpret_cast<const int*>(&mesh.geometry.face(0)));
    }
        
        template<typename float_type, typename int_type>
    void Manifold::build(   int_type no_vertices,
                            const float_type* vertvec,
                            int_type no_faces,
                            const int_type* facevec,
                            const int_type* indices,
                            const int* touch)
    {
        // clean up the manifold for the build
        clear();

        // allocate space
        vertices.resize(no_vertices);
        faces.resize(no_faces);

        // create vertices corresponding to positions stored in vertvec
        for(size_t i = 0; i < no_vertices; ++i){
            Vec3f v;
            v[0] = vertvec[i*3];
            v[1] = vertvec[i*3+1];
            v[2] = vertvec[i*3+2];              
            vertices[i].pos = v;
        }

        // update touched values if the optional touch array was passed to build
        if(touch){
            for(size_t i = 0; i < no_vertices; ++i){
                vertices[i].touched = touch[i];
            }
        }

        //map over the created edges - needed to preserve edge uniqueness
        typedef map<EdgeKey, Edge> EdgeMap;
        EdgeMap edge_map;

        // counter that jumps between faces in indices vector
        size_t n  = 0;

        // create faces correspponding to faces stored in facevec
        for(size_t i = 0; i < no_faces; ++i){
            //amount of vertices in current face
            size_t N = facevec[i];
            vector<HalfEdgeHandle> fh;

            //each face indice results corresponds to 1 edge, 2 halfedges
            for(size_t j = 0; j < N; ++j){
                // each iteration uses two indices from the face
                VIDX v_idx0 = indices[j+n];
                VIDX v_idx1 = indices[(j+1)%N+n];

                // ensure indice integrity
                assert(v_idx0 < no_vertices);
                assert(v_idx1 < no_vertices);

                // create key and search map for edge
                EdgeKey ek(v_idx0, v_idx1);
                EdgeMap::iterator em_iter = edge_map.find(ek);

                // current edge has not been created
                if(em_iter == edge_map.end()){ 
                    HalfEdgeHandle h0 = add_halfedge(HalfEdge());
                    HalfEdgeHandle h1 = add_halfedge(HalfEdge());
                    
                    // create edge for map
                    Edge e;
                    e.h0 = h0.get_idx();
                    e.h1 = h1.get_idx();
                    e.count = 1;

                    // glue operation: 1 edge = 2 glued halfedges
                    glue(h0, h1);

                    // update vertices with their outgoing halfedges
                    vertices[v_idx0].out_idx = e.h0;
                    vertices[v_idx1].out_idx = e.h1;

                    // update halfedges with the vertices they point to
                    halfedges[e.h0].vert_idx = v_idx1;
                    halfedges[e.h1].vert_idx = v_idx0;

                    // update map
                    edge_map[ek] = e;

                    // update vector of halfedges belonging to current face
                    fh.push_back(h0);
                }
                else{
                    // update current face with halfedge from edge
                    fh.push_back(HalfEdgeHandle(*this, em_iter->second.h1));

                    // asserting that a halfedge is visited exactly twice;
                    // once for each face on either side of the edge. 
                    em_iter->second.count++;
                    assert(em_iter->second.count == 2);
                }
            }
        
            for(size_t j = 0; j < N; ++j){
                // update halfedge with face
                fh[j].get().face_idx = i;

                // link operation: link two halfedges in the same face
                link(fh[j], fh[(j+1)%N]);
            }
            //update face with the first halfedge created
            faces[i].last_idx = fh[0].get_idx();

            // step to first indice of next face
            n += N;
        }

        // test for unused vertices
        for(size_t i = 0; i < no_vertices; ++i){
            if(vertices[i].out_idx == NULL_HALFEDGE_IDX){
                vertices.remove(i);
            }
        }

        // boundary check while avoiding unused vertices
        for(size_t i = 0; i < no_vertices; ++i){
            if(vertices[i].out_idx != NULL_HALFEDGE_IDX){
                check_boundary_consistency(VertexHandle(*this, i));
            }

        }     
    }

    bool Manifold::is_valid()
    {
        // Verify components of halfedges
        for(HalfEdgeHandle h = halfedges_begin(); h != halfedges_end(); ++h){
            if(h.get().face_idx == NULL_FACE_IDX){
                cout << "Halfedge [" << h.get_idx() << "] lacks face" << endl;
                return false;
            }
            if(h.get().vert_idx == NULL_VERTEX_IDX){
                cout << "Halfedge [" << h.get_idx() << "] lacks vert" << endl;
                return false;
            }
            if(h.get().next_idx == NULL_HALFEDGE_IDX){
                cout << "Halfedge [" << h.get_idx() << "] lacks next" << endl;
                return false;
            }
            if(h.get().prev_idx == NULL_HALFEDGE_IDX){
                cout << "Halfedge [" << h.get_idx() << "] lacks prev" << endl;
                return false;
            }
            if(h.get().opp_idx == NULL_HALFEDGE_IDX){
                cout << "Halfedge [" << h.get_idx() << "] lacks opp" << endl;
                return false;
            }
        }
        // Verify components of vertices
        for(VertexHandle v = vertices_begin(); v != vertices_end(); ++v){
            vector<VIDX> link;

            for(VertexCirculator vc(v); !vc.end(); ++vc){
                // test halfedges around v
                if(vc.halfedge() == NULL_HALFEDGE_HANDLE){
                    cout << "Vertex [" << v.get_idx() << "] circulation produced null halfedge at step " << vc.no_steps() << endl;
                    return false;
                }
                VIDX ring_v = vc.vertex().get_idx();

                // test one-ring for multiple occurences of vertex
                if(find(link.begin(), link.end(), ring_v) != link.end()){
                    cout << "Vertex [" << ring_v << "] appears two times in the one-ring of vertex [" << v.get_idx() << "]" << endl;
                    return false;
                }
                link.push_back(ring_v);

                // test for infinite loop around vertex
                if(vc.no_steps() > vertices.size()){
                    cout << "Vertex [" << v.get_idx() << "] loop contains more vertices than manifold" << endl;
                    return false;
                }
            }

            // test one_ring size for boundary consistency
            if(link.size() == 2){
                if(!is_boundary(v)){
                    cout << "Vertex [" << v.get_idx() << "] contains only two or less incident edges" << endl;
                }
                else{
                    cout << "Boundary vertex [" << v.get_idx() << "]  contains only two or less incident edges" << endl;
                }
            }

            assert(link.size() >= 2);
        }

        // verify components of faces
        for(FaceHandle f = faces_begin(); f != faces_end(); ++f){
            // test faces for valid geometrical properties
            if(no_edges(f) < 3){
                cout << "Face [" << f.get_idx() << "] contains only " << no_edges(f) << " edge(s)" << endl;
            }
            // test that all halfedges in faces bind properly to their face
            for(FaceCirculator fc(f); !fc.end(); ++fc){
                if(fc.next_halfedge().face().get_idx() != f.get_idx()){
                    cout << "Face [" << f.get_idx() << "] is inconsistent" << endl;
                    return false;
                }
                // test for infinite loop around face
                if(fc.no_steps() > halfedges.size() * 0.5f){
                    cout << "Face [" << f.get_idx() << "] loop contains more halfedges than manifold" << endl;
                    return false;
                }
            }
        }

        return true;
    }

    void Manifold::bbox(Vec3f& pmin, Vec3f& pmax) 
    {
        VertexHandle v = vertices_begin();
        pmin = pmax = v.get().pos;
        ++v;
        for(; v != vertices_end(); ++v){
            pmin = v_min(v.get().pos, pmin);
            pmax = v_max(v.get().pos, pmax);
        }
    }

    void Manifold::bsphere(Vec3f& c, float& r) 
    {
        Vec3f p0, p7;
        bbox(p0, p7);
        Vec3f rad = (p7 - p0) * 0.5f;
        c = p0 + rad;
        r = rad.length();
    }

    void Manifold::remove_face_if_degenerate(HalfEdgeHandle h)
    {
        // face is degenerate if there is only two halfedges in face loop
        if(h.next().next() == h)
        {
            HalfEdgeHandle hn = h.next();
            HalfEdgeHandle ho = h.opp();
            HalfEdgeHandle hno = hn.opp();

            // glue opposite halfedge to halfedge opposite next halfedge, obsoleting h and hn from loop
            glue(ho, hno);

            VertexHandle hv = h.vert();
            VertexHandle hnv = hn.vert();

            // make v and vn point to opposite and next opposite halfedge, obsoleting h and hn from loop
            hnv.get().out_idx = hno.get_idx();
            hv.get().out_idx = ho.get_idx();

            FaceHandle f = h.face();

            // if face owning h is valid, remove face
            if(f != NULL_FACE_HANDLE){
                remove_face(f);
            }
            // remove the two invalid halfedges and the invalid face loop
            remove_halfedge(h);
            remove_halfedge(hn);

            // verify that v and vn is sane after removing the degenerate face
            check_boundary_consistency(hv);
            check_boundary_consistency(hnv);
        }
    }

    bool Manifold::collapse_halfedge_test(HalfEdgeHandle h)
    {
        // get the two vertices of the edge being tested
        const VertexHandle v0 = h.opp().vert();
        const VertexHandle v1 = h.vert();

        // get the one-ring of v0
        vector<VIDX> link0; 
        for(VertexCirculator vc0(v0); !vc0.end(); ++vc0){
            link0.push_back(vc0.vertex().get_idx());
        }
        assert(link0.size() > 1);

        // get the one-ring of v1
        vector<VIDX> link1;
        for(VertexCirculator vc1(v1); !vc1.end(); ++vc1){
            link1.push_back(vc1.vertex().get_idx());
        }
        assert(link1.size() > 1);

        // sort the vertices of the two rings
        sort(link0.begin(), link0.end());
        sort(link1.begin(), link1.end());

        // get the intersection of the shared vertices from both rings
        vector<VIDX> lisect;
        std::back_insert_iterator<vector<VIDX> > lii(lisect);
                set_intersection(link0.begin(), link0.end(),
                                                 link1.begin(), link1.end(),
                                                 lii);

        
        int k = 0;
        // if the adjacent face is a triangle (see 2)
        if(h.next().next().next() == h){
            VertexHandle v = h.next().vert();
            
            // valency test (see 5)
            if(valency(v) < 4){
                return false;
            }
            // remove the vertex shared by the two rings from the intersection
            vector<VIDX>::iterator iter;
            iter = find(lisect.begin(), lisect.end(), v.get_idx());
            assert(iter != lisect.end());
            lisect.erase(iter);
            ++k;
        }
        // if the adjacent face is a triangle (see 2)
        if(h.opp().next().next().next() == h.opp()){
            VertexHandle v = h.opp().next().vert();
            
            // valency test (see 5)
            if(valency(v) < 4){
                return false;
            }
            // remove the vertex shared by the two rings from the intersection
            vector<VIDX>::iterator iter;
            iter = find(lisect.begin(), lisect.end(), v.get_idx());
            assert(iter != lisect.end());
            lisect.erase(iter);
            ++k;
        }
        // double edge test (see 3)
        if(lisect.size() != 0){
            return false;
        }
        // tetrahedon test (see 4)
        if(k == 2 && (link0.size() + link1.size() == 6)){
            return false;
        }
        // test that we do not merge holes (see 6)
        if(is_boundary(v0) && is_boundary(v1) && h.face() != NULL_FACE_HANDLE && h.opp().face() != NULL_FACE_HANDLE){
            return false;
        }
        

        return true;
    }


    void Manifold::collapse_halfedge(HalfEdgeHandle h, bool avg_vertices)
    {
        HalfEdgeHandle ho = h.opp();
        VertexHandle hv = h.vert();
        VertexHandle hov = ho.vert();

        // average the vertex positions
        hv.get().pos = avg_vertices * 0.5f * (hov.get().pos - hv.get().pos) + hv.get().pos;

        HalfEdgeHandle hn = h.next();
        HalfEdgeHandle hp = h.prev();
        HalfEdgeHandle hon = ho.next();
        HalfEdgeHandle hop = ho.prev();

        // update all halfedges pointing to hov to point to hv, effectively removing hov from all loops
        for(VertexCirculator vc(hov); !vc.end(); ++vc){
            vc.opp_halfedge().get().vert_idx = hv.get_idx();
        }
        hv.get().out_idx = hn.get_idx();

        // link hp and hn, effectively removing h from opposite loop
        link(hp, hn);
        // make face owning h own hn instead
        if(h.face() != NULL_FACE_HANDLE){
            h.face().get().last_idx = hn.get_idx();
        }
        // link hop and hon, effectively removing h from opposite face loop
        link(hop, hon);
        // make opposite face owning h own hon instead
        if(ho.face() != NULL_FACE_HANDLE){
            ho.face().get().last_idx = hon.get_idx();
        }
        // remove the obsolete entities
        remove_vertex(hov);
        remove_halfedge(h);
        remove_halfedge(ho);

        // verify that remaining faces haven't become degenerate because of collapse
        remove_face_if_degenerate(hn);
        remove_face_if_degenerate(hon);

        // verify that v is sane after collapse
        check_boundary_consistency(hv);
    }

    FaceHandle Manifold::split_face_by_edge(FaceHandle f, VertexHandle v0, VertexHandle v1)
    {
        // make sure this is not a triangle
        assert(no_edges(f) > 3);
        // make sure we are not trying to connect a vertex to itself
        assert(v0 != v1);

        // find the halfege emanating from v0 which belongs to face being split
        VertexCirculator vc0(v0);
        while(vc0.halfedge().face() != f && !vc0.end()){ 
            ++vc0;
        }
        assert(!vc0.end());
        HalfEdgeHandle h0 = vc0.halfedge();
        assert(h0.face() == f);

        // the halfedge belonging to f, going out from v0, is denoted h. Move along h until we hit v1.
        // now we have the halfedge which belongs to f and points to v1.
        HalfEdgeHandle h = h0;
        while(h.vert() != v1){
            h = h.next();
        }
        // create a new halfedge ha which connects v1 and v0 closing the firt loop.
        assert(h != h0);
        HalfEdgeHandle h1 = h.next();
        HalfEdgeHandle ha = add_halfedge(HalfEdge());
        link(h, ha);
        link(ha, h0);
        ha.get().face_idx = f.get_idx();
        ha.get().vert_idx = v0.get_idx();
        f.get().last_idx = ha.get_idx();

        // create a new face, f2, and set all halfedges in the remaining part of the polygon to point to this face.
        h = h1;
        FaceHandle f2 = add_face(Face());
        while(h.vert() != v0){
            h.get().face_idx = f2.get_idx();
            h = h.next();
        }
        h.get().face_idx = f2.get_idx();
        assert(h != h1);

        // create a new halfedge hb to connect v0 and v1.
        HalfEdgeHandle hb = add_halfedge(HalfEdge());
        link(h, hb);
        link(hb, h1);
        hb.get().face_idx = f2.get_idx();
        hb.get().vert_idx = v1.get_idx();
        f2.get().last_idx = hb.get_idx();

        // complete the operation by gluing the two new halfedges
        glue(ha, hb);

        // assert sanity of operation
        assert(h1.prev().opp().next() == h0);
        assert(h0.prev().opp().next() == h1);
        assert(hb.next().face() == f2);
        assert(hb.next().next().face() == f2);
        assert(hb.face() == f2);

        // return handle to newly created face
        return f2;
    }

    VertexHandle Manifold::split_face_by_vertex(FaceHandle f)
    {
        Vec3f p(0.0f);
        FaceCirculator fc(f);
        while(!fc.end()){
            p += fc.vertex().get().pos;
            ++fc;
        }
        p /= fc.no_steps();
        VertexHandle v = add_vertex(Vertex(p));

        vector<HalfEdgeHandle> eout;
        vector<HalfEdgeHandle> ein;

        HalfEdgeHandle last = f.last();
        HalfEdgeHandle h = last;

        do{
            HalfEdgeHandle hn = h.next();

            HalfEdgeHandle o = add_halfedge(HalfEdge());
            HalfEdgeHandle i = add_halfedge(HalfEdge());

            FaceHandle fn = add_face(Face());
            i.get().face_idx = fn.get_idx();
            i.get().vert_idx = v.get_idx();
            o.get().face_idx = fn.get_idx();
            o.get().vert_idx = h.opp().vert().get_idx();
            h.get().face_idx = fn.get_idx();
            fn.get().last_idx = o.get_idx();

            link(i, o);
            link(o, h);
            link(h, i);

            eout.push_back(o);
            ein.push_back(i);

            h = hn;
        }
        while(h != last);

        size_t N = eout.size();
        for(size_t i = 0; i < N; ++i){
            glue(ein[i], eout[(i+1)%N]);
        }
        v.get().out_idx = eout[0].get_idx();
        remove_face(f);

        return v;
    }

    VertexHandle Manifold::split_edge(HalfEdgeHandle h)
    {
        HalfEdgeHandle ho = h.opp();
        VertexHandle v = h.vert();
        VertexHandle vo = ho.vert();
        Vec3f np = 0.5f * (v.get().pos + vo.get().pos);

        VertexHandle vn = add_vertex(Vertex(np));
        vn.get().out_idx = h.get_idx();

        HalfEdgeHandle hn = add_halfedge(HalfEdge());
        HalfEdgeHandle hno = add_halfedge(HalfEdge());

        vo.get().out_idx = hn.get_idx();
        v.get().out_idx = ho.get_idx();

        glue(hn, hno);
        link(h.prev(), hn);
        link(hn, h);
        hn.get().vert_idx = vn.get_idx();

        link(hno, ho.next());
        link(ho, hno);
        hno.get().vert_idx = vo.get_idx();
        ho.get().vert_idx = vn.get_idx();

        if(h.face() != NULL_FACE_HANDLE){
            h.face().get().last_idx = hn.get_idx();
        }
        if(ho.face() != NULL_FACE_HANDLE){
            ho.face().get().last_idx = ho.get_idx();
        }
        hn.get().face_idx = h.face().get_idx();
        hno.get().face_idx = ho.face().get_idx();

        check_boundary_consistency(vn);
        check_boundary_consistency(v);
        check_boundary_consistency(vo);

        return vn;
    }

    bool Manifold::merge_faces(FaceHandle f, HalfEdgeHandle h)
    {
        assert(h.face() == f);

        HalfEdgeHandle ho = h.opp();
        FaceHandle fo = ho.face();
        HalfEdgeHandle hn = h.next();
        HalfEdgeHandle hon = ho.next();

        if(hn.vert() == hon.vert()){
            return false;
        }
        HalfEdgeHandle hp = h.prev();
        HalfEdgeHandle hop = ho.prev();
        VertexHandle v = h.vert();
        VertexHandle vo = ho.vert();

        link(hop, hn);
        v.get().out_idx = hn.get_idx();

        link(hp, hon);
        vo.get().out_idx = hn.get_idx();

        f.get().last_idx = hn.get_idx();
        HalfEdgeHandle hx = hon;
        assert(hx.face() == fo);
        while(h.face() != f){
            hx.get().face_idx = f.get_idx();
            hx = hx.next();
        }

        check_boundary_consistency(v);
        check_boundary_consistency(vo);

        remove_halfedge(h);
        remove_halfedge(ho);
        remove_face(fo);

        return true;
    }

    void Manifold::close_hole(HalfEdgeHandle h)
    {
        if(h.face() == NULL_FACE_HANDLE){
            FaceHandle f = add_face(Face());
            f.get().last_idx  = h.get_idx();
            do{
                h.get().face_idx = f.get_idx();
                h = h.next();
            }
            while(h.face() != f);
        }
    }

    void Manifold::enumerate_vertices()
    {
        size_t k = 0;
        for(VertexHandle v = vertices_begin(); v != vertices_end(); ++v, ++k){
            v.get().touched = k;
        }
    }
    void Manifold::enumerate_halfedges()
    {
        size_t k = 0;
        for(HalfEdgeHandle h = halfedges_begin(); h != halfedges_end(); ++h, ++k){
            h.get().touched = k;
        }
    }
    void Manifold::enumerate_faces()
    {
        size_t k = 0;
        for(FaceHandle f = faces_begin(); f != faces_end(); ++f, ++k){
            f.get().touched = k;
        }
    }

    void Manifold::clear()
    {
        vertices.clear();
        halfedges.clear();
        faces.clear();
    }
    void Manifold::cleanup()
    {
        //1. store new location of all entities in seperate arrays for future lookups
        vector<VIDX> vert_idx(vertices.full_size());
        vector<FIDX> face_idx(faces.full_size());
        vector<HIDX> he_idx(halfedges.full_size());

        size_t k = 0;
        for(VertexHandle v = vertices_begin(); v != vertices_end(); ++v, ++k){
            vert_idx[v.get_idx()] = k;
        }
        k = 0;
        for(FaceHandle f = faces_begin(); f != faces_end(); ++f, ++k){
            face_idx[f.get_idx()] = k;
        }
        k = 0;
        for(HalfEdgeHandle h = halfedges_begin(); h != halfedges_end(); ++h, ++k){
            he_idx[h.get_idx()] = k;
        }

        //2. update the remainding attributes of all entities with the indices stored in the touched attributes of their known entities
        for(VertexHandle v = vertices_begin(); v != vertices_end(); ++v){
            v.get().out_idx = he_idx[v.out().get_idx()];
        }
        for(FaceHandle f = faces_begin(); f != faces_end(); ++f){
            f.get().last_idx = he_idx[f.last().get_idx()];
        }
        for(HalfEdgeHandle h = halfedges_begin(); h != halfedges_end(); ++h){ 
                        if(h.face().get_idx() != NULL_FACE_IDX)
                                h.get().face_idx = face_idx[h.face().get_idx()];
            h.get().next_idx = he_idx[h.next().get_idx()];
            h.get().prev_idx = he_idx[h.prev().get_idx()];
            h.get().opp_idx = he_idx[h.opp().get_idx()];
            h.get().vert_idx = vert_idx[h.vert().get_idx()];
        }
        vertices.cleanup();
        halfedges.cleanup();
        faces.cleanup();
    }

    VertexHandle Manifold::vertex_handle(VIDX idx)
    {
        return VertexHandle(*this, idx);
    }
    HalfEdgeHandle Manifold::halfedge_handle(HIDX idx)
    {
        return HalfEdgeHandle(*this, idx);
    }
    FaceHandle Manifold::face_handle(FIDX idx)
    {
        return FaceHandle(*this, idx);
    }
    VertexHandle Manifold::vertices_begin()
    {
        size_t vertices_full_size = vertices.full_size();
        VIDX idx = 0;

        while(idx < vertices_full_size && !vertices.in_use(idx))
            ++idx;

        return VertexHandle(*this, idx);
    }
    HalfEdgeHandle Manifold::halfedges_begin()
    {
        size_t halfedges_full_size = halfedges.full_size();
        HIDX idx = 0;

        while(idx < halfedges_full_size && !halfedges.in_use(idx))
            ++idx;

        return HalfEdgeHandle(*this, idx);
    }
    FaceHandle Manifold::faces_begin()
    {
        size_t faces_full_size = faces.full_size();
        FIDX idx = 0;

        while(idx < faces_full_size && !faces.in_use(idx))
            ++idx;

        return FaceHandle(*this, idx);
    }
    VertexHandle Manifold::vertices_end()
    {
        return VertexHandle(*this, vertices.full_size());
    }
    HalfEdgeHandle Manifold::halfedges_end()
    {
        return HalfEdgeHandle(*this, halfedges.full_size());
    }
    FaceHandle Manifold::faces_end()
    {
        return FaceHandle(*this, faces.full_size());
    }

    void Manifold::remove_vertex(VertexHandle v)
    {
        vertices.remove(v.get_idx());
    }
    void Manifold::remove_halfedge(HalfEdgeHandle h)
    {
        halfedges.remove(h.get_idx());
    }
    void Manifold::remove_face(FaceHandle f)
    {
        faces.remove(f.get_idx());
    }

    VertexHandle Manifold::add_vertex(const Vertex& v)
    {
        vertices.add(v);
        return VertexHandle(*this, vertices.full_size() - 1);
    }
    HalfEdgeHandle Manifold::add_halfedge(const HalfEdge& h)
    {
        halfedges.add(h);
        return HalfEdgeHandle(*this, halfedges.full_size() - 1);
    }
    FaceHandle Manifold::add_face(const Face& f)
    {
        faces.add(f);
        return FaceHandle(*this, faces.full_size() - 1);
    }
        
        template
    void Manifold::build(unsigned int no_vertices,
                                                 const float* vertvec,
                                                 unsigned int no_faces,
                                                 const unsigned int* facevec,
                                                 const unsigned int* indices,
                                                 const int* touch);
        
        template
    void Manifold::build(unsigned long no_vertices,
                                                 const float* vertvec,
                                                 unsigned long no_faces,
                                                 const unsigned long* facevec,
                                                 const unsigned long* indices,
                                                 const int* touch);
        
        template
    void Manifold::build(int no_vertices,
                                                 const float* vertvec,
                                                 int no_faces,
                                                 const int* facevec,
                                                 const int* indices,
                                                 const int* touch);     
        
        
        template
    void Manifold::build(unsigned int no_vertices,
                                                 const double* vertvec,
                                                 unsigned int no_faces,
                                                 const unsigned int* facevec,
                                                 const unsigned int* indices,
                                                 const int* touch);
        
        template
    void Manifold::build(unsigned long no_vertices,
                                                 const double* vertvec,
                                                 unsigned long no_faces,
                                                 const unsigned long* facevec,
                                                 const unsigned long* indices,
                                                 const int* touch);
        template
    void Manifold::build(int no_vertices,
                                                 const double* vertvec,
                                                 int no_faces,
                                                 const int* facevec,
                                                 const int* indices,
                                                 const int* touch);
        

        
}