Subversion Repositories gelsvn

Rev

Rev 642 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

//
//  polarize.cpp
//  GEL
//
//  Created by J. Andreas Bærentzen on 18/03/12.
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//
#include <queue>
#include <iomanip>


#include "harmonics.h"
#include "polarize.h"
#include <CGLA/Vec2d.h>
#include <CGLA/Mat4x4d.h>
#include <CGLA/Vec3i.h>
#include <LinAlg/LapackFunc.h>
#include <HMesh/triangulate.h>
#include <HMesh/obj_save.h>
#include <HMesh/curvature.h>
#include <HMesh/quadric_simplify.h>
#include <HMesh/mesh_optimization.h>
#include <HMesh/smooth.h>
#include <HMesh/dual.h>

#include <Geometry/GridAlgorithm.h>
#include <Geometry/build_bbtree.h>
#include <Geometry/RGrid.h>
#include <Geometry/TrilinFilter.h>
#include <GLGraphics/ManifoldRenderer.h>

#include <complex>

using namespace CGLA;
using namespace Geometry;
using namespace std;
using namespace HMesh;
using namespace GLGraphics;

inline bool same_level(double a, double b) {return abs(a-b) < 1e-10;}

enum VertexStatus {
    RAW, COOKED
};


void shortest_edge_triangulate_face(Manifold& m, FaceID f0, const VertexAttributeVector<int>& level_set_id_vertex)
{
    queue<FaceID> face_queue;
    
    face_queue.push(f0);
    
    while(!face_queue.empty())
    {
        FaceID f = face_queue.front();
        face_queue.pop();
        
        // Create a vector of vertices.
        vector<VertexID> verts;
        for(Walker w = m.walker(f); !w.full_circle(); w = w.circulate_face_ccw())
        {
            FaceID fa = w.face();
            FaceID fb = f;
            assert(fa==fb);
            verts.push_back(w.vertex());
        }
        // If there are just three we are done.
        if(verts.size() == 3) continue;
        
        // Find vertex pairs that may be connected.
        vector<pair<int,int> > vpairs;
        const int N = verts.size();
        for(int i = 0; i < N - 2; ++i){
            for(int j = i + 2; j < N; ++j){
                if(verts[i] != verts[j] &&
                   !connected(m, verts[i], verts[j]) &&
                   (level_set_id_vertex[verts[i]] == 0 || level_set_id_vertex[verts[i]] != level_set_id_vertex[verts[j]])
                   )
                    vpairs.push_back(pair<int,int>(i, j));
            }
        }
        if(vpairs.empty()){
            cout << "Warning: could not triangulate a face."
            << "Probably a vertex appears more than one time in other vertex's one-ring" << endl;
            continue;
        }
        
        /* For all vertex pairs, find the edge lengths. Combine the
         vertices forming the shortest edge. */
        
        float min_len=FLT_MAX;
        int min_k = -1;
        for(size_t k = 0; k < vpairs.size(); ++k){
            int i = vpairs[k].first;
            int j = vpairs[k].second;
            float len = length(m.pos(verts[i]) - m.pos(verts[j]));
            //            cout << m.pos(verts[i]) << m.pos(verts[j]) << len << endl;
            if(len<min_len){
                min_len = len;
                min_k = k;
            }
        }
        assert(min_k != -1);
        
        if(min_k>=0)
        {
            // Split faces along edge whose midpoint is closest to isovalue
            int i = vpairs[min_k].first;
            int j = vpairs[min_k].second;
            //           cout << i << " " << j << " " << min_k << " " << vpairs.size() << endl;
            FaceID f_new = m.split_face_by_edge(f, verts[i], verts[j]);
            
            if(no_edges(m, f)>3)
                face_queue.push(f);
            if(no_edges(m, f_new)>3)
                face_queue.push(f_new);
        }
        else
            cout << "failed to triangle. Suspect NaN vertex positions!!" << endl;
        
    }
}

