Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
667 khor 1
//
2
//  MeshEditor.cpp
3
//  GEL
4
//
5
//  Created by J. Andreas Bærentzen on 09/10/13.
6
//
7
//
676 janba 8
#include <thread>
9
#include <unistd.h>
667 khor 10
#include <GL/glew.h>
11
#include <functional>
12
#include "MeshEditor.h"
13
#include <string>
14
#include <iostream>
15
#include <vector>
16
#include <algorithm>
17
#include <queue>
18
 
19
#include <GLGraphics/Console.h>
676 janba 20
#include <GLGraphics/glsl_shader.h>
21
#include <GLGraphics/ShadowBuffer.h>
667 khor 22
 
23
#include <CGLA/eigensolution.h>
24
#include <CGLA/Vec2d.h>
25
#include <CGLA/Vec3d.h>
26
#include <CGLA/Mat3x3d.h>
27
#include <CGLA/Mat2x2d.h>
28
#include <CGLA/Mat2x3d.h>
29
#include <CGLA/Mat4x4d.h>
30
 
31
#include <LinAlg/Matrix.h>
32
#include <LinAlg/Vector.h>
33
#include <LinAlg/LapackFunc.h>
34
 
35
#include <HMesh/Manifold.h>
36
#include <HMesh/AttributeVector.h>
37
#include <HMesh/mesh_optimization.h>
38
#include <HMesh/curvature.h>
39
#include <HMesh/triangulate.h>
40
#include <HMesh/flatten.h>
41
#include <HMesh/dual.h>
42
#include <HMesh/load.h>
43
#include <HMesh/quadric_simplify.h>
44
#include <HMesh/smooth.h>
45
#include <HMesh/x3d_save.h>
46
#include <HMesh/obj_save.h>
47
#include <HMesh/off_save.h>
48
#include <HMesh/mesh_optimization.h>
49
#include <HMesh/triangulate.h>
50
#include <HMesh/cleanup.h>
51
#include <HMesh/cleanup.h>
52
#include <HMesh/refine_edges.h>
53
#include <HMesh/subdivision.h>
54
#include <HMesh/harmonics.h>
55
 
56
#include <Util/Timer.h>
57
 
58
#include "VisObj.h"
59
 
60
using namespace std;
61
using namespace CGLA;
62
using namespace HMesh;
63
using namespace Util;
64
 
