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