void flip_edges(Manifold& m, VertexAttributeVector<int> ls_id)
{
    vector<HalfEdgeID> hvec;
    for(HalfEdgeID hid : m.halfedges())
    {
        Walker w = m.walker(hid);
        if(hid< w.opp().halfedge() &&
           ls_id[w.vertex()] > 0 &&
           ls_id[w.opp().vertex()] > 0 &&
           ls_id[w.vertex()] != ls_id[w.opp().vertex()])
            hvec.push_back(hid);
    }
    
    ValencyEnergy mae;
    bool did_work = false;
    int iter=0;
    do {
        did_work = false;
        random_shuffle(begin(hvec), end(hvec));
        for(auto hid : hvec)
        {
            Walker w =m.walker(hid);
            if(mae.delta_energy(m, hid)<=0 &&
               ls_id[w.next().vertex()] != ls_id[w.opp().next().vertex()]) {
                m.flip_edge(hid);
                did_work = true;
            }
        }
    }
    while (did_work && ++iter<1000);
    cout << "flip iter" << iter << endl;
}

void compute_edge_weights(const Manifold& m, HalfEdgeAttributeVector<double>& edge_weights, FaceAttributeVector<int>& included)
{
    edge_weights = HalfEdgeAttributeVector<double>(m.allocated_halfedges(), 0);
    for(FaceIDIterator f = m.faces_begin(); f != m.faces_end(); ++f)
        if(included[*f])
        {
            for(Walker wv = m.walker(*f); !wv.full_circle(); wv = wv.circulate_face_ccw())
            {
                HalfEdgeID h = wv.halfedge();
                Vec3d p1(m.pos(wv.vertex()));
                Vec3d p2(m.pos(wv.next().vertex()));
                Vec3d p0(m.pos(wv.opp().vertex()));
                double ang = acos(min(1.0, max(-1.0, dot(normalize(p1-p0), normalize(p2-p0)))));
                double ang_opp = acos(min(1.0, max(-1.0, dot(normalize(p2-p1), normalize(p0-p1)))));
                double l = (p1-p0).length();
                edge_weights[h] += tan(ang/2) / l;
                edge_weights[wv.opp().halfedge()] += tan(ang_opp/2) / l;
            }
        }
}

template<typename T>
void smooth_fun(const Manifold& m,
                VertexAttributeVector<int>& nailed,
                VertexAttributeVector<T>& fun, int iter=100)
{
    HalfEdgeAttributeVector<double> edge_weights;
    FaceAttributeVector<int> included(m.allocated_faces(),1);
    compute_edge_weights(m,edge_weights, included);
    VertexAttributeVector<T> new_fun(m.no_vertices());
    for(int i = 0; i < iter; ++i)
    {
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
            if(!nailed[*v])
            {
                double w_sum = 0;
                new_fun[*v] = T(0);
                for(Walker wv = m.walker(*v); !wv.full_circle(); wv = wv.circulate_vertex_ccw())
                {
                    double w = edge_weights[wv.halfedge()];
                    new_fun[*v] += w * fun[wv.vertex()];
                    w_sum += w;
                }
                new_fun[*v] /= w_sum;
            }
            else
                new_fun[*v] = fun[*v];
        fun = new_fun;
    }
}

void label_connected_components(Manifold&m, int& cur_id, const vector<VertexID>& vertices,
                                const VertexAttributeVector<double>& fun,
                                const VertexAttributeVector<VertexStatus>& status,
                                VertexAttributeVector<int>& level_id)
{
    for(auto vid : vertices)
    {
        if(level_id[vid]>0)
            continue;
        
        queue<VertexID> vq;
        vq.push(vid);
        while(!vq.empty())
        {
            VertexID v = vq.front();
            vq.pop();
            level_id[v] = cur_id;
            for(Walker w = m.walker(v); !w.full_circle(); w = w.circulate_vertex_ccw())
            {
                if(status[w.vertex()]==COOKED && same_level(fun[v], fun[w.vertex()]))
                    if(level_id[w.vertex()]==0)
                        vq.push(w.vertex());
                    else if(level_id[w.vertex()] != cur_id)
                        cout << "previously labeled vertex encountered" << endl;
            }
        }
        ++cur_id;
    }
}