65
namespace GLGraphics {
66
 
67
    namespace {
68
 
69
        bool wantshelp(const std::vector<std::string> & args)
70
        {
71
            if(args.size() == 0)
72
                return false;
73
 
74
            string str = args[0];
75
 
76
            if(str=="help" || str=="HELP" || str=="Help" || str=="?")
77
                return true;
78
 
79
            return false;
80
        }
81
 
82
 
83
        bool wantshelp(MeshEditor* me, const std::vector<std::string> & args)
84
        {
85
            if(args.size() == 0)
86
                return false;
87
 
88
            string str = args[0];
89
 
90
            if(str=="help" || str=="HELP" || str=="Help" || str=="?")
91
                return true;
92
 
93
            return false;
94
        }
95
 
96
        /// Function that aligns two meshes.
97
        void console_align(MeshEditor* me, const std::vector<std::string> & args)
98
        {
99
            if(wantshelp(args)) {
100
                me->printf("usage: align <dest> <src>");
101
                me->printf("This function aligns dest mesh with src");
102
                me->printf("In practice the GLViewController of src is copied to dst.");
103
                me->printf("both arguments are mandatory and must be numbers between 1 and 9.");
104
                me->printf("Note that results might be unexpexted if the meshes are not on the same scale");
105
            }
106
 
107
            int dest = 0;
108
 
109
            if(args.size()>0){
110
                istringstream a0(args[0]);
111
                a0 >> dest;
112
                --dest;
113
 
114
                if(dest <0 || dest>8)
115
                {
116
                    me->printf("dest mesh out of range (1-9)");
117
                    return;
118
                }
119
            }
120
            else
121
            {
122
                me->printf("neither source nor destination mesh?!");
123
                return;
124
            }
125
 
126
            int src = 0;
127
            if(args.size()>1){
128
                istringstream a1(args[1]);
129
                a1 >> src;
130
                --src;
131
 
132
                if(src <0 || src>8)
133
                {
134
                    me->printf("src mesh out of range (1-9)");
135
                    return;
136
                }
137
            }
138
            else
139
            {
140
                me->printf("no src mesh?");
141
                return;
142
            }
143
            me->align(src,dest);
144
        }
145
 
146
 
147
 
148
 
149
        void console_ridge_lines(MeshEditor* me, const std::vector<std::string> & args)
150
        {
151
            if(wantshelp(args)) {
152
                me->printf("usage: ridge_lines");
153
                return;
154
            }
155
 
156
            me->save_active_mesh();
157
 
158
            Manifold& mani = me->active_mesh();
159
 
160
            VertexAttributeVector<Mat3x3d> curvature_tensors(mani.allocated_vertices());
161
            VertexAttributeVector<Vec3d> min_curv_direction(mani.allocated_vertices());
162
            VertexAttributeVector<Vec3d> max_curv_direction(mani.allocated_vertices());
163
            VertexAttributeVector<Vec2d> curvature(mani.allocated_vertices());
164
 
165
 
166
 
167
            curvature_paraboloids(mani,
168
                                  min_curv_direction,
169
                                  max_curv_direction,
170
                                  curvature);
171
 
172
            for(auto vid : mani.vertices())
173
            {
174
                Vec3d max_curv_dir = normalize(max_curv_direction[vid]);
175
                Vec3d min_curv_dir = normalize(min_curv_direction[vid]);
176
                double vid_min_pc = curvature[vid][0];
177
                double vid_max_pc = curvature[vid][1];
178
                bool ridge = true;
179
                bool ravine = true;
180
                Walker w = mani.walker(vid);
181
                Vec3d r(0);
182
                for(; !w.full_circle();w = w.circulate_vertex_ccw())
183
                {
184
                    Vec3d e = (mani.pos(w.vertex()) - mani.pos(vid));
185
 
186
                    if(abs(dot(min_curv_dir,e)) > abs(dot(max_curv_dir,e)))
187
                    {
188
                        if(curvature[w.vertex()][0]<vid_min_pc+20)
189
                            ravine = false;
190
 
191
                    }
192
                    else
193
                    {
194
                        if(curvature[w.vertex()][1]>vid_max_pc-20)
195
                            ridge = false;
196
                    }
197
                }
198
                DebugRenderer::vertex_colors[vid] = Vec3f(ridge,ravine,0.0);
199
            }
200
            for(auto fid : mani.faces())
201
                DebugRenderer::face_colors[fid] = Vec3f(.3,.3,.6);
202
            for(auto hid : mani.halfedges()) {
203
 
204
                Walker w = mani.walker(hid);
205
                Vec3f c0 = DebugRenderer::vertex_colors[w.opp().vertex()];
206
                Vec3f c1 = DebugRenderer::vertex_colors[w.vertex()];
207
 
208
                DebugRenderer::edge_colors[hid] = (c0==c1) ? c0 : Vec3f(0.1,0.1,0.3);
209
 
210
            }
211
        }
212
 
213
        void transform_mesh(Manifold& mani, const Mat4x4d& m)
214
        {
215
            for(VertexIDIterator vid = mani.vertices_begin(); vid != mani.vertices_end(); ++vid)
216
                mani.pos(*vid) = m.mul_3D_point(mani.pos(*vid));
217
        }
218
 
219
        void console_scale(MeshEditor* me, const std::vector<std::string> & args)
220
        {
221
            if(wantshelp(args)) {
222
                me->printf("usage: scale sx sy sz");
223
                return;
224
            }
225
 
226
            Vec3d s;
227
 
228
            if(args.size() > 0){
229
                istringstream a0(args[0]);
230
                a0 >> s[0];
231
            }
232
            if(args.size() > 1){
233
                istringstream a0(args[0]);
234
                a0 >> s[1];
235
            }
236
            if(args.size() > 2){
237
                istringstream a0(args[0]);
238
                a0 >> s[2];
239
            }
240
 
241
            me->save_active_mesh();
242
            transform_mesh(me->active_mesh(),scaling_Mat4x4d(s));
243
            me->refit();
244
        }
245
 
246
        void console_test(MeshEditor* me, const std::vector<std::string> & args)
247
        {
248
            if(wantshelp(args)) {
249
                me->printf("usage: test");
250
                return;
251
            }
252
 
253
            me->save_active_mesh();
254
            me->active_mesh().slit_edges(me->get_vertex_selection());
255
        }
256
 
257
 
258
        void console_flatten(MeshEditor* me, const std::vector<std::string> & args)
259
        {
260
            if(wantshelp(args)) {
261
                me->printf("usage: flatten <floater|harmonic|barycentric>");
262
                me->printf("This function flattens a meshs with a simple boundary. It is mostly for showing mesh");
263
                me->printf("parametrization methods. The current mesh MUST have a SINGLE boundary loop");
264
                me->printf("This loop is mapped to the unit circle in a regular fashion (equal angle intervals).");
265
                me->printf("All non boundary vertices are placed at the origin. Then the system is relaxed iteratively");
266
                me->printf("using the weight scheme given as argument.");
267
                return;
268
            }
269
 
270
            me->save_active_mesh();
271
 
272
            WeightScheme ws = BARYCENTRIC_W;
273
            if(args.size()>0){
274
                if(args[0] == "floater")
275
                    ws = FLOATER_W;
276
                else if(args[0] == "harmonic")
277
                    ws = HARMONIC_W;
278
                else if(args[0] == "lscm")
279
                    ws = LSCM_W;
280
            }
281
            else
282
                return;
283
 
284
            flatten(me->active_mesh(), ws);
285
 
286
            return;
287
        }
288
 
289
        void console_save(MeshEditor* me, const std::vector<std::string> & args)
290
        {
291
            if(wantshelp(args)) {
292
                me->printf("usage: save <name->x3d|name->obj> ");
293
 
294
                return;
295
            }
296
            const string& file_name = args[0];
297
            if(args.size() == 1){
298
                if(file_name.substr(file_name.length()-4,file_name.length())==".obj"){
299
                    obj_save(file_name, me->active_mesh());
300
 
301
                    return;
302
                }
303
                else if(file_name.substr(file_name.length()-4,file_name.length())==".off"){
304
                    off_save(file_name, me->active_mesh());
305
 
306
                    return;
307
                }
308
                else if(file_name.substr(file_name.length()-4,file_name.length())==".x3d"){
309
                    x3d_save(file_name, me->active_mesh());
310
 
311
                    return;
312
                }
313
                me->printf("unknown format");
314
                return;
315
            }
316
            me->printf("usage: save <name->x3d|name->obj> ");
317
        }
318
 
319
 
320
        void console_refine_edges(MeshEditor* me, const std::vector<std::string> & args)
321
        {
322
            if(wantshelp(args)) {
323
                me->printf("usage: refine.split_edges <length>");
324
                me->printf("splits edges longer than <length>; default is 0.5 times average length");
325
                return;
326
            }
327
 
328
            me->save_active_mesh();
329
 
330
            float thresh = 0.5f;
331
 
332
            if(args.size() > 0){
333
                istringstream a0(args[0]);
334
                a0 >> thresh;
335
            }
336
 
337
            float avg_length = average_edge_length(me->active_mesh());
338
 
339
            refine_edges(me->active_mesh(), thresh * avg_length);
340
 
341
            return;
342
 
343
        }
344
 
345
        void console_refine_faces(MeshEditor* me, const std::vector<std::string> & args)
346
        {
347
            if(wantshelp(args)) {
348
                me->printf("usage: refine.split_faces ");
349
                me->printf("usage:  Takes no arguments. Inserts a vertex at the centre of each face.");
350
 
351
                return;
352
            }
353
            me->save_active_mesh();
354
 
355
            triangulate_by_vertex_face_split(me->active_mesh());
356
 
357
            return;
358
 
359
        }
360
 
361
        void console_cc_subdivide(MeshEditor* me, const std::vector<std::string> & args)
362
        {
363
            if(wantshelp(args)) {
364
                me->printf("usage: subdivide.catmull_clark ");
365
                me->printf("Does one step of Catmull-Clark subdivision");
366
 
367
                return;
368
            }
369
            me->save_active_mesh();
370
 
371
            cc_split(me->active_mesh(),me->active_mesh());
372
            cc_smooth(me->active_mesh());
373
 
374
            return;
375
        }
376
 
676 janba 377
        void console_root_cc_subdivide(MeshEditor* me, const std::vector<std::string> & args)
378
        {
379
            if(wantshelp(args)) {
380
                me->printf("usage: subdivide.catmull_clark ");
381
                me->printf("Does one step of Catmull-Clark subdivision");
382
 
383
                return;
384
            }
385
            me->save_active_mesh();
386
 
387
            rootCC_subdivide(me->active_mesh(),me->active_mesh());
388
            return;
389
        }
390
 
391
 
667 khor 392
        void console_loop_subdivide(MeshEditor* me, const std::vector<std::string> & args)
393
        {
394
            if(wantshelp(args)) {
395
                me->printf("usage: subdivide.loop");
396
                me->printf("Does one step of Loop subdivision");
397
 
398
                return;
399
            }
400
            me->save_active_mesh();
401
 
402
            loop_split(me->active_mesh(),me->active_mesh());
403
            loop_smooth(me->active_mesh());
404
 
405
            return;
406
        }
407
 
676 janba 408
        void console_stitch(MeshEditor* me, const std::vector<std::string> & args)
409
        {
410
            if(wantshelp(args)) {
411
                me->printf("usage: cleanup.stitch <rad>");
412
                me->printf("Stitches faces");
413
 
414
                return;
415
            }
416
            double r = 0.001;
417
 
418
            if(args.size() > 0){
419
                istringstream a0(args[0]);
420
                a0 >> r;
421
            }
422
 
423
            me->save_active_mesh();
424
            Manifold& m = me->active_mesh();
425
            Vec3d c;
426
            float rad;
427
            bsphere(m, c, rad);
428
            stitch_mesh(me->active_mesh(), r * rad);
429
            return;
430
        }
431
 
432
        void console_remove_duplicates(MeshEditor* me, const std::vector<std::string> & args)
433
        {
434
            if(wantshelp(args)) {
435
                me->printf("usage: cleanup.remove_duplicates <rad>");
436
                me->printf("Removes duplicate vertices and incident faces");
437
 
438
                return;
439
            }
440
            double r = 0.001;
441
 
442
            if(args.size() > 0){
443
                istringstream a0(args[0]);
444
                a0 >> r;
445
            }
446
 
447
            me->save_active_mesh();
448
            Manifold& m = me->active_mesh();
449
            Vec3d c;
450
            float rad;
451
            bsphere(m, c, rad);
452
            remove_duplicates(me->active_mesh(), r * rad);
453
            return;
454
        }
455
 
456
 
457
        void console_remove_val2(MeshEditor* me, const std::vector<std::string> & args)
458
        {
459
            if(wantshelp(args)) {
460
                me->printf("usage: cleanup.remove_val2");
461
                me->printf("Removes valence 2 vertices");
462
 
463
                return;
464
            }
465
            me->save_active_mesh();
466
            Manifold& m = me->active_mesh();
467
            remove_valence_two_vertices(m);
468
            return;
469
        }
470
 
471
 
667 khor 472
        void console_root3_subdivide(MeshEditor* me, const std::vector<std::string> & args)
473
        {
474
            if(wantshelp(args)) {
475
                me->printf("usage: subdivide.root3");
476
                me->printf("Does one step of sqrt(3) subdivision");
477
 
478
                return;
479
            }
480
            me->save_active_mesh();
481
 
482
            root3_subdivide(me->active_mesh(),me->active_mesh());
483
 
484
            return;
485
        }
486
 
487
 
488
        void console_doosabin_subdivide(MeshEditor* me, const std::vector<std::string> & args)
489
        {
490
            if(wantshelp(args)) {
491
                me->printf("usage: subdivide.doo_sabin ");
492
                me->printf("Does one step of Doo-Sabin Subdivision");
493
 
494
                return;
495
            }
496
            me->save_active_mesh();
497
 
498
            cc_split(me->active_mesh(),me->active_mesh());
499
            dual(me->active_mesh());
500
 
501
            return;
502
        }
503
 
504
        void console_butterfly_subdivide(MeshEditor* me, const std::vector<std::string> & args)
505
        {
506
            if(wantshelp(args)) {
507
                me->printf("usage: subdivide.butterfly ");
508
                me->printf("Does one step of Modified Butterfly Subdivision");
509
 
510
                return;
511
            }
512
            me->save_active_mesh();
513
 
514
            butterfly_subdivide(me->active_mesh(),me->active_mesh());
515
 
516
            return;
517
        }
518
 
519
        void console_dual(MeshEditor* me, const std::vector<std::string> & args)
520
        {
521
            if(wantshelp(args))
522
            {
523
                me->printf("usage: dual ");
524
                me->printf("Produces the dual by converting each face to a vertex placed at the barycenter.");
525
                return;
526
            }
527
            me->save_active_mesh();
528
 
529
            dual(me->active_mesh());
530
 
531
            return;
532
        }
533
 
534
 
535
        void console_minimize_curvature(MeshEditor* me, const std::vector<std::string> & args)
536
        {
537
            if(wantshelp(args))
538
            {
539
                me->printf("usage: optimize.minimize_curvature <anneal>");
540
                me->printf("Flip edges to minimize mean curvature.");
541
                me->printf("If anneal is true, simulated annealing (slow) is used rather than a greedy scheme");
542
                return;
543
            }
544
            me->save_active_mesh();
545
 
546
            bool anneal=false;
547
            if(args.size() > 0)
548
            {
549
                istringstream a0(args[0]);
550
                a0 >> anneal;
551
            }
552
 
553
            minimize_curvature(me->active_mesh(), anneal);
554
            me->post_create_display_list();
555
            return;
556
        }
557
 
558
        void console_minimize_dihedral(MeshEditor* me, const std::vector<std::string> & args)
559
        {
560
            if(wantshelp(args))
561
            {
562
                me->printf("usage: optimize.minimize_dihedral <iter> <anneal> <use_alpha> <gamma> ");
563
                me->printf("Flip edges to minimize dihedral angles.");
564
                me->printf("Iter is the max number of iterations. anneal tells us whether to use ");
565
                me->printf("simulated annealing and not greedy optimization. use_alpha (default=true) ");
566
                me->printf("means to use angle and not cosine of anglegamma (default=4) is the power ");
567
                me->printf("to which we raise the dihedral angle");
568
                return;
569
            }
570
            me->save_active_mesh();
571
 
572
            int iter = 1000;
573
            if(args.size() > 0)
574
            {
575
                istringstream a0(args[0]);
576
                a0 >> iter;
577
            }
578
 
579
            bool anneal = false;
580
            if(args.size() > 1)
581
            {
582
                istringstream a0(args[1]);
583
                a0 >> anneal;
584
            }
585
 
586
            bool use_alpha = true;
587
            if(args.size() > 2)
588
            {
589
                istringstream a0(args[2]);
590
                a0 >> use_alpha;
591
            }
592
 
593
            float gamma = 4.0f;
594
            if(args.size() > 3)
595
            {
596
                istringstream a0(args[3]);
597
                a0 >> gamma;
598
            }
599
 
600
 
601
            minimize_dihedral_angle(me->active_mesh(), iter, anneal, use_alpha, gamma);
602
            return;
603
        }
604
 
605
        void console_maximize_min_angle(MeshEditor* me, const std::vector<std::string> & args)
606
        {
607
            if(wantshelp(args))
608
            {
609
                me->printf("usage: optimize.maximize_min_angle <thresh> <anneal>");
610
                me->printf("Flip edges to maximize min angle - to make mesh more Delaunay.");
611
                me->printf("If the dot product of the normals between adjacent faces < thresh");
612
                me->printf("no flip will be made. anneal selects simulated annealing rather ");
613
                me->printf("nthan greedy optimization.");
614
                return;
615
            }
616
            me->save_active_mesh();
617
 
618
            float thresh = 0.0f;
619
            if(args.size() > 0)
620
            {
621
                istringstream a0(args[0]);
622
                a0 >> thresh;
623
            }
624
            bool anneal = false;
625
            if(args.size() > 1)
626
            {
627
                istringstream a0(args[1]);
628
                a0 >> anneal;
629
            }
630
            maximize_min_angle(me->active_mesh(),thresh,anneal);
631
            return;
632
        }
633
 
634
 
635
        void console_optimize_valency(MeshEditor* me, const std::vector<std::string> & args)
636
        {
637
            if(wantshelp(args))
638
            {
639
                me->printf("usage: optimize.valency <anneal> ");
640
                me->printf("Optimizes valency for triangle meshes. Anneal selects simulated annealing rather than greedy optim.");
641
                return;
642
            }
643
            me->save_active_mesh();
644
 
645
            bool anneal = false;
646
            if(args.size() > 0)
647
            {
648
                istringstream a0(args[0]);
649
                a0 >> anneal;
650
            }
651
            optimize_valency(me->active_mesh(), anneal);
652
            return;
653
        }
654
 
655
            void console_analyze(MeshEditor* me, const std::vector<std::string> & args)
656
            {
657
                if(wantshelp(args))
658
                {
659
                    me->printf("usage:  harmonics.analyze");
660
                    me->printf("Creates the Laplace Beltrami operator for the mesh and finds all eigensolutions.");
661
                    me->printf("It also projects the vertices onto the eigenvectors - thus transforming the mesh");
662
                    me->printf("to this basis.");
663
                    me->printf("Note that this will stall the computer for a large mesh - as long as we use Lapack.");
664
                    return;
665
                }
666
                me->harmonics_analyze_mesh();
667
                return;
668
            }
669
 
670
 
676 janba 671
        void console_partial_reconstruct(MeshEditor* me, const std::vector<std::string> & args)
672
        {
673
            if(args.size() != 3)
674
                me->printf("usage: haramonics.partial_reconstruct <e0> <e1> <s>");
675
 
676
            if(wantshelp(args)) {
677
                me->printf("Reconstruct from projections onto eigenvectors. The two first arguments indicate");
678
                me->printf("the eigenvector interval that we reconstruct from. The last argument is the ");
679
                me->printf("scaling factor. Thus, for a vertex, v, the formula for computing the position, p, is:");
680
                me->printf("for (i=e0; i<=e1;++i) p += proj[i] * Q[i][v] * s;");
681
                me->printf("where proj[i] is the 3D vector containing the x, y, and z projections of the mesh onto");
682
                me->printf("eigenvector i. Q[i][v] is the v'th coordinate of the i'th eigenvector.");
683
                me->printf("Note that if vertex coordinates are not first reset, the result is probably unexpected.");
684
            }
685
            me->save_active_mesh();
686
 
687
            if(args.size() != 3)
688
                return;
689
 
690
            int E0,E1;
691
            float scale;
692
            istringstream a0(args[0]);
693
            a0 >> E0;
694
            istringstream a1(args[1]);
695
            a1 >> E1;
696
            istringstream a2(args[2]);
697
            a2 >> scale;
698
            me->harmonics_partial_reconstruct(E0,E1,scale);
699
            return;
700
        }
667 khor 701
 
676 janba 702
        void console_reset_shape(MeshEditor* me, const std::vector<std::string> & args)
703
        {
704
            if(wantshelp(args))
705
            {
706
                me->printf("usage: harmonics.reset_shape ");
707
                me->printf("Simply sets all vertices to 0,0,0. Call this before doing partial_reconstruct");
708
                me->printf("unless you know what you are doing.");
709
                return;
710
            }
711
            me->save_active_mesh();
712
            me->harmonics_reset_shape();
713
            return;
714
        }
667 khor 715
 
676 janba 716
 
667 khor 717
        void console_close_holes(MeshEditor* me, const std::vector<std::string> & args)
718
        {
719
            if(wantshelp(args))
720
            {
721
                me->printf("usage: cleanup.close_holes");
722
                me->printf("This function closes holes. It simply follows the loop of halfvectors which");
723
                me->printf("enclose the hole and add a face to which they all point.");
724
                return;
725
            }
726
            me->save_active_mesh();
727
 
728
            close_holes(me->active_mesh());
729
            return;
730
        }
731
 
732
        void console_reload(MeshEditor* me, const std::vector<std::string> & args)
733
        {
734
            if(wantshelp(args))
735
            {
736
                me->printf("usage:  load <file>");
737
                me->printf("(Re)loads the current file if no argument is given, but");
738
                me->printf("if an argument is given, then that becomes the current file");
739
                return;
740
            }
741
            me->save_active_mesh();
742
 
743
            if(!me->reload_active_from_file(args.size() > 0 ? args[0]:""))
744
                me->printf("failed to load");
745
 
746
            return;
747
        }
748
 
749
 
750
        void console_add_mesh(MeshEditor* me, const std::vector<std::string> & args)
751
        {
752
            if(wantshelp(args))
753
            {
754
                me->printf("usage:  add_mesh <file>");
755
                me->printf("Loads the file but without clearing the mesh. Thus, the loaded mesh is added to the");
756
                me->printf("current model.");
757
                return;
758
            }
759
            me->save_active_mesh();
760
 
761
            if(!me->add_to_active_from_file(args.size() > 0 ? args[0]:""))
762
                me->printf("failed to load");
763
 
764
            return;
765
        }
766
 
767
        void console_valid(MeshEditor* me, const std::vector<std::string> & args)
768
        {
769
            if(wantshelp(args))
770
            {
771
                me->printf("usage:  validity");
772
                me->printf("Tests validity of Manifold");
773
                return;
774
            }
775
            if(valid(me->active_mesh()))
776
                me->printf("Mesh is valid");
777
            else
778
                me->printf("Mesh is invalid - check console output");
779
            return;
780
        }
781
 
782
        void console_Dijkstra(MeshEditor* me, const std::vector<std::string> & args)
783
        {
784
            if(wantshelp(args))
785
            {
786
                me->printf("usage:  Dijkstra");
787
                return;
788
            }
789
 
790
            Manifold& m = me->active_mesh();
791
 
792
 
793
            VertexAttributeVector<double> dist(m.allocated_vertices(), DBL_MAX);
794
            VertexAttributeVector<int> visited(m.allocated_vertices(), 0);
795
            VertexID v = *m.vertices_begin();
796
            dist[v]=0;
797
            priority_queue<pair<double,VertexID>> pq;
798
            pq.push(make_pair(-dist[v], v));
799
            double max_dist;
800
            while(!pq.empty())
801
            {
802
                VertexID v = pq.top().second;
803
                max_dist = dist[v];
804
                pq.pop();
805
 
806
                if(!visited[v]){
807
                    visited[v]=1;
808
 
809
                    for(Walker w = m.walker(v); !w.full_circle(); w = w.circulate_vertex_ccw())
810
                        if(!visited[w.vertex()])
811
                        {
812
                            double d = dist[v] + length(m, w.halfedge());
813
                            if(d<dist[w.vertex()]) {
814
                                dist[w.vertex()] = d;
815
                                pq.push(make_pair(-d, w.vertex()));
816
                            }
817
                        }
818
                }
819
            }
820
 
821
            for(auto vid : m.vertices()) {
822
                DebugRenderer::vertex_colors[vid] = Vec3f(1-dist[vid]/max_dist,0,0);
823
                cout << dist[vid] << endl;
824
            }
825
            for(auto fid : m.faces())
826
                DebugRenderer::face_colors[fid] = Vec3f(0.3);
827
 
828
            for(auto hid : m.halfedges()) {
829
                Walker w = m.walker(hid);
830
                DebugRenderer::edge_colors[hid] = Vec3f(1.0-max(dist[w.vertex()],dist[w.opp().vertex()])/max_dist,0,0);
831
            }
832
            return;
833
        }
676 janba 834
 
835
        const Vec3f& get_color(int i)
836
        {
837
            static Vec3f ctable[100000];
838
            static bool was_here;
839
            gel_srand(0);
840
            if(!was_here)
841
            {
842
                was_here = true;
843
                ctable[0] = Vec3f(0);
844
                for(int j=1;j<100000;++j)
845
                    ctable[j] = Vec3f(0.3)+0.7*normalize(Vec3f(gel_rand(),gel_rand(),gel_rand()));
846
                ctable[3] = Vec3f(1,0,0);
847
                ctable[4] = Vec3f(0,1,0);
848
                ctable[5] = Vec3f(0,0,1);
849
                ctable[6] = Vec3f(1,0,1);
850
            }
851
            return ctable[i%100000];
852
        }
853
 
667 khor 854
        void console_info(MeshEditor* me, const std::vector<std::string> & args)
855
        {
856
            if(wantshelp(args))
857
            {
858
                me->printf("usage:  info");
859
                me->printf("Provides information about mesh.");
860
                return;
861
            }
862
            Vec3d p0, p7;
863
            bbox(me->active_mesh(), p0, p7);
864
            stringstream bbox_corners;
865
            bbox_corners << p0 << " - " << p7 << endl;
866
            me->printf("Bounding box corners : %s", bbox_corners.str().c_str());
867
            map<int,int> val_hist;
868
 
676 janba 869
            Manifold& m = me->active_mesh();
870
            for(HalfEdgeID h: m.halfedges())
871
                DebugRenderer::edge_colors[h] = Vec3f(0.3);
872
            for(VertexID v: m.vertices())
667 khor 873
            {
676 janba 874
                int val = valency(m,v);
875
                DebugRenderer::vertex_colors[v] = get_color(val);
667 khor 876
                ++val_hist[val];
676 janba 877
 
878
                if(val != 4)
879
                    circulate_vertex_ccw(m, v, [&](HalfEdgeID h){
880
                        Walker w = m.walker(h);
881
                        DebugRenderer::edge_colors[h] = Vec3f(1);
882
                        DebugRenderer::edge_colors[w.opp().halfedge()] = Vec3f(1);
883
                        while(valency(m, w.vertex())==4) {
884
                            w = w.next().opp().next();
885
                            DebugRenderer::edge_colors[w.halfedge()] = Vec3f(1);
886
                            DebugRenderer::edge_colors[w.opp().halfedge()] = Vec3f(1);
887
                        }
888
                    });
667 khor 889
            }
676 janba 890
            map<int, int> ngon_hist;
891
            for(FaceID f: m.faces()) {
892
                int ne = no_edges(m, f);
893
                ++ngon_hist[ne];
894
                DebugRenderer::face_colors[f] = 0.7*get_color(ne);
895
            }
667 khor 896
 
676 janba 897
            me->printf("Valency histogram");
667 khor 898
            for(map<int,int>::iterator iter = val_hist.begin(); iter != val_hist.end(); ++iter)
899
            {
900
                me->printf("%d, %d", iter->first, iter->second);
901
            }
902
 
676 janba 903
            me->printf("Ngon histogram");
904
            for(map<int,int>::iterator iter = ngon_hist.begin(); iter != ngon_hist.end(); ++iter)
905
            {
906
                me->printf("%d, %d", iter->first, iter->second);
907
            }
908
 
909
 
667 khor 910
            me->printf("Mesh contains %d faces", me->active_mesh().no_faces());
911
            me->printf("Mesh contains %d halfedges", me->active_mesh().no_halfedges());
912
            me->printf("Mesh contains %d vertices", me->active_mesh().no_vertices());
913
            return;
914
        }
915
 
916
 
917
        void console_simplify(MeshEditor* me, const std::vector<std::string> & args)
918
        {
919
            if(wantshelp(args))
920
            {
921
                me->printf("usage: simplify <fraction> ");
922
                me->printf("Performs Garland Heckbert (quadric based) mesh simplification.");
923
                me->printf("The only argument is the fraction of vertices to keep.");
924
                return;
925
            }
926
            me->save_active_mesh();
927
 
928
            float keep_fraction;
929
            if(args.size() == 0)
930
            {
931
                me->printf("you must specify fraction of vertices to keep");
932
                return;
933
            }
934
            istringstream a0(args[0]);
935
            a0 >> keep_fraction;
936
 
937
            Vec3d p0, p7;
938
            bbox(me->active_mesh(), p0, p7);
939
            Vec3d d = p7-p0;
940
            float s = 1.0/d.max_coord();
941
            Vec3d pcentre = (p7+p0)/2.0;
942
            for(VertexIDIterator vi = me->active_mesh().vertices_begin(); vi != me->active_mesh().vertices_end(); ++vi){
943
                me->active_mesh().pos(*vi) = (me->active_mesh().pos(*vi) - pcentre) * s;
944
            }
945
            cout << "Timing the Garland Heckbert (quadric based) mesh simplication..." << endl;
946
            Timer timer;
947
            timer.start();
948
 
949
            //simplify
950
            quadric_simplify(me->active_mesh(),keep_fraction,0.0001f,true);
951
 
952
            cout << "Simplification complete, process time: " << timer.get_secs() << " seconds" << endl;
953
 
954
            //clean up the mesh, a lot of edges were just collapsed
955
            me->active_mesh().cleanup();
956
 
957
            for(VertexIDIterator vi = me->active_mesh().vertices_begin(); vi != me->active_mesh().vertices_end(); ++vi)
958
                me->active_mesh().pos(*vi) = me->active_mesh().pos(*vi)*d.max_coord() + pcentre;
959
            return;
960
        }
961
 
962
        void console_vertex_noise(MeshEditor* me, const std::vector<std::string> & args)
963
        {
964
            if(wantshelp(args))
965
            {
966
                me->printf("usage: noise.perturb_vertices <amplitude>");
967
                me->printf("adds a random vector to each vertex. A random vector in the unit cube is generated and");
968
                me->printf("to ensure an isotropic distribution, vectors outside the unit ball are discarded.");
969
                me->printf("The vector is multiplied by the average edge length and then by the amplitude specified.");
970
                me->printf("If no amplitude is specified, the default (0.5) is used.");
971
                return;
972
            }
973
            me->save_active_mesh();
974
 
975
            float avg_length = average_edge_length(me->active_mesh());
976
 
977
            float noise_amplitude = 0.5f;
978
            if(args.size() > 0) {
979
                istringstream a0(args[0]);
980
                a0 >> noise_amplitude;
981
            }
982
 
983
            gel_srand(0);
984
            for(VertexIDIterator vi = me->active_mesh().vertices_begin(); vi != me->active_mesh().vertices_end(); ++vi){
985
                Vec3d v;
986
                do{
987
                    v = Vec3d(gel_rand(),gel_rand(),gel_rand());
988
                    v /= (float)(GEL_RAND_MAX);
989
                    v -= Vec3d(0.5);
990
                    v *= 2.0;
991
                }
992
                while(sqr_length(v) > 1.0);
993
 
994
                v *= noise_amplitude;
995
                v *= avg_length;
996
                me->active_mesh().pos(*vi) += v;
997
            }
998
            return;
999
        }
1000
 
1001
        void console_perpendicular_vertex_noise(MeshEditor* me, const std::vector<std::string> & args)
1002
        {
1003
            if(wantshelp(args)) {
1004
                me->printf("usage: noise.perturb_vertices_perpendicular <amplitude>");
1005
                me->printf("adds the normal times a random scalar times amplitude times");
1006
                me->printf("times average edge length to the vertex. (default amplitude=0.5)");
1007
                return;
1008
            }
1009
            me->save_active_mesh();
1010
 
1011
            float avg_length = average_edge_length(me->active_mesh());
1012
 
1013
            float noise_amplitude = 0.5;
1014
            if(args.size() > 0)
1015
            {
1016
                istringstream a0(args[0]);
1017
                a0 >> noise_amplitude;
1018
            }
1019
 
1020
            VertexAttributeVector<Vec3d> normals(me->active_mesh().allocated_vertices());
1021
            for(VertexIDIterator vi = me->active_mesh().vertices_begin(); vi != me->active_mesh().vertices_end(); ++vi)
1022
                normals[*vi] = normal(me->active_mesh(), *vi);
1023
 
1024
            gel_srand(0);
1025
            for(VertexIDIterator vi = me->active_mesh().vertices_begin(); vi != me->active_mesh().vertices_end(); ++vi)
1026
            {
1027
                float rval = 0.5-gel_rand() / float(GEL_RAND_MAX);
1028
                me->active_mesh().pos(*vi) += normals[*vi]*rval*noise_amplitude*avg_length*2.0;
1029
            }
1030
            return;
1031
        }
1032
 
1033
        void console_noisy_flips(MeshEditor* me, const std::vector<std::string> & args)
1034
        {
1035
            if(wantshelp(args)){
1036
                me->printf("usage:  noise.perturb_topology <iter>");
1037
                me->printf("Perform random flips. iter (default=1) is the number of iterations.");
1038
                me->printf("mostly for making nasty synthetic test cases.");
1039
                return;
1040
            }
1041
            me->save_active_mesh();
1042
 
1043
            int iter = 1;
1044
            if(args.size() > 0){
1045
                istringstream a0(args[0]);
1046
                a0 >> iter;
1047
            }
1048
 
1049
            randomize_mesh(me->active_mesh(),  iter);
1050
            return;
1051
        }
1052
 
1053
        void console_laplacian_smooth(MeshEditor* me, const std::vector<std::string> & args)
1054
        {
1055
            if(wantshelp(args)) {
1056
                me->printf("usage:  smooth.laplacian <weight> <iter>");
1057
                me->printf("Perform Laplacian smoothing. weight is the scaling factor for the Laplacian.");
1058
                me->printf("default weight = 1.0. Default number of iterations = 1");
1059
                return;
1060
            }
1061
            me->save_active_mesh();
1062
 
1063
            float t=1.0;
1064
            if(args.size() > 0){
1065
                istringstream a0(args[0]);
1066
                a0 >> t;
1067
            }
1068
            int iter = 1;
1069
            if(args.size()>1){
1070
                istringstream a0(args[1]);
1071
                a0 >> iter;
1072
            }
1073
            Util::Timer tim;
1074
            tim.start();
1075
            /// Simple laplacian smoothing with an optional weight.
1076
            laplacian_smooth(me->active_mesh(), t, iter);
1077
            cout << "It took "<< tim.get_secs();
1078
            return;
1079
        }
1080
 
1081
 
1082
        void console_mean_curvature_smooth(MeshEditor* me, const std::vector<std::string> & args){
1083
            if(wantshelp(args)) {
1084
                me->printf("usage:  smooth.mean_curvature <weight> <iter>");
1085
                me->printf("Perform mean curvature smoothing. weight is the scaling factor for the");
1086
                me->printf("mean curvature vector which has been normalized by dividing by edge lengths");
1087
                me->printf("this allows for larger steps as suggested by Desbrun et al.");
1088
                me->printf("default weight = 1.0. Default number of iterations = 1");
1089
                return;
1090
            }
1091
            me->save_active_mesh();
1092
 
1093
            double t=1.0;
1094
            if(args.size() > 0){
1095
                istringstream a0(args[0]);
1096
                a0 >> t;
1097
            }
1098
            int iter=1;
1099
            if(args.size() > 1){
1100
                istringstream a0(args[1]);
1101
                a0 >> iter;
1102
            }
1103
            VertexAttributeVector<Vec3d> new_pos(me->active_mesh().allocated_vertices());
1104
            for(int j = 0; j < iter; ++j){
1105
                for(VertexIDIterator v = me->active_mesh().vertices_begin(); v != me->active_mesh().vertices_end(); ++v) {
1106
                    Vec3d m;
1107
                    double w_sum;
1108
                    unnormalized_mean_curvature_normal(me->active_mesh(), *v, m, w_sum);
1109
                    new_pos[*v] = Vec3d(me->active_mesh().pos(*v))  + (t * m/w_sum);
1110
                }
1111
                for(VertexIDIterator v = me->active_mesh().vertices_begin(); v != me->active_mesh().vertices_end(); ++v)
1112
                    me->active_mesh().pos(*v) = new_pos[*v];
1113
            }
1114
            return;
1115
        }
1116
 
1117
        void console_taubin_smooth(MeshEditor* me, const std::vector<std::string> & args)
1118
        {
1119
            if(wantshelp(args)){
1120
                me->printf("usage:  smooth.taubin <iter>");
1121
                me->printf("Perform Taubin smoothing. iter (default=1) is the number of iterations.");
1122
                return;
1123
            }
1124
            me->save_active_mesh();
1125
 
1126
            int iter = 1;
1127
            if(args.size() > 0){
1128
                istringstream a0(args[0]);
1129
                a0 >> iter;
1130
            }
1131
            /// Taubin smoothing is similar to laplacian smoothing but reduces shrinkage
1132
            taubin_smooth(me->active_mesh(),  iter);
1133
 
1134
            return;
1135
        }
1136
 
1137
        void console_fvm_anisotropic_smooth(MeshEditor* me, const std::vector<std::string> & args)
1138
        {
1139
            if(wantshelp(args)){
1140
                me->printf("usage: smooth.fuzzy_vector_median <iter>");
1141
                me->printf("Smooth normals using fuzzy vector median smoothing. iter (default=1) is the number of iterations");
1142
                me->printf("This function does a very good job of preserving sharp edges.");
1143
                return;
1144
            }
1145
            me->save_active_mesh();
1146
 
1147
            int iter=1;
1148
            if(args.size() > 0){
1149
                istringstream a0(args[0]);
1150
                a0 >> iter;
1151
            }
1152
            // Fuzzy vector median smoothing is effective when it comes to preserving sharp edges.
1153
            anisotropic_smooth(me->active_mesh(),  iter, FVM_NORMAL_SMOOTH);
1154
 
1155
            return;
1156
        }
1157
 
1158
        void console_bilateral_anisotropic_smooth(MeshEditor* me, const std::vector<std::string> & args)
1159
        {
1160
            if(wantshelp(args)){
1161
                me->printf("usage: smooth.fuzzy_vector_median <iter>");
1162
                me->printf("Smooth normals using fuzzy vector median smoothing. iter (default=1) is the number of iterations");
1163
                me->printf("This function does a very good job of preserving sharp edges.");
1164
                return;
1165
            }
1166
            me->save_active_mesh();
1167
 
1168
            int iter=1;
1169
            if(args.size() > 0){
1170
                istringstream a0(args[0]);
1171
                a0 >> iter;
1172
            }
1173
 
1174
            anisotropic_smooth(me->active_mesh(),  iter, BILATERAL_NORMAL_SMOOTH);
1175
 
1176
            return;
1177
        }
1178
 
1179
        void console_triangulate(MeshEditor* me, const std::vector<std::string> & args)
1180
        {
1181
            if(wantshelp(args)) {
1182
                me->printf("usage:  triangulate");
1183
                me->printf("This function triangulates all non triangular faces of the mesh.");
1184
                me->printf("you may want to call it after hole closing. For a polygon it simply connects");
1185
                me->printf("the two closest vertices in a recursive manner until only triangles remain");
1186
                return;
1187
            }
1188
            me->save_active_mesh();
1189
 
1190
            shortest_edge_triangulate(me->active_mesh());
1191
            me->active_mesh().cleanup();
1192
            valid(me->active_mesh());
1193
            return;
1194
        }
1195
 
1196
 
1197
        void console_remove_caps(MeshEditor* me, const std::vector<std::string> & args)
1198
        {
1199
            if(wantshelp(args)) {
1200
                me->printf("usage:  cleanup.remove_caps thresh");
1201
                me->printf("Remove caps (triangles with one very big angle). The thresh argument is the fraction of PI to");
1202
                me->printf("use as threshold for big angle. Default is 0.85. Caps are removed by flipping.");
1203
                return;
1204
            }
1205
            me->save_active_mesh();
1206
 
1207
            float t = 0.85f;
1208
            if(args.size() > 0){
1209
                istringstream a0(args[0]);
1210
                a0 >> t;
1211
            }
1212
            remove_caps(me->active_mesh(), static_cast<float>(M_PI) *t);
1213
            me->active_mesh().cleanup();
1214
 
1215
            return;
1216
        }
1217
 
1218
        void console_remove_needles(MeshEditor* me, const std::vector<std::string> & args)
1219
        {
1220
            if(wantshelp(args)){
1221
                me->printf("usage: cleanup.remove_needles <thresh>");
1222
                me->printf("Removes very short edges by collapse. thresh is multiplied by the average edge length");
1223
                me->printf("to get the length shorter than which we collapse. Default = 0.1");
1224
                return;
1225
            }
1226
            me->save_active_mesh();
1227
 
1228
            float thresh = 0.1f;
1229
            if(args.size() > 0){
1230
                istringstream a0(args[0]);
1231
                a0 >> thresh;
1232
            }
1233
            float avg_length = average_edge_length(me->active_mesh());
1234
            remove_needles(me->active_mesh(), thresh * avg_length);
1235
            me->active_mesh().cleanup();
1236
 
1237
            return;
1238
        }
1239
 
676 janba 1240
        void console_flip_orientation(MeshEditor* me, const std::vector<std::string> & args)
1241
        {
1242
            if(wantshelp(args)){
1243
                me->printf("usage: cleanup.flip_orientation");
1244
                me->printf("reorients all faces - flipping normal direction");
1245
                return;
1246
            }
1247
            me->save_active_mesh();
1248
            flip_orientation(me->active_mesh());
1249
            return;
1250
        }
1251
 
1252
 
667 khor 1253
        void console_undo(MeshEditor* me, const std::vector<std::string> & args)
1254
        {
1255
            if(wantshelp(args)) {
1256
                me->printf("usage:  undo");
1257
                me->printf("This function undoes one operation. Repeated undo does nothing");
1258
                return;
1259
            }
1260
            me->restore_active_mesh();
1261
            return;
1262
        }
1263
 
676 janba 1264
        void console_save_trackball(MeshEditor* me, const std::vector<std::string> & args)
1265
        {
1266
            if(wantshelp(args)) {
1267
                me->printf("usage:  display.save_trackball");
1268
                me->printf("This function saves the trackball to disk");
1269
                return;
1270
            }
1271
            me->save_ball();
1272
            return;
1273
        }
1274
 
1275
        void console_load_trackball(MeshEditor* me, const std::vector<std::string> & args)
1276
        {
1277
            if(wantshelp(args)) {
1278
                me->printf("usage:  display.load_trackball");
1279
                me->printf("This function loads the trackball from disk");
1280
                return;
1281
            }
1282
            me->load_ball();
1283
            return;
1284
        }
1285
 
667 khor 1286
 
1287
    }
1288
 
1289
 
1290
    void MeshEditor::register_console_function(const std::string& name,
1291
                                               const std::function<void(MeshEditor*, const std::vector<std::string>&)>& con_fun,
1292
                                               const std::string& help_txt)
1293
    {
1294
        std::function<void (const std::vector<std::string>&)> f = bind(con_fun, this, placeholders::_1);
1295
        theConsole.reg_cmdN(name, f, help_txt);
1296
    }
1297
 
1298
    void MeshEditor::keyparse(unsigned short key){
1299
        //toggle console with ESC
1300
        if (key == 27)
1301
        {
1302
            console_visible = !console_visible;
1303
            return;
1304
        }
1305
 
1306
        if (console_visible)
1307
        {
676 janba 1308
            static Timer tim;
1309
            if(key==13)
1310
                tim.start();
667 khor 1311
            theConsole.keyboard(key);
1312
            if(key == 13)
1313
            {
1314
                active_visobj().post_create_display_list();
676 janba 1315
                double t = tim.get_secs();
1316
                printf("%f seconds",t);
667 khor 1317
            }
1318
            return;
1319
        }
1320
        else {
1321
 
1322
            switch(key) {
676 janba 1323
                    case 'R':
1324
                {
1325
                    theConsole.key_up();
1326
                    theConsole.keyboard(13);
1327
                    active_visobj().post_create_display_list();
1328
                }
1329
                    break;
667 khor 1330
                case 'q': exit(0);
1331
                case '\033':
1332
                    console_visible = false;
1333
                    break;
1334
                case '1':
1335
                case '2':
1336
                case '3':
1337
                case '4':
1338
                case '5':
1339
                case '6':
1340
                case '7':
1341
                case '8':
1342
                case '9':
1343
                {
1344
                    int w[4];
1345
                    glGetIntegerv(GL_VIEWPORT, w);
1346
                    active = key - '1';
1347
                    active_view_control().reshape(w[2],w[3]);
1348
                }
1349
                    break;
1350
                case 'f': display_smooth_shading = !display_smooth_shading; break;
1351
                case 'w':
1352
                    display_render_mode = "wire"; break;
1353
                case 'n':
1354
                    display_render_mode = "normal"; break;
1355
                case 'i':
1356
                    display_render_mode = "isophotes"; break;
1357
                case 'r':
1358
                    display_render_mode = "reflection"; break;
1359
                case 'h':
1360
                    display_render_mode = "harmonics"; break;
1361
                case 't':
1362
                    display_render_mode = "toon"; break;
1363
                case 'g':
1364
                    display_render_mode = "glazed"; break;
1365
                case 'a':
1366
                    display_render_mode = "ambient_occlusion"; break;
1367
                case 'c':
1368
                    display_render_mode = "copper"; break;
1369
                case 'C':
1370
                    display_render_mode = "curvature_lines"; break;
1371
                case 'M':
1372
                    display_render_mode = "mean_curvature"; break;
1373
                case 'G':
1374
                    display_render_mode = "gaussian_curvature"; break;
1375
                case ' ':
1376
                    active_visobj().clear_selection();
1377
                    break;
1378
 
1379
            }
1380
 
1381
            if(key != '\033') post_create_display_list();
1382
        }
1383
 
1384
    }
1385
 
1386
    void MeshEditor::printf(const char* format, ...)
1387
    {
1388
        //format text
1389
        char buffer[1024];
1390
        va_list args;
1391
        va_start(args, format);
1392
        vsprintf(buffer, format, args);
1393
        va_end(args);
1394
        theConsole.print(buffer);
1395
    }
1396
 
1397
    void MeshEditor::key_up(){theConsole.key_up();}
1398
    void MeshEditor::key_down(){theConsole.key_down();}
1399
    void MeshEditor::key_left(){theConsole.key_left();}
1400
    void MeshEditor::key_right(){theConsole.key_right();}
1401
    void MeshEditor::key_home(){theConsole.key_home();}
1402
    void MeshEditor::key_end(){theConsole.key_end();}
1403
 
676 janba 1404
 
1405
 
667 khor 1406
    void MeshEditor::grab_ball(TrackBallAction action, const CGLA::Vec2i& pos){
1407
        active_view_control().grab_ball(action, pos);
1408
    }
1409
    void MeshEditor::roll_ball(const CGLA::Vec2i& pos){
1410
        active_view_control().roll_ball(pos);
1411
    }
1412
    void MeshEditor::release_ball(){
1413
        active_view_control().release_ball();
1414
    }
1415
    bool MeshEditor::try_spinning_ball(){
1416
        return active_view_control().try_spin();
1417
    }
1418
 
676 janba 1419
    void MeshEditor::save_ball() {
1420
        ofstream ofs("trackball.bin", ios_base::binary);
1421
        active_view_control().save(ofs);
1422
 
1423
    }
1424
    void MeshEditor::load_ball() {
1425
        ifstream ifs("trackball.bin", ios_base::binary);
1426
        active_view_control().load(ifs);
1427
 
1428
    }
1429
 
1430
 
667 khor 1431
    bool MeshEditor::grab_mesh(const CGLA::Vec2i& pos)
1432
    {
1433
        if(depth_pick(pos[0], pos[1], depth))
1434
        {
1435
            dragging = true;
1436
            mouse_x = pos[0];
1437
            mouse_y = pos[1];
1438
            Vec3d p0 = screen2world(mouse_x, mouse_y, depth);
1439
            Manifold& m = active_mesh();
1440
            active_visobj().save_old();
1441
            Vec3d c;
1442
            float r;
1443
            bsphere(m, c, r);
1444
            for(auto vid : m.vertices())
1445
            {
1446
                double l = sqr_length(p0-m.pos(vid));
1447
                weight_vector[vid] = exp(-l/(brush_size*r*r));
1448
            }
1449
            return true;
1450
        }
1451
        return false;
1452
    }
1453
 
1454
    bool MeshEditor::drag_mesh(const CGLA::Vec2i& pos)
1455
    {
1456
        if(dragging)
1457
        {
1458
            Vec3d p0 = screen2world(mouse_x, mouse_y, depth);
1459
            Vec3d p1 = screen2world(pos[0], pos[1], depth);
1460
            Vec3d v = p1-p0;
1461
            Manifold& m = active_mesh();
1462
            for(auto vid : m.vertices())
1463
                m.pos(vid) = active_visobj().mesh_old().pos(vid) + weight_vector[vid] * v;
1464
            post_create_display_list();
1465
            return true;
1466
        }
1467
        return false;
1468
    }
1469
 
1470
    void MeshEditor::release_mesh()
1471
    {
1472
        dragging = false;
1473
    }
1474
 
676 janba 1475
 
1476
 
1477
 
1478
    mutex parallel_work;
1479
    void MeshEditor::display(int scale){
667 khor 1480
 
676 janba 1481
        // Clear screen.
667 khor 1482
        glClearColor(1, 1, 1, 0);
1483
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
676 janba 1484
 
1485
        //        parallel_work.lock();
1486
        //        active_visobj().post_create_display_list();
1487
 
1488
 
1489
        // Display object.
667 khor 1490
        active_visobj().display(display_render_mode, theConsole, display_smooth_shading, display_gamma);
676 janba 1491
 
1492
        // Draw console
667 khor 1493
        if(console_visible)
1494
        {
1495
            glUseProgram(0);
1496
            theConsole.display(scale);
1497
        }
676 janba 1498
 
1499
        // Static variable controlling whether we render shadow at all.
1500
        static Console::variable<int> shadow_enable(0);
1501
        shadow_enable.reg(theConsole, "display.shadow.enable", "");
1502
        if(shadow_enable) {
1503
            // Static variables that control the shadow display created and linked to console
1504
            static Console::variable<float> zenith(1.571);
1505
            static Console::variable<float> azimuth(0);
1506
            static Console::variable<float> shadow_alpha(0.3);
1507
            azimuth.reg(theConsole, "display.shadow.azimuth", "");
1508
            zenith.reg(theConsole, "display.shadow.zenith", "");
1509
            shadow_alpha.reg(theConsole, "display.shadow.shadow_alpha", "");
667 khor 1510
 
676 janba 1511
 
1512
            // Shadow buffer (really a frame buffer object)
1513
            static ShadowBuffer sb;
1514
 
1515
            // String containing fragment program for shadow rendering
1516
            static string shadow_shdr_fp = "#version 120\n"
1517
            "    uniform sampler2DShadow shadow_map;\n"
1518
            "    uniform mat4 Mat;\n"
1519
            "   uniform float shadow_alpha;\n"
1520
            "    varying vec4 ep;\n"
1521
            "    void main()\n"
1522
            "    {\n"
1523
            "        vec4 light_pos =  Mat * ep;\n"
1524
            "        light_pos.z = max(0.001,min(0.999,light_pos.z-0.003));\n"
1525
            "        if(light_pos.x <=0 || light_pos.x >=1 || light_pos.y <=0 || light_pos.y>=1) gl_FragColor = vec4(1);"
1526
            "   else      gl_FragColor= vec4(1.0-shadow_alpha)+shadow_alpha*0.25*(shadow2D(shadow_map, light_pos.xyz+vec3(0.001,-0.001,0))+shadow2D(shadow_map, light_pos.xyz+vec3(0.001,0.001,0))+shadow2D(shadow_map, light_pos.xyz-vec3(0.001,0.001,0))+shadow2D(shadow_map, light_pos.xyz+vec3(-0.001,0.001,0)));\n"
1527
            "    }\n";
1528
 
1529
            // Shader program for shadow rendering is compiled and linked.
1530
            static GLuint prog = 0;
1531
            if(!prog)
1532
            {
1533
                GLuint vp = create_glsl_shader(GL_VERTEX_SHADER,"#version 120\n varying vec4 ep; void main(){ep = gl_Vertex; gl_Position = ftransform();}");
1534
                GLuint fp = create_glsl_shader(GL_FRAGMENT_SHADER, shadow_shdr_fp);
1535
                prog = glCreateProgram();
1536
 
1537
                glAttachShader(prog, vp);
1538
                glAttachShader(prog, fp);
1539
                glLinkProgram(prog);
1540
            }
1541
 
1542
 
1543
            // Setup OpenGL state for lighting - used when rendering 3D object casting shadow
1544
            Vec4f lpos = Vec4f(cos(azimuth)*cos(zenith),sin(zenith),sin(azimuth)*cos(zenith),0);
1545
            glLightfv(GL_LIGHT0, GL_POSITION, lpos.get());
1546
            Vec4f mamb(.8,.8,.8,0);
1547
            Vec4f lamb(.4,.4,.5,0);
1548
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mamb.get());
1549
            glLightfv(GL_LIGHT0, GL_AMBIENT, lamb.get());
1550
 
1551
            // Get old viewport dimensions. Setup rendering to FBO and set viewport
1552
            // dimensions for rendering shadows.
1553
            GLint viewp[4];
1554
            glGetIntegerv(GL_VIEWPORT, viewp);
1555
            sb.enable();
1556
            glViewport(0, 0, 1024, 1024);
1557
 
1558
            // Setup object transformations using old school GL.
1559
            Mat4x4f m;
1560
            float r = active_visobj().get_bsphere_radius();
1561
            glMatrixMode(GL_MODELVIEW);
1562
            glPushMatrix();
1563
            glLoadIdentity();
1564
            glMatrixMode(GL_PROJECTION);
1565
            glPushMatrix();
1566
            glLoadIdentity();
1567
            glOrtho(-2*r, 2*r, -2*r, 2*r, -2*r, 2*r);
1568
            gluLookAt(0.1*r*cos(azimuth)*cos(zenith),0.1*r*sin(zenith),0.1*r*sin(azimuth)*cos(zenith), 0,0,0, 0,1,0);
1569
 
1570
            // Copy the transformation matrix to user code.
1571
            glGetFloatv(GL_PROJECTION_MATRIX, m.get());
1572
 
1573
            // Draw the object in light space.
1574
            draw(active_visobj().mesh());
1575
 
1576
            // Restore transformation matrices.
1577
            glPopMatrix();
1578
            glMatrixMode(GL_MODELVIEW);
1579
            glPopMatrix();
1580
 
1581
            // Restore the usual on screen framebuffer.
1582
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1583
            glDrawBuffer(GL_BACK);
1584
            glViewport(0, 0, viewp[2], viewp[3]);
1585
 
1586
            // Use shadow: bind the shadow texture to unit 0.
1587
            sb.bind_textures(0);
1588
 
1589
            // Use the shadow rendering shader program.
1590
            glUseProgram(prog);
1591
            active_visobj().view_control().set_gl_modelview();
1592
            glUniform1i(glGetUniformLocation(prog, "shadow_map"), 0);
1593
            glUniform1f(glGetUniformLocation(prog, "shadow_alpha"), shadow_alpha);
1594
            m = translation_Mat4x4f(Vec3f(0.5)) * scaling_Mat4x4f(Vec3f(0.5)) * transpose(m);
1595
            glUniformMatrix4fv(glGetUniformLocation(prog, "Mat"), 1, 1, m.get());
1596
 
1597
 
1598
            // Setup blending such that the shadow is alpha blended with model.
1599
            glDepthFunc(GL_LEQUAL);
1600
            glEnable(GL_BLEND);
1601
            glBlendFunc(GL_ZERO, GL_SRC_COLOR);
1602
 
1603
            // Draw ground plane for shadows.
1604
            Vec3d p0, p7;
1605
            bbox(active_visobj().mesh(), p0, p7);
1606
            glBegin(GL_QUADS);
1607
            glVertex3f(-100*r, p0[1],-100*r);
1608
            glVertex3f(-100*r, p0[1],100*r);
1609
            glVertex3f(100*r, p0[1],100*r);
1610
            glVertex3f(100*r, p0[1],-100*r);
1611
            glEnd();
1612
 
1613
            // Draw model again ... just to add shadow.
1614
            draw(active_visobj().mesh());
1615
 
1616
            // Disable blending and shader program.
1617
            glDisable(GL_BLEND);
1618
            glUseProgram(0);
1619
        }
1620
        //        parallel_work.unlock();
1621
        //        std::this_thread::sleep_for(std::chrono::milliseconds(10));
667 khor 1622
    }
