Subversion Repositories gelsvn

Rev

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

#pragma warning(disable: 4786) // disable warning C4786: symbol greater than 255 

#include <stack>
#include "TriMeshBuilder.h"

using namespace std;
using namespace CGLA;

namespace IMesh
{


        namespace
        {
                /** Neighbours is a simple class which overloads ().
                                Given an instance nbrs of this class nbrs(a,b) will
                                return true if a and b share an edge. */
                class Neighbours
                {
                        const TriMeshBuilder* const bldr;
                public:
                        
                        Neighbours(const TriMeshBuilder* const _bldr):
                                bldr(_bldr)
                        {}
                        
                        bool operator()(int a, int b)
                        {
                                Vec3i fa = bldr->face(a);
                                Vec3i fb = bldr->face(b);
                                for(int i=0;i<3;++i)
                                        for(int j=0;j<3;++j)
                                                if(fa[i]==fb[j] && fa[(i+1)%3]==fb[(j+2)%3])
                                                        return true;
                                return false;
                        }
                        
                };
        }

        
        void compute_face_normals(TriMeshBuilder& bldr, bool do_flip)
        {
                bldr.register_face_normals();
                for(int i=0;i<bldr.no_faces(); ++i)
                        {
                                Vec3f p0 = bldr.vpos(i,0);
                                Vec3f p1 = bldr.vpos(i,1);
                                Vec3f p2 = bldr.vpos(i,2);
                                Vec3f norm = cross(p1-p0,p2-p0);

                                float len = norm.length();
                                if(len > 0)
                                        norm /= len;

                                if(do_flip)
                                        bldr.add_fnorm(-norm);
                                else
                                        bldr.add_fnorm(norm);
                        }
        }


        void compute_vertex_normals(TriMeshBuilder& bldr)
        {
                AttrHandle<CGLA::Vec3f> norm_handle; 
                if(!bldr.get_vattr_handle("VA_NORM", norm_handle))
                        {
                                bldr.register_vertex_normals();
                                for(int i=0;i<bldr.no_vertices(); ++i)
                                        bldr.add_vnorm(Vec3f(0));
                        }
                for(int face_idx=0; face_idx<bldr.no_faces(); ++face_idx)
                        {
                                int i;
                                Vec3f p[3];     
                                for(i=0;i<3;++i)
                                        p[i] = bldr.vpos(face_idx,i);
                                
                                Vec3f v10 = p[1]-p[0];
                                Vec3f v20 = p[2]-p[0];
                                Vec3f v21 = p[2]-p[1];
                                Vec3f v01 = p[0]-p[1];

                                float l10 = v10.length();
                                float l20 = v20.length();
                                float l21 = v21.length();
                                float l01 = v01.length();

                                v10 = (l10>0.0f) ? v10 / l10 : Vec3f(0);
                                v20 = (l20>0.0f) ? v20 / l20 : Vec3f(0);
                                v21 = (l21>0.0f) ? v21 / l21 : Vec3f(0);
                                v01 = (l01>0.0f) ? v01 / l01 : Vec3f(0);
                                        
                                float a[3];
                                a[0] = acos(dot(v10, v20));
                                a[1] = acos(dot(v21,v01));
                                a[2] = M_PI - a[0] - a[1];

                                Vec3f fn = bldr.fnorm(face_idx);
                                for(i=0;i<3;++i)
                                        bldr.vnorm(face_idx,i) += fn * a[i];
                        }
                for(int norm_idx=0;norm_idx<bldr.no_vnorm();++norm_idx)
                        bldr.vnorm(norm_idx).normalize();
        }
        