void connect_touched(Manifold& m, const VertexAttributeVector<int>& touched)
{
    for(FaceID fid : m.faces())
        for(Walker w = m.walker(fid);!w.full_circle(); w = w.next())
            if(touched[w.vertex()])
            {
                Walker w0 = w;
                w = w.next().next();
                do
                {
                    if(touched[w.vertex()] && w.next().halfedge() != w0.halfedge())
                    {
                        m.split_face_by_edge(fid, w0.vertex(), w.vertex());
                        break;
                    }
                    w = w.next();
                }
                while(!w.full_circle());
                break;
            }
}

void remove_shorts(Manifold& m, VertexAttributeVector<int> ls_id)
{
    double avghlen=0;
    for(auto hid : m.halfedges())
        avghlen += length(m, hid);
    avghlen /= m.no_halfedges();
    
    for(auto hid : m.halfedges())
        if(m.in_use(hid))
        {
            Walker w = m.walker(hid);
            if(ls_id[w.vertex()] > 0 &&         
               ls_id[w.vertex()] == ls_id[w.opp().vertex()] &&
               length(m, w.halfedge()) < 0.1 * avghlen &&
               precond_collapse_edge(m, hid))
                m.collapse_edge(hid);
        }
}

vector<VertexID> separate_edges(Manifold& m, const vector<VertexID>& vertices, int id,
                                VertexAttributeVector<double>& fun,
                                VertexAttributeVector<VertexStatus>& status,
                                VertexAttributeVector<int>& ls_id)
{
    VertexAttributeVector<int> touched(m.allocated_vertices(),0);
    vector<VertexID> new_vertices;
    // Cut all edges to vertices on other LS ID
    for(auto vid: vertices)
        if(ls_id[vid]==id)
        {
            vector<HalfEdgeID> edges_to_split;
            for(Walker w = m.walker(vid); !w.full_circle(); w = w.circulate_vertex_ccw())
            {
                int id = ls_id[w.vertex()];
                if(id > 0 & id != ls_id[vid])
                    edges_to_split.push_back(w.halfedge());
            }
            
            for (auto hid : edges_to_split)
            {
                VertexID vnew = m.split_edge(hid);
                fun[vnew] = fun[vid];
                m.pos(vnew) = m.pos(vid);
                status[vnew] = COOKED;
                ls_id[vnew] = ls_id[vid];
                touched[vnew] = 1;
                new_vertices.push_back(vnew);
            }
        }
    
    // Label old vertices as plain (uncooked)
    for(auto vid: vertices)
        if(ls_id[vid]==id)
        {
            status[vid] = RAW;
            ls_id[vid] = 0;
        }
    connect_touched(m, touched);
    
    return new_vertices;
}

vector<VertexID> cut_mesh(Manifold& m, VertexAttributeVector<double>& fun, double cut_val,
                          VertexAttributeVector<VertexStatus>& status)
{
    cout << "cutting @ " << cut_val << endl;
    
    vector<VertexID> new_verts;
    vector<HalfEdgeID> hidvec;
    VertexAttributeVector<int> touched(m.allocated_vertices(), 0);
    for(HalfEdgeID hid : m.halfedges())
    {
        Walker w = m.walker(hid);
        double bval = fun[w.vertex()];
        double aval = fun[w.opp().vertex()];
        if(aval<bval && aval < cut_val && cut_val <= bval)
        {
            double t = (cut_val-aval)/(bval-aval);
            Vec3d p = t*m.pos(w.vertex()) + (1.0-t)*m.pos(w.opp().vertex());
            VertexID vnew = m.split_edge(hid);
            m.pos(vnew) = p;
            status[vnew] = COOKED;
            fun[vnew] = cut_val;
            touched[vnew] = 1;
            new_verts.push_back(vnew);
        }
    }
    
    connect_touched(m, touched);
    
    return new_verts;
}

