Subversion Repositories gelsvn

Rev

Rev 178 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <iostream>

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


namespace HMesh
{
        using namespace std;
        using namespace CGLA;

        void Manifold::remove_unused()
        {
    for(size_t i=0;i<unused_vertices.size(); ++i)
                        vertex_db.erase(unused_vertices[i]);

    std::vector<VertexIter> vdummy(0);
    unused_vertices = vdummy;

    for(size_t i=0;i<unused_faces.size(); ++i)
                        face_db.erase(unused_faces[i]);

    std::vector<FaceIter> fdummy(0);
    unused_faces = fdummy;

    for(size_t i=0;i<unused_halfedges.size(); ++i)
                        halfedge_db.erase(unused_halfedges[i]);

    std::vector<HalfEdgeIter> hdummy(0);
    unused_halfedges = hdummy;
        }
        
        void Manifold::clear()
        {
                vertex_db.clear();
                face_db.clear();
                halfedge_db.clear();

                std::vector<VertexIter> vdummy(0);
                unused_vertices = vdummy;
                                        
                std::vector<FaceIter> fdummy(0);
                unused_faces = fdummy;

                std::vector<HalfEdgeIter> hdummy(0);
                unused_halfedges = hdummy;
        }


        void Manifold::erase_halfedge(HalfEdgeIter h)
        {
                if(erase_immediately)
                        halfedge_db.erase(h);
                else
                        {
                                unused_halfedges.push_back(h);
                                HalfEdge h_dummy;
                                (*h) = h_dummy;
                        }
        }

        void Manifold::erase_vertex(VertexIter v)
        {
                if(erase_immediately)
                        vertex_db.erase(v);
                else
                        {
                                unused_vertices.push_back(v);
                                Vertex v_dummy(v->pos);
                                (*v) = v_dummy;
                        }
        }

        void Manifold::erase_face(FaceIter f)
        {
                if(erase_immediately)
                        face_db.erase(f);
                else
                        {
                                unused_faces.push_back(f);
                                Face f_dummy;
                                (*f) = f_dummy;
                        }
        }




        void Manifold::get_bbox(Vec3f& pmin, Vec3f& pmax)
        {
    VertexIter vi = vertices_begin();
    pmin = pmax = vi->pos;
    for(++vi;vi != vertices_end(); ++vi)
                        {
        pmin = v_min(vi->pos, pmin);
        pmax = v_max(vi->pos, pmax);
                        }
        }

        void Manifold::get_bsphere(CGLA::Vec3f& c, float& r)
        {
    Vec3f p0,p7;
    get_bbox(p0, p7);
    Vec3f rad = (p7 - p0)/2.0;
    c = p0 + rad;
    r = rad.length();
        }


        VertexIter Manifold::split_edge(HalfEdgeIter h)
        {
    HalfEdgeIter ho = h->opp;
    VertexIter v  = h->vert;
    VertexIter vo = ho->vert;
    Vec3f np = (v->pos+vo->pos)/2.0f;

    VertexIter vn = create_vertex(np);
    vn->he = h;

    HalfEdgeIter hn = create_halfedge();
    HalfEdgeIter hno = create_halfedge();

    vo->he = hn;
    v->he = ho;

    glue(hn,hno);
    link(h->prev, hn);
    link(hn,h);
    hn->vert = vn;

    link(hno,ho->next);
    link(ho, hno);
    hno->vert = vo;
    ho->vert = vn;

    if(h->face != NULL_FACE_ITER)
                        h->face->last = hn;
    if(ho->face != NULL_FACE_ITER)
                        ho->face->last = ho;

    hn->face = h->face;
    hno->face = ho->face;

    check_boundary_consistency(vn);
    check_boundary_consistency(v);
    check_boundary_consistency(vo);
    return vn;
        }


        void Manifold::remove_face_if_degenerate(HalfEdgeIter h0)
        {
    if(h0->next->next == h0)
                        {
        HalfEdgeIter h1 = h0->next;

        HalfEdgeIter h0o = h0->opp;
        HalfEdgeIter h1o = h1->opp;

        glue(h0o, h1o);

        VertexIter v0 = h1->vert;
        VertexIter v1 = h0->vert;
        v0->he = h1o;
        v1->he = h0o;

        if(h0->face != NULL_FACE_ITER)
                                        erase_face(h0->face);
        erase_halfedge(h0);
        erase_halfedge(h1);

        check_boundary_consistency(v0);
        check_boundary_consistency(v1);

                        }
        }

