Subversion Repositories gelsvn

Rev

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