void smooth_cooked_vertices(Manifold& m, const vector<VertexID>& vertices,
                            VertexAttributeVector<VertexStatus>& status, int iter=7)
{
    for(int i=0;i<iter;++i)
    {
        VertexAttributeVector<Vec3d> npos = m.positions_attribute_vector();
        VertexAttributeVector<int> cnt(m.allocated_vertices(), 1);
        for(auto vid : vertices)
            if(m.in_use(vid))
                for(Walker w = m.walker(vid); !w.full_circle(); w = w.circulate_vertex_ccw())
                    if(status[vid]==COOKED) {
                        npos[vid] += m.pos(w.vertex());
                        ++cnt[vid];
                    }
        for(auto vid : vertices)
            if(m.in_use(vid))
                m.pos(vid) = (npos[vid])/cnt[vid];
    }
}

void remove_v5_vertices(Manifold& m, VertexAttributeVector<int>& ls_id, int id_ceiling)
{
    for(auto vid: m.vertices())
    {
        int id = ls_id[vid];
        if(id>0 && id<id_ceiling)
        {
            vector<HalfEdgeID> hit_list;
            for(Walker w = m.walker(vid); !w.full_circle(); w=w.circulate_vertex_ccw())
                if(ls_id[w.vertex()] >= id_ceiling)
                    hit_list.push_back(w.halfedge());
            
            if(hit_list.size()>1)
            {
                sort(begin(hit_list),end(hit_list),
                     [&m](HalfEdgeID a, HalfEdgeID b){return length(m,a)>length(m, b);});
                for(int i=1;i<hit_list.size();++i)
                {
                    HalfEdgeID hid = hit_list[i];
                    Walker w = m.walker(hid);
                    HalfEdgeID surplus_h = w.opp().prev().halfedge();
                    if(precond_collapse_edge(m,surplus_h))
                    {
                        m.collapse_edge(surplus_h,true);
                        m.merge_faces(m.walker(hid).face(), hid);
                    }
                }
            }
            
        }
    }
    
}

void remove_wedges(Manifold& m, VertexAttributeVector<int>& ls_id)
{
    for(auto hid : m.halfedges())
        if(m.in_use(hid))
        {
            Walker w = m.walker(hid);
            if(ls_id[w.vertex()]>0 &&
               ls_id[w.vertex()] == ls_id[w.opp().vertex()] &&
               ls_id[w.next().vertex()]>0 &&
               no_edges(m, w.face())==3 &&
               precond_collapse_edge(m, hid))
                m.collapse_edge(hid, true);
            
        }
}



int ssb(double a, double b)
{
    const double THRESH = 1e-6;
    double delta = a-b;
    if(delta<-THRESH) return -1;
    if(delta>THRESH) return 1;
    return 0;
}

void remove_vertices(Manifold& m, VertexAttributeVector<double>& fun,
                     const VertexAttributeVector<VertexStatus>& status,
                     const VertexAttributeVector<int>& level_id, double rmin, double rmax)
{
    vector<VertexID> vertices_to_push;
    for(auto vid: m.vertices())
        if(status[vid]==RAW &&
           fun[vid] >= rmin &&
           fun[vid] <= rmax)
            vertices_to_push.push_back(vid);
    
    random_shuffle(begin(vertices_to_push), end(vertices_to_push));
    
    for(auto vid : vertices_to_push)
    {
        FaceID fid = m.merge_one_ring(vid);
        if(fid != InvalidFaceID)
            shortest_edge_triangulate_face(m, fid, level_id);
    }
}


