Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
677 janba 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
#include <thread>
8
#include "smooth.h"
9
 
10
#include <future>
11
#include <vector>
12
#include <algorithm>
13
#include "../CGLA/Mat3x3d.h"
14
#include "../CGLA/Vec3d.h"
15
#include "../CGLA/Quatd.h"
16
#include "../Util/Timer.h"
17
 
18
#include "Manifold.h"
19
#include "AttributeVector.h"
20
 
21
namespace HMesh
22
{
23
    using namespace std;
24
    using namespace CGLA;
25
 
26
 
27
    class range {
28
    public:
29
        class iterator {
30
            friend class range;
31
        public:
32
            long int operator *() const { return i_; }
33
            const iterator &operator ++() { ++i_; return *this; }
34
            iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }
35
 
36
            bool operator ==(const iterator &other) const { return i_ == other.i_; }
37
            bool operator !=(const iterator &other) const { return i_ != other.i_; }
38
 
39
        protected:
40
            iterator(long int start) : i_ (start) { }
41
 
42
        private:
43
            unsigned long i_;
44
        };
45
 
46
        iterator begin() const { return begin_; }
47
        iterator end() const { return end_; }
48
        range(long int  begin, long int end) : begin_(begin), end_(end) {}
49
    private:
50
        iterator begin_;
51
        iterator end_;
52
    };
53
 
54
    void for_each_vertex(Manifold& m, function<void(VertexID)> f) { for(auto v : m.vertices()) f(v); }
55
    void for_each_face(Manifold& m, function<void(FaceID)> f) { for(auto p : m.faces()) f(p); }
56
    void for_each_halfedge(Manifold& m, function<void(HalfEdgeID)> f) { for(auto h : m.halfedges()) f(h); }
57
 
58
 
59
    inline Vec3d laplacian(const Manifold& m, VertexID v)
60
    {
61
        Vec3d p(0);
62
        int n = circulate_vertex_ccw(m, v, (std::function<void(VertexID)>)[&](VertexID v){ p += m.pos(v); });
63
        return p / n - m.pos(v);
64
    }
65
 
66
 
67
    int CORES = 8;
68
 
69
    void laplacian_smooth_example(Manifold& m)
70
    {
71
        VertexAttributeVector<Vec3d> new_pos = m.positions_attribute_vector();
72
        for(VertexID v : m.vertices())
73
            if(!boundary(m, v))
74
            {
75
                Vec3d L(0);
76
                int n = circulate_vertex_ccw(m, v, (std::function<void(VertexID)>)[&](VertexID v){ L += m.pos(v); });
77
                new_pos[v] = L/n;
78
            }
79
        m.positions_attribute_vector() = new_pos;
80
 
81
    }
82
 
83
    void laplacian_smooth0(Manifold& m,float weight, int max_iter)
84
    {
85
        for(int iter=0;iter<max_iter; ++iter) {
86
            VertexAttributeVector<Vec3d> L_attr(m.no_vertices());
87
 
88
            for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v)
89
                if(!boundary(m, *v))
90
                    L_attr[*v] =laplacian(m, *v);
91
            for(VertexIDIterator v = m.vertices_begin(); v != m.vertices_end(); ++v){
92
                if(!boundary(m, *v))
93
                    m.pos(*v) += weight*L_attr[*v];
94
            }
95
        }
96
    }
97
 
98
    void laplacian_smooth1(Manifold& m,float weight, int max_iter)
99
    {
100
        for(int iter=0;iter<max_iter; ++iter) {
101
            VertexAttributeVector<Vec3d> L_attr(m.no_vertices());
102
 
103
            for(VertexID v : m.vertices())
104
                if(!boundary(m, v))
105
                    L_attr[v] =laplacian(m, v);
106
            for(VertexID v : m.vertices()){
107
                if(!boundary(m, v))
108
                    m.pos(v) += weight*L_attr[v];
109
            }
110
        }
111
    }
112
 
113
    void laplacian_smooth2(Manifold& m,float weight, int max_iter)
114
    {
115
        auto new_pos = m.positions_attribute_vector();
116
        for(int iter=0;iter<max_iter; ++iter) {
117
            for(auto v : m.vertices())
118
                if(!boundary(m, v))
119
                    new_pos[v] = weight*laplacian(m, v)+m.pos(v);
120
            m.positions_attribute_vector() = new_pos;
121
        }
122
    }
