Subversion Repositories gelsvn

Rev

Rev 632 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
595 jab 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
 
8
#include "mesh_optimization.h"
9
 
149 jab 10
#include <cfloat>
11
#include <queue>
595 jab 12
#include <vector>
149 jab 13
 
601 jab 14
#include "../CGLA/Vec3d.h"
652 janba 15
#include "../Geometry/Implicit.h"
595 jab 16
//#include "Manifold.h"
17
#include "AttributeVector.h"
652 janba 18
#include "triangulate.h"
19
#include "smooth.h"
595 jab 20
 
150 jab 21
namespace HMesh
149 jab 22
{
595 jab 23
    using namespace std;
24
    using namespace CGLA;
652 janba 25
    using namespace Geometry;
595 jab 26
 
27
    // Small utility functions
28
    namespace 
29
    {
30
        class LineSeg
31
        {
32
            const Vec3d p0;
33
            const Vec3d p1;
34
            const float l;
35
            const CGLA::Vec3d dir;
36
        public:
149 jab 37
 
595 jab 38
            LineSeg(const Vec3d& _p0, const Vec3d& _p1): 
39
			p0(_p0), p1(_p1), l(length(p1-p0)), dir((p1-p0)/l) {}
40
 
41
			bool inseg(const Vec3d& p) const
149 jab 42
			{
43
				double t = dot(dir, p-p0);
44
				if(t<0)
45
					return false;
46
				if(t>l)
47
					return false;
48
				return true;
49
			}
595 jab 50
        };
51
 
52
        Vec3d compute_normal(Vec3d* v)
53
        {
54
            Vec3d norm;
55
            for(int i = 0; i < 4; ++i)
56
            {
57
                norm[0] += (v[i][1]-v[(i+1)%4][1])*(v[i][2]+v[(i+1)%4][2]);
58
                norm[1] += (v[i][2]-v[(i+1)%4][2])*(v[i][0]+v[(i+1)%4][0]);
59
                norm[2] += (v[i][0]-v[(i+1)%4][0])*(v[i][1]+v[(i+1)%4][1]);
60
            }
61
            float l = norm.length();
62
            if(l>0.0f)
63
                norm /= l;
64
            return norm;
65
        }
66
 
67
        bool would_flip(const Manifold& m, HalfEdgeID h)
68
        {
69
            Walker w = m.walker(h);
70
 
71
            VertexID hv = w.vertex();
72
            VertexID hov = w.opp().vertex();
73
            VertexID hnv = w.next().vertex();
74
            VertexID honv = w.opp().next().vertex();
75
 
76
            Vec3d v[4];
77
            v[0] = Vec3d(m.pos(hv));
78
            v[1] = Vec3d(m.pos(hov));
79
            v[2] = Vec3d(m.pos(hnv));
80
            v[3] = Vec3d(m.pos(honv));
81
 
82
            Vec3d dir = compute_normal(v);
83
 
84
            Vec3d n1a = cross(v[3]-v[0], v[2]-v[0]);
85
            Vec3d n2a = cross(v[2]-v[1], v[3]-v[1]);
86
 
87
            if(dot(normalize(n1a), dir) < 0)
88
                return true;
89
            if(dot(normalize(n2a), dir) < 0)
90
                return true;
91
            return false;
92
        }
93
    }
94
 
95
 
96
    double ValencyEnergy::delta_energy(const Manifold& m, HalfEdgeID h) const
97
    {
98
        Walker w = m.walker(h);
99
 
100
        VertexID v1 = w.opp().vertex();
101
        VertexID v2 = w.vertex();
102
        VertexID vo1 = w.next().vertex();
103
        VertexID vo2 = w.opp().next().vertex();
104
 
105
        int val1  = valency(m, v1);
106
        int val2  = valency(m, v2);
107
        int valo1 = valency(m, vo1);
108
        int valo2 = valency(m, vo2);
109
 
110
        // The optimal valency is four for a boundary vertex
111
        // and six elsewhere.
112
        int t1 = boundary(m, v1) ? 4 : 6;
113
        int t2 = boundary(m, v2) ? 4 : 6;
114
        int to1 = boundary(m, vo1) ? 4 : 6;
115
        int to2 = boundary(m, vo2) ? 4 : 6;
116
 
117
        int before = 
118
        sqr(val1-t1)+sqr(val2-t2)+
119
        sqr(valo1-to1)+sqr(valo2-to2);
120
        int after = 
121
        sqr(valo1+1-to1)+sqr(val1-1-t1)+
122
        sqr(val2-1-t2)+sqr(valo2+1-to2);
123
 
124
        return static_cast<double>(after-before);
125
    }
126
 
127
 
128
	class RandomEnergy: public EnergyFun
129
	{
130
	public:
131
		double delta_energy(const Manifold& m, HalfEdgeID he) const
149 jab 132
		{
595 jab 133
			return static_cast<double>(gel_rand()/static_cast<float>(GEL_RAND_MAX));
149 jab 134
		}
595 jab 135
	};
136
 
137
 
138
	double MinAngleEnergy::min_angle(const Vec3d& v0, const Vec3d& v1, const Vec3d& v2) const
139
	{
140
		Vec3d a = normalize(v1-v0);
141
		Vec3d b = normalize(v2-v1);
142
		Vec3d c = normalize(v0-v2);
143
 
144
		return min(dot(a,-c), min(dot(b,-a), dot(c,-b)));
145
	}
146
	double MinAngleEnergy::delta_energy(const Manifold& m, HalfEdgeID h) const
147
	{
148
		Walker w = m.walker(h);
149
 
150
		VertexID hv = w.vertex();
151
		VertexID hnv = w.next().vertex();
152
		VertexID hov= w.opp().vertex();
153
		VertexID honv = w.opp().next().vertex();
154
 
155
		Vec3d v0(m.pos(hv));
156
		Vec3d v1(m.pos(hnv));
157
		Vec3d v2(m.pos(hov));
158
		Vec3d v3(m.pos(honv));
159
 
160
		Vec3d n1a = normalize(cross(v1-v0,v3-v0));
161
		Vec3d n2a = normalize(cross(v3-v2,v1-v2));
162
 
163
		if(dot(n1a, n2a) > thresh){
164
			double before = min(min_angle(v0,v1,v2), min_angle(v0,v2,v3));
165
			double after = min(min_angle(v0,v1,v3), min_angle(v1,v2,v3));
166
			return -(after-before);
167
		}
168
		return DBL_MAX;
169
	}
170
 
171
 
172
	void DihedralEnergy::compute_angles(const Manifold & m, HalfEdgeID h) const
173
	{
174
		Walker w = m.walker(h);
175
 
176
		VertexID hv = w.vertex();
177
		VertexID hov = w.opp().vertex();
178
		VertexID hnv = w.next().vertex();
179
		VertexID honv = w.opp().next().vertex();
180
 
181
		Vec3d va(m.pos(hv));
182
		Vec3d vb(m.pos(hov));
183
		Vec3d vc(m.pos(hnv));
184
		Vec3d vd(m.pos(honv));
185
 
186
		FaceID fa = w.next().opp().face();
187
		FaceID fb = w.next().next().opp().face();
188
		FaceID fc = w.opp().next().opp().face();
189
		FaceID fd = w.opp().next().next().opp().face();
190
 
191
		Vec3d n1 = normalize(cross(vc-va, vb-va));
192
		Vec3d n2 = normalize(cross(vb-va, vd-va));
193
 
194
		Vec3d na = fa == InvalidFaceID ? Vec3d(0) : Vec3d(normal(m, fa));
195
		Vec3d nb = fb == InvalidFaceID ? Vec3d(0) : Vec3d(normal(m, fb));
196
		Vec3d nc = fc == InvalidFaceID ? Vec3d(0) : Vec3d(normal(m, fc));
197
		Vec3d nd = fd == InvalidFaceID ? Vec3d(0) : Vec3d(normal(m, fd));
198
 
199
 
200
		Vec3d fn1 = normalize(cross(vb-vc, vd-vc));
201
		Vec3d fn2 = normalize(cross(vd-vc, va-vc));
202
 
203
		ab_12 = cos_ang(n1,n2);
204
		ab_a1 = cos_ang(na,n1);
205
		ab_b1 = cos_ang(nb,n1);
206
		ab_2c = cos_ang(n2,nc);
207
		ab_2d = cos_ang(n2,nd);
208
 
209
		aa_12 = cos_ang(fn1,fn2);
210
		aa_b1 = cos_ang(nb,fn1);
211
		aa_c1 = cos_ang(nc, fn1);
212
		aa_2a = cos_ang(fn2, na);
213
		aa_2d = cos_ang(fn2,nd);
214
	}
215
 
216
	double DihedralEnergy::energy(const Manifold& m, HalfEdgeID h) const
217
	{
218
		Walker w = m.walker(h);
219
 
220
		FaceID hf = w.face();
221
		FaceID hof = w.opp().face();
222
 
223
		double a = cos_ang(Vec3d(normal(m, hf)), Vec3d(normal(m, hof)));
224
 
225
		VertexID hv = w.vertex();
226
		VertexID hov = w.opp().vertex();
227
 
228
		Vec3d va(m.pos(hv));
229
		Vec3d vb(m.pos(hov));
230
 
231
		if(use_alpha)
232
			return edge_alpha_energy(va,vb,a);
233
 
234
		return edge_c_energy(va,vb,a);
235
	}
236
 
237
 
238
	double DihedralEnergy::delta_energy(const Manifold& m, HalfEdgeID h) const
239
	{
240
		compute_angles(m, h);
241
 
242
		Walker w = m.walker(h);
243
 
244
		VertexID hv = w.vertex();
245
		VertexID hov = w.opp().vertex();
246
		VertexID hnv = w.next().vertex();
247
		VertexID honv = w.opp().next().vertex();
248
 
249
		Vec3d va(m.pos(hv));
250
		Vec3d vb(m.pos(hov));
251
		Vec3d vc(m.pos(hnv));
252
		Vec3d vd(m.pos(honv));
253
 
254
		if(use_alpha){
255
			double before = 
256
			edge_alpha_energy(va,vb,ab_12)
257
			+edge_alpha_energy(va,vc,ab_a1)
258
			+edge_alpha_energy(vc,vb,ab_b1)
259
			+edge_alpha_energy(vd,vb,ab_2c)
260
			+edge_alpha_energy(vd,va,ab_2d);
149 jab 261
 
595 jab 262
			double after = 
263
			edge_alpha_energy(vd,vc,aa_12)
264
			+edge_alpha_energy(vb,vc,aa_b1)
265
			+edge_alpha_energy(vd,vb,aa_c1)
266
			+edge_alpha_energy(va,vc,aa_2a)
267
			+edge_alpha_energy(vd,va,aa_2d);
149 jab 268
 
595 jab 269
			return (after-before);
149 jab 270
		}
595 jab 271
		double before = 
272
		edge_c_energy(va,vb,ab_12)
273
		+edge_c_energy(va,vc,ab_a1)
274
		+edge_c_energy(vc,vb,ab_b1)
275
		+edge_c_energy(vd,vb,ab_2c)
276
		+edge_c_energy(vd,va,ab_2d);
277
 
278
		double after = 
279
		edge_c_energy(vd,vc,aa_12)
280
		+edge_c_energy(vb,vc,aa_b1)
281
		+edge_c_energy(vd,vb,aa_c1)
282
		+edge_c_energy(va,vc,aa_2a)
283
		+edge_c_energy(vd,va,aa_2d);
284
 
285
		return after-before;
149 jab 286
	}
595 jab 287
 
288
 
289
 
290
	double CurvatureEnergy::abs_mean_curv(const Vec3d& v, const vector<Vec3d>& ring) const
149 jab 291
	{
595 jab 292
		const size_t N = ring.size();
293
 
294
		double H = 0;
607 jrf 295
		for(size_t i = 0; i < N; ++i){
595 jab 296
			Vec3d vnim1 = ring[(i+N-1)%N] - v;
297
			Vec3d vni   = ring[i] - v;
298
			Vec3d vnip1 = ring[(i+1)%N] - v;
299
 
300
			Vec3d Nm = normalize(cross(vni, vnim1));
301
			Vec3d Np = normalize(cross(vnip1, vni));
302
 
303
			double beta = acos(max(-1.0, min(1.0, dot(Nm, Np))));
304
			H += vni.length() * beta;
305
		}
306
		H /= 4;
307
 
308
		return H;
309
	}
310
 
311
	double CurvatureEnergy::delta_energy(const Manifold& m, HalfEdgeID h) const
312
	{
313
		Walker w = m.walker(h);
314
 
315
		VertexID va = w.vertex();
316
		VertexID vb = w.opp().vertex();
317
		VertexID vc = w.next().vertex();
318
		VertexID vd = w.opp().next().vertex();
319
 
320
 
321
 
322
		Vec3d va_pos(m.pos(va));
323
		Vec3d vb_pos(m.pos(vb));
324
		Vec3d vc_pos(m.pos(vc));
325
		Vec3d vd_pos(m.pos(vd));
326
 
327
		vector<Vec3d> va_ring_bef;
328
		vector<Vec3d> va_ring_aft;
329
		vector<Vec3d> vb_ring_bef;
330
		vector<Vec3d> vb_ring_aft;
331
		vector<Vec3d> vc_ring_bef;
332
		vector<Vec3d> vc_ring_aft;
333
		vector<Vec3d> vd_ring_bef;
334
		vector<Vec3d> vd_ring_aft;
335
 
336
		for(Walker wv = m.walker(va); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
337
			VertexID v = wv.vertex();
338
			Vec3d pos(m.pos(v));
339
 
340
			va_ring_bef.push_back(pos);
341
			if(v != vb)
342
				va_ring_aft.push_back(pos);
343
		}
344
		for(Walker wv = m.walker(vb); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
345
			VertexID v = wv.vertex();
346
			Vec3d pos(m.pos(v));
347
 
348
			vb_ring_bef.push_back(pos);
349
			if(v != va)
350
				vb_ring_aft.push_back(pos);
351
		}
352
		for(Walker wv = m.walker(vc); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
353
			VertexID v = wv.vertex();
354
			Vec3d pos(m.pos(v));
355
 
356
			vc_ring_bef.push_back(pos);
357
			vc_ring_aft.push_back(pos);
358
			if(v == va)
359
				vc_ring_aft.push_back(vd_pos);
360
		}
361
		for(Walker wv = m.walker(vd); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
362
			VertexID v = wv.vertex();
363
			Vec3d pos(m.pos(v));
364
 
365
			vd_ring_bef.push_back(pos);
366
			vd_ring_aft.push_back(pos);
367
			if(v == vb)
368
				vd_ring_aft.push_back(vc_pos);
369
		}
370
		double before =
371
		abs_mean_curv(va_pos, va_ring_bef) +
372
		abs_mean_curv(vb_pos, vb_ring_bef) +
373
		abs_mean_curv(vc_pos, vc_ring_bef) +
374
		abs_mean_curv(vd_pos, vd_ring_bef);
375
 
376
		double after =
377
		abs_mean_curv(va_pos, va_ring_aft) +
378
		abs_mean_curv(vb_pos, vb_ring_aft) +
379
		abs_mean_curv(vc_pos, vc_ring_aft) +
380
		abs_mean_curv(vd_pos, vd_ring_aft);
381
 
382
		return after-before;
383
	}
384
 
385
 
386
	class GaussCurvatureEnergy: public EnergyFun
387
	{
388
 
389
		double gauss_curv(const Vec3d& v, const vector<Vec3d>& ring) const
149 jab 390
		{
595 jab 391
			const size_t N = ring.size();
392
			double asum=0.0f;
393
			double area_sum=0;
607 jrf 394
			for(size_t i = 0; i < N; ++i){
595 jab 395
				const Vec3d& v1 = ring[i];
396
				const Vec3d& v2 = ring[(i+1)%N];
397
				Vec3d a = v1-v;
398
				Vec3d b = v2-v;
399
				asum += acos(max(-1.0, min(1.0, dot(a,b)/(length(a)*length(b)))));
400
				area_sum += 0.5 * length(cross(a,b));
149 jab 401
			}
595 jab 402
			return 3*abs(2 * M_PI - asum)/area_sum;
403
		}
404
 
405
	public:
406
		double delta_energy(const Manifold& m, HalfEdgeID h) const
149 jab 407
		{
595 jab 408
			Walker w = m.walker(h);
149 jab 409
 
595 jab 410
			VertexID va = w.vertex();
411
			VertexID vb = w.opp().vertex();
412
			VertexID vc = w.next().vertex();
413
			VertexID vd = w.opp().next().vertex();
149 jab 414
 
595 jab 415
			Vec3d va_pos(m.pos(va));
416
			Vec3d vb_pos(m.pos(vb));
417
			Vec3d vc_pos(m.pos(vc));
418
			Vec3d vd_pos(m.pos(vd));
419
 
420
			vector<Vec3d> va_ring_bef;
421
			vector<Vec3d> va_ring_aft;
422
			vector<Vec3d> vb_ring_bef;
423
			vector<Vec3d> vb_ring_aft;
424
			vector<Vec3d> vc_ring_bef;
425
			vector<Vec3d> vc_ring_aft;
426
			vector<Vec3d> vd_ring_bef;
427
			vector<Vec3d> vd_ring_aft;
428
 
429
			for(Walker wv = m.walker(va); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
430
				VertexID v = wv.vertex();
431
				Vec3d pos(m.pos(v));
149 jab 432
 
595 jab 433
				va_ring_bef.push_back(pos);
434
				if(v != vb)
435
					va_ring_aft.push_back(pos);
149 jab 436
			}
595 jab 437
			for(Walker wv = m.walker(vb); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
438
				VertexID v = wv.vertex();
439
				Vec3d pos(m.pos(v));
149 jab 440
 
595 jab 441
				vb_ring_bef.push_back(pos);
442
				if(v != va)
443
					vb_ring_aft.push_back(pos);
149 jab 444
			}
595 jab 445
			for(Walker wv = m.walker(vc); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
446
				VertexID v = wv.vertex();
447
				Vec3d pos(m.pos(v));
149 jab 448
 
595 jab 449
				vc_ring_bef.push_back(pos);
450
				vc_ring_aft.push_back(pos);
451
				if(v == va)
452
					vc_ring_aft.push_back(pos);
149 jab 453
			}
595 jab 454
			for(Walker wv = m.walker(vd); !wv.full_circle(); wv = wv.circulate_vertex_cw()){
455
				VertexID v = wv.vertex();
456
				Vec3d pos(m.pos(v));
149 jab 457
 
595 jab 458
				vd_ring_bef.push_back(pos);
459
				vd_ring_aft.push_back(pos);
460
				if(v == vb)
461
					vd_ring_aft.push_back(pos);
149 jab 462
			}
595 jab 463
			double before =
464
			gauss_curv(va_pos,va_ring_bef) +
465
			gauss_curv(vb_pos,vb_ring_bef) +
466
			gauss_curv(vc_pos,vc_ring_bef) +
467
			gauss_curv(vd_pos,vd_ring_bef);
468
 
469
			double after =
470
			gauss_curv(va_pos,va_ring_aft) +
471
			gauss_curv(vb_pos,vb_ring_aft) +
472
			gauss_curv(vc_pos,vc_ring_aft) +
473
			gauss_curv(vd_pos,vd_ring_aft);
474
 
475
			return after-before;
476
		}
477
	};
478
 
479
	struct PQElem
480
	{
481
		double pri;
482
		HalfEdgeID h;
483
		int time;
149 jab 484
 
595 jab 485
		//PQElem() {}
486
		PQElem(double _pri, HalfEdgeID _h, int _time): 
487
		pri(_pri), h(_h), time(_time) {}
488
	};
489
 
490
	bool operator<(const PQElem& e0, const PQElem& e1)
491
	{
492
		return e0.pri > e1.pri;
493
	}
494
 
495
 
496
	void add_to_queue(const Manifold& m, HalfEdgeAttributeVector<int>& touched, priority_queue<PQElem>& Q, HalfEdgeID h, const EnergyFun& efun)
497
	{
498
		if(boundary(m, h))
499
			return;
149 jab 500
 
595 jab 501
		Walker w = m.walker(h);
502
		HalfEdgeID ho = w.opp().halfedge();
149 jab 503
 
595 jab 504
		double energy = efun.delta_energy(m, h);
505
		int t = touched[h] + 1;
506
		touched[h] = t;
507
		touched[ho] = t;
508
		if((energy<0) && (t < 10000)){
509
			Q.push(PQElem(energy, h, t));
149 jab 510
		}
595 jab 511
 
512
	}
149 jab 513
 
595 jab 514
	void add_one_ring_to_queue(const Manifold& m, HalfEdgeAttributeVector<int>& touched, priority_queue<PQElem>& Q, VertexID v, const EnergyFun& efun)
515
	{
516
 
517
		for(Walker w = m.walker(v); !w.full_circle(); w = w.circulate_vertex_cw()){
518
			add_to_queue(m, touched, Q, w.halfedge(), efun);
149 jab 519
		}
520
	}
595 jab 521
 
522
 
149 jab 523
	void priority_queue_optimization(Manifold& m, const EnergyFun& efun)
524
	{
595 jab 525
		HalfEdgeAttributeVector<int> touched(m.allocated_halfedges(), 0);
149 jab 526
		priority_queue<PQElem> Q;
595 jab 527
 
528
		cout << "Building priority queue"<< endl;
529
 
530
		for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
531
			if(!touched[*h])
532
				add_to_queue(m, touched, Q, *h, efun);
533
		}
534
 
535
		cout << "Emptying priority queue of size: " << Q.size() << " ";
536
		while(!Q.empty())
149 jab 537
		{
595 jab 538
			if(Q.size() % 1000 == 0)
539
				cout << ".";
540
			if(Q.size() % 10000 == 0)
541
				cout << Q.size();
149 jab 542
 
595 jab 543
			PQElem elem = Q.top();
544
			Q.pop();
545
 
546
			if(touched[elem.h] != elem.time)
547
				continue;
548
			if(!precond_flip_edge(m, elem.h))
549
				continue;
550
 
551
			m.flip_edge(elem.h);
552
 
553
			Walker w = m.walker(elem.h);
554
			add_one_ring_to_queue(m, touched, Q, w.vertex(), efun);
555
			add_one_ring_to_queue(m, touched, Q, w.next().vertex(), efun);
556
			add_one_ring_to_queue(m, touched, Q, w.opp().vertex(), efun);
557
			add_one_ring_to_queue(m, touched, Q, w.opp().next().vertex(), efun);
558
 
149 jab 559
		}
595 jab 560
		cout << endl;
149 jab 561
	}
