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