Subversion Repositories gelsvn

Rev

Rev 543 | Rev 572 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
514 s042372 1
/* ----------------------------------------------------------------------- *
2
* This file is part of GEL, www.imm.dtu.dk/GEL
3
* Copyright (C) the authors (see AUTHORS.txt) and DTU Informatics
4
*
5
* Principal authors:
6
*  Christian Thode Larsen (thode2d@gmail.com)
7
*  J. Andreas Baerentzen (jab@imm.dtu.dk)
8
*
9
* See LICENSE.txt for licensing information
10
* ----------------------------------------------------------------------- */
11
 
12
#include "curvature.h"
13
 
14
#include <GLGraphics/gel_glut.h>
15
 
16
#include <iostream>
17
#include <CGLA/eigensolution.h>
18
#include <CGLA/Vec2d.h>
19
#include <CGLA/Vec3d.h>
20
#include <CGLA/Mat3x3d.h>
21
#include <CGLA/Mat2x2d.h>
22
#include <CGLA/Mat2x3d.h>
23
 
24
#include <HMesh/Manifold.h>
25
#include <HMesh/AttributeVector.h>
26
#include <HMesh/x3d_save.h>
27
#include <HMesh/x3d_load.h>
28
#include <HMesh/obj_load.h>
29
#include <HMesh/mesh_optimization.h>
30
 
31
#include <LinAlg/Matrix.h>
32
#include <LinAlg/Vector.h>
33
#include <LinAlg/LapackFunc.h>
34
 
35
using namespace std;
36
 
37
using namespace LinAlg;
38
using namespace CGLA;
39
using namespace HMesh;
40
 
41
namespace HMesh
42
{
43
    namespace 
44
    {
45
        //double scal = 0.001;
46
        //double vector_scal = 0.001;
47
 
48
        template<class T> 
49
        void smooth_something_on_mesh(const Manifold& m, VertexAttributeVector<T>& vec, int smooth_steps)
50
        {
51
            for(int iter=0;iter<smooth_steps;++iter){
519 s042372 52
                VertexAttributeVector<T> new_vec(m.total_vertices());
514 s042372 53
                for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
54
                    new_vec[*v] = vec[*v];
55
                    for(HalfEdgeWalker w = m.halfedgewalker(*v); !w.full_circle(); w = w.circulate_vertex_cw()){
56
                        new_vec[*v] += vec[w.vertex()];
57
                    }
58
                    new_vec[*v] /= (valency(m, *v) + 1.0);
59
                }
60
                swap(vec,new_vec);
61
            }		
62
        }
63
    }
64
 
65
    double voronoi_area(const Manifold& m, VertexID v)
66
    {
67
        double area_mixed = 0;
68
        //For each triangle T from the 1-ring neighborhood of x
69
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw()){
70
            double f_area = area(m, w.face());
71
 
566 jab 72
            Vec3d v0(m.pos(v));
514 s042372 73
            Vec3d v1(m.pos(w.vertex()));
74
            Vec3d v2(m.pos(w.next().vertex()));
75
 
76
            double a0 = acos(dot(v1-v0, v2-v0)/(length(v1-v0)*length(v2-v0)));
77
            double a1 = acos(dot(v2-v1, v0-v1)/(length(v2-v1)*length(v0-v1)));
78
            double a2 = acos(dot(v0-v2, v1-v2)/(length(v0-v2)*length(v1-v2)));
79
 
80
            if(a0>(M_PI/2.0) && a1>(M_PI/2.0) && a2>(M_PI/2.0)) // f is non-obtuse
81
            {
82
                // Add Voronoi formula (see Section 3.3)
83
                area_mixed += (1.0/8) * 
84
                    ((1.0/tan(a1)) * sqr_length(v2-v0) + 
85
                    (1.0/tan(a2)) * sqr_length(v1-v0));
86
            }
87
            else // Voronoi inappropriate
88
            {
89
                // Add either area(f)/4 or area(f)/2
90
                if(a0>M_PI/2.0)// the angle of f at x is obtuse
91
                    area_mixed += f_area/2;
92
                else
93
                    area_mixed += f_area/4;
94
            }
95
        }
96
        return area_mixed;
97
    }
98
 
99
    double barycentric_area(const Manifold& m, VertexID v)