595 jab 562
 
563
	void simulated_annealing_optimization(Manifold& m, const EnergyFun& efun, int max_iter)
149 jab 564
	{
417 jrf 565
		gel_srand(0);
149 jab 566
		int swaps;
567
		int iter = 0;
568
		double T = 1;
595 jab 569
 
149 jab 570
		double tmin=0;
571
		{
595 jab 572
			for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
573
				if(boundary(m, *h)) 
574
					continue;  
575
				double e = efun.delta_energy(m, *h);
632 janba 576
				tmin = std::min(e, tmin);
595 jab 577
			}
578
		}
579
		if (tmin < 0.0) 
580
			T = -2*tmin;
581
 
582
		if(max_iter>0){ 
583
			do{
584
				cout << "Temperature : " << T << endl;
585
				vector<HalfEdgeID>  halfedges;
586
				for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end(); ++h){
587
					if(boundary(m, *h))
588
						continue;
589
					halfedges.push_back(*h);
149 jab 590
				}
591
				random_shuffle(halfedges.begin(), halfedges.end());
592
				swaps = 0;
595 jab 593
				for(size_t i = 0; i < halfedges.size(); ++i){
594
					HalfEdgeID h = halfedges[i];
595
					DihedralEnergy dih_en;
596
					double dma = dih_en.min_angle(m, h);
597
					if(dma > -0.4){
598
						double delta = efun.delta_energy(m, h);
599
						if(delta < -1e-8){
600
							if(precond_flip_edge(m, h)){
601
								m.flip_edge(h);
602
								++swaps;
149 jab 603
							}
595 jab 604
						}
605
						else{
606
							delta = max(1e-8, delta);
607
							double prob = min(0.9999, exp(-delta/T));
608
							if(gel_rand()/double(GEL_RAND_MAX) < prob){
609
								if(precond_flip_edge(m, h)){
610
									m.flip_edge(h);
611
									++swaps;
612
								}
613
							}
614
						}
149 jab 615
					}
595 jab 616
				}
149 jab 617
				cout << "Swaps = " << swaps << " T = " << T << endl;
618
				if(iter % 5 == 0 && iter > 0)
619
					T *= 0.9;
620
			}