        bool Manifold::collapse_precond(HalfEdgeIter h)
        {
    VertexIter v1 = h->opp->vert;
    VertexIter v2 = h->vert;

    std::vector<Vertex*> link1;
    VertexCirculator vc1(v1);
    for(;!vc1.end();++vc1)
                        link1.push_back(&(*vc1.get_vertex()));
    assert(link1.size()>=2);

    std::vector<Vertex*> link2;
    VertexCirculator vc2(v2);
    for(;!vc2.end();++vc2)
                        link2.push_back(&(*vc2.get_vertex()));
    assert(link2.size()>=2);

    sort(link1.begin(),link1.end());
    sort(link2.begin(),link2.end());

    vector<Vertex*> lisect;
    back_insert_iterator<vector<Vertex*> > lii(lisect);

    set_intersection(link1.begin(), link1.end(),
                     link2.begin(), link2.end(),
                     lii);


    // If the adjacent face is a triangle (see 2)
    int k=0;
    if(h->next->next->next == h)
                        {
        // VALENCY 4 TEST
        if(valency(h->next->vert)<4)
                                        return false;

        vector<Vertex*>::iterator iter;
        iter = find(lisect.begin(),     lisect.end(),&(*h->next->vert));
        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)
                        {
        // VALENCY 4 TEST
        if(valency(h->opp->next->vert)<4)
                                        return false;

        vector<Vertex*>::iterator iter;
        iter = find(lisect.begin(),     lisect.end(),&(*h->opp->next->vert));
        assert(iter != lisect.end());
        lisect.erase(iter);
        ++k;

                        }
    if(lisect.size() !=0) // See 3.
                        return false;

    // TETRAHEDRON TEST
    if(k==2 && (link1.size()+link2.size()==6))
                        return false;

    // Test that we are not merging holes (see 6)
    if(is_boundary(v1) && is_boundary(v2) &&
                         (h->face != NULL_FACE_ITER) &&
                         (h->opp->face != NULL_FACE_ITER))
                        return false;


    return true;
        }


        void Manifold::collapse_halfedge(HalfEdgeIter h, bool avg_vertices)
        {
    VertexIter v = h->opp->vert;
    HalfEdgeIter ho = h->opp;
    VertexIter n = h->vert;

    if(avg_vertices)
                        n->pos = ((v->pos + n->pos) / 2.0f);

    HalfEdgeIter hn = h->next;
    HalfEdgeIter hp = h->prev;
    HalfEdgeIter hon = ho->next;
    HalfEdgeIter hop = ho->prev;

    VertexCirculator vc(v);
    for(;!vc.end();++vc)
                        vc.get_opp_halfedge()->vert = n;

    n->he = h->next;

    link(hp, hn);
    if(h->face != NULL_FACE_ITER)
                        h->face->last = hn;

    link(hop, hon);
    if(ho->face != NULL_FACE_ITER)
                        ho->face->last = hon;



    erase_vertex(v);
    erase_halfedge(h);
    erase_halfedge(ho);

    remove_face_if_degenerate(hn);
    remove_face_if_degenerate(hon);

    check_boundary_consistency(n);
        }