        void compute_vertex_normals(TriMeshBuilder& bldr, 
                                                                                         AttrHandle<int> smooth_group_attr)
        {
                int face_set = bldr.register_face_set();
                bldr.register_vertex_normals(face_set);

                vector<vector<int> > per_vertex_face_vec(bldr.no_vertices());

                for(int face_idx=0; face_idx < bldr.no_faces(); ++face_idx)
                        {
                                Vec3i face = bldr.face(face_idx);
                                per_vertex_face_vec[face[0]].push_back(face_idx);
                                per_vertex_face_vec[face[1]].push_back(face_idx);
                                per_vertex_face_vec[face[2]].push_back(face_idx);
                        }
                Neighbours nbrs(&bldr);
                for(int vert_idx=0; vert_idx<bldr.no_vertices(); ++vert_idx)
                        {
                                int n_faces = per_vertex_face_vec[vert_idx].size();
                                vector<int> N(n_faces, -1);
                                for(int i=0;i<n_faces;++i)
                                        {
                                                if(N[i] == -1)
                                                        {
                                                                N[i] = bldr.add_vnorm(Vec3f(0));

                                                                stack<int> q;
                                                                q.push(i);
                                                                while(!q.empty())
                                                                        {
                                                                                int l = q.top();
                                                                                q.pop();

                                                                                int idx_l = per_vertex_face_vec[vert_idx][l];
                                                                                int sg_l = bldr.fattr(smooth_group_attr, idx_l);
                                                                                for(int j=i+1;j<n_faces;++j)
                                                                                        {
                                                                                                int idx_j = per_vertex_face_vec[vert_idx][j];
                                                                                                int sg_j = bldr.fattr(smooth_group_attr, idx_j);
                                                                                                if((N[j] == -1) && 
                                                                                                         nbrs(idx_j,idx_l) && 
                                                                                                         ((sg_j&sg_l) != 0))
                                                                                                        {
                                                                                                                N[j] = N[l];
                                                                                                                q.push(j);
                                                                                                        }
                                                                                        }
                                                                        }
                                                        }
                                        }
                                for(int k=0;k<n_faces; ++k)
                                        {
                                                assert(N[k] != -1);
                                                int face_idx = per_vertex_face_vec[vert_idx][k];
                                                Vec3i face = bldr.face(face_idx);
                                                Vec3i norm_face = bldr.face(face_idx, face_set);
                                                for(int j=0;j<3;++j)
                                                        if(face[j] == vert_idx)
                                                                norm_face[j] = N[k];
                                                bldr.face(face_idx, face_set) = norm_face;
                                        }
                        }
                compute_vertex_normals(bldr);
        }



        void compute_vertex_normals(TriMeshBuilder& bldr, float cos_ang) 
        {
                int face_set = bldr.register_face_set();
                bldr.register_vertex_normals(face_set);

                vector<vector<int> > per_vertex_face_vec(bldr.no_vertices());

                for(int face_idx=0; face_idx < bldr.no_faces(); ++face_idx)
                        {
                                Vec3i face = bldr.face(face_idx);
                                per_vertex_face_vec[face[0]].push_back(face_idx);
                                per_vertex_face_vec[face[1]].push_back(face_idx);
                                per_vertex_face_vec[face[2]].push_back(face_idx);
                        }
                Neighbours nbrs(&bldr);
                for(int vert_idx=0; vert_idx<bldr.no_vertices(); ++vert_idx)
                        {
                                int n_faces = per_vertex_face_vec[vert_idx].size();
                                vector<int> N(n_faces, -1);
                                for(int i=0;i<n_faces;++i)
                                        {
                                                if(N[i] == -1)
                                                        {
                                                                N[i] = bldr.add_vnorm(Vec3f(0));

                                                                stack<int> q;
                                                                q.push(i);
                                                                while(!q.empty())
                                                                        {
                                                                                int l = q.top();
                                                                                q.pop();

                                                                                int idx_l = per_vertex_face_vec[vert_idx][l];
                                                                                Vec3f norm_l = bldr.fnorm(idx_l);
                                                                                for(int j=i+1;j<n_faces;++j)
                                                                                        {
                                                                                                int idx_j = per_vertex_face_vec[vert_idx][j];
                                                                                                Vec3f norm_j = bldr.fnorm(idx_j);
                                                                                                if((N[j] == -1) && 
                                                                                                         nbrs(idx_j,idx_l) && 
                                                                                                         (dot(norm_l, norm_j)>cos_ang))
                                                                                                        {
                                                                                                                N[j] = N[l];
                                                                                                                q.push(j);
                                                                                                        }
                                                                                        }
                                                                        }
                                                        }
                                        }
                                for(int k=0;k<n_faces; ++k)
                                        {
                                                assert(N[k] != -1);
                                                int face_idx = per_vertex_face_vec[vert_idx][k];
                                                Vec3i face = bldr.face(face_idx);
                                                Vec3i norm_face = bldr.face(face_idx, face_set);
                                                for(int j=0;j<3;++j)
                                                        if(face[j] == vert_idx)
                                                                norm_face[j] = N[k];
                                                bldr.face(face_idx, face_set) = norm_face;
                                        }
                        }
                compute_vertex_normals(bldr);
        }
}