100
    {
101
        double barea = 0;
102
        //For each triangle T from the 1-ring neighborhood of x
103
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw()){
104
            barea += area(m, w.face())/3.0;
105
        }
106
        return barea;
107
    }
108
 
109
    void unnormalized_mean_curvature_normal(const Manifold& m, VertexID v, Vec3d& curv_normal, double& w_sum)
110
    {
111
        if(boundary(m, v))
112
            return;
113
 
114
        Vec3d vertex(m.pos(v));
115
        curv_normal = Vec3d(0);
116
        w_sum = 0;
566 jab 117
        for(HalfEdgeWalker walker = m.halfedgewalker(v); !walker.full_circle(); walker = walker.circulate_vertex_ccw()){
514 s042372 118
            Vec3d nbr(m.pos(walker.vertex()));
119
            Vec3d left(m.pos(walker.next().vertex()));
566 jab 120
            Vec3d right(m.pos(walker.opp().next().vertex()));
514 s042372 121
 
566 jab 122
            double d_left = dot(cond_normalize(nbr-left),cond_normalize(vertex-left));
123
            double d_right = dot(cond_normalize(nbr-right),cond_normalize(vertex-right));
514 s042372 124
            double a_left  = acos(min(1.0, max(-1.0, d_left)));
125
            double a_right = acos(min(1.0, max(-1.0, d_right)));
126
 
566 jab 127
            double w = 1.0/(1e-300+tan(a_left));
128
            w += 1.0/(1e-300+tan(a_right));
129
//            double w = sin(a_left + a_right) / (1e-300 + sin(a_left)*sin(a_right));
130
            curv_normal += w * (nbr-vertex);
514 s042372 131
            w_sum += w;
132
        }
133
 
134
    }
135
 
136
    Vec3d mean_curvature_normal(const Manifold& m, VertexID v)
137
    {
138
        Vec3d curv_normal;
139
        double w_sum;
140
        unnormalized_mean_curvature_normal(m, v, curv_normal, w_sum);
141
 
142
        return curv_normal / (4*voronoi_area(m, v));
143
    }
144
 
145
    double sum_curvatures(const Manifold& m, VertexAttributeVector<double>& curvature)
146
    {
147
        double sum = 0;
148
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
149
            if(boundary(m, *v))
150
                continue;	
151
            sum += curvature[*v] * voronoi_area(m, *v);
152
        }
153
        return sum;
154
    }
155
 
156
 
157
    double gaussian_curvature_angle_defect(const Manifold& m, VertexID v)
158
    {
159
        if(boundary(m, v))
160
            return 0;
161
 
162
        Vec3f vertex(m.pos(v));
163
        vector<Vec3d> edges;
164
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw()){
165
            Vec3d e(normalize(m.pos(w.vertex()) - vertex));
166
            edges.push_back(e);
167
        }
168
        int N=edges.size();
169
        double angle_sum = 0;
170
        for(int i = 0; i < N; ++i)
171
        {
172
            double dot_prod = 
173
                s_max(-1.0, s_min(1.0, dot(edges[i],edges[(i+1)%N])));
174
            angle_sum += acos(dot_prod);
175
        }
176
        return (2*M_PI - angle_sum)/voronoi_area(m, v);
177
 
178
    }
179
 
180
    Mat3x3d curvature_tensor(const Manifold& m, HalfEdgeID h)
181
    {
182
        if(boundary(m, h))
183
            return Mat3x3d(0);
184
 
185
        HalfEdgeWalker w = m.halfedgewalker(h);
186
        Vec3d edge(m.pos(w.vertex()) - m.pos(w.opp().vertex()));
187
        double edge_len = length(edge);
188
        edge /= edge_len;
189
 
190
        Vec3d h_norm(normal(m, w.face()));
191
        Vec3d h_opp_norm(normal(m, w.opp().face()));
192
 
193
        Vec3d nc = cross(h_norm, h_opp_norm);
194
 
195
        double sign = (dot(nc, edge) >= 0) ? 1 : -1;
196
        double beta = asin(nc.length());
197
 
198
        Mat3x3d mat;
199
        outer_product(edge, edge, mat);
200
        return sign * edge_len * beta * mat;
201
    }
