Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
183 jab 1
#include <cfloat>
2
#include <algorithm>
3
#include <fstream>
4
#include <iostream>
5
#include <list>
6
 
7
#include "CGLA/Mat2x3f.h"
8
#include "CGLA/Mat2x2f.h"
9
#include "HMesh/Manifold.h"
10
#include "HMesh/VertexCirculator.h"
11
#include "HMesh/FaceCirculator.h"
12
#include "HMesh/build_manifold.h"
13
 
14
 
15
#include "Geometry/RGrid.h"
16
#include "Geometry/TrilinFilter.h"
17
#include "Geometry/GradientFilter.h"
18
#include "Geometry/Neighbours.h"
19
#include "Util/HashTable.h"
20
#include "Util/HashKey.h"
21
 
22
#include "volume_polygonize.h"
23
 
24
namespace HMesh
25
{
26
	using namespace Geometry;
27
	using namespace Util;
28
	using namespace CGLA;
29
	using namespace std;
30
 
31
	namespace 
32
	{
33
 
192 jab 34
		template<class T>
35
		Vec3f push_vertex(const RGrid<T>& grid, const Vec3f& pos0, float iso)
36
		{
37
			Geometry::TrilinFilter<Geometry::RGrid<T> > inter(&grid);
38
			Vec3f corner_min = pos0 - Vec3f(1);
39
			Vec3f corner_max = pos0 + Vec3f(1);
40
			Vec3f pos = pos0;
41
			for(int i=0;i<1000;++i)
42
				if(inter.in_domain(pos))
43
					{
44
						float val = inter(pos)-iso;
45
						Vec3f grad = inter.grad(pos);
46
						float sqlen_grad = sqr_length(grad);
47
 
48
						// Compute the projection in the gradient direction
49
						Vec3f d1 = - val * grad/sqlen_grad;
50
						Vec3f p_new = pos + 0.5 * d1; // "0.5 *" to add damping
51
 
52
						// Don't move outside the box.
53
						if(!(corner_max.all_g(p_new) && 
54
								 corner_min.all_l(p_new)))
55
							return pos;
56
 
57
						// Move so that the gradient points in the direction
58
						// of the original position
59
						Vec3f d2 = (pos0-pos) - 
60
							grad*dot((pos0-pos),grad)/sqlen_grad;
183 jab 61
 
192 jab 62
						// Compute new position and distance up to original position.
63
						p_new += 0.5 * d2; // "0.5 *" to add damping
183 jab 64
 
192 jab 65
						// Don't move outside the box.
66
						if(corner_max.all_g(p_new) && 
67
							 corner_min.all_l(p_new))
68
							pos = p_new;
69
						else
70
							return pos;
183 jab 71
 
192 jab 72
						// Did we converge?
73
						if(sqrt(sqr_length(d1)+sqr_length(d2))<.001)
74
							return pos;
75
					}
76
			return pos;
77
		}
78
 
183 jab 79
		void compute_dual(Manifold& m, Manifold& m2, const vector<Vec3f>& face_positions)
80
		{
81
			// make sure every face knows its number
82
			m.enumerate_faces();
83
 
84
			int i=0;
85
			vector<VertexIter> vertices(m.no_faces());
86
			for(FaceIter f=m.faces_begin(); f!=m.faces_end(); ++f, ++i)
87
					vertices[i] = m2.create_vertex(face_positions[f->touched]);
88
 
89
 
90
			vector<HalfEdgeIter> hedges(m.no_halfedges(), NULL_HALFEDGE_ITER);
91
			int he_num=0;
92
			for(VertexIter v=m.vertices_begin(); v!= m.vertices_end(); ++v)
93
				if(!is_boundary(v))
94
				{
95
						FaceIter f = m2.create_face();
96
						vector<int> indices;
97
						for(VertexCirculator vc(v); !vc.end(); ++vc)
98
						{
99
								TouchType t = vc.get_halfedge()->touched;
100
								int h_idx = he_num++;
101
								vc.get_halfedge()->touched = h_idx;
102
								HalfEdgeIter h = m2.create_halfedge();
103
								h->face = f;
104
								h->touched = t;
105
 
106
								int f_idx = vc.get_face()->touched;
107
								h->vert = vertices[f_idx];
108
								hedges[h_idx] = h;
109
 
110
								indices.push_back(h_idx);
111
						}
112
						f->last = hedges[indices[0]];
113
						int N=indices.size();
114
						for(int j=0;j<N;++j)
115
						{
116
								HalfEdgeIter h1 = hedges[indices[j]];
117
								HalfEdgeIter h2 = hedges[indices[(j+1)%N]];
118
 
119
								link(h2,h1);
120
								h2->vert->he = h1;
121
						}
122
				}
123
			for(VertexIter v=m.vertices_begin(); v!= m.vertices_end(); ++v)
124
				if(!is_boundary(v))
125
						for(VertexCirculator vc(v); !vc.end(); ++vc)
126
								if(!is_boundary(vc.get_vertex()))
127
								{
128
										int idx0 = vc.get_halfedge()->touched;
129
										int idx1 = vc.get_opp_halfedge()->touched;
130
										glue(hedges[idx0], hedges[idx1]);
131
								}
132
 
133
			for(HalfEdgeIter h = m2.halfedges_begin(); h != m2.halfedges_end(); ++h)
134
					if(h->opp == NULL_HALFEDGE_ITER)
135
							glue(h, m2.create_halfedge());
136
			for(VertexIter v = m2.vertices_begin(); v != m2.vertices_end(); ++v)
137
					check_boundary_consistency(v);
138
		}
139
 
140
		/*
141
			Vectors along edges. For each of six cube faces there are four such vectors
142
			since the faces of a cube are quads.
143
		*/
144
		const Vec3i edges[6][4] = {
145
			{Vec3i(0,-1,0),Vec3i(0,0,1),Vec3i(0,1,0),Vec3i(0,0,-1)},
146
			{Vec3i(0,1,0),Vec3i(0,0,1),Vec3i(0,-1,0),Vec3i(0,0,-1)},
147
			{Vec3i(0,0,-1),Vec3i(1,0,0),Vec3i(0,0,1),Vec3i(-1,0,0)},
148
			{Vec3i(0,0,1),Vec3i(1,0,0),Vec3i(0,0,-1),Vec3i(-1,0,0)},
149
			{Vec3i(-1,0,0),Vec3i(0,1,0),Vec3i(1,0,0),Vec3i(0,-1,0)},
150
			{Vec3i(1,0,0),Vec3i(0,1,0),Vec3i(-1,0,0),Vec3i(0,-1,0)}};
151
 
152
		/* Convert a direction vector to a cube face index. */
153
		int dir_to_face(const Vec3i& dir)
154
		{
155
			assert(dot(dir,dir)==1);
156
 
157
			if(dir[0] != 0)
158
				return (dir[0]<0) ? 0 : 1;
159
			if(dir[1] != 0)
160
				return (dir[1]<0) ? 2 : 3;
161
			if(dir[2] != 0)
162
				return (dir[2]<0) ? 4 : 5;
163
 
164
			return -1;
165
		}
166
 
167
		/* Convert a face index and an edge vector to an edge index. */
168
		int dir_to_edge(int face, const Vec3i& edge)
169
		{
170
			for(int i=0;i<4;++i)
171
				if(edges[face][i] == edge) return i;
172
			assert(0);
173
			return -1;
174
		}
175
 
176
		Vec3f cube_corner(const Vec3i& pos, int i, int e)
177
		{
178
			Vec3i to_face = N6i[i];
179
			Vec3i along_edge = edges[i][e];	
180
			Vec3i to_edge = cross(along_edge,to_face);
181
			return Vec3f(pos) + 0.5*Vec3f(to_face+to_edge+along_edge);
182
		}
183
 
184
		/* Cube faces are created whenever a voxel that is inside is adjacent
185
			 to a voxel that is outside. Thus the voxel can be seen as a small
186
			 box that either contains material or not. A face is created where
187
			 full and empty boxes meet. A vertex is placed on every box face.
188
 
189
			 A halfedge is created for every edge of the (quadrilateral) face.
190
			 This halfedge connects the face to its neighbour. */
191
		struct CubeFace
192
		{
193
				bool used;
194
				HalfEdgeIter he[4];
195
				CubeFace(): used(false)
196
						{
197
								for(int i=0;i<4;++i)
198
										he[i] = NULL_HALFEDGE_ITER;
199
						}
200
		};
201
 
202
		/* A cube consists of six faces and a position. The cube centre is
203
			 an integer (voxel grid) position. */
204
		struct Cube
205
		{
206
			Vec3i pos;
207
			CubeFace faces[6];
208
 
209
			Cube(const Vec3i& _pos): pos(_pos) {}
210
		};
211
 
212
 
213
		/* The mesher class does the actual work. It is not pretty and it
214
			 is not seen by the user. */
215
		template<class T>
216
		class CubeGrid
217
		{
218
			float iso;
219
			HashTable<HashKey3usi,Cube*> cube_hash;  // Hashtable of cube pointers
220
			list<Cube> cube_table;                   // Linked list containing
221
			// the actual cubes.
222
 
223
		public:
224
 
225
			CubeGrid(const RGrid<T>& _voxel_grid, // input voxel grid
226
							 float iso);                   // iso value
227
 
228
 
229
			HalfEdgeIter edge_to_glue(const RGrid<T>& voxel_grid,
230
																Cube& cube, int face_idx, int edge_idx);
231
 
232
			void cuberille_mesh(const RGrid<T>&, Manifold& m, 
233
													bool push_vertices,
234
													bool compute_face_positions,
235
													vector<Vec3f>& face_positions);
236
		};
237
 
238
		template<class T>
239
		HalfEdgeIter CubeGrid<T>::edge_to_glue(const RGrid<T>& voxel_grid,
240
																					 Cube& cube, int face_idx, int edge_idx)
241
		{
242
			/*  Figure.
243
 
244
			0|B
245
			-+-
246
			A|C
247
 
248
			Explanation: ... pending
249
			*/
250
 
251
			Vec3i dir = N6i[face_idx];
252
			Vec3i along_edge = edges[face_idx][edge_idx];	 // Vector _along_ edge
253
			Vec3i to_edge = cross(along_edge,dir); // vector to edge
254
 
255
			Vec3i a_pos = cube.pos;
256
			Vec3i o_pos = a_pos + dir;
257
			Vec3i b_pos = o_pos + to_edge;
258
			Vec3i c_pos = a_pos + to_edge;
259
 
260
			if(!voxel_grid.in_domain(b_pos))
261
				return NULL_HALFEDGE_ITER;
262
 
263
			Cube* cube_n=0;
264
			Vec3i dir_n;   // direction from center to neighbour face
265
			Vec3i along_edge_n; // Edge vector for neighbour face
266
			if(!cube_hash.find_entry(HashKey3usi(b_pos),	cube_n))
267
				{
268
					if(cube.faces[dir_to_face(to_edge)].used)
269
						{
270
							dir_n = to_edge;
271
							along_edge_n = - along_edge; 
272
							cube_n = &cube;  
273
						}
274
					else
275
						{
276
							dir_n = dir;
277
							along_edge_n = - along_edge;
278
							cube_hash.find_entry(HashKey3usi(c_pos), cube_n);
279
							assert(cube_n->faces[dir_to_face(dir_n)].used);
280
						}									
281
				}
282
			else
283
				{
284
					float a_val = voxel_grid[a_pos];
285
					float b_val = voxel_grid[b_pos];
286
					float c_val = voxel_grid[c_pos];
287
					float o_val = voxel_grid[o_pos];
288
					bool connect = (a_val*b_val-c_val*o_val)/(a_val+b_val-c_val-o_val) >iso;
289
 
290
					if(connect || !cube.faces[dir_to_face(to_edge)].used)
291
						{
292
							dir_n = - to_edge;
293
							along_edge_n = - along_edge;
294
							assert(cube_n->faces[dir_to_face(dir_n)].used);
295
						}
296
					else
297
						{
298
							dir_n = to_edge;
299
							along_edge_n = - along_edge; 
300
							cube_n = &cube;  
301
						}
302
				}
303
			int i_n = dir_to_face(dir_n);
304
			int e_n = dir_to_edge(i_n, along_edge_n);
305
 
306
			HalfEdgeIter he = cube_n->faces[i_n].he[e_n];
307
			if(cube_n == &cube)
308
					he->touched = 1;
309
			else
310
					he->touched = 0;
311
 
312
			return he;
313
		}
314
 
315
		template<class T>
316
		inline bool comp(bool d, T a, T b)
317
		{
318
			return d? (a<b) : (b<a); 
319
		}
320
 
321
		template<class T>
322
		CubeGrid<T>::CubeGrid(const RGrid<T>& voxel_grid, float _iso): iso(_iso)
323
		{
324
			/* Loop over all voxels */
325
			for(int k=0;k<voxel_grid.get_dims()[ 2 ];++k)
326
				for(int j=0;j<voxel_grid.get_dims()[ 1 ];++j)
327
					for(int i=0;i<voxel_grid.get_dims()[ 0 ];++i)
328
						{
329
							Vec3i pi0(i,j,k);
330
							float val0 = voxel_grid[pi0];
331
 
332
							/* If the voxel value is above the isovalue */
333
							if(val0>iso)
334
								{
335
									bool interface_cell = false;
336
									vector<VertexIter> vertices;
337
									Cube* cube;
338
 
339
									// For each neighbouring voxel.
340
									for(int l=0;l<6;++l)
341
										{
342
											// First make sure the voxel is inside the voxel grid.
343
											Vec3i pi1(pi0);
344
											pi1 += N6i[l];
345
											bool indom = voxel_grid.in_domain(pi1);
346
 
347
											/* If the neighbour is **not** in the grid or it 
348
												 is on the other side of the isovalue */
349
											if(indom && voxel_grid[pi1]<=iso)
350
												{
351
													/* Store the cube in a hash table. This code is
352
														 executed the first time we create a face
353
														 for the cube. In other words only cubes that 
354
														 actually have faces are stored in the hash */
355
													if(!interface_cell)
356
														{
357
															interface_cell = true;
358
															Cube** c_ptr;
359
															cube_hash.create_entry(HashKey3usi(pi0), c_ptr);
360
															Cube c(pi0);
361
															cube_table.push_back(c);
362
															cube = (*c_ptr) = &cube_table.back();
363
														}
364
													// Now add the face to the cube.
365
													int face_idx  = dir_to_face(N6i[l]);
366
													CubeFace& face = cube->faces[face_idx];
367
													face.used = true;
368
 
369
												}
370
										}
371
								}
372
						}		
373
		}
374
 
375
 
376
		template<class T>
377
		void CubeGrid<T>::cuberille_mesh(const RGrid<T>& voxel_grid, Manifold& m, 
378
																		 bool push_vertices,
379
																		 bool compute_face_positions,
380
																		 vector<Vec3f>& face_positions)
381
		{
382
			face_positions.clear();
383
 
384
			typename list<Cube>::iterator cube_iter = cube_table.begin();
385
 
386
			/* For each cube in the table of cubes */
387
			cube_iter = cube_table.begin();
388
			for(;cube_iter != cube_table.end(); ++cube_iter)
389
				{
390
					/* For each of the six faces, if the face is used */
391
					Cube& cube = *cube_iter;
392
					for(int i=0;i<6;++i)
393
						if(cube.faces[i].used)
394
							{
395
								CubeFace& face = cube.faces[i];  // The face
396
								FaceIter hmesh_face = m.create_face();
397
								hmesh_face->touched = face_positions.size();
398
 
399
								if(compute_face_positions)
400
								{
401
										Vec3i p0(cube.pos);
402
										Vec3i p1 = p0 + N6i[i];
403
										float v0 = voxel_grid[p0];
404
										float v1 = voxel_grid[p1];
405
										float t = (iso-v0)/(v1-v0);
406
										face_positions.push_back(Vec3f(p0)*(1.0f-t)+Vec3f(p1)*t);
407
								}
408
 
409
								// Let e be one of the four edges of the face
410
								for(int e=0;e<4;++e)
411
								{
412
										face.he[e] = m.create_halfedge();
413
										face.he[e]->face = hmesh_face;
414
								}
415
								hmesh_face->last = face.he[0];
416
							}
417
 
418
				}
419
 
420
			/* For each cube in the table of cubes */
421
			cube_iter = cube_table.begin();
422
			for(;cube_iter != cube_table.end(); ++cube_iter)
423
				{
424
					/* For each of the six faces, if the face is used */
425
					Cube& cube = *cube_iter;
426
					for(int i=0;i<6;++i)
427
						if(cube.faces[i].used)
428
							{
429
								CubeFace& face = cube.faces[i];  // The face
430
								// Let e be one of the four edges of the face
431
								for(int e=0;e<4;++e)
432
									{
433
											HalfEdgeIter he = face.he[e];
434
											link(he,face.he[(e+1)%4]);
435
											link(face.he[(e+3)%4],he);
436
											if(he->opp == NULL_HALFEDGE_ITER)
437
											{
438
													HalfEdgeIter he_n = 
439
															edge_to_glue(voxel_grid, cube, i, e);
440
													if(he_n != NULL_HALFEDGE_ITER)
441
													{
442
															glue(he, he_n);
443
															he->touched = he_n->touched;
444
													}
445
											}
446
									}
447
							}
448
 
449
				}
450
 
451
			for(HalfEdgeIter h = m.halfedges_begin(); h != m.halfedges_end(); ++h)
452
				{
453
					if (h->opp == NULL_HALFEDGE_ITER)
454
						{
455
							HalfEdgeIter ho = m.create_halfedge();
456
							glue(ho,h);
457
						}
458
				}
459
 
460
			cube_iter = cube_table.begin();
461
			for(;cube_iter != cube_table.end(); ++cube_iter)
462
				{
463
					//For each of the six faces, if the face is used 
464
					Cube& cube = *cube_iter;
465
					for(int i=0;i<6;++i)
466
						if(cube.faces[i].used)
467
							{
468
								CubeFace& face = cube.faces[i];  // The face
469
								// Let e be one of the four edges of the face
470
								for(int e=0;e<4;++e)
471
									if(face.he[e]->vert == NULL_VERTEX_ITER)
472
										{
473
											HalfEdgeIter last = face.he[e];
474
											HalfEdgeIter he = last;
475
											while(he->opp->face != NULL_FACE_ITER)
476
												{
477
													he = he->opp->prev;
478
													if(he == last) 
479
														break;
480
												}
481
											last = he;
482
 
483
											Vec3f pos = cube_corner(cube.pos, i, e);
484
											if(push_vertices)
485
													pos = push_vertex(voxel_grid, pos, iso);
486
											VertexIter vert = m.create_vertex(pos);
487
 
488
											do
489
												{
490
													he->vert = vert;
491
													he = he->next->opp;
492
												}
493
											while(he->face != NULL_FACE_ITER && he != last);
494
 
495
											if(he->face == NULL_FACE_ITER)
496
												{
497
													he->vert = vert;
498
													link(he,last->opp);
499
												}
500
 
501
											vert->he = last->opp;
502
										}
503
							}
504
				}
505
		}
506
	}
507
 
508
 
509
 
510
	template<typename T>
511
	void mc_polygonize(const RGrid<T>& voxel_grid, 
512
											 Manifold& mani_out, 
513
											 float iso)
514
	{
515
			Manifold mani;
516
			CubeGrid<T> cube_grid(voxel_grid, iso);
517
			vector<Vec3f> face_positions;
518
			cube_grid.cuberille_mesh(voxel_grid, mani, false, true, face_positions);
519
			compute_dual(mani, mani_out, face_positions);
520
	}
521
 
522
	template<typename T>
523
	void cuberille_polygonize(const RGrid<T>& voxel_grid, 
524
														Manifold& mani, 
525
														float iso,
526
														bool push)
527
	{
528
		CubeGrid<T> cube_grid(voxel_grid, iso);
529
		vector<Vec3f> face_positions;
530
		cube_grid.cuberille_mesh(voxel_grid, mani, push, false, face_positions);
531
	}
532
 
191 jab 533
		template void mc_polygonize<unsigned char>(const RGrid<unsigned char>&,
183 jab 534
																							 Manifold&, float);
191 jab 535
		template void mc_polygonize<float>(const RGrid<float>&, Manifold&, float);
183 jab 536
 
191 jab 537
		template void cuberille_polygonize<unsigned short>(const RGrid<unsigned short>&,
538
																											Manifold&, float, bool);
539
		template void cuberille_polygonize<unsigned char>(const RGrid<unsigned char>&,
540
																											Manifold&, float, bool);
541
		template void cuberille_polygonize<float>(const RGrid<float>&,
542
																							Manifold&, float, bool);
183 jab 543
 
544
}
545
 
546
 
547
 
548
 
549