Subversion Repositories gelsvn

Rev

Rev 155 | 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"
12
 
13
 
14
#include "Geometry/RGrid.h"
15
#include "Geometry/TrilinFilter.h"
16
#include "Geometry/GradientFilter.h"
17
#include "Geometry/Neighbours.h"
18
#include "Util/HashTable.h"
19
#include "Util/HashKey.h"
20
 
21
#include "fair_polygonize.h"
22
 
155 jab 23
namespace HMesh
149 jab 24
{
155 jab 25
		using namespace Geometry;
149 jab 26
		using namespace Util;
27
		using namespace CGLA;
28
		using namespace std;
29
 
30
		namespace 
31
		{
32
				/*
33
					Vectors along edges. For each of six cube faces there are four such vectors
34
					since the faces of a cube are quads.
35
				*/
36
				const Vec3i edges[6][4] = {
37
						{Vec3i(0,-1,0),Vec3i(0,0,1),Vec3i(0,1,0),Vec3i(0,0,-1)},
38
						{Vec3i(0,1,0),Vec3i(0,0,1),Vec3i(0,-1,0),Vec3i(0,0,-1)},
39
						{Vec3i(0,0,-1),Vec3i(1,0,0),Vec3i(0,0,1),Vec3i(-1,0,0)},
40
						{Vec3i(0,0,1),Vec3i(1,0,0),Vec3i(0,0,-1),Vec3i(-1,0,0)},
41
						{Vec3i(-1,0,0),Vec3i(0,1,0),Vec3i(1,0,0),Vec3i(0,-1,0)},
42
						{Vec3i(1,0,0),Vec3i(0,1,0),Vec3i(-1,0,0),Vec3i(0,-1,0)}};
43
 
44
				/* Convert a direction vector to a cube face index. */
45
				int dir_to_face(const Vec3i& dir)
46
				{
47
						assert(dot(dir,dir)==1);
48
 
49
						if(dir[0] != 0)
50
								return (dir[0]<0) ? 0 : 1;
51
						if(dir[1] != 0)
52
								return (dir[1]<0) ? 2 : 3;
53
						if(dir[2] != 0)
54
								return (dir[2]<0) ? 4 : 5;
55
 
56
						return -1;
57
				}
58
 
59
				/* Convert a face index and an edge vector to an edge index. */
60
				int dir_to_edge(int face, const Vec3i& edge)
61
				{
62
						for(int i=0;i<4;++i)
63
								if(edges[face][i] == edge) return i;
64
						assert(0);
65
						return -1;
66
				}
67
 
68
				/* Cube faces are created whenever a voxel that is inside is adjacent
69
					 to a voxel that is outside. Thus the voxel can be seen as a small
70
					 box that either contains material or not. A face is created where
71
					 full and empty boxes meet. A vertex is placed on every box face.
72
 
73
					 A halfedge is created for every edge of the (quadrilateral) face.
74
					 This halfedge connects the face to its neighbour. */
75
				struct CubeFace
76
				{
77
						bool used;
78
						VertexIter vert;
79
						HalfEdgeIter he[4];
80
 
81
						CubeFace();
82
 
169 jab 83
						HalfEdgeIter& get_he(Manifold& m, int i)
149 jab 84
								{
85
										if(he[i] == NULL_HALFEDGE_ITER)
169 jab 86
												he[i] = m.create_halfedge();
149 jab 87
										return he[i];
88
								}
89
				};
90
 
91
				CubeFace::CubeFace(): used(false), vert(NULL_VERTEX_ITER)
92
				{
93
						for(int i=0;i<4;++i)
94
								he[i] = NULL_HALFEDGE_ITER;
95
				}
96
 
97
 
98
				/* A cube consists of six faces and a position. The cube centre is
99
					 an integer (voxel grid) position. */
100
				struct Cube
101
				{
102
						Vec3i pos;
103
						CubeFace faces[6];
104
 
105
						Cube(const Vec3i& _pos): pos(_pos) {}
106
				};
107
 
108
 
109
				/* The mesher class does the actual work. It is not pretty and it
110
					 is not seen by the user. */
111
				template<class T>
169 jab 112
				class CubeGrid
149 jab 113
				{
169 jab 114
						float iso;
149 jab 115
						HashTable<HashKey3usi,Cube*> cube_hash;  // Hashtable of cube pointers
116
						list<Cube> cube_table;                   // Linked list containing
169 jab 117
                                          					 // the actual cubes.
149 jab 118
 
119
				public:
120
 
169 jab 121
						CubeGrid(const RGrid<T>& _voxel_grid, // input voxel grid
122
										 float iso,                   // iso value
123
										 bool inv_cont);              // invert contour?
149 jab 124
 
169 jab 125
						void find_neighbour_face_disconnect(Cube& cube, int face_idx, int edge_idx,
126
																								Cube*& cube_n, int& i_n, int& e_n);
149 jab 127
 
169 jab 128
						void find_neighbour_face_connect(Cube& cube, int face_idx, int edge_idx,
129
																						 Cube*& cube_n, int& i_n, int& e_n);
130
 
131
						void dual_cuberille_mesh(const RGrid<T>&, Manifold& m, bool connect=false);
132
						void cuberille_mesh(const RGrid<T>&, Manifold& m, bool connect=false);
133
				};
149 jab 134
 
169 jab 135
				template<class T>
136
				void CubeGrid<T>::find_neighbour_face_disconnect(Cube& cube, int face_idx, int edge_idx,
137
																												 Cube*& cube_n,  // Neighbouring cube
138
																												 int& i_n,  // direction from center to neighbour face
139
																												 int& e_n) // Edge vector for neighbour face
140
				{
141
						/*
142
							Algorithm: Pick faces to glue
149 jab 143
 
169 jab 144
							Algorithm which connects cube faces. If both A and B
145
							are above the isovalue and 0 and C are below, A and B
146
							will be seperated, i.e. the 0A and AC faces will be 
147
							connected. There is a different out-commented algorithm
148
							at the end of this file which connects AO and 0B
149
							instead.
150
 
151
							Figure.
149 jab 152
 
169 jab 153
							0|B
154
							-+-
155
							A|C
156
 
157
							Explanation:
158
 
159
							Let the current cube be A. Since we are here, the voxel
160
							of A is above the isovalue, and the voxel of O is below
161
							since there is a face AO.
149 jab 162
 
169 jab 163
							We first check if there is a face between A and C. 
164
							if that is the case, the AO face is connected to the AC 
165
							face. 
166
 
167
							Otherwise, we check if B is also inside the isocontour.
168
							If that is true there is an OB face, and we connect the
169
							A0 and the 0B faces.
170
 
171
							Failing that, there must be a CB face, and we connect
172
							with that.
173
						*/
174
						Vec3i pos = cube.pos;
175
						Vec3i dir = N6i[face_idx];
176
 
177
 
178
						Vec3i dir_n;   // direction from center to neighbour face
179
						Vec3i edge_n; // Edge vector for neighbour face
180
 
181
						Vec3i edge = edges[face_idx][edge_idx];	       // Vector _along_ edge
182
						Vec3i to_edge = cross(edge,dir); // vector to edge
183
 
184
 
185
						// Begin "Pick faces to glue"
186
						Cube* dummy;
187
						if(cube.faces[dir_to_face(to_edge)].used)
188
						{
189
								dir_n = to_edge;
190
								edge_n = - edge; 
191
								cube_n = &cube;  
192
						}
193
						else if(!cube_hash.find_entry(HashKey3usi(pos+dir+to_edge),
194
																					dummy))
195
						{
196
								assert(sqr_length(to_edge)==1);
197
								dir_n = dir;
198
								edge_n = - edge;
199
								cube_hash.find_entry(HashKey3usi(pos + to_edge), 
200
																		 cube_n);
201
						}
202
						else 
203
						{
204
								dir_n = - to_edge;
205
								edge_n = - edge;
206
								cube_n = dummy;
207
						}
208
 
209
						i_n = dir_to_face(dir_n);
210
						e_n = dir_to_edge(i_n, edge_n);
211
				}
212
 
149 jab 213
				template<class T>
169 jab 214
				void CubeGrid<T>::find_neighbour_face_connect(Cube& cube, int face_idx, int edge_idx,
215
																											Cube*& cube_n,  // Neighbouring cube
216
																											int& i_n,  // direction from center to neighbour face
217
																											int& e_n) // Edge vector for neighbour face
218
				{
219
						Vec3i pos = cube.pos;
220
						Vec3i dir = N6i[face_idx];
221
 
222
						Vec3i dir_n;   // direction from center to neighbour face
223
						Vec3i edge_n; // Edge vector for neighbour face
224
 
225
						Vec3i edge = edges[face_idx][edge_idx];	       // Vector _along_ edge
226
						Vec3i to_edge = cross(edge,dir); // vector to edge
227
 
228
						if(cube_hash.find_entry(HashKey3usi(pos + dir + to_edge),
229
																		cube_n))
230
						{
231
								assert(sqr_length(dir + to_edge)==2);
232
																dir_n = - to_edge;
233
																edge_n = - edge;
234
						}
235
						else if(cube_hash.find_entry(HashKey3usi(pos + to_edge), 
236
																				 cube_n))
237
						{
238
								assert(sqr_length(to_edge)==1);
239
								dir_n = dir;
240
								edge_n = - edge;
241
						}
242
						else
243
						{
244
								dir_n = to_edge;
245
								edge_n = - edge;
246
								cube_n = &cube;
247
						}
248
 
249
						i_n = dir_to_face(dir_n);
250
						e_n = dir_to_edge(i_n, edge_n);
251
				}
252
 
253
 
254
				template<class T>
149 jab 255
				inline bool comp(bool d, T a, T b)
256
				{
257
						return d? (a<b) : (b<a); 
258
				}
259
 
260
				template<class T>
169 jab 261
				CubeGrid<T>::CubeGrid(const RGrid<T>& voxel_grid, float _iso, bool inv_cont): iso(_iso)
149 jab 262
				{
263
						/* Loop over all voxels */
169 jab 264
						for(int k=0;k<voxel_grid.get_dims()[ 2 ];++k)
265
								for(int j=0;j<voxel_grid.get_dims()[ 1 ];++j)
266
										for(int i=0;i<voxel_grid.get_dims()[ 0 ];++i)
149 jab 267
										{
268
												Vec3i pi0(i,j,k);
169 jab 269
												float val0 = voxel_grid[pi0];
149 jab 270
 
271
												/* If the voxel value is above the isovale (or below if we
272
													 are finding the inverse contour) */
273
												if(comp(inv_cont,val0,iso))
274
												{
275
														bool interface_cell = false;
276
														vector<VertexIter> vertices;
277
														Cube* cube;
278
 
279
														// For each neighbouring voxel.
280
														for(int l=0;l<6;++l)
281
														{
282
																// First make sure the voxel is inside the voxel grid.
283
																Vec3i pi1(pi0);
284
																pi1 += N6i[l];
169 jab 285
																bool indom = voxel_grid.in_domain(pi1);
149 jab 286
 
287
																/* If the neighbour is **not** in the grid or it 
288
																	 is on the other side of the isovalue */
289
																if(!indom || 
169 jab 290
																	 !comp(inv_cont,float(voxel_grid[pi1]),iso))
149 jab 291
																{
292
																		/* Store the cube in a hash table. This code is
293
																			 executed the first time we create a face
294
																			 for the cube. In other words only cubes that 
295
																			 actually have faces are stored in the hash */
296
																		if(!interface_cell)
297
																		{
298
																				interface_cell = true;
299
																				Cube** c_ptr;
300
																				cube_hash.create_entry(HashKey3usi(pi0), c_ptr);
301
																				Cube c(pi0);
302
																				cube_table.push_back(c);
303
																				cube = (*c_ptr) = &cube_table.back();
304
																		}
305
																		// Now add the face to the cube.
306
																		int face_idx  = dir_to_face(N6i[l]);
307
																		CubeFace& face = cube->faces[face_idx];
308
																		face.used = true;
309
 
310
																}
311
														}
312
												}
313
										}		
314
				}
315
 
316
 
317
				/* This complicated function is used to connect the cube faces.
169 jab 318
					 If the faces are considered to be little square pieces of paper, this
149 jab 319
					 function glues them along the edges. However, it takes care to glue
169 jab 320
					 faces in such a way as to not create edges with more than two adjacent
149 jab 321
					 faces. */
322
				template<class T>
169 jab 323
				void CubeGrid<T>::dual_cuberille_mesh(const RGrid<T>& voxel_grid, Manifold& m, bool connect)
149 jab 324
				{
325
						/* For each cube in the table of cubes */
326
						typename list<Cube>::iterator cube_iter = cube_table.begin();
327
						for(;cube_iter != cube_table.end(); ++cube_iter)
328
						{
329
								/* For each of the six faces, if the face is used */
330
								Cube& cube = *cube_iter;
169 jab 331
								Vec3i pi0 = cube.pos;
332
								float val0 = voxel_grid[pi0];
333
								for(int face_idx=0; face_idx<6; ++face_idx)
334
								{
335
										CubeFace& face = cube.faces[face_idx];
336
										if(face.used)
337
										{
338
												Vec3i pi1(pi0);
339
												pi1 += N6i[face_idx];
340
												Vec3f p;
341
												if(voxel_grid.in_domain(pi1))
342
												{
343
														float val1 = voxel_grid[pi1];
344
														float t= (iso-val0)/(val1-val0);
345
														p = Vec3f(pi0)*(1.0f-t)+Vec3f(pi1)*t;
346
												}
347
												else
348
														p = Vec3f(pi0) * 0.5 + Vec3f(pi1) * 0.5;
349
												face.vert = m.create_vertex(p);
350
												// We mark the vertex with the cube index.
351
												face.vert->touched = reinterpret_cast<TouchType>(&cube);
352
										}
353
								}
354
						}
355
 
356
						/* For each cube in the table of cubes */
357
						cube_iter = cube_table.begin();
358
						for(;cube_iter != cube_table.end(); ++cube_iter)
359
						{
360
								/* For each of the six faces, if the face is used */
361
								Cube& cube = *cube_iter;
149 jab 362
								for(int i=0;i<6;++i)
363
										if(cube.faces[i].used)
364
										{
169 jab 365
												CubeFace& face = cube.faces[i];  // The face
366
 
149 jab 367
												// Let e be one of the four edges of the face
368
												for(int e=0;e<4;++e)
369
												{
370
														Cube* cube_n;  // Neighbouring cube
169 jab 371
														int i_n, e_n;
149 jab 372
 
169 jab 373
														// Do the actual gluing ...
374
														if(!connect) 
375
																find_neighbour_face_disconnect(cube, i, e, cube_n, i_n, e_n);
376
														else
377
																find_neighbour_face_connect(cube, i, e, cube_n, i_n, e_n);
149 jab 378
 
379
														CubeFace& face_n = cube_n->faces[i_n];
380
														HalfEdgeIter& he = face.get_he(m,e);
381
														face.vert->he = he;
382
														he->vert = face_n.vert;
383
 
384
														/* Link this halfedge to the _next_ halfedge on the 
385
															 connected face. */
386
														assert(face_n.used);
387
														HalfEdgeIter& he_n = face_n.get_he(m, (e_n+3)%4);
388
														link(he, he_n);
389
 
390
														/* Glue this halfedge to the corresponding one on the
391
															 connected face.*/
392
														HalfEdgeIter& he_opp = face_n.get_he(m, e_n);
393
														face_n.vert->he = he_opp;
394
														glue(he, he_opp);
395
												}
396
										}
397
 
398
						}
399
 
169 jab 400
						HalfEdgeIter he0 = m.halfedges_begin();
401
						while(he0 != m.halfedges_end())
149 jab 402
						{
403
								// If this halfedge is not assigned to a face.
404
								if(he0->face == NULL_FACE_ITER)
405
								{
406
										// Create a face and let the current halfedge belong to it.
169 jab 407
										FaceIter fi = m.create_face();
149 jab 408
										fi->last = he0;
409
										he0->face = fi;
169 jab 410
 
149 jab 411
										// Loop over all connected halfedges and let them also belong 
412
										// to the face.
413
										HalfEdgeIter he = he0->next;
414
										while(he != he0)
415
										{
416
												he->face = fi;
417
												he = he->next;
418
										}
169 jab 419
							}
149 jab 420
								++he0;
421
						}
422
				}
423
 
169 jab 424
				template<class T>
425
				void CubeGrid<T>::cuberille_mesh(const RGrid<T>& voxel_grid, Manifold& m, bool connect)
426
				{
427
						typename list<Cube>::iterator cube_iter = cube_table.begin();
149 jab 428
 
169 jab 429
						/* For each cube in the table of cubes */
430
						cube_iter = cube_table.begin();
431
						for(;cube_iter != cube_table.end(); ++cube_iter)
432
						{
433
								/* For each of the six faces, if the face is used */
434
								Cube& cube = *cube_iter;
435
								for(int i=0;i<6;++i)
436
										if(cube.faces[i].used)
437
										{
438
												CubeFace& face = cube.faces[i];  // The face
439
												FaceIter hmesh_face = m.create_face();
440
												// Let e be one of the four edges of the face
441
												for(int e=0;e<4;++e)
442
												{
443
														Cube* cube_n;  // Neighbouring cube
444
														int i_n, e_n;
445
 
446
														// Do the actual gluing ...
447
														if(!connect) 
448
																find_neighbour_face_disconnect(cube, i, e, cube_n, i_n, e_n);
449
														else
450
																find_neighbour_face_connect(cube, i, e, cube_n, i_n, e_n);
451
 
452
														CubeFace& face_n = cube_n->faces[i_n];
453
														HalfEdgeIter he = face.get_he(m,e);
454
														HalfEdgeIter he_n = face_n.get_he(m,e_n);
455
 
456
														link(he,face.get_he(m,(e+1)%4));
457
														link(face.get_he(m,(e+3)%4),he);
458
														glue(he, he_n);
459
														he->face = hmesh_face;
460
												}
461
												hmesh_face->last = face.get_he(m,0);
462
 
463
 
464
										}
465
 
466
						}
467
						cube_iter = cube_table.begin();
468
						for(;cube_iter != cube_table.end(); ++cube_iter)
469
						{
470
								/* For each of the six faces, if the face is used */
471
								Cube& cube = *cube_iter;
472
								for(int i=0;i<6;++i)
473
										if(cube.faces[i].used)
474
										{
475
												CubeFace& face = cube.faces[i];  // The face
476
												// Let e be one of the four edges of the face
477
												for(int e=0;e<4;++e)
478
														if(face.he[e]->vert == NULL_VERTEX_ITER)
479
														{
480
																Vec3i to_face = N6i[i];
481
																Vec3i along_edge = edges[i][e];	
482
																Vec3i to_edge = cross(along_edge,to_face);
483
																Vec3f pos = Vec3f(cube.pos) + 0.5*Vec3f(to_face + along_edge + to_edge);
484
																HalfEdgeIter last = face.he[e];
485
																VertexIter vi = m.create_vertex(pos);
486
																vi->he = last->opp;
487
																HalfEdgeIter he = last;
488
																do
489
																{
490
																		he->vert = vi;
491
																		he = he->next->opp;
492
																}
493
																while(he != last);
494
														}
495
										}
496
						}
497
				}
498
 
149 jab 499
				/* A fairly complex algorithm which triangulates faces. It triangulates
500
					 by iteratively splitting faces. It always splits a face by picking the
501
					 edge whose midpoint is closest to the isovalue. */
502
 
503
				template<class T>
169 jab 504
				void triangulate(const RGrid<T>& voxel_grid, Manifold& m, float iso)
149 jab 505
				{
506
#ifndef NDEBUG
169 jab 507
						cout << "Initial mesh valid : " << m.is_valid() << endl;
149 jab 508
#endif
169 jab 509
						Geometry::TrilinFilter<Geometry::RGrid<T> > grid_interp(&voxel_grid);
149 jab 510
						int work;
511
						do
512
						{
513
								// For every face.
514
								work = 0;
169 jab 515
								for(FaceIter fi =m.faces_begin(); fi != m.faces_end(); ++fi)
149 jab 516
								{
517
										// Create a vector of vertices.
518
										vector<VertexIter> verts;
519
										for(FaceCirculator fc(fi); !fc.end(); ++fc)
520
												verts.push_back(fc.get_vertex());
521
 
522
										// If there are just three we are done.
523
										if(verts.size() == 3) continue;
524
 
525
										// Find vertex pairs that may be connected.
526
										vector<pair<int,int> > vpairs;
527
										const int N = verts.size();
528
										for(int i=0;i<N-2;++i)
529
												for(int j=i+2;j<N; ++j)
530
														if(!is_connected(verts[i], verts[j]))
531
																vpairs.push_back(pair<int,int>(i,j));
532
 
533
										assert(!vpairs.empty());
534
 
535
										/* For all vertex pairs, find the absolute value of iso-x
536
											 where x is the interpolated value of the volume at the 
537
											 midpoint of the line segment connecting the two vertices.*/
538
 
539
										float min_val=FLT_MAX;
540
										int min_k = -1;
541
										for(size_t k=0;k<vpairs.size(); ++k)
542
										{
543
												int i = vpairs[k].first;
544
												int j = vpairs[k].second;
545
												Vec3f centre = 
546
														(verts[i]->pos + 
547
														 verts[j]->pos)/2.0f;
548
 
549
												float val;
550
												if(grid_interp.in_domain(centre))
551
														val = fabs(grid_interp(centre)-iso);
552
												else
553
														val = 0.0f;
554
												if(val<min_val)
555
												{
556
														min_val = val;
557
														min_k = k;
558
												}
559
										}
560
										assert(min_k != -1);
561
 
562
										{
169 jab 563
												// Split faces along edge whose midpoint is closest to isovalue
564
												int i = vpairs[min_k].first;
565
												int j = vpairs[min_k].second;
566
												m.split_face(fi, verts[i], verts[j]);
149 jab 567
										}
568
										++work;
569
 
570
								}
571
						}
572
						while(work);
573
 
574
#ifndef NDEBUG
169 jab 575
						cout << "Valid after triangulation : " << m.is_valid() << endl;
149 jab 576
#endif
577
				}
578
 
579
				/* This function collapses every edge whose endpoints belong to the same 
580
					 cube if this edge can be removed without violating the manifold condition*/
169 jab 581
				void remove_duplicates(Manifold& m)
149 jab 582
				{
583
						// BUG --- we never do this loop more than one time.
584
						// does it matter.
169 jab 585
						VertexIter vi = m.vertices_begin();
149 jab 586
						bool did_work = false;
587
						do
588
						{
589
								did_work = false;
169 jab 590
								while(vi != m.vertices_end())
149 jab 591
								{
592
										bool did = false;
593
										VertexCirculator vc(vi);
594
										int k=0;
595
										for(;!vc.end();++vc)
596
										{
597
												assert(++k<1000);
598
												HalfEdgeIter he = vc.get_halfedge();
599
												VertexIter n = vc.get_vertex();
169 jab 600
												if(n->touched == vi->touched && m.collapse_precond(he))
149 jab 601
												{
602
														++vi;
169 jab 603
														m.collapse_halfedge(he,true);
149 jab 604
														did = did_work = true;
605
														break;
606
												}
607
										}
608
										if(!did) ++vi;
609
								}
610
 
611
						}
612
						while(did_work);
613
#ifndef NDEBUG
169 jab 614
						cout << "Valid after removal of excess vertices : " << m.is_valid() << endl;
149 jab 615
#endif
616
				}
169 jab 617
 
149 jab 618
				/* A function (not used now) which pushes vertices onto the isosurface. */
619
				template<class T>
169 jab 620
				void push_vertices(const RGrid<T>& voxel_grid, Manifold& m, float iso)
149 jab 621
				{
169 jab 622
						GradientFilter<RGrid<T> > grad(&voxel_grid);
149 jab 623
						TrilinFilter<GradientFilter<RGrid<T> > > ginter(&grad);
169 jab 624
						TrilinFilter<RGrid<T> > inter(&voxel_grid);
149 jab 625
						for(int i=0;i<4;++i)
626
						{
169 jab 627
								for(VertexIter vi= m.vertices_begin();
628
										vi != m.vertices_end(); ++vi)
149 jab 629
								{
630
										Vec3f p = vi->pos;
631
										if(ginter.in_domain(p))
632
										{
633
												Vec3f g = ginter(p);
634
												float s = sqr_length(g);
169 jab 635
												if(s>0.01)
149 jab 636
												{
637
														float v = inter(p)-iso;
638
														vi->pos = (p-g*v/s);
639
												}
640
										}
641
								}
642
						}
643
				}
644
 
645
		}
646
 
647
		template<typename T>
648
		void fair_polygonize(const RGrid<T>& voxel_grid, 
649
												 Manifold& mani, 
650
												 float iso,
169 jab 651
												 bool invert_contour, 
652
												 bool connect,
653
												 bool push)
149 jab 654
		{
169 jab 655
				CubeGrid<T> cube_grid(voxel_grid, iso, invert_contour);
656
				cube_grid.dual_cuberille_mesh(voxel_grid, mani, connect);
657
 				triangulate(voxel_grid, mani, iso);
658
 				remove_duplicates(mani);
659
				if(push) push_vertices(voxel_grid, mani, iso);
149 jab 660
		}
661
 
169 jab 662
		template<typename T>
663
		void cuberille_polygonize(const RGrid<T>& voxel_grid, 
664
															Manifold& mani, 
665
															float iso,
666
															bool invert_contour, 
667
															bool connect,
668
															bool push)
669
		{
670
				CubeGrid<T> cube_grid(voxel_grid, iso, invert_contour);
671
				cube_grid.cuberille_mesh(voxel_grid, mani, connect);
672
				if(push) push_vertices(voxel_grid, mani, iso);
673
		}
674
 
149 jab 675
		template void fair_polygonize<unsigned char>(const RGrid<unsigned char>&,
169 jab 676
																								 Manifold&, float, bool,bool,bool);
149 jab 677
		template void fair_polygonize<float>(const RGrid<float>&,
169 jab 678
																				 Manifold&, float, bool,bool,bool);
679
 
680
		template void cuberille_polygonize<unsigned char>(const RGrid<unsigned char>&,
681
																											Manifold&, float, bool,bool,bool);
682
		template void cuberille_polygonize<float>(const RGrid<float>&,
683
																							Manifold&, float, bool,bool,bool);
149 jab 684
}
685
 
686