Subversion Repositories gelsvn

Rev

Rev 412 | Rev 416 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
386 jab 1
/*
2
 *  MeshEdit is a small application which allows you to load and edit a mesh.
3
 *  The mesh will be stored in GEL's half edge based Manifold data structure.
4
 *  A number of editing operations are supported. Most of these are accessible from the 
5
 *  console that pops up when you hit 'esc'.
6
 *
7
 *  Created by J. Andreas Bærentzen on 15/08/08.
8
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
9
 *
10
 */
399 jab 11
 
12
#include <string>
386 jab 13
#include <iostream>
14
#include <CGLA/eigensolution.h>
15
#include <CGLA/Vec2d.h>
16
#include <CGLA/Vec3d.h>
17
#include <CGLA/Mat3x3d.h>
18
#include <CGLA/Mat2x2d.h>
19
#include <CGLA/Mat2x3d.h>
20
 
21
#include <LinAlg/Matrix.h>
22
#include <LinAlg/Vector.h>
23
#include <LinAlg/LapackFunc.h>
24
 
25
#include <Util/Timer.h>
26
#include <Util/ArgExtracter.h>
27
 
28
#include <GL/glew.h>
29
#include <GLGraphics/gel_glut.h>
30
 
31
#include <HMesh/Manifold.h>
32
#include <HMesh/VertexCirculator.h>
33
#include <HMesh/FaceCirculator.h>
34
#include <HMesh/build_manifold.h>
35
#include <HMesh/mesh_optimization.h>
36
#include <HMesh/triangulate.h>
37
#include <HMesh/load.h>
387 jab 38
#include <HMesh/quadric_simplify.h>
39
#include <HMesh/smooth.h>
386 jab 40
#include <HMesh/x3d_save.h>
388 jab 41
#include <HMesh/obj_save.h>
387 jab 42
#include <HMesh/mesh_optimization.h>
388 jab 43
#include <HMesh/triangulate.h>
44
#include <HMesh/close_holes.h>
45
#include <HMesh/caps_and_needles.h>
46
#include <HMesh/refine_edges.h>
47
#include <HMesh/subdivision.h>
386 jab 48
 
49
#include <GLConsole/GLConsole.h>
394 jab 50
#include <Util/Timer.h>
386 jab 51
#include "harmonics.h"
412 jab 52
#include "curvature.h"
399 jab 53
#include "Renderer.h"
54
#include "VisObj.h"
386 jab 55
 
391 jab 56
using namespace std;
57
using namespace HMesh;
58
using namespace Geometry;
59
using namespace GLGraphics;
60
using namespace CGLA;
61
using namespace Util;
62
using namespace LinAlg;
412 jab 63
using namespace CVarUtils;
386 jab 64
 
391 jab 65
inline VisObj& get_vis_obj(int i)
66
{
67
	static VisObj vo[9];
68
	return vo[i];
69
}
70
 
71
inline VisObj& avo()
72
{
412 jab 73
	static int& active = CreateCVar("active_mesh",0);
391 jab 74
	return get_vis_obj(active);
75
}
76
 
77
inline Manifold& active_mesh()
78
{
79
	return avo().mesh();
80
}
81
 
82
inline GLViewController& active_view_control()
83
{
84
	return avo().view_control();
85
}
86
 
386 jab 87
// Single global instance so glut can get access
412 jab 88
Trie CVarTrie;
386 jab 89
GLConsole theConsole;
90
 
91
////////////////////////////////////////////////////////////////////////////////
92
char* ConsoleHelp(std::vector<std::string> &args)
93
{
94
    theConsole.Printf("");
95
    theConsole.Printf("----------------- HELP -----------------");
391 jab 96
    theConsole.Printf("Press ESC key to open and close console");
386 jab 97
    theConsole.Printf("Press TAB to see the available commands and functions");
98
    theConsole.Printf("Functions are shown in green and variables in yellow");
99
    theConsole.Printf("Setting a value: [command] = value");
100
    theConsole.Printf("Getting a value: [command]");
101
    theConsole.Printf("Functions: [function] [arg1] [arg2] ...");
391 jab 102
    theConsole.Printf("Entering arg1=? or arg1=help will give a description.");
386 jab 103
    theConsole.Printf("History: Up and Down arrow keys move through history.");
104
    theConsole.Printf("Tab Completion: TAB does tab completion and makes suggestions.");
391 jab 105
    theConsole.Printf("");
106
    theConsole.Printf("Keyboard commands (when console is not active):");
399 jab 107
    theConsole.Printf("w   : switch to display.render_mode = wireframe");
108
    theConsole.Printf("i   : switch to display.render_mode = isophotes");
109
    theConsole.Printf("r   : switch to display.render_mode = reflection");
401 jab 110
    theConsole.Printf("m   : switch to display.render_mode = metallic");
111
    theConsole.Printf("g   : switch to display.render_mode = glazed");
112
    theConsole.Printf("n   : switch to display.render_mode = normal");
399 jab 113
    theConsole.Printf("h   : switch to display.render_mode = harmonics");
114
    theConsole.Printf("f   : toggle smooth/flat shading");
391 jab 115
    theConsole.Printf("1-9 : switch between active meshes.");
399 jab 116
    theConsole.Printf("d   : (display.render_mode = harmonics) diffuse light on and off");
117
    theConsole.Printf("h   : (display.render_mode = harmonics) highlight on and off ");
118
    theConsole.Printf("+/- : (display.render_mode = harmonics) which eigenvector to show");
391 jab 119
    theConsole.Printf("q   : quit program");
120
    theConsole.Printf("ESC : open console");
121
    theConsole.Printf("");
122
    theConsole.Printf("Mouse: Left button rotates, middle zooms, right pans");
386 jab 123
    theConsole.Printf("----------------- HELP -----------------");
124
    theConsole.Printf("");
125
    return "";
126
}
127
 
