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