Subversion Repositories gelsvn

Rev

Rev 170 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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