391 jab 128
bool wantshelp(std::vector<std::string> &args)
129
{
130
	if(args.size()==0) return false;
131
	string str = args[0];
132
	if(str=="help" || str=="HELP" || str=="Help" || str=="?") return true;
133
	return false;
134
}
386 jab 135
 
391 jab 136
/// Function that aligns two meshes.
137
char* console_align(std::vector<std::string> &args)
138
{
139
	if(wantshelp(args)) 
399 jab 140
	{
141
		theConsole.Printf("usage: align <dest> <src>");
142
		theConsole.Printf("This function aligns dest mesh with src");
143
		theConsole.Printf("In practice the GLViewController of src is copied to dst.");
144
		theConsole.Printf("both arguments are mandatory and must be numbers between 1 and 9.");
145
		theConsole.Printf("Note that results might be unexpexted if the meshes are not on the same scale");
146
		return "";
147
	}
148
 
391 jab 149
	int dest = 0;
150
	if(args.size()>0)
151
	{
152
		istringstream a0(args[0]);
153
		a0 >> dest;
154
		--dest;
155
		if(dest <0 || dest>8) return "dest mesh out of range (1-9)";
156
	}
157
	else return "neither source nor destination mesh?!";
158
	int src = 0;
159
	if(args.size()>1)
160
	{
161
		istringstream a1(args[1]);
162
		a1 >> src;
163
		--src;
164
		if(src <0 || src>8) return "src mesh out of range (1-9)";
165
	}	
166
	else return "no src mesh?";
386 jab 167
 
391 jab 168
	get_vis_obj(dest).view_control() = get_vis_obj(src).view_control();
169
 
170
	return "";
386 jab 171
}
172
 
391 jab 173
 
388 jab 174
char* console_save(std::vector<std::string> &args)
175
{
391 jab 176
	if(wantshelp(args)) 
399 jab 177
	{
178
		theConsole.Printf("usage: save <name.x3d|name.obj> ");
179
		return "";
180
	}
388 jab 181
	string& file_name = args[0];
182
	if(args.size() == 1)
183
	{
184
		if(file_name.substr(file_name.length()-4,file_name.length())==".obj")
185
		{
391 jab 186
			obj_save(file_name, active_mesh());
388 jab 187
			return "";
188
		}
189
		else if(file_name.substr(file_name.length()-4,file_name.length())==".x3d")
190
		{
391 jab 191
			x3d_save(file_name, active_mesh());
388 jab 192
			return "";
193
		}
194
		return "unknown format";
195
	}
196
	return "usage: save <name.x3d|name.obj> ";
197
}
386 jab 198
 
415 jab 199
////////////////////////////////////////////////////////////////////////////////
200
/**
201
 */
202
char* ConsoleSaveHistory( std::vector<std::string> &vArgs )
412 jab 203
{
415 jab 204
    if( vArgs.size() != 0 ) {
205
        theConsole.SaveHistory( vArgs[0] );
206
    }
207
    else {
208
        theConsole.SaveHistory();
209
    }
210
	return "";
412 jab 211
}
212
 
415 jab 213
////////////////////////////////////////////////////////////////////////////////
214
/**
215
 */
216
char* ConsoleLoadHistory( std::vector<std::string> &vArgs )
412 jab 217
{
415 jab 218
    if( vArgs.size() != 0 ) {
219
        theConsole.LoadHistory( vArgs[0] );
220
    }
221
    else {
222
        theConsole.LoadHistory();
223
    }
224
	return "";
412 jab 225
}
226
 
415 jab 227
////////////////////////////////////////////////////////////////////////////////
228
/**
229
 */
230
char* ConsoleClearHistory( std::vector<std::string> &vArgs )
231
{
232
	theConsole.ClearHistory();
233
	return "";
234
}
412 jab 235
 
415 jab 236
////////////////////////////////////////////////////////////////////////////////
237
/**
238
 */
239
char* ConsoleStartScript( std::vector<std::string> &vArgs )
240
{
241
    theConsole.StartScript();
242
	return "";
243
}
244
 
245
////////////////////////////////////////////////////////////////////////////////
246
/**
247
 */
248
char* ConsoleStopScript( std::vector<std::string> &vArgs )
249
{
250
    theConsole.StopScript();
251
	return "";
252
}
253
 
254
////////////////////////////////////////////////////////////////////////////////
255
/**
256
 */
257
char* ConsoleShowScript( std::vector<std::string> &vArgs )
258
{
259
    theConsole.ShowScript();
260
	return "";
261
}
262
 
263
////////////////////////////////////////////////////////////////////////////////
264
/**
265
 */
266
char* ConsoleRunScript( std::vector<std::string> &vArgs )
267
{
268
    theConsole.RunScript();
269
    return "";
270
}
271
 
272
////////////////////////////////////////////////////////////////////////////////
273
/**
274
 */
275
char* ConsoleSaveScript( std::vector<std::string> &vArgs )
276
{
277
    if( vArgs.size() != 0 ) {
278
        theConsole.SaveScript( vArgs[0] );
279
    }
280
    else {
281
        theConsole.SaveScript();
282
    }
283
	return "";
284
}
285
 
286
////////////////////////////////////////////////////////////////////////////////
287
/**
288
 */
289
char* ConsoleLaunchScript( std::vector<std::string> &vArgs )
290
{
291
    if( vArgs.size() != 0 ) {
292
        theConsole.LaunchScript( vArgs[0] );
293
    } 
294
    else {
295
        theConsole.LaunchScript();
296
    }
297
	return "";
298
}
299
 
300
 
301
////////////////////////////////////////////////////////////////////////////////
302
/**
303
 */
