Subversion Repositories gelsvn

Rev

Rev 650 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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