1623
 
1624
    void MeshEditor::reshape(int w, int h) {
1625
        for(VisObj& v : vo)
1626
            v.view_control().reshape(w, h);
1627
    }
1628
 
1629
    void MeshEditor::init() {
1630
        glewInit();
1631
 
1632
        GLint vp[4];
1633
        glGetIntegerv(GL_VIEWPORT, vp);
1634
        for(VisObj& vis_obj : vo)
1635
            vis_obj.view_control().reshape(vp[2], vp[3]);
1636
 
1637
        glEnable(GL_CULL_FACE);
1638
        glCullFace(GL_BACK);
1639
        glEnable(GL_LIGHTING);
1640
        glEnable(GL_LIGHT0);
1641
        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
1642
 
1643
        glMatrixMode(GL_MODELVIEW);
1644
        glLoadIdentity();
1645
        glClearColor(1,1,0, 0.f);
1646
        glColor4f(1.0f, 1.0f, 1.0f, 0.f);
1647
        float material[4] = {1,1,1,1};
1648
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material);
1649
        glEnable(GL_DEPTH_TEST);
1650
 
1651
        register_console_function("simplify", console_simplify,"");
1652
 
1653
        register_console_function("ridge_lines", console_ridge_lines,"");
1654
 
1655
        register_console_function("smooth.mean_curvature", console_mean_curvature_smooth,"");