304
char* ConsoleLoad( std::vector<std::string> &vArgs )
305
{
306
    std::string sFile = "cvars.xml";
307
    std::vector< std::string > vAcceptedSubstrings;
308
 
309
    if( vArgs.size() > 0 ) {
310
        sFile = vArgs[0]; 
311
        for( size_t i=1; i<vArgs.size(); i++ ) {
312
            vAcceptedSubstrings.push_back( vArgs[i] );
313
        }
314
    }
315
    theConsole.Printf("Loading file from \"%s\".", sFile.c_str() );
316
    if( !CVarUtils::Load( sFile, vAcceptedSubstrings) ) {
317
        theConsole.Printf( "Error loading file.\n" );
318
    }
319
    return "";
320
}
321
 
322
 
388 jab 323
char* console_refine_edges(std::vector<std::string> &args)
324
{
391 jab 325
	if(wantshelp(args)) 
399 jab 326
	{
327
		theConsole.Printf("usage: refine.split_edges <length>");
328
		theConsole.Printf("splits edges longer than <length>; default is 0.5 times average length");
329
		return "";
330
	}
331
 
388 jab 332
	float thresh = 0.5;
333
	if(args.size()>0)
334
	{
335
		istringstream a0(args[0]);
336
		a0 >> thresh;
337
	}
391 jab 338
	float avg_length = average_edge_length(active_mesh());
339
	refine_edges(active_mesh(), thresh * avg_length);
388 jab 340
	return "";
391 jab 341
 
388 jab 342
}
343
 
344
char* console_refine_faces(std::vector<std::string> &args)
345
{
391 jab 346
	if(wantshelp(args)) 
399 jab 347
	{
348
		theConsole.Printf("usage: refine.split_faces ");
349
		theConsole.Printf("usage:  Takes no arguments. Inserts a vertex at the centre of each face.");
350
		return "";
351
	}
352
 
391 jab 353
	safe_triangulate(active_mesh());
388 jab 354
	return "";
391 jab 355
 
388 jab 356
}
357
 
358
char* console_cc_subdivide(std::vector<std::string> &args)
359
{
391 jab 360
	if(wantshelp(args)) 
399 jab 361
	{
362
		theConsole.Printf("usage: refine.catmull_clark ");
363
		theConsole.Printf("Splits each polygon into four (Catmull Clark style)");
364
		return "";
365
	}
391 jab 366
	cc_split(active_mesh(),active_mesh());
388 jab 367
	return "";
368
}
369
 
394 jab 370
char* console_dual(std::vector<std::string> &args)
371
{
372
	if(wantshelp(args)) 
373
	{
374
		theConsole.Printf("usage: dual ");
375
		theConsole.Printf("Produces the dual by converting each face to a vertex placed at the barycenter.");
376
		return "";
377
	}
378
 
379
	Manifold& m = active_mesh();
380
 
381
	// make sure every face knows its number
382
	m.enumerate_faces();
383
 
384
	vector<Vec3f> vertices(m.no_faces());
399 jab 385
	vector<int> faces;
394 jab 386
	vector<int> indices;
387
 
388
	// Create new vertices. Each face becomes a vertex whose position
389
	// is the centre of the face
390
	int i=0;
391
	for(FaceIter f=m.faces_begin(); f!=m.faces_end(); ++f,++i)
392
		vertices[i] = centre(f);
393
 
394
	// Create new faces. Each vertex is a new face with N=valency of vertex
395
	// edges.
396
	i=0;
397
	for(VertexIter v=m.vertices_begin(); v!= m.vertices_end(); ++v,++i)
399 jab 398
		if(!is_boundary(v))
399
		{
400
			VertexCirculator vc(v);
401
			vector<int> index_tmp;
402
			for(; !vc.end(); ++vc)
403
				index_tmp.push_back(vc.get_face()->touched);
404
 
405
			// Push vertex indices for this face onto indices vector.
406
			// The circulator moves around the face in a clockwise fashion
407
			// so we just reverse the ordering.
408
			indices.insert(indices.end(), index_tmp.rbegin(), index_tmp.rend());
409
 
410
			// Insert face valency in the face vector.
411
			faces.push_back(vc.no_steps());
412
		}
394 jab 413
 
414
	// Clear the manifold before new geometry is inserted.
415
	m.clear();
416
 
417
	// And build
418
	build_manifold(m, vertices.size(), &vertices[0], faces.size(),
419
				   &faces[0],&indices[0]);
420
 
421
	return "";
422
}
388 jab 423
 
424
 
387 jab 425
char* console_minimize_curvature(std::vector<std::string> &args)
426
{
391 jab 427
	if(wantshelp(args)) 
399 jab 428
	{
429
		theConsole.Printf("usage: optimize.minimize_curvature <anneal>");
430
		theConsole.Printf("Flip edges to minimize mean curvature.");
431
		theConsole.Printf("If anneal is true, simulated annealing (slow) is used rather than a greedy scheme");
432
		return "";
433
	}
387 jab 434
	bool anneal=false;
435
	if(args.size()>0)
436
	{
437
		istringstream a0(args[0]);
438
		a0 >> anneal;
439
	}
391 jab 440
 
441
	minimize_curvature(active_mesh(), anneal);
442
	avo().post_create_display_list();
387 jab 443
	return "";
444
}
445
 