202
 
203
    Mat3x3d curvature_tensor_from_edges(const Manifold& m, VertexID v)
204
    {
205
        Mat3x3d curv_tensor(0);
206
 
207
        if(boundary(m, v))
208
            return curv_tensor;
209
 
210
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw())
211
            curv_tensor += 0.5*curvature_tensor(m, w.halfedge());
212
 
213
        curv_tensor /= voronoi_area(m, v);
214
 
215
        return curv_tensor;
216
    }
217
 
218
 
219
    void curvature_tensor_paraboloid(const Manifold& m, VertexID v, Mat2x2d& curv_tensor, Mat3x3d& frame)
220
    {
221
        if(boundary(m, v))
222
            return;
223
        // First estimate the normal and compute a transformation matrix
224
        // which takes us into tangent plane coordinates.
225
        Vec3d Norm = Vec3d(normal(m, v));
226
        Vec3d X,Y;
227
        orthogonal(Norm,X,Y);
228
        frame = Mat3x3d(X,Y,Norm);
229
        Vec3d centre(m.pos(v));
230
 
231
        vector<Vec3d> points;
232
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw())
233
            points.push_back(Vec3d(m.pos(w.vertex())));
234
 
235
        int N = points.size();
236
 
237
        CVector b(N);
238
        // Compute the matrix of parameter values
239
        CMatrix PMat(N, 3);
240
        for(int i = 0; i < N; ++i){
241
            Vec3d p = frame * (points[i]-centre);
242
            b[i] = p[2];
243
 
244
            PMat.set(i,0,0.5*sqr(p[0]));
245
            PMat.set(i,1,p[0]*p[1]);
246
            PMat.set(i,2,0.5*sqr(p[1]));
247
        }
248
 
249
        // Compute the coefficients of the polynomial surface
250
        CVector x(3);
251
        x = LinearLSSolve(PMat,b);
252
        if(isnan(x[0])) cout << __LINE__ << " " << PMat << b << endl ;
253
 
254
        // Finally compute the shape tensor from the coefficients
255
        // using the first and second fundamental forms.
256
        curv_tensor =Mat2x2d(x[0],x[1],x[1],x[2]);
257
 
258
    }
259
 
260
    void curvature_tensors_from_edges(const Manifold& m, VertexAttributeVector<Mat3x3d>& curvature_tensors)
261
    {
262
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
263
            curvature_tensors[*v] = curvature_tensor_from_edges(m, *v);
264
    }
265
 
266
    void smooth_curvature_tensors(const Manifold& m, VertexAttributeVector<Mat3x3d>& curvature_tensors)
267
    {
529 s042372 268
        assert(curvature_tensors.size() == m.total_vertices());
519 s042372 269
        VertexAttributeVector<Mat3x3d> tmp_curvature_tensors(m.total_vertices());
514 s042372 270
        double tmp_area;
271
 
272
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
273
            if(boundary(m, *v))
274
                continue;
275
            double a = voronoi_area(m, *v);
276
            tmp_curvature_tensors[*v] = curvature_tensors[*v] * a;
277
            tmp_area = a;
278
            for(HalfEdgeWalker w = m.halfedgewalker(*v); !w.full_circle(); w = w.circulate_vertex_cw()){
279
                if(!boundary(m, w.vertex())){
280
                    double a = voronoi_area(m, w.vertex());
281
                    tmp_curvature_tensors[*v] += curvature_tensors[w.vertex()]*a;
282
                    tmp_area += a;
283
                }
284
                tmp_curvature_tensors[*v] /= tmp_area;
285
            }
286
        }
287
        curvature_tensors = tmp_curvature_tensors;
288
    }
289
 
290
    void gaussian_curvature_angle_defects(const Manifold& m, VertexAttributeVector<double>& curvature, int smooth_steps)
291
    {
292
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
293
            curvature[*v] = gaussian_curvature_angle_defect(m, *v);
294
 
295
        smooth_something_on_mesh(m, curvature, smooth_steps);
296
    }
297
 
298
    void mean_curvatures(const Manifold& m, VertexAttributeVector<double>& curvature, int smooth_steps)