void polarize_mesh(Manifold& m, VertexAttributeVector<double>& fun, double vmin, double vmax, const int divisions, VertexAttributeVector<Vec2d>& parametrization)
{
    VertexAttributeVector<VertexStatus> status(m.allocated_vertices(), RAW);
    VertexAttributeVector<int> level_id(m.allocated_vertices(), 0);
    int cur_id = 1;
    
    double interval = (vmax-vmin)/(divisions+1);
    double cut_val = vmin + 0.065*(vmax-vmin);
    
    vector<VertexID> cut_verts = cut_mesh(m, fun, cut_val, status);
    label_connected_components(m, cur_id, cut_verts, fun, status, level_id);
    remove_vertices(m, fun, status, level_id, vmin, cut_val);
    flip_edges(m, level_id);
    
    for(int id=1;id<cur_id;++id) {
        vector<VertexID> loop_verts = separate_edges(m, cut_verts, id, fun, status, level_id);
        smooth_cooked_vertices(m, loop_verts, status, 50);
    }
    
    for(int iter=0;iter<divisions+2;++iter)
    {
        cut_val += interval;
        vector<VertexID> cut_verts = cut_mesh(m, fun,cut_val, status);
        
        int old_id = cur_id;
        label_connected_components(m, cur_id, cut_verts, fun, status, level_id);
        remove_vertices(m, fun, status, level_id, cut_val-1.01*interval, cut_val);
        
        vector<VertexID> loop_verts;
        for(int id=old_id;id<cur_id;++id)
        {
            vector<VertexID> tmp = separate_edges(m, cut_verts, id, fun, status, level_id);
            loop_verts.insert(loop_verts.end(), tmp.begin(),tmp.end());
        }
        remove_wedges(m, level_id);
        remove_v5_vertices(m, level_id, old_id);
        
        smooth_cooked_vertices(m, loop_verts, status);
        
    }
    dual(m);
    m.cleanup();
}

void simplify_polar_mesh(Manifold& m, double frac)
{
    int N_orig = m.no_vertices();
    HalfEdgeAttributeVector<int> touched(m.allocated_halfedges(),0);
    
    vector<pair<double,vector<HalfEdgeID>>> work_vector;
    for(auto hid : m.halfedges())
    {
        Walker w = m.walker(hid);
        if(!touched[hid] &&
           no_edges(m, w.face()) == 4 &&
           no_edges(m, w.opp().face()) == 4)
        {
            
            double l_sum=0;
            int n=0;
            vector<HalfEdgeID> hvec;
            
            bool abort=false;
            for(int i=0;i<2;++i)
            {
                Walker w0 = (i==0?w:w.opp().next().next().opp());
                while(!touched[w0.halfedge()])
                {
                    touched[w0.halfedge()] = 1;
                    touched[w0.opp().halfedge()] = 1;
                    hvec.push_back(w0.halfedge());
                    ++n;
                    l_sum += sqr(area(m,w0.face()));
                    if(valency(m,w0.vertex()) != 4 || valency(m, w0.opp().vertex()) != 4)
                        abort = true;
                    if(no_edges(m, w0.face())==4)
                        w0 = w0.next().next().opp();
                    else {
                        if (valency(m,w0.next().vertex())<5)
                            abort = true;
                        break;
                    }
                }
            }
            if(abort)
                continue;
            else
                work_vector.push_back(make_pair(l_sum/sqr(n),hvec));
        }
    }
    
    sort(begin(work_vector),end(work_vector));
    
    for(auto work : work_vector)
    {
        for(HalfEdgeID h :work.second)
            if(m.in_use(h) && precond_collapse_edge(m, h))
                m.collapse_edge(h,true);
            else cout << "Collapse failed ..." << endl;
        
        if(N_orig * frac > m.no_vertices())
            break;
    }
    m.cleanup();
    
}

using namespace Geometry;