123
 
124
 
125
 
126
    void laplacian_smooth3(Manifold& m, float weight, int max_iter)
127
    {
128
        for(int iter=0;iter<max_iter; ++iter) {
129
            auto new_pos = m.positions_attribute_vector();
130
            for(auto v : m.vertices())
131
                if(!boundary(m, v))
132
                    new_pos[v] = weight*laplacian(m, v)+m.pos(v);
133
            m.positions_attribute_vector() = move(new_pos);
134
        }
135
    }
136
 
137
    void laplacian_smooth4(Manifold& m,float weight, int max_iter)
138
    {
139
        auto new_pos = m.positions_attribute_vector();
140
        for(int iter=0;iter<max_iter; ++iter) {
141
            for(VertexID v : m.vertices())
142
                if(!boundary(m, v))
143
                    new_pos[v] = weight*laplacian(m, v)+m.pos(v);
144
            swap(m.positions_attribute_vector(),new_pos);
145
        }
146
    }
147
 
148
    void laplacian_smooth4_5(Manifold& m,float weight, int max_iter)
149
    {
150
        auto new_pos = m.positions_attribute_vector();
151
        for(int iter=0;iter<max_iter; ++iter) {
152
            for_each_vertex(m, [&](VertexID v) {new_pos[v] = weight*laplacian(m, v)+m.pos(v);});
153
            swap(m.positions_attribute_vector(),new_pos);
154
        }
155
    }
156
 
157
 
158
 
159
    void laplacian_smooth5(Manifold& m, float weight, int max_iter)
160
    {
161
        for(int iter=0;iter<max_iter; ++iter) {
162
            auto new_pos = m.positions_attribute_vector();
163
            vector<thread> t_vec;
164
            for(auto v : m.vertices())
165
                if(!boundary(m, v))
166
                    t_vec.push_back(thread([&](VertexID vid){
167
                        if(!boundary(m, vid))
168
                            new_pos[vid] = weight*laplacian(m, vid)+ m.pos(vid);},v));
169
            for(int i=0;i<t_vec.size();++i)
170
                t_vec[i].join();
171
            m.positions_attribute_vector() = move(new_pos);
172
        }
173
    }
174
 
175
 
176
 
177
    inline void laplacian_smooth_vertex(Manifold& m, const vector<VertexID>& vids,
178
                                        VertexAttributeVector<Vec3d>& new_pos,
179
                                        float weight){
180
        for(VertexID v: vids)
181
            new_pos[v] = m.pos(v)+weight*laplacian(m, v);
182
    }
183
 
184
 
185
    void laplacian_smooth6(Manifold& m, float weight, int max_iter)
186
    {
187
        vector<vector<VertexID>> vertex_ids(CORES);
188
        auto batch_size = m.no_vertices()/CORES;
189
        int cnt = 0;
190
        for_each_vertex(m, [&](VertexID v) {
191
            if (!boundary(m, v))
192
                vertex_ids[(cnt++/batch_size)%CORES].push_back(v);
193
        });
194
        vector<thread> t_vec(CORES);
195
        VertexAttributeVector<Vec3d> new_pos = m.positions_attribute_vector();
196
        for(int iter=0;iter<max_iter; ++iter) {
197
            for(int thread_no=0;thread_no<CORES;++thread_no)
198
                t_vec[thread_no] = thread(laplacian_smooth_vertex,
199
                                          ref(m), ref(vertex_ids[thread_no]),
200
                                          ref(new_pos), weight);
201
            for(int thread_no=0;thread_no<CORES;++thread_no)
202
                t_vec[thread_no].join();
203
            swap(m.positions_attribute_vector(), new_pos);
204
        }
205
 
206
    }
207
 
208
 
209
    typedef std::vector<std::vector<VertexID>> VertexIDBatches;
210
 
211
//    template<typename  T>
212
//    void for_each_vertex_parallel(int no_threads, const VertexIDBatches& batches, const T& f) {
213
//        vector<future<void>> f_vec(no_threads);
214
//        for(auto t : range(0, no_threads))
215
//            f_vec[t] = async(launch::async, f, ref(batches[t]));
216
//    }
217
 
218
 
219
    template<typename  T>
