Subversion Repositories gelsvn

Rev

Rev 529 | Rev 566 | 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
 
72
            Vec3d v1(m.pos(w.vertex()));
73
            Vec3d v2(m.pos(w.next().vertex()));
74
            Vec3d v0(m.pos(w.next().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;
117
        for(HalfEdgeWalker walker = m.halfedgewalker(v); !walker.full_circle(); walker = walker.circulate_vertex_cw()){
118
            Vec3d nbr(m.pos(walker.vertex()));
119
            Vec3d left(m.pos(walker.next().vertex()));
120
            Vec3d right(m.pos(walker.opp().prev().opp().vertex()));
121
 
122
            double d_left = dot(normalize(nbr-left),
123
                normalize(vertex-left));
124
            double d_right = dot(normalize(nbr-right),
125
                normalize(vertex-right));
126
            double a_left  = acos(min(1.0, max(-1.0, d_left)));
127
            double a_right = acos(min(1.0, max(-1.0, d_right)));
128
 
129
            double w = 1.0/tan(a_left) + 1.0/tan(a_right);
130
 
131
            curv_normal += w * (vertex-nbr);
132
            w_sum += w;
133
        }
134
 
135
    }
136
 
137
    Vec3d mean_curvature_normal(const Manifold& m, VertexID v)
138
    {
139
        Vec3d curv_normal;
140
        double w_sum;
141
        unnormalized_mean_curvature_normal(m, v, curv_normal, w_sum);
142
 
143
        return curv_normal / (4*voronoi_area(m, v));
144
    }
145
 
146
    double sum_curvatures(const Manifold& m, VertexAttributeVector<double>& curvature)
147
    {
148
        double sum = 0;
149
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
150
            if(boundary(m, *v))
151
                continue;	
152
            sum += curvature[*v] * voronoi_area(m, *v);
153
        }
154
        return sum;
155
    }
156
 
157
 
158
    double gaussian_curvature_angle_defect(const Manifold& m, VertexID v)
159
    {
160
        if(boundary(m, v))
161
            return 0;
162
 
163
        Vec3f vertex(m.pos(v));
164
        vector<Vec3d> edges;
165
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw()){
166
            Vec3d e(normalize(m.pos(w.vertex()) - vertex));
167
            edges.push_back(e);
168
        }
169
        int N=edges.size();
170
        double angle_sum = 0;
171
        for(int i = 0; i < N; ++i)
172
        {
173
            double dot_prod = 
174
                s_max(-1.0, s_min(1.0, dot(edges[i],edges[(i+1)%N])));
175
            angle_sum += acos(dot_prod);
176
        }
177
        return (2*M_PI - angle_sum)/voronoi_area(m, v);
178
 
179
    }
180
 
181
    Mat3x3d curvature_tensor(const Manifold& m, HalfEdgeID h)
182
    {
183
        if(boundary(m, h))
184
            return Mat3x3d(0);
185
 
186
        HalfEdgeWalker w = m.halfedgewalker(h);
187
        Vec3d edge(m.pos(w.vertex()) - m.pos(w.opp().vertex()));
188
        double edge_len = length(edge);
189
        edge /= edge_len;
190
 
191
        Vec3d h_norm(normal(m, w.face()));
192
        Vec3d h_opp_norm(normal(m, w.opp().face()));
193
 
194
        Vec3d nc = cross(h_norm, h_opp_norm);
195
 
196
        double sign = (dot(nc, edge) >= 0) ? 1 : -1;
197
        double beta = asin(nc.length());
198
 
199
        Mat3x3d mat;
200
        outer_product(edge, edge, mat);
201
        return sign * edge_len * beta * mat;
202
    }
203
 
204
    Mat3x3d curvature_tensor_from_edges(const Manifold& m, VertexID v)
205
    {
206
        Mat3x3d curv_tensor(0);
207
 
208
        if(boundary(m, v))
209
            return curv_tensor;
210
 
211
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw())
212
            curv_tensor += 0.5*curvature_tensor(m, w.halfedge());
213
 