446
char* console_minimize_dihedral(std::vector<std::string> &args)
447
{
391 jab 448
	if(wantshelp(args)) 
399 jab 449
	{
450
		theConsole.Printf("usage: optimize.minimize_dihedral <iter> <anneal> <use_alpha> <gamma> ");
451
		theConsole.Printf("Flip edges to minimize dihedral angles.");
452
		theConsole.Printf("Iter is the max number of iterations. anneal tells us whether to use ");
453
		theConsole.Printf("simulated annealing and not greedy optimization. use_alpha (default=true) ");
454
		theConsole.Printf("means to use angle and not cosine of anglegamma (default=4) is the power ");
455
		theConsole.Printf("to which we raise the dihedral angle");
456
		return "";
457
	}
387 jab 458
	int iter = 1000;
459
	if(args.size()>0)
460
	{
461
		istringstream a0(args[0]);
462
		a0 >> iter;
463
	}
391 jab 464
 
387 jab 465
	bool anneal = false;
466
	if(args.size()>1)
467
	{
468
		istringstream a0(args[0]);
469
		a0 >> anneal;
470
	}
391 jab 471
 
387 jab 472
	bool use_alpha = true;
388 jab 473
	if(args.size()>2)
387 jab 474
	{
475
		istringstream a0(args[0]);
476
		a0 >> use_alpha;
477
	}
391 jab 478
 
387 jab 479
	float gamma = 4.0;
480
	if(args.size()>3)
481
	{
482
		istringstream a0(args[0]);
483
		a0 >> gamma;
484
	}
485
 
486
 
391 jab 487
	minimize_dihedral_angle(active_mesh(), iter, anneal, use_alpha, gamma);
387 jab 488
	return "";
489
}
490
 
388 jab 491
char* console_maximize_min_angle(std::vector<std::string> &args)
492
{
391 jab 493
	if(wantshelp(args)) 
399 jab 494
	{
495
		theConsole.Printf("usage: optimize.maximize_min_angle <thresh> <anneal>");
496
		theConsole.Printf("Flip edges to maximize min angle - to make mesh more Delaunay.");
497
		theConsole.Printf("If the dot product of the normals between adjacent faces < thresh");
498
		theConsole.Printf("no flip will be made. anneal selects simulated annealing rather ");
499
		theConsole.Printf("nthan greedy optimization.");
500
		return "";
501
	}
388 jab 502
	float thresh=0.0;
503
	if(args.size()>0)
504
	{
505
		istringstream a0(args[0]);
506
		a0 >> thresh;
507
	}
508
	bool anneal=false;
509
	if(args.size()>1)
510
	{
511
		istringstream a0(args[0]);
512
		a0 >> anneal;
513
	}
391 jab 514
	maximize_min_angle(active_mesh(),thresh,anneal);
388 jab 515
	return "";
516
}
517
 
518
 
387 jab 519
char* console_optimize_valency(std::vector<std::string> &args)
520
{
391 jab 521
	if(wantshelp(args)) 
399 jab 522
	{
523
		theConsole.Printf("usage: optimize.valency <anneal> ");
524
		theConsole.Printf("Optimizes valency for triangle meshes. Anneal selects simulated annealing rather than greedy optim.");
525
		return "";
526
	}
387 jab 527
	bool anneal=false;
528
	if(args.size()>0)
529
	{
530
		istringstream a0(args[0]);
531
		a0 >> anneal;
532
	}
391 jab 533
	optimize_valency(active_mesh(), anneal);
387 jab 534
	return "";
535
}
536
 
388 jab 537
char* console_analyze(std::vector<std::string> &args)
538
{
391 jab 539
	if(wantshelp(args)) 
399 jab 540
	{
541
		theConsole.Printf("usage:  harmonics.analyze");
542
		theConsole.Printf("Creates the Laplace Beltrami operator for the mesh and finds all eigensolutions.");
543
		theConsole.Printf("It also projects the vertices onto the eigenvectors - thus transforming the mesh");
544
		theConsole.Printf("to this basis.");
545
		theConsole.Printf("Note that this will stall the computer for a large mesh - as long as we use Lapack.");
546
		return "";
547
	}
391 jab 548
	avo().harmonics_analyze_mesh();
388 jab 549
	return "";
550
}
551
 
552
 
386 jab 553
char* console_partial_reconstruct(std::vector<std::string> &args)
554
{
411 jrf 555
  if(args.size() != 3)
556
		theConsole.Printf("usage: haramonics.partial_reconstruct <e0> <e1> <s>");
557
 
558
  if(wantshelp(args)) 
399 jab 559
	{
560
		theConsole.Printf("Reconstruct from projections onto eigenvectors. The two first arguments indicate");
561
		theConsole.Printf("the eigenvector interval that we reconstruct from. The last argument is the ");
562
		theConsole.Printf("scaling factor. Thus, for a vertex, v, the formula for computing the position, p, is:");
563
		theConsole.Printf("for (i=e0; i<=e1;++i) p += proj[i] * Q[i][v] * s;");
564
		theConsole.Printf("where proj[i] is the 3D vector containing the x, y, and z projections of the mesh onto");
565
		theConsole.Printf("eigenvector i. Q[i][v] is the v'th coordinate of the i'th eigenvector.");
566
		theConsole.Printf("Note that if vertex coordinates are not first reset, the result is probably unexpected.");
411 jrf 567
	}
568
 
569
  if(args.size() != 3)
399 jab 570
		return "";
411 jrf 571
 
572
  int E0,E1;
386 jab 573
	float scale;
574
	istringstream a0(args[0]);
575
	a0 >> E0;
576
	istringstream a1(args[1]);
577
	a1 >> E1;
578
	istringstream a2(args[2]);
579
	a2 >> scale;
391 jab 580
	avo().harmonics_partial_reconstruct(E0,E1,scale);
386 jab 581
	return "";
582
}
583
 