220
    void for_each_vertex_parallel(int no_threads, const VertexIDBatches& batches, const T& f) {
221
        vector<thread> t_vec(no_threads);
222
        for(auto t : range(0, no_threads))
223
            t_vec[t] = thread(f, ref(batches[t]));
224
        for(auto t : range(0, no_threads))
225
            t_vec[t].join();
226
    }
227
 
228
    VertexIDBatches batch_vertices(Manifold& m) {
229
        VertexIDBatches vertex_ids(CORES);
230
        auto batch_size = m.no_vertices()/CORES;
231
        int cnt = 0;
232
        for_each_vertex(m, [&](VertexID v) {
233
            //if (!boundary(m, v))
234
                vertex_ids[(cnt++/batch_size)%CORES].push_back(v);
235
        });
236
        return vertex_ids;
237
    }
238
 
239
    void laplacian_smooth7(Manifold& m, float weight, int max_iter)
240
    {
241
        auto vertex_ids = batch_vertices(m);
242
        auto new_pos = m.positions_attribute_vector();
243
        auto f = [&](const vector<VertexID>& vids) {
244
            for(VertexID v: vids)
245
                new_pos[v] = m.pos(v)+weight*laplacian(m, v);
246
        };
247
 
248
        for(auto _ : range(0, max_iter)) {
249
            for_each_vertex_parallel(CORES, vertex_ids, f);
250
            swap(m.positions_attribute_vector(), new_pos);
251
        }
252
    }
253
 
254
 
255
 
256
 
257
    void laplacian_smooth(Manifold& m,float weight, int max_iter)
258
    {
259
//        laplacian_smooth_example(m);
260
        laplacian_smooth7(m,weight,max_iter);
261
 
262
//        Util::Timer tim;
263
//        cout << "Method 0: ";
264
//        for(int i=0;i<5;++i) {
265
//            Manifold m2 = m;
266
//            tim.start();
267
//            laplacian_smooth0(m2, 1, 1000);
268
//            cout << tim.get_secs() << ", ";
269
//        }
270
//        cout << endl;
271
//
272
//        cout << "Method 1: ";
273
//        for(int i=0;i<5;++i) {
274
//            Manifold m2 = m;
275
//            tim.start();
276
//            laplacian_smooth1(m2, 1, 1000);
277
//            cout << tim.get_secs() << ", ";
278
//        }
279
//        cout << endl;
280
//
281
//        cout << "Method 2: ";
282
//        for(int i=0;i<5;++i) {
283
//            Manifold m2 = m;
284
//            tim.start();
285
//            laplacian_smooth2(m2, 1, 1000);
286
//            cout << tim.get_secs() << ", ";
287
//        }
288
//        cout << endl;
289
//
290
//        cout << "Method 3: ";
291
//        for(int i=0;i<5;++i) {
292
//            Manifold m2 = m;
293
//            tim.start();
294
//            laplacian_smooth3(m2, 1, 1000);
295
//            cout << tim.get_secs() << ", ";
296
//        }
297
//        cout << endl;
298
//
299
//        cout << "Method 4: ";
300
//        for(int i=0;i<5;++i) {
301
//            Manifold m2 = m;
302
//            tim.start();
303
//            laplacian_smooth4(m2, 1, 1000);
304
//            cout << tim.get_secs() << ", ";
305
//        }
306
//        cout << endl;
307
//
308
//        cout << "Method 5: ";
309
//        for(int i=0;i<3;++i) {
310
//            Manifold m2 = m;
311
//            tim.start();
312
//            laplacian_smooth5(m2, 1, 1000);
313
//            cout << " sec: "<< tim.get_secs() << ",";
314
//        }
315
//        cout << endl;
316
//
317
//        CORES = 2;
318
//        cout << "Method 6 (2): ";
319
//        for(int i=0;i<5;++i) {
320
//            Manifold m2 = m;
321
//            tim.start();
322
//            laplacian_smooth6(m2, 1, 1000);
323
//            cout << tim.get_secs() << ", ";
324
//        }
325
//        cout << endl;
326
//        
327
//        CORES = 4;
328
//        cout << "Method 7 (4): ";
329
//        for(int i=0;i<5;++i) {
330
//            Manifold m2 = m;
331
//            tim.start();
332
//            laplacian_smooth6(m2, 1, 1000);
333
//            cout << tim.get_secs() << ", ";
334
//        }
335
//        cout << endl;
336
//
337
//        CORES = 8;
338
//        cout << "Method 7 (8): ";
339
//        for(int i=0;i<5;++i) {
340
//            Manifold m2 = m;
341
//            tim.start();
342
//            laplacian_smooth6(m2, 1, 1000);
343
//            cout << tim.get_secs() << ", ";
344
//        }
345
//        cout << endl;
346
 
347
 
348
    }