595 jab 621
			while(++iter < max_iter && swaps);
622
		}
149 jab 623
		cout << "Iterations "  << iter << endl; 
595 jab 624
 
149 jab 625
	}
626
 
595 jab 627
 
149 jab 628
	void minimize_dihedral_angle(Manifold& m, 
595 jab 629
								 int iter,
630
								 bool anneal, 
631
								 bool alpha,
632
								 double gamma)
149 jab 633
	{
634
		DihedralEnergy energy_fun(gamma, alpha);
635
		if(anneal)
636
			simulated_annealing_optimization(m, energy_fun, iter);
637
		else
638
			priority_queue_optimization(m, energy_fun);
639
	}
595 jab 640
 
149 jab 641
	void randomize_mesh(Manifold& m, int max_iter)
642
	{
643
		RandomEnergy energy_fun;
644
		simulated_annealing_optimization(m, energy_fun, max_iter);
645
	}
595 jab 646
 
149 jab 647
	void minimize_curvature(Manifold& m, bool anneal)
648
	{
649
		CurvatureEnergy energy_fun;
650
		if(anneal)
651
			simulated_annealing_optimization(m, energy_fun);
652
		else
653
			priority_queue_optimization(m, energy_fun);
654
	}
595 jab 655
 
149 jab 656
	void minimize_gauss_curvature(Manifold& m, bool anneal)