299
    {
543 jab 300
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
301
			if(!boundary(m,*v))
302
			{
566 jab 303
				Vec3d N = -mean_curvature_normal(m, *v);
543 jab 304
				curvature[*v] = length(N) * sign(dot(N,Vec3d(normal(m, *v))));
305
			}	
514 s042372 306
        smooth_something_on_mesh(m, curvature, smooth_steps);	
307
    }
308
 
309
 
310
    void curvature_paraboloids( const Manifold& m, 
311
                                VertexAttributeVector<Vec3d>& min_curv_direction, 
312
                                VertexAttributeVector<Vec3d>& max_curv_direction,
313
                                VertexAttributeVector<double>& curvature)
314
    {
315
 
316
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
317
            Mat2x2d tensor;
318
            Mat3x3d frame;
319
            curvature_tensor_paraboloid(m, *v, tensor, frame);
320
 
321
            Mat2x2d Q,L;
322
            int s = power_eigensolution(tensor, Q, L);
323
 
324
            if(s < 2)	
325
                cout << tensor << Q << L << endl;
326
 
327
            int max_idx = 0;
328
            int min_idx = 1;
329
 
330
            if(fabs(L[max_idx][max_idx])<fabs(L[min_idx][min_idx])) swap(max_idx, min_idx);
331
 
332
            Mat3x3d frame_t = transpose(frame);
333
 
566 jab 334
            max_curv_direction[*v] = cond_normalize(frame_t * Vec3d(Q[max_idx][0], Q[max_idx][1], 0));
514 s042372 335
 
566 jab 336
            min_curv_direction[*v] = cond_normalize(frame_t * Vec3d(Q[min_idx][0], Q[min_idx][1], 0));
514 s042372 337
 
338
            curvature[*v] = L[0][0]*L[1][1];
339
        }
340
    }
341
 
342
 
343
    void curvature_from_tensors(const Manifold& m,
344
                                const VertexAttributeVector<Mat3x3d>& curvature_tensors,
345
                                VertexAttributeVector<Vec3d>& min_curv_direction,
346
                                VertexAttributeVector<Vec3d>& max_curv_direction,
347
                                VertexAttributeVector<double>& curvature)
348
    {
529 s042372 349
        assert(curvature_tensors.size() == m.total_vertices());
514 s042372 350
 
351
        double max_val = -1e30;
352
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
353
            Mat3x3d C,Q,L;
354
            C = curvature_tensors[*v];
355
            int s = power_eigensolution(C, Q, L);
356
            Vec3d dmin, dmax;
357
            if(s == 0)
358
            {
359
                Vec3d n(normal(m, *v));
360
                orthogonal(n, dmin, dmax);
361
                curvature[*v] = 0;
362
                cout << " rank 0 " << endl;
363
            }
364
            else if(s == 1)
365
            {
366
                Vec3d n(normal(m, *v));
367
                dmin = normalize(Q[0]);
368
                dmax = cross(n, dmin);
369
                curvature[*v] = 0;
370
                cout << " rank 1 " << endl;
371
            }
372
            else
373
            {
374
                /*				Vec3d l(fabs(L[0][0]), fabs(L[1][1]), fabs(L[2][2]));
375
 
376
                int z_idx=2;
377
                if(s==3)
378
                {
379
                if(l[0] < l[1])
380
                z_idx = l[0]<l[2] ? 0 : 2;
381
                else
382
                z_idx = l[1]<l[2] ? 1 : 2;
383
                }
384
                int max_idx = (z_idx + 1) % 3;
385
                int min_idx = (z_idx + 2) % 3;
386
 
387
                if(l[max_idx] < l[min_idx]) swap(max_idx, min_idx);
388
                */
389
                int max_idx = 0;
390
                int min_idx = 1;
391
                // Yes - the biggest eigenvalue corresponds to the min direction
392
                // and vice versa.
393
                dmin = normalize(Q[max_idx]);
394
                dmax = normalize(Q[min_idx]);
395
 
396
                curvature[*v] = L[max_idx][max_idx]*L[min_idx][min_idx];
397
 
398
            }
399
            min_curv_direction[*v] = dmin;
400
            max_curv_direction[*v] = dmax;
401
            max_val = max(fabs(curvature[*v]), max_val);
402
 
403
        }
404
        //scal = 1.0/max_val;
405
    }
406
}
407