584
char* console_reset_shape(std::vector<std::string> &args)
585
{
391 jab 586
	if(wantshelp(args)) 
399 jab 587
	{
588
		theConsole.Printf("usage: harmonics.reset_shape ");
589
		theConsole.Printf("Simply sets all vertices to 0,0,0. Call this before doing partial_reconstruct");
590
		theConsole.Printf("unless you know what you are doing.");
591
		return "";
592
	}
391 jab 593
	avo().harmonics_reset_shape();
386 jab 594
	return "";
595
}
596
 
597
 
388 jab 598
char* console_close_holes(std::vector<std::string> &args)
599
{
391 jab 600
	if(wantshelp(args)) 
399 jab 601
	{
602
		theConsole.Printf("usage: cleanup.close_holes");
603
		theConsole.Printf("This function closes holes. It simply follows the loop of halfvectors which");
604
		theConsole.Printf("enclose the hole and add a face to which they all point.");
605
		return "";
606
	}
391 jab 607
	close_holes(active_mesh());
388 jab 608
	return "";
609
}
386 jab 610
 
388 jab 611
char* console_reload(std::vector<std::string> &args)
612
{
391 jab 613
	if(wantshelp(args)) 
399 jab 614
	{
412 jab 615
		theConsole.Printf("usage:  load <file>");
616
		theConsole.Printf("(Re)loads the current file if no argument is given, but");
399 jab 617
		theConsole.Printf("if an argument is given, then that becomes the current file");
618
		return "";
619
	}
391 jab 620
	if(!avo().reload(args.size()>0 ? args[0]:""))
621
		return "failed to load";
388 jab 622
	return "";
623
}
624
 
625
 
387 jab 626
char* console_simplify(std::vector<std::string> &args)
627
{
391 jab 628
	if(wantshelp(args)) 
399 jab 629
	{
630
		theConsole.Printf("usage: simplify <fraction> ");
631
		theConsole.Printf("Performs Garland Heckbert (quadric based) mesh simplification.");
632
		theConsole.Printf("The only argument is the fraction of vertices to keep.");
633
		return "";
634
	}
387 jab 635
	float keep_fraction;
636
	if(args.size()==0) return "you must specify fraction of vertices to keep";
637
	istringstream a0(args[0]);
638
	a0 >> keep_fraction;
391 jab 639
 
387 jab 640
	Vec3f p0, p7;
391 jab 641
	active_mesh().get_bbox(p0, p7);
387 jab 642
	Vec3f d = p7-p0;
643
	float s = 1.0/d.max_coord();
644
	Vec3f pcentre = (p7+p0)/2.0;
391 jab 645
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
387 jab 646
		vi->pos = (vi->pos - pcentre) * s;
391 jab 647
	quadric_simplify(active_mesh(),keep_fraction,0.0001f,true);
648
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
387 jab 649
		vi->pos = vi->pos*d.max_coord() + pcentre;
650
	return "";
651
}
652
 
391 jab 653
char* console_vertex_noise(std::vector<std::string> &args)
654
{
655
	if(wantshelp(args)) 
399 jab 656
	{
657
		theConsole.Printf("usage: noise.perturb_vertices <amplitude>");
403 jab 658
		theConsole.Printf("adds a random vector to each vertex. A random vector in the unit cube is generated and");
659
		theConsole.Printf("to ensure an isotropic distribution, vectors outside the unit ball are discarded.");
660
		theConsole.Printf("The vector is multiplied by the average edge length and then by the amplitude specified.");
661
		theConsole.Printf("If no amplitude is specified, the default (0.5) is used.");
399 jab 662
		return "";
663
	}
391 jab 664
	float avg_length = average_edge_length(active_mesh());
665
 
666
	float noise_amplitude = 0.5;
667
	if(args.size()>0) 
668
	{
669
		istringstream a0(args[0]);
670
		a0 >> noise_amplitude;
671
	}
672
 
673
	srand(0);
674
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
675
	{
676
		Vec3f v;
677
		do {
678
			v = Vec3f(rand(),rand(),rand());
679
			v /= RAND_MAX;
680
		} while(sqr_length(v) > 1.0);
681
		v -= Vec3f(0.5);
682
		v *= 2.0;
683
		v *= noise_amplitude;
684
		v *= avg_length;
685
		vi->pos += v;
686
	}		
687
	return "";
688
}
689
 
412 jab 690
char* console_perpendicular_vertex_noise(std::vector<std::string> &args)
691
{
692
	if(wantshelp(args)) 
693
	{
694
		theConsole.Printf("usage: noise.perturb_vertices_perpendicular <amplitude>");
695
		theConsole.Printf("adds the normal times a random scalar times amplitude times");
696
		theConsole.Printf("times average edge length to the vertex. (default amplitude=0.5)");
697
		return "";
698
	}
699
	float avg_length = average_edge_length(active_mesh());
700
 
701
	float noise_amplitude = 0.5;
702
	if(args.size()>0) 
703
	{
704
		istringstream a0(args[0]);
705
		a0 >> noise_amplitude;
706
	}
707
 
708
	vector<Vec3f> normals(active_mesh().no_vertices());
709
	int i=0;
710
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi,++i)
711
		normals[i] = normal(vi);
712
	i=0;
713
	srandom(0);
714
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi,++i)
715
	{
716
		float rval = 0.5-random()/float(RAND_MAX);
717
		vi->pos += normals[i]*rval*noise_amplitude*avg_length*2.0;
718
	}
719
	return "";
720
}
721
 
391 jab 722
char* console_noisy_flips(std::vector<std::string> &args)
723
{
724
	if(wantshelp(args)) 
399 jab 725
	{
726
		theConsole.Printf("usage:  noise.perturb_topology <iter>");
727
		theConsole.Printf("Perform random flips. iter (default=1) is the number of iterations.");
728
		theConsole.Printf("mostly for making nasty synthetic test cases.");
729
		return "";
730
	}
391 jab 731
	int iter=1;
732
	if(args.size()>0)
733
	{
734
		istringstream a0(args[0]);
735
		a0 >> iter;
736
	}
737
 
738
	randomize_mesh(active_mesh(),  iter);
739
	return "";
740
}
741
 