1656
        register_console_function("smooth.laplacian", console_laplacian_smooth,"");
1657
        register_console_function("smooth.taubin", console_taubin_smooth,"");
1658
        register_console_function("smooth.fuzzy_vector_median_anisotropic", console_fvm_anisotropic_smooth ,"");
1659
        register_console_function("smooth.bilateral_anisotropic", console_bilateral_anisotropic_smooth ,"");
1660
 
1661
        register_console_function("optimize.valency", console_optimize_valency,"");
1662
        register_console_function("optimize.minimize_dihedral_angles", console_minimize_dihedral,"");
1663
        register_console_function("optimize.minimize_curvature", console_minimize_curvature,"");
1664
        register_console_function("optimize.maximize_min_angle", console_maximize_min_angle,"");
1665
        register_console_function("cleanup.close_holes", console_close_holes,"");
1666
        register_console_function("load_mesh", console_reload,"");
1667
        register_console_function("add_mesh", console_add_mesh,"");
1668
 
676 janba 1669
        register_console_function("cleanup.stitch", console_stitch,"");
1670
        register_console_function("cleanup.remove_duplicates", console_remove_duplicates,"");
1671
        register_console_function("cleanup.remove_val2", console_remove_val2, "");
1672
        register_console_function("cleanup.flip_orientation", console_flip_orientation,"");
