Subversion Repositories gelsvn

Rev

Rev 417 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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