387 jab 742
char* console_laplacian_smooth(std::vector<std::string> &args)
743
{
391 jab 744
	if(wantshelp(args)) 
399 jab 745
	{
412 jab 746
		theConsole.Printf("usage:  smooth.laplacian <weight> <iter>");
399 jab 747
		theConsole.Printf("Perform Laplacian smoothing. weight is the scaling factor for the Laplacian.");
412 jab 748
		theConsole.Printf("default weight = 1.0. Default number of iterations = 1");
399 jab 749
		return "";
750
	}
387 jab 751
	float t=1.0;
752
	if(args.size()>0)
753
	{
754
		istringstream a0(args[0]);
755
		a0 >> t;
756
	}
412 jab 757
	int iter=1;
758
	if(args.size()>1)
759
	{
760
		istringstream a0(args[1]);
761
		a0 >> iter;
762
	}
763
 
387 jab 764
	/// Simple laplacian smoothing with an optional weight.
412 jab 765
	for(int i=0;i<iter;++i) laplacian_smooth(active_mesh(), t);
387 jab 766
	return "";
767
}
768
 
412 jab 769
char* console_mean_curvature_smooth(std::vector<std::string> &args)
770
{
771
	if(wantshelp(args)) 
772
	{
773
		theConsole.Printf("usage:  smooth.mean_curvature <weight> <iter>");
774
		theConsole.Printf("Perform mean curvature smoothing. weight is the scaling factor for the");
775
		theConsole.Printf("mean curvature vector which has been normalized by dividing by edge lengths");
776
		theConsole.Printf("this allows for larger steps as suggested by Desbrun et al.");
777
		theConsole.Printf("default weight = 1.0. Default number of iterations = 1");
778
		return "";
779
	}
780
	float t=1.0;
781
	if(args.size()>0)
782
	{
783
		istringstream a0(args[0]);
784
		a0 >> t;
785
	}
786
	int iter=1;
787
	if(args.size()>1)
788
	{
789
		istringstream a0(args[1]);
790
		a0 >> iter;
791
	}	
792
	vector<Vec3d> new_pos(active_mesh().no_vertices());
793
	for(int j=0;j<iter;++j)
794
	{
795
		int i=0;
796
		for(VertexIter v = active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v,++i) {
797
			Vec3d m;
798
			double w_sum;
799
			unnormalized_mean_curvature_normal(v, m, w_sum);
800
			new_pos[i] = Vec3d(v->pos)  - (t * m/w_sum);
801
		}
802
		i=0;
803
		for(VertexIter v = active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v,++i)
804
			v->pos = Vec3f(new_pos[i]);
805
	}
806
	return "";
807
}
808
 
809
 
387 jab 810
char* console_taubin_smooth(std::vector<std::string> &args)
811
{
391 jab 812
	if(wantshelp(args)) 
399 jab 813
	{
814
		theConsole.Printf("usage:  smooth.taubin <iter>");
815
		theConsole.Printf("Perform Taubin smoothing. iter (default=1) is the number of iterations.");
816
		return "";
817
	}
387 jab 818
	int iter=1;
819
	if(args.size()>0)
820
	{
821
		istringstream a0(args[0]);
822
		a0 >> iter;
823
	}
824
 
825
	/// Taubin smoothing is similar to laplacian smoothing but reduces shrinkage
391 jab 826
	taubin_smooth(active_mesh(),  iter);
387 jab 827
	return "";
828
}
829
 
830
char* console_fvm_smooth(std::vector<std::string> &args)
831
{	
391 jab 832
	if(wantshelp(args)) 
399 jab 833
	{
834
		theConsole.Printf("usage: smooth.fuzzy_vector_median <iter>");
835
		theConsole.Printf("Smooth normals using fuzzy vector median smoothing. iter (default=1) is the number of iterations");
836
		theConsole.Printf("This function does a very good job of preserving sharp edges.");
837
		return "";
838
	}
387 jab 839
	int iter=1;
840
	if(args.size()>0)
841
	{
842
		istringstream a0(args[0]);
843
		a0 >> iter;
844
	}
845
	/** Fuzzy vector median smoothing is effective when it comes to
846
	 preserving sharp edges. */
391 jab 847
	fvm_smooth(active_mesh(),  iter);
387 jab 848
	return "";
391 jab 849
 
387 jab 850
}
851
 
388 jab 852
char* console_triangulate(std::vector<std::string> &args)
853
{	
391 jab 854
	if(wantshelp(args)) 
399 jab 855
	{
856
		theConsole.Printf("usage:  triangulate");
857
		theConsole.Printf("This function triangulates all non triangular faces of the mesh.");
858
		theConsole.Printf("you may want to call it after hole closing. For a polygon it simply connects");
859
		theConsole.Printf("the two closest vertices in a recursive manner until only triangles remain");
860
		return "";
861
	}
391 jab 862
	shortest_edge_triangulate(active_mesh());
388 jab 863
	return "";
864
}
865
 
866
 
867
char* console_remove_caps(std::vector<std::string> &args)
868
{	
391 jab 869
	if(wantshelp(args)) 
399 jab 870
	{
871
		theConsole.Printf("usage:  cleanup.remove_caps thresh");
872
		theConsole.Printf("Remove caps (triangles with one very big angle). The thresh argument is the fraction of PI to");
873
		theConsole.Printf("use as threshold for big angle. Default is 0.85. Caps are removed by flipping.");
874
		return "";
875
	}
391 jab 876
	float t=0.85;
877
	if(args.size()>0)
878
	{
879
		istringstream a0(args[0]);
880
		a0 >> t;
881
	}
399 jab 882
 
391 jab 883
	remove_caps_from_trimesh(active_mesh(), static_cast<float>(M_PI) *t);
388 jab 884
	return "";
885
}
886
 