657
	{
658
		GaussCurvatureEnergy energy_fun;
659
		if(anneal)
660
			simulated_annealing_optimization(m, energy_fun);
661
		else
662
			priority_queue_optimization(m, energy_fun);
663
	}
595 jab 664
 
149 jab 665
	void maximize_min_angle(Manifold& m, float thresh, bool anneal)
666
	{
667
		MinAngleEnergy energy_fun(thresh);
668
		if(anneal)
669
			simulated_annealing_optimization(m, energy_fun);
670
		else
671
			priority_queue_optimization(m, energy_fun);
672
	}
595 jab 673
 
149 jab 674
	void optimize_valency(Manifold& m, bool anneal)
675
	{
676
		ValencyEnergy energy_fun;
677
		if(anneal)
678
			simulated_annealing_optimization(m, energy_fun);
679
		else
680
			priority_queue_optimization(m, energy_fun);
681
	}
652 janba 682
 
683
 
684
    void edge_equalize(Manifold& m, const Implicit& imp, int max_iter)
685
    {
686
 
687
        for(int iter=0;iter<max_iter;++iter)
688
        {
689
            float avg_edge_len=0;
690
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end();++h)
691
                avg_edge_len += length(m, *h);
692
            avg_edge_len /= m.no_halfedges();
693
 
694
            TAL_smoothing(m,1,1);
695
            for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
696
                imp.push_to_surface(m.pos(*vid),0,avg_edge_len*0.5);
697
 
698
            vector<float> edge_lengths;
699
            int n=0;
700
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end();++h,++n)
701
                edge_lengths.push_back(length(m, *h));