349
 
350
 
351
 
352
 
353
 
354
    void taubin_smooth(Manifold& m, int max_iter)
355
    {
356
        auto new_pos = m.positions_attribute_vector();
357
        for(int iter = 0; iter < 2*max_iter; ++iter) {
358
            for(VertexID v : m.vertices())
359
                if(!boundary(m, v))
360
                    new_pos[v] = (iter%2 == 0 ? 0.5 : -0.52) * laplacian(m, v) + m.pos(v);
361
            swap(m.positions_attribute_vector(), new_pos);
362
        }
363
    }
364
 
365
    void face_neighbourhood(Manifold& m, FaceID f, vector<FaceID>& nbrs)
366
    {
367
        FaceAttributeVector<int> touched(m.allocated_faces(), -1);
368
        touched[f] = 1;
369
        nbrs.push_back(f);
370
        for(Walker wf = m.walker(f); !wf.full_circle(); wf = wf.circulate_face_cw()){
371
            for(Walker wv = m.walker(wf.vertex()); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
372
                FaceID fn = wv.face();
373
                if(fn != InvalidFaceID && touched[fn] != touched[f]){
374
                    nbrs.push_back(fn);
375
                    touched[fn] = 1;
376
                }
377
            }
378
        }
379
    }
380
 
381
 
382
 
383
    Vec3d fvm_filtered_normal(Manifold& m, FaceID f)
384
    {
385
        const float sigma = .1f;
386
 
387
        vector<FaceID> nbrs;
388
        face_neighbourhood(m, f, nbrs);
389
        float min_dist_sum=1e32f;
390
        long int median=-1;
391
 
392
        vector<Vec3d> normals(nbrs.size());
393
        for(size_t i=0;i<nbrs.size();++i)
394
        {
395
            normals[i] = normal(m, nbrs[i]);
396
            float dist_sum = 0;
397
            for(size_t j=0;j<nbrs.size(); ++j)
398
                dist_sum += 1.0f - dot(normals[i], normals[j]);
399
            if(dist_sum < min_dist_sum)
400
            {
401
                min_dist_sum = dist_sum;
402
                median = i;
403
            }
404
        }
405
        assert(median != -1);
406
        Vec3d median_norm = normals[median];
407
        Vec3d avg_norm(0);
408
        for(size_t i=0;i<nbrs.size();++i)
409
        {
410
            float w = exp((dot(median_norm, normals[i])-1)/sigma);
411
            if(w<1e-2) w = 0;
412
            avg_norm += w*normals[i];
413
        }
414
        return normalize(avg_norm);
415
    }
416
    Vec3d bilateral_filtered_normal(Manifold& m, FaceID f, double avg_len)
417
    {
418
        vector<FaceID> nbrs;
419
        face_neighbourhood(m, f, nbrs);
420
        Vec3d p0 = centre(m, f);
421
        Vec3d n0 = normal(m, f);
422
        vector<Vec3d> normals(nbrs.size());
423
        vector<Vec3d> pos(nbrs.size());
424
        Vec3d fn(0);
425
        for(FaceID nbr : nbrs)
426
        {
427
            Vec3d n = normal(m, nbr);
428
            Vec3d p = centre(m, nbr);
429
            double w_a = exp(-acos(max(-1.0,min(1.0,dot(n,n0))))/(M_PI/32.0));
430
            double w_s = exp(-length(p-p0)/avg_len);
431
 
432
            fn += area(m, nbr)* w_a * w_s * n;
433
 
434
        }
435
        return normalize(fn);
436
    }
437
 
438
    void anisotropic_smooth(HMesh::Manifold& m, int max_iter, NormalSmoothMethod nsm)