667 khor 1673
        register_console_function("cleanup.remove_caps", console_remove_caps,"");
1674
        register_console_function("cleanup.remove_needles", console_remove_needles,"");
1675
        register_console_function("triangulate", console_triangulate,"");
1676
        register_console_function("refine.split_edges", console_refine_edges,"");
1677
        register_console_function("refine.split_faces", console_refine_faces,"");
1678
        register_console_function("subdivide.catmull_clark", console_cc_subdivide,"");
676 janba 1679
        register_console_function("subdivide.rootcc", console_root_cc_subdivide,"");
667 khor 1680
        register_console_function("subdivide.loop", console_loop_subdivide,"");
1681
        register_console_function("subdivide.root3", console_root3_subdivide,"");
1682
        register_console_function("subdivide.doo_sabin", console_doosabin_subdivide,"");
1683
        register_console_function("subdivide.butterfly", console_butterfly_subdivide,"");
1684
        register_console_function("save_mesh", console_save,"");
1685
        register_console_function("noise.perturb_vertices", console_vertex_noise,"");
1686
        register_console_function("noise.perturb_vertices_perpendicular", console_perpendicular_vertex_noise,"");
1687
        register_console_function("noise.perturb_topology", console_noisy_flips,"");
1688
 
1689
        register_console_function("dual", console_dual,"");