702
            sort(edge_lengths.begin(), edge_lengths.end());
703
            float med_len = edge_lengths[n/2];
704
 
705
            vector<HalfEdgeID> short_edges, long_edges;
706
            for(HalfEdgeIDIterator h = m.halfedges_begin(); h != m.halfedges_end();++h)
707
                if(*h<m.walker(*h).opp().halfedge())
708
                {
709
                    float l = length(m,*h);
710
                    if(l> (4/3.0) * med_len)
711
                        long_edges.push_back(*h);
712
                    else if(l< (4/5.0) * med_len)
713
                        short_edges.push_back(*h);
714
                }
715
            for(int i=0;i<long_edges.size(); ++i)
716
                if(m.in_use(long_edges[i]))
717
                    m.split_edge(long_edges[i]);
718
            shortest_edge_triangulate(m);
719
 
720
            for(int i=0;i<short_edges.size(); ++i)
721
                if(m.in_use(short_edges[i]) && precond_collapse_edge(m, short_edges[i]))
722
                {
723
                    Walker w = m.walker(short_edges[i]);
724
                    Vec3d mid_point = 0.5*(m.pos(w.vertex())+m.pos(w.opp().vertex()));
725
                    bool illegal = false;
726
                    for(Walker wc=m.walker(w.vertex()); !wc.full_circle(); wc = wc.circulate_vertex_ccw())
727
                        if(length(m.pos(wc.vertex())-mid_point) > (4/3.0)* med_len)
728
                            illegal = true;
729
                    for(Walker wc=m.walker(w.opp().vertex()); !wc.full_circle(); wc = wc.circulate_vertex_ccw())
730
                        if(length(m.pos(wc.vertex())-mid_point) > (4/3.0)* med_len)
731
                            illegal = true;
732
 
733
                    if(!illegal)
734
                    {
735
                        if(boundary(m,w.vertex()) && !boundary(m,w.opp().vertex()))
736
                            m.collapse_edge(short_edges[i],false);
737
                        else if(!boundary(m,w.vertex()) && boundary(m,w.opp().vertex()));
738
                        else
739
                            m.collapse_edge(short_edges[i],true);
740
                    }
741
                }
742
            //        TAL_smoothing(m,.95,5);
743
            //        for(VertexIDIterator vid = m.vertices_begin(); vid != m.vertices_end(); ++vid)
744
            //            imp.push_to_surface(m.pos(*vid));
745
 
746
            maximize_min_angle(m, 0.9);
747
        }
748
        m.cleanup();
749
 
750
    }
149 jab 751
}