887
char* console_remove_needles(std::vector<std::string> &args)
888
{	
391 jab 889
	if(wantshelp(args)) 
399 jab 890
	{
891
		theConsole.Printf("usage: cleanup.remove_needles <thresh>");
892
		theConsole.Printf("Removes very short edges by collapse. thresh is multiplied by the average edge length");
893
		theConsole.Printf("to get the length shorter than which we collapse. Default = 0.1");
894
		return "";
895
	}
388 jab 896
	float thresh = 0.1;
897
	if(args.size()>0)
898
	{
899
		istringstream a0(args[0]);
900
		a0 >> thresh;
901
	}
391 jab 902
	float avg_length = average_edge_length(active_mesh());
903
	remove_needles_from_trimesh(active_mesh(), thresh * avg_length);
388 jab 904
	return "";
905
}
906
 
391 jab 907
void reshape(int W, int H)
908
{
909
	active_view_control().reshape(W,H);
910
}
911
 
386 jab 912
void display() 
913
{
914
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
915
 
412 jab 916
	static string& display_render_mode = CreateCVar<string>("display.render_mode","");
917
	static int& display_smooth= CreateCVar<int>("display.smooth_shading",1);
386 jab 918
 
919
	glPushMatrix();
920
 
399 jab 921
	avo().display(display_render_mode, display_smooth);
386 jab 922
 
923
	glPopMatrix();
924
 
925
	glUseProgram(0);
926
	theConsole.RenderConsole();
927
 
928
	glutSwapBuffers();
929
}
930
 
931
void animate() 
932
{	
394 jab 933
	//usleep( (int)1e4 );
391 jab 934
	active_view_control().try_spin();
386 jab 935
	glutPostRedisplay();
936
}
937
 
938
 
939
void mouse(int button, int state, int x, int y) 
940
{
941
	Vec2i pos(x,y);
942
	if (state==GLUT_DOWN) 
943
	{
944
		if (button==GLUT_LEFT_BUTTON) 
391 jab 945
			active_view_control().grab_ball(ROTATE_ACTION,pos);
386 jab 946
		else if (button==GLUT_MIDDLE_BUTTON) 
391 jab 947
			active_view_control().grab_ball(ZOOM_ACTION,pos);
386 jab 948
		else if (button==GLUT_RIGHT_BUTTON) 
391 jab 949
			active_view_control().grab_ball(PAN_ACTION,pos);
386 jab 950
	}
951
	else if (state==GLUT_UP)
391 jab 952
		active_view_control().release_ball();
386 jab 953
}
954
 
955
void motion(int x, int y) {
956
	Vec2i pos(x,y);
391 jab 957
	active_view_control().roll_ball(Vec2i(x,y));
386 jab 958
}
959
 
960
void keyboard_spec(int key, int x, int y)
961
{
391 jab 962
	int mod = glutGetModifiers();
412 jab 963
	if( theConsole.IsOpen() ) {
391 jab 964
		// If shift held, scroll the console
965
		if( mod == GLUT_ACTIVE_SHIFT ) {
966
			switch (key){
967
				case GLUT_KEY_UP:
968
					theConsole.ScrollDownLine();
969
					break;
970
				case GLUT_KEY_DOWN: 
971
					theConsole.ScrollUpLine();
972
					break;
973
			}
974
		} else {
975
			theConsole.StandardKeyBindings( key );
976
		}
977
	}
386 jab 978
}
979
 
980
 
981
void keyboard(unsigned char key, int x, int y) 
982
{	
412 jab 983
	if(theConsole.IsOpen())
391 jab 984
	{
386 jab 985
		switch(key) {
986
			case '\033': 
987
				theConsole.ToggleConsole();
412 jab 988
			default:
989
				theConsole.EnterCommandCharacter(key);
990
			break;
388 jab 991
		}
391 jab 992
		if(key == 13)	avo().post_create_display_list();
993
 
994
	}	
386 jab 995
	else {
412 jab 996
		string& display_render_mode = GetCVarRef<string>("display.render_mode");
997
		int& display_smooth = GetCVarRef<int>("display.smooth_shading");
998
		int& active  = GetCVarRef<int>("active_mesh");
386 jab 999
 
391 jab 1000
 
386 jab 1001
		switch(key) {
1002
			case 'q': exit(0);
1003
			case '\033':
1004
				theConsole.ToggleConsole();
1005
				break;
391 jab 1006
			case '1':
1007
			case '2':
1008
			case '3':
1009
			case '4':
1010
			case '5':
1011
			case '6':
1012
			case '7':
1013
			case '8':
1014
			case '9':
1015
				active = key - '1'; break;
399 jab 1016
			case 'f': display_smooth = !display_smooth; break;
386 jab 1017
			case 'w':
399 jab 1018
				display_render_mode = "wire"; break;
1019
			case 'n':
1020
				display_render_mode = "normal"; break;
1021
			case 'i':
1022
				display_render_mode = "isophotes"; break;
1023
			case 'r':
1024
				display_render_mode = "reflection"; break;
1025
			case 'h':
1026
				display_render_mode = "harmonics"; break;
403 jab 1027
			case 't':
1028
				display_render_mode = "toon"; break;
401 jab 1029
			case 'g':
1030
				display_render_mode = "glazed"; break;
406 jab 1031
			case 'a':
1032
				display_render_mode = "ambient_occlusion"; break;
1033
			case 'c':
1034
				display_render_mode = "copper"; break;
403 jab 1035
			case 'C':
1036
				display_render_mode = "curvature_lines"; break;
1037
			case 'M':
1038
				display_render_mode = "mean_curvature"; break;
1039
			case 'G':
1040
				display_render_mode = "gaussian_curvature"; break;
386 jab 1041
		}
391 jab 1042
 
399 jab 1043
		if(display_render_mode.substr(0,4) == "harm")
391 jab 1044
			avo().harmonics_parse_key(key);
1045
 
403 jab 1046
		if(key != '\033') avo().post_create_display_list();		
386 jab 1047
	}
1048
}
1049
 