        bool Manifold::is_valid()
        {
    HalfEdgeIter he0 = halfedges_begin();
    while(he0 != halfedges_end())
                        {
        if(he0->prev == NULL_HALFEDGE_ITER)
                                        {
            cout << "Halfedge lacks previous" << endl;
            return false;
                                        }
        if(he0->next == NULL_HALFEDGE_ITER)
                                        {
            cout << "Halfedge lacks next" << endl;
            return false;
                                        }
        if(he0->opp == NULL_HALFEDGE_ITER)
                                        {
            cout << "Halfedge lacks opposite" << endl;
            return false;
                                        }
        if(he0->vert == NULL_VERTEX_ITER)
                                        {
            cout << "Halfedge lacks vertex" << endl;
            return false;
                                        }
        ++he0;
                        }

    VertexIter vi = vertices_begin();
    while(vi != vertices_end())
                        {
        std::vector<Vertex*> link;
        VertexCirculator vc(vi);
        int k=0;
        for(;!vc.end();++vc,++k)
                                        {
            if(vc.get_halfedge() == NULL_HALFEDGE_ITER)
                                                        {
                cout << "Vertex has null outgoing he" << endl;
                return false;
                                                        }
            Vertex* x = &(*vc.get_vertex());
            if(find(link.begin(), link.end(), x) != link.end())
                                                        {
                cout << "Vertex appears two times in one-ring of other vertex" << endl;
                return false;
                                                        }
            link.push_back(x);
            if(k==1e6)
                                                        {
                cout << "infin. loop around vertex" << endl;
                return false;
                                                        }
                                        }
        if(link.size()==2)
                                        {
                                                if(!is_boundary(vi))
                                                        cout << "Warning: A vertex with only two incident edges" << endl;
                                                else
                                                        cout << "Comment: A boundary vertex with only two incident edges" << endl;
                                        }
        assert(link.size()>=2);
        ++vi;
                        }

    HMesh::FaceIter f = faces_begin();
    for(;f != faces_end(); ++f)
                        {
        if(no_edges(f)<3)
                                        {
            cout << "Degenerate face" << endl;
                                        }
        FaceCirculator fc(f);
        int k=0;
        while(!fc.end())
                                        {
            if(fc.get_halfedge()->face != f)
                                                        {
                cout << "Inconsistent face" << endl;
                return false;
                                                        }
            if(++k==1e6) cout << "infin. loop around face" << endl;
            ++fc;
                                        }
                        }
    return true;
        }

        FaceIter Manifold::split_face(FaceIter f, VertexIter v0, VertexIter 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 halfedge emanating from v0 which belongs to the
    // face, we need to split.
    VertexCirculator vc0(v0);
    while(vc0.get_halfedge()->face != f && !vc0.end()) vc0++;
    assert(!vc0.end());
    HalfEdgeIter h0 = vc0.get_halfedge();
    assert(h0->face == f); // Sanity check.

    // 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.
    HalfEdgeIter h = h0;
    while(h->vert != v1)
                        h = h->next;

    // Create a new halfedge ha which connects v1 and v0 closing the first
    // loop. This new halfedge becomes f->last
    assert(h != h0);
    HalfEdgeIter h1 = h->next;
    HalfEdgeIter ha = create_halfedge();
    link(h,ha);
    link(ha, h0);
    ha->face = f;
    ha->vert = v0;
    f->last = ha;

    // Create a new face, f2, and set all halfedges in the remaining part of
    // the polygon to point to this face.
    h = h1;
    FaceIter f2 = create_face();
    while(h->vert != v0)
                        {
        h->face = f2;
        h = h->next;
                        }
    h->face = f2;
    assert(h != h1);

    // Create a new halfedge hb to connect v0 and v1. this new halfedge
    // becomes f2->last
    HalfEdgeIter hb = create_halfedge();
    link(h,hb);
    link(hb, h1);
    hb->face = f2;
    hb->vert = v1;
    f2->last = hb;

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

    // Assert that the pointers are sane :-)
    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 the newly created face
    return f2;
        }

        void Manifold::triangulate(FaceIter f)
        {
    // Assert sanity of pointers
    assert(f->last->next->next != f->last);
    assert(f->last->next != f->last);
    assert(--(++f) == f);
    // As long as f is not a triangle.
    while(f->last->next->next->next != f->last)
                        {
        assert(no_edges(f) != 3);
        // Call split face to split f into a triangle
        // from the first three vertices and a polygon
        // containing the rest of the vertices. In the
        // next iteration, f becomes this polygon.

        assert(f->last->next->next != f->last);
        VertexIter v0 = f->last->vert;
        VertexIter v1 = f->last->next->next->vert;
        assert(v0 != v1);
        f = split_face(f, v0, v1);
                        }
        }

        bool Manifold::merge_faces(FaceIter f1, HalfEdgeIter h)
        {
    assert(h->face == f1);

    HalfEdgeIter ho = h->opp;
    FaceIter f2 = ho->face;
    HalfEdgeIter hn = h->next;
    HalfEdgeIter hon = ho->next;

    if(hn->vert == hon->vert) return false;

    HalfEdgeIter hp = h->prev;
    HalfEdgeIter hop = ho->prev;
    VertexIter v  = h->vert;
    VertexIter vo = ho->vert;

    link(hop, hn);
    v->he = hn;

    link(hp, hon);
    vo->he = hon;

    f1->last = hn;
    HalfEdgeIter hx = hon;
    assert(hx->face == f2);
    while(hx->face != f1)
                        {
        hx->face = f1;
        hx = hx->next;
                        }

    check_boundary_consistency(v);
    check_boundary_consistency(vo);

    erase_halfedge(h);
    erase_halfedge(ho);
    erase_face(f2);

    return true;
        }