const Mat4x4d fit_bounding_volume(const Vec3d& p0,
                                  const Vec3d& p7,
                                  float buf_reg,
                                  int vol_dim)
{
    Vec3d sz = p7 - p0;
    Vec3i dims(vol_dim);
    Vec3d scal_vec = (Vec3d(dims)-Vec3d(2*buf_reg+2))/sz;
    float scal = min(scal_vec[0], min(scal_vec[1],scal_vec[2]));
    
    Mat4x4d m = translation_Mat4x4d(Vec3d(0)+Vec3d(buf_reg+1));
    m *= scaling_Mat4x4d(Vec3d(scal));
    m *= translation_Mat4x4d(-p0);
    return m;
}

void smooth_and_refit(HMesh::Manifold& m_in,  HMesh::Manifold& m_ref, int iter, int vol_dim)
{
    AABBTree tree;
    
    Manifold m_tmp = m_ref;
    Vec3d p0,p7;
    bbox(m_tmp, p0, p7);
    Mat4x4d mat = fit_bounding_volume(p0, p7, 3, vol_dim);
    Mat4x4d imat = invert(mat);
    for(auto vid : m_tmp.vertices())
        m_tmp.pos(vid) = mat.mul_3D_point(m_tmp.pos(vid));
    build_AABBTree(m_tmp, tree);
    
    cout << "Done building AABB tree" << endl;
    RGrid<float> grid(Vec3i(vol_dim),FLT_MAX);
    auto F = [&](const Vec3i& p,float& v)
    {
        v =  tree.compute_signed_distance(Vec3f(p));
    };
    for_each_voxel(grid, F);
    cout << "Made distance field" << endl;
    TrilinFilter<RGrid<float>> df(&grid);
    for (int i=0;i<iter; ++i)
    {
        auto vsafe = m_in.positions_attribute_vector();
        laplacian_smooth(m_in,.25,10);
        for(auto vid : m_in.vertices())
        {
            double w = exp(4-valency(m_in, vid));
            m_in.pos(vid) *= w;
            m_in.pos(vid) += (1-w) * vsafe[vid];
        }
        float avg = 0;
        for(auto hid : m_in.halfedges())
            avg += length(m_in, hid);
        avg /= m_in.no_halfedges();
        auto npos = m_in.positions_attribute_vector();
        for(auto vid : m_in.vertices())
        {
            npos[vid] += 0.5 * avg * normal(m_in, vid);
        }
        m_in.positions_attribute_vector() = npos;
        for(auto vid : m_in.vertices())
        {
            Vec3f pos = Vec3f(mat.mul_3D_point(m_in.pos(vid)));
            if(df.in_domain(pos))
                m_in.pos(vid) = imat.mul_3D_point(Vec3d(pos - df(pos) * df.grad(pos)));
            else
                cout << "outside domain" << endl;
        }
    }
    
}

void make_height_fun(const HMesh::Manifold& m, HMesh::VertexAttributeVector<double>& fun,
                     double& vmin, double& vmax)
{
    VertexIDIterator vid = m.vertices_begin();
    VertexAttributeVector<int> nailed(m.allocated_vertices(), 0);
    smooth_fun(m, nailed, fun,0);
    vmin = vmax = m.pos(*vid)[1];
    for(; vid != m.vertices_end(); ++vid)
    {
        double v = dot(m.pos(*vid),Vec3d(0.0,1,0.00));
        fun[*vid] = v;
        vmin = min(v, vmin);
        vmax = max(v, vmax);
    }
    
}

void make_adf_fun(HMesh::Manifold& m, double t, HMesh::VertexAttributeVector<double>& F,
                  double& vmin, double& vmax)
{
    Harmonics harm(m);
    harm.compute_adf(F, t);
    VertexAttributeVector<int> nailed(m.allocated_vertices(), 0);
    vmin = vmax = F[*m.vertices_begin()];
    for(auto vid : m.vertices())
    {
        vmin = min(F[vid], vmin);
        vmax = max(F[vid], vmax);
    }
    cout << vmin << vmax << endl;
    
}