214
        curv_tensor /= voronoi_area(m, v);
215
 
216
        return curv_tensor;
217
    }
218
 
219
 
220
    void curvature_tensor_paraboloid(const Manifold& m, VertexID v, Mat2x2d& curv_tensor, Mat3x3d& frame)
221
    {
222
        if(boundary(m, v))
223
            return;
224
        // First estimate the normal and compute a transformation matrix
225
        // which takes us into tangent plane coordinates.
226
        Vec3d Norm = Vec3d(normal(m, v));
227
        Vec3d X,Y;
228
        orthogonal(Norm,X,Y);
229
        frame = Mat3x3d(X,Y,Norm);
230
        Vec3d centre(m.pos(v));
231
 
232
        vector<Vec3d> points;
233
        for(HalfEdgeWalker w = m.halfedgewalker(v); !w.full_circle(); w = w.circulate_vertex_cw())
234
            points.push_back(Vec3d(m.pos(w.vertex())));
235
 
236
        int N = points.size();
237
 
238
        CVector b(N);
239
        // Compute the matrix of parameter values
240
        CMatrix PMat(N, 3);
241
        for(int i = 0; i < N; ++i){
242
            Vec3d p = frame * (points[i]-centre);
243
            b[i] = p[2];
244
 
245
            PMat.set(i,0,0.5*sqr(p[0]));
246
            PMat.set(i,1,p[0]*p[1]);
247
            PMat.set(i,2,0.5*sqr(p[1]));
248
        }
249
 
250
        // Compute the coefficients of the polynomial surface
251
        CVector x(3);
252
        x = LinearLSSolve(PMat,b);
253
        if(isnan(x[0])) cout << __LINE__ << " " << PMat << b << endl ;
254
 
255
        // Finally compute the shape tensor from the coefficients
256
        // using the first and second fundamental forms.
257
        curv_tensor =Mat2x2d(x[0],x[1],x[1],x[2]);
258
 
259
    }
260
 
261
    void curvature_tensors_from_edges(const Manifold& m, VertexAttributeVector<Mat3x3d>& curvature_tensors)
262
    {
263
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
264
            curvature_tensors[*v] = curvature_tensor_from_edges(m, *v);
265
    }
266
 
267
    void smooth_curvature_tensors(const Manifold& m, VertexAttributeVector<Mat3x3d>& curvature_tensors)
268
    {
529 s042372 269
        assert(curvature_tensors.size() == m.total_vertices());
519 s042372 270
        VertexAttributeVector<Mat3x3d> tmp_curvature_tensors(m.total_vertices());
514 s042372 271
        double tmp_area;
272
 
273
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
274
            if(boundary(m, *v))
275
                continue;
276
            double a = voronoi_area(m, *v);
277
            tmp_curvature_tensors[*v] = curvature_tensors[*v] * a;
278
            tmp_area = a;
279
            for(HalfEdgeWalker w = m.halfedgewalker(*v); !w.full_circle(); w = w.circulate_vertex_cw()){
280
                if(!boundary(m, w.vertex())){
281
                    double a = voronoi_area(m, w.vertex());
282
                    tmp_curvature_tensors[*v] += curvature_tensors[w.vertex()]*a;
283
                    tmp_area += a;
284
                }
285
                tmp_curvature_tensors[*v] /= tmp_area;
286
            }
287
        }
288
        curvature_tensors = tmp_curvature_tensors;
289
    }
290
 
291
    void gaussian_curvature_angle_defects(const Manifold& m, VertexAttributeVector<double>& curvature, int smooth_steps)
292
    {
293
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
294
            curvature[*v] = gaussian_curvature_angle_defect(m, *v);
295
 
296
        smooth_something_on_mesh(m, curvature, smooth_steps);
297
    }
298
 
299
    void mean_curvatures(const Manifold& m, VertexAttributeVector<double>& curvature, int smooth_steps)
300
    {
543 jab 301
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
302
			if(!boundary(m,*v))
303
			{
304
				Vec3d N = mean_curvature_normal(m, *v);
305
				curvature[*v] = length(N) * sign(dot(N,Vec3d(normal(m, *v))));
306
			}	
514 s042372 307
        smooth_something_on_mesh(m, curvature, smooth_steps);	
308
    }