1690
        register_console_function("flatten", console_flatten,"");
1691
 
1692
        register_console_function("align", console_align,"");
1693
        register_console_function("undo", console_undo,"");
1694
 
1695
        register_console_function("validity", console_valid,"");
1696
        register_console_function("info", console_info,"");
1697
 
676 janba 1698
        register_console_function("harmonics.reset_shape", console_reset_shape, "");
667 khor 1699
        register_console_function("harmonics.analyze", console_analyze, "");
676 janba 1700
        register_console_function("harmonics.partial_reconstruct", console_partial_reconstruct,"");
667 khor 1701
 
1702
        register_console_function("Dijkstra", console_Dijkstra,"");
1703
 
676 janba 1704
        register_console_function("display.save_trackball", console_save_trackball, "Saves trackball to disk");
1705
        register_console_function("display.load_trackball", console_load_trackball, "Load trackball to disk");
1706
 
667 khor 1707
        register_console_function("transform.scale", console_scale, "Scale mesh");
1708
        register_console_function("test", console_test, "Test some shit");
1709
        active.reg(theConsole, "active_mesh", "The active mesh");
1710
        display_render_mode.reg(theConsole, "display.render_mode", "Display render mode");
1711
        brush_size.reg(theConsole, "brush_size", "Size of brush used for editing");