1050
void init_glut(int argc, char** argv)
1051
{
397 jab 1052
	glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH|GLUT_ALPHA);
386 jab 1053
	glutInitWindowSize(WINX, WINY);
1054
	glutInit(&argc, argv);
1055
	glutCreateWindow("Shape Harmonics");
1056
	glutDisplayFunc(display);
1057
	glutKeyboardFunc(keyboard);
1058
	glutSpecialFunc(keyboard_spec);
1059
	glutReshapeFunc(reshape);
1060
	glutMouseFunc(mouse);
1061
	glutMotionFunc(motion);
1062
	glutIdleFunc(animate);
1063
}
1064
 
1065
void init_gl()
1066
{
1067
	glewInit();
1068
	glEnable(GL_LIGHTING);
1069
	glEnable(GL_LIGHT0);
388 jab 1070
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
399 jab 1071
 
386 jab 1072
	// Set the value of a uniform
1073
	//glUniform2f(glGetUniformLocation(prog_P0,"WIN_SCALE"), win_size_x/2.0, win_size_y/2.0);
1074
 
1075
	glMatrixMode(GL_MODELVIEW);
1076
	glLoadIdentity();
1077
	glClearColor(0.50f, 0.50f, 0.50f, 0.f);
1078
	glColor4f(1.0f, 1.0f, 1.0f, 0.f);
406 jab 1079
	float material[4] = {1,1,1,1};
1080
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material);
386 jab 1081
	glEnable(GL_DEPTH_TEST);
1082
 
412 jab 1083
	CreateCVar( "help", ConsoleHelp );
1084
	CreateCVar("harmonics.reset_shape", console_reset_shape);
1085
	CreateCVar("harmonics.analyze", console_analyze);
1086
	CreateCVar("harmonics.partial_reconstruct", console_partial_reconstruct);
1087
	CreateCVar("simplify", console_simplify);
1088
	CreateCVar("smooth.mean_curvature", console_mean_curvature_smooth);
1089
	CreateCVar("smooth.laplacian", console_laplacian_smooth);
1090
	CreateCVar("smooth.taubin", console_taubin_smooth);
1091
	CreateCVar("smooth.fuzzy_vector_median", console_fvm_smooth);
391 jab 1092
 
412 jab 1093
	CreateCVar("optimize.valency", console_optimize_valency);
1094
	CreateCVar("optimize.minimize_dihedral_angles", console_minimize_dihedral);
1095
	CreateCVar("optimize.minimize_curvature", console_minimize_curvature);
1096
	CreateCVar("optimize.maximize_min_angle", console_maximize_min_angle);
1097
	CreateCVar("cleanup.close_holes", console_close_holes);
1098
	CreateCVar("load", console_reload);
391 jab 1099
 
412 jab 1100
	CreateCVar("cleanup.remove_caps", console_remove_caps);
1101
	CreateCVar("cleanup.remove_needles", console_remove_needles);
1102
	CreateCVar("triangulate", console_triangulate);
1103
	CreateCVar("refine.split_edges", console_refine_edges);
1104
	CreateCVar("refine.split_faces", console_refine_faces);
1105
	CreateCVar("refine.catmull_clark", console_cc_subdivide);
1106
	CreateCVar("save", console_save);
1107
	CreateCVar("noise.perturb_vertices", console_vertex_noise);
1108
	CreateCVar("noise.perturb_vertices_perpendicular", console_perpendicular_vertex_noise);
1109
	CreateCVar("noise.perturb_topology", console_noisy_flips);
399 jab 1110
 
412 jab 1111
	CreateCVar("dual", console_dual);
399 jab 1112
 
412 jab 1113
	CreateCVar("align", console_align);
387 jab 1114
 
415 jab 1115
	CVarUtils::CreateCVar( "history.load", ConsoleLoadHistory );
1116
    CVarUtils::CreateCVar( "history.save", ConsoleSaveHistory );
1117
    CVarUtils::CreateCVar( "history.clear", ConsoleClearHistory );
387 jab 1118
 
415 jab 1119
    CVarUtils::CreateCVar( "script.start", ConsoleStartScript );
1120
    CVarUtils::CreateCVar( "script.stop", ConsoleStopScript );
1121
    CVarUtils::CreateCVar( "script.show", ConsoleShowScript );
1122
    CVarUtils::CreateCVar( "script.run", ConsoleRunScript );
1123
    CVarUtils::CreateCVar( "script.save", ConsoleSaveScript );
1124
    CVarUtils::CreateCVar( "script.launch", ConsoleLaunchScript );
1125
 
1126
 
386 jab 1127
}
1128
 
1129
int main(int argc, char** argv)
1130
{
1131
	ArgExtracter ae(argc, argv);
391 jab 1132
 
1133
	init_glut(argc,argv);
1134
	init_gl();
1135
 
1136
	Harmonics::init();
1137
 
399 jab 1138
	if(argc>1)
386 jab 1139
	{		
391 jab 1140
		string file = ae.get_last_arg();
1141
		avo().reload(file);
386 jab 1142
	}
1143
 
399 jab 1144
 
386 jab 1145
	glutMainLoop();
1146
}
1147
 
1148