309
 
310
 
311
    void curvature_paraboloids( const Manifold& m, 
312
                                VertexAttributeVector<Vec3d>& min_curv_direction, 
313
                                VertexAttributeVector<Vec3d>& max_curv_direction,
314
                                VertexAttributeVector<double>& curvature)
315
    {
316
 
317
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
318
            Mat2x2d tensor;
319
            Mat3x3d frame;
320
            curvature_tensor_paraboloid(m, *v, tensor, frame);
321
 
322
            Mat2x2d Q,L;
323
            int s = power_eigensolution(tensor, Q, L);
324
 
325
            if(s < 2)	
326
                cout << tensor << Q << L << endl;
327
 
328
            int max_idx = 0;
329
            int min_idx = 1;
330
 
331
            if(fabs(L[max_idx][max_idx])<fabs(L[min_idx][min_idx])) swap(max_idx, min_idx);
332
 
333
            Mat3x3d frame_t = transpose(frame);
334
 
335
            max_curv_direction[*v] = frame_t * Vec3d(Q[max_idx][0], Q[max_idx][1], 0);
336
 
337
            min_curv_direction[*v] = frame_t * Vec3d(Q[min_idx][0], Q[min_idx][1], 0);
338
 
339
            curvature[*v] = L[0][0]*L[1][1];
340
        }
341
    }
342
 
343
 
344
    void curvature_from_tensors(const Manifold& m,
345
                                const VertexAttributeVector<Mat3x3d>& curvature_tensors,
346
                                VertexAttributeVector<Vec3d>& min_curv_direction,
347
                                VertexAttributeVector<Vec3d>& max_curv_direction,
348
                                VertexAttributeVector<double>& curvature)
349
    {
529 s042372 350
        assert(curvature_tensors.size() == m.total_vertices());
514 s042372 351
 
352
        double max_val = -1e30;
353
        for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
354
            Mat3x3d C,Q,L;
355
            C = curvature_tensors[*v];
356
            int s = power_eigensolution(C, Q, L);
357
            Vec3d dmin, dmax;
358
            if(s == 0)
359
            {
360
                Vec3d n(normal(m, *v));
361
                orthogonal(n, dmin, dmax);
362
                curvature[*v] = 0;
363
                cout << " rank 0 " << endl;
364
            }
365
            else if(s == 1)
366
            {
367
                Vec3d n(normal(m, *v));
368
                dmin = normalize(Q[0]);
369
                dmax = cross(n, dmin);
370
                curvature[*v] = 0;
371
                cout << " rank 1 " << endl;
372
            }
373
            else
374
            {
375
                /*				Vec3d l(fabs(L[0][0]), fabs(L[1][1]), fabs(L[2][2]));
376
 
377
                int z_idx=2;
378
                if(s==3)
379
                {
380
                if(l[0] < l[1])
381
                z_idx = l[0]<l[2] ? 0 : 2;
382
                else
383
                z_idx = l[1]<l[2] ? 1 : 2;
384
                }
385
                int max_idx = (z_idx + 1) % 3;
386
                int min_idx = (z_idx + 2) % 3;
387
 
388
                if(l[max_idx] < l[min_idx]) swap(max_idx, min_idx);
389
                */
390
                int max_idx = 0;
391
                int min_idx = 1;
392
                // Yes - the biggest eigenvalue corresponds to the min direction
393
                // and vice versa.
394
                dmin = normalize(Q[max_idx]);
395
                dmax = normalize(Q[min_idx]);
396
 
397
                curvature[*v] = L[max_idx][max_idx]*L[min_idx][min_idx];
398
 
399
            }
400
            min_curv_direction[*v] = dmin;
401
            max_curv_direction[*v] = dmax;
402
            max_val = max(fabs(curvature[*v]), max_val);
403
 
404
        }
405
        //scal = 1.0/max_val;
406
    }
407
}
408