1712
        display_smooth_shading.reg(theConsole, "display.smooth_shading", "1 for smooth shading 0 for flat");
1713
        display_gamma.reg(theConsole, "display.gamma", "The gamma setting for the display");
1714
 
1715
        theConsole.print("Welcome to MeshEdit");
1716
        theConsole.newline();
1717
    }
1718
 
1719
    bool MeshEditor::add_file(const std::string& str)
1720
    {
1721
        while (active_mesh().no_vertices()>0 && active<NO_MESHES)
1722
            active  = active + 1;
1723
        if(active == NO_MESHES)
1724
            active = 0;
1725
        if(active_visobj().reload(str)) {
1726
            active_visobj().post_create_display_list();
1727
            return true;
1728
        }
1729
        return false;
1730
    }
1731
 
1732
    bool MeshEditor::reload_active_from_file(const std::string& str)
1733
    {
1734
        if(active_visobj().reload(str)) {
1735
            active_visobj().post_create_display_list();
1736
            return true;
1737
        }
1738
        return false;
1739
    }
1740
 
1741
    bool MeshEditor::add_to_active_from_file(const std::string& str)
1742
    {
1743
        if(active_visobj().add_mesh(str)) {
1744
            active_visobj().post_create_display_list();
1745
            return  true;
1746
        }
1747
        return false;
1748
    }
1749
 
1750
 
1751
}