        VertexIter Manifold::safe_triangulate(FaceIter f)
        {
    Vec3f p(0.0f);
    FaceCirculator fc(f);
    for(;!fc.end(); ++fc)
                        p += fc.get_vertex()->pos;
    int n = fc.no_steps();
    p /= n;
    VertexIter v = create_vertex(p);
    face_insert_point(f,v);
    return v;
        }


        void Manifold::face_insert_point(FaceIter f, VertexIter v)
        {
    vector<HalfEdgeIter> eout;
    vector<HalfEdgeIter> ein;

    HalfEdgeIter hlast = f->last;
    HalfEdgeIter h = hlast;

    do
                        {
        HalfEdgeIter hn = h->next;

        HalfEdgeIter o = create_halfedge();
        HalfEdgeIter i = create_halfedge();

        FaceIter fn = create_face();
        i->face = fn;
        i->vert = v;
        o->face = fn;
        o->vert = h->opp->vert;
        h->face = fn;
        fn->last = o;

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

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

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

    int N = eout.size();
    for(int i=0;i<N;++i)
                        glue(ein[i],eout[(i+1)%N]);

    v->he = eout[0];
    erase_face(f);
        }


        bool Manifold::flip(HalfEdgeIter h1)
        {
    FaceIter f1 = h1->face;
    HalfEdgeIter h2 = h1->opp;
    FaceIter f2 = h2->face;

    if(f1 == NULL_FACE_ITER || f2 == NULL_FACE_ITER)
                        return false;

    // We can only flip an edge if both incident polygons
    // are triangles. Otherwise, this operation makes no sense.
    if(no_edges(f1) != 3)
                        return false;
    if(no_edges(f2) !=3)
                        return false;

    // If the valency of either vertex incident on the edge
    // being flipped is three, we cannot perform this operation.
    // That is because the vertex would then have valency two
    // after the operation which means it would be degenerate.
    VertexIter va = h1->vert;
    VertexIter vb = h2->vert;
    int vala = valency(va);
    int valb = valency(vb);
    if((vala <= 3 && !is_boundary(va)) ||
                         (valb <= 3 && !is_boundary(vb)))
                        return false;

    // If the two vertices being connected by the flip are already
    // connected, the mesh would become degenerate, so we disallow
    // the operation.
    VertexIter vc = h1->next->vert;
    VertexIter vd = h2->next->vert;
    if(is_connected(vc,vd))
                        return false;

    HalfEdgeIter ha = h1->next;
    HalfEdgeIter hb = h1->prev;
    HalfEdgeIter hc = h2->next;
    HalfEdgeIter hd = h2->prev;

    hd->face = f1;
    hb->face = f2;
    f1->last = h1;
    f2->last = h2;

    link(ha,h1);
    link(h1,hd);
    link(hd,ha);

    link(hc,h2);
    link(h2,hb);
    link(hb,hc);

    h1->vert = vd;
    h2->vert = vc;

    va->he = ha;
    vb->he = hc;

    check_boundary_consistency(va);
    check_boundary_consistency(vb);
    return true;
        }

        /** Give each vertex a unique id corresponding to its iterator
                        position */
        void Manifold::enumerate_vertices()
        {
    int i=0;
    for(VertexIter vi=vertices_begin(); vi != vertices_end(); ++vi)
                        vi->touched = i++;
        }

        /** Give each halfedge a unique id corresponding to its iterator
                        position */
        void Manifold::enumerate_halfedges()
        {
    int i=0;
    for(HalfEdgeIter h=halfedges_begin(); h != halfedges_end(); ++h)
                        h->touched = i++;
        }

        /** Give each face a unique id corresponding to its iterator
                        position */
        void Manifold::enumerate_faces()
        {
    int i=0;
    for(FaceIter f=faces_begin(); f != faces_end(); ++f)
                        f->touched = i++;
        }


}