439
    {
440
        double avg_len=0;
441
        for(HalfEdgeID hid : m.halfedges())
442
            avg_len += length(m, hid);
443
        avg_len /= 2.0;
444
        for(int iter = 0;iter<max_iter; ++iter)
445
        {
446
 
447
            FaceAttributeVector<Vec3d> filtered_norms(m.allocated_faces());
448
 
449
            for(FaceID f: m.faces()){
450
                filtered_norms[f] = (nsm == BILATERAL_NORMAL_SMOOTH)?
451
                bilateral_filtered_normal(m, f, avg_len):
452
                fvm_filtered_normal(m, f);
453
            }
454
 
455
            VertexAttributeVector<Vec3d> vertex_positions(m.allocated_vertices(), Vec3d(0));
456
            VertexAttributeVector<int> count(m.allocated_vertices(), 0);
457
            for(int sub_iter=0;sub_iter<100;++sub_iter)
458
            {
459
                for(HalfEdgeID hid : m.halfedges())
460
                {
461
                    Walker w = m.walker(hid);
462
                    FaceID f = w.face();
463
 
464
                    if(f != InvalidFaceID){
465
                        VertexID v = w.vertex();
466
                        Vec3d dir = m.pos(w.opp().vertex()) - m.pos(v);
467
                        Vec3d n = filtered_norms[f];
468
                        vertex_positions[v] += m.pos(v) + 0.5 * n * dot(n, dir);
469
                        count[v] += 1;
470
                    }
471
 
472
                }
473
                double max_move= 0;
474
                for(VertexID v : m.vertices())
475
                {
476
                    Vec3d npos = vertex_positions[v] / double(count[v]);
477
                    double move = sqr_length(npos - m.pos(v));
478
                    if(move > max_move)
479
                        max_move = move;
480
 
481
                    m.pos(v) = npos;
482
                }
483
                if(max_move<sqr(1e-8*avg_len))
484
                {
485
                    cout << "iters " << sub_iter << endl;
486
                    break;
487
                }
488
            }
489
        }
490
    }
491
 
492
    void TAL_smoothing(Manifold& m, float w, int max_iter)
493
    {
494
        for(int iter=0;iter<max_iter;++iter) {
495
            VertexAttributeVector<float> vertex_areas;
496
            VertexAttributeVector<Vec3d> laplacians;
497
 
498
            for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
499
            {
500
                vertex_areas[*vid] = 0;
501
                for(Walker w = m.walker(*vid); !w.full_circle(); w = w.circulate_vertex_ccw())
502
                    if(w.face() != InvalidFaceID)
503
                        vertex_areas[*vid] += area(m, w.face());
504
            }
505
 
506
            for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
507
            {
508
                laplacians[*vid] = Vec3d(0);
509
                double weight_sum = 0.0;
510
                if(boundary(m, *vid))
511
                {
512
                    double angle_sum = 0;
513
                    for(Walker w = m.walker(*vid); !w.full_circle(); w = w.circulate_vertex_ccw())
514
                    {
515
                        if (w.face() != InvalidFaceID)
516
                        {
517
                            Vec3d vec_a = normalize(m.pos(w.vertex()) - m.pos(*vid));
518
                            Vec3d vec_b = normalize(m.pos(w.circulate_vertex_ccw().vertex()) -
519
                                                    m.pos(*vid));
520
                            angle_sum += acos(max(-1.0,min(1.0,dot(vec_a,vec_b))));
521
                        }
522
                        if(boundary(m,w.vertex()))
523
                        {
524
                            laplacians[*vid] += m.pos(w.vertex()) - m.pos(*vid);
525
                            weight_sum += 1.0;
526
                        }
527
                    }
528
                    laplacians[*vid] /= weight_sum;
529
                    laplacians[*vid] *= exp(-3.0*sqr(max(0.0, M_PI-angle_sum)));
530
                }
531
                else
532
                {
533
                    for(Walker w = m.walker(*vid); !w.full_circle(); w = w.circulate_vertex_ccw())
534
                    {
535
                        float weight = vertex_areas[w.vertex()];
536
                        Vec3d l = m.pos(w.vertex()) - m.pos(*vid);
537
                        laplacians[*vid] +=  weight * l;
538
                        weight_sum += weight;
539
                    }
540
                    laplacians[*vid] /= weight_sum;
541
                    //                Vec3d n = normal(m, *vid);
542
                    //                if(sqr_length(n)>0.9)
543
                    //                    laplacians[*vid] -= n * dot(n, laplacians[*vid]);
544
                }
545
            }
546
            for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
547
                m.pos(*vid) += w*laplacians[*vid];
548
        }
549
    }
550
 
551
 
552
 
553
}