61 |
jab |
1 |
/**********************************************************************
|
|
|
2 |
|
|
|
3 |
polygonizer.h
|
|
|
4 |
|
|
|
5 |
This is Jules Bloomenthal's implicit surface polygonizer from GRAPHICS
|
|
|
6 |
GEMS IV. Bloomenthal's polygonizer is still used and the present code
|
|
|
7 |
is simply the original code morphed into C++.
|
|
|
8 |
|
|
|
9 |
J. Andreas Bærentzen 2003.
|
|
|
10 |
|
|
|
11 |
**********************************************************************/
|
|
|
12 |
|
385 |
jab |
13 |
#include <string>
|
61 |
jab |
14 |
#include <stdlib.h>
|
|
|
15 |
#include <math.h>
|
|
|
16 |
#include <iostream>
|
|
|
17 |
#include <vector>
|
|
|
18 |
#include <list>
|
|
|
19 |
#include <sys/types.h>
|
|
|
20 |
#include "Polygonizer.h"
|
|
|
21 |
|
|
|
22 |
using namespace std;
|
|
|
23 |
|
64 |
jab |
24 |
namespace Geometry
|
61 |
jab |
25 |
{
|
|
|
26 |
|
|
|
27 |
namespace
|
|
|
28 |
{
|
|
|
29 |
const int RES = 10; /* # converge iterations */
|
|
|
30 |
|
|
|
31 |
const int L = 0; /* left direction: -x, -i */
|
|
|
32 |
const int R = 1; /* right direction: +x, +i */
|
|
|
33 |
const int B = 2; /* bottom direction: -y, -j */
|
|
|
34 |
const int T = 3; /* top direction: +y, +j */
|
|
|
35 |
const int N = 4; /* near direction: -z, -k */
|
|
|
36 |
const int F = 5; /* far direction: +z, +k */
|
|
|
37 |
const int LBN = 0; /* left bottom near corner */
|
|
|
38 |
const int LBF = 1; /* left bottom far corner */
|
|
|
39 |
const int LTN = 2; /* left top near corner */
|
|
|
40 |
const int LTF = 3; /* left top far corner */
|
|
|
41 |
const int RBN = 4; /* right bottom near corner */
|
|
|
42 |
const int RBF = 5; /* right bottom far corner */
|
|
|
43 |
const int RTN = 6; /* right top near corner */
|
|
|
44 |
const int RTF = 7; /* right top far corner */
|
|
|
45 |
|
|
|
46 |
|
|
|
47 |
/* the LBN corner of cube (i, j, k), corresponds with location
|
|
|
48 |
* (start.x+(i-.5)*size, start.y+(j-.5)*size, start.z+(k-.5)*size) */
|
|
|
49 |
|
|
|
50 |
inline float RAND()
|
|
|
51 |
{
|
|
|
52 |
return (rand()&32767)/32767.0f;
|
|
|
53 |
}
|
|
|
54 |
|
|
|
55 |
const int HASHBIT = 5;
|
|
|
56 |
|
|
|
57 |
const int HASHSIZE = (size_t)(1<<(3*HASHBIT));
|
|
|
58 |
|
|
|
59 |
const int MASK = ((1<<HASHBIT)-1);
|
|
|
60 |
|
|
|
61 |
inline int HASH( int i, int j,int k)
|
|
|
62 |
{
|
|
|
63 |
return (((((i&MASK)<<HASHBIT)|j&MASK)<<HASHBIT)|k&MASK);
|
|
|
64 |
}
|
|
|
65 |
|
|
|
66 |
inline int BIT(int i, int bit)
|
|
|
67 |
{
|
|
|
68 |
return (i>>bit)&1;
|
|
|
69 |
}
|
|
|
70 |
|
|
|
71 |
// flip the given bit of i
|
|
|
72 |
inline int FLIP(int i, int bit)
|
|
|
73 |
{
|
|
|
74 |
return i^1<<bit;
|
|
|
75 |
}
|
|
|
76 |
|
|
|
77 |
struct TEST { /* test the function for a signed value */
|
|
|
78 |
POINT p; /* location of test */
|
|
|
79 |
float value; /* function value at p */
|
|
|
80 |
int ok; /* if value is of correct sign */
|
|
|
81 |
};
|
|
|
82 |
|
|
|
83 |
struct CORNER { /* corner of a cube */
|
|
|
84 |
int i, j, k; /* (i, j, k) is index within lattice */
|
|
|
85 |
float x, y, z, value; /* location and function value */
|
|
|
86 |
};
|
|
|
87 |
|
|
|
88 |
struct CUBE { /* partitioning cell (cube) */
|
|
|
89 |
int i, j, k; /* lattice location of cube */
|
|
|
90 |
CORNER *corners[8]; /* eight corners */
|
|
|
91 |
};
|
|
|
92 |
|
|
|
93 |
struct CENTERELEMENT { /* list of cube locations */
|
|
|
94 |
int i, j, k; /* cube location */
|
|
|
95 |
CENTERELEMENT(int _i, int _j, int _k): i(_i), j(_j), k(_k) {}
|
|
|
96 |
};
|
|
|
97 |
typedef list<CENTERELEMENT> CENTERLIST;
|
|
|
98 |
|
|
|
99 |
struct CORNERELEMENT { /* list of corners */
|
|
|
100 |
int i, j, k; /* corner id */
|
|
|
101 |
float value; /* corner value */
|
|
|
102 |
CORNERELEMENT(int _i, int _j, int _k, float _value):
|
|
|
103 |
i(_i), j(_j), k(_k), value(_value) {}
|
|
|
104 |
};
|
|
|
105 |
typedef list<CORNERELEMENT> CORNERLIST;
|
|
|
106 |
|
|
|
107 |
struct EDGEELEMENT { /* list of edges */
|
|
|
108 |
int i1, j1, k1, i2, j2, k2; /* edge corner ids */
|
|
|
109 |
int vid; /* vertex id */
|
|
|
110 |
};
|
|
|
111 |
|
|
|
112 |
typedef list<EDGEELEMENT> EDGELIST;
|
|
|
113 |
typedef list<int> INTLIST;
|
|
|
114 |
typedef list<INTLIST> INTLISTS;
|
|
|
115 |
|
|
|
116 |
|
|
|
117 |
//----------------------------------------------------------------------
|
|
|
118 |
// Implicit surface evaluation functions
|
|
|
119 |
//----------------------------------------------------------------------
|
|
|
120 |
|
|
|
121 |
/* converge: from two points of differing sign, converge to zero crossing */
|
|
|
122 |
|
|
|
123 |
void converge (POINT* p1, POINT* p2, float v,
|
|
|
124 |
ImplicitFunction* function, POINT* p)
|
|
|
125 |
{
|
|
|
126 |
int i = 0;
|
|
|
127 |
POINT pos, neg;
|
|
|
128 |
if (v < 0) {
|
|
|
129 |
pos.x = p2->x; pos.y = p2->y; pos.z = p2->z;
|
|
|
130 |
neg.x = p1->x; neg.y = p1->y; neg.z = p1->z;
|
|
|
131 |
}
|
|
|
132 |
else {
|
|
|
133 |
pos.x = p1->x; pos.y = p1->y; pos.z = p1->z;
|
|
|
134 |
neg.x = p2->x; neg.y = p2->y; neg.z = p2->z;
|
|
|
135 |
}
|
|
|
136 |
while (1) {
|
102 |
bj |
137 |
p->x = 0.5f*(pos.x + neg.x);
|
|
|
138 |
p->y = 0.5f*(pos.y + neg.y);
|
|
|
139 |
p->z = 0.5f*(pos.z + neg.z);
|
61 |
jab |
140 |
if (i++ == RES) return;
|
|
|
141 |
if ((function->eval(p->x, p->y, p->z)) > 0.0)
|
|
|
142 |
{pos.x = p->x; pos.y = p->y; pos.z = p->z;}
|
|
|
143 |
else {neg.x = p->x; neg.y = p->y; neg.z = p->z;}
|
|
|
144 |
}
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
|
|
|
148 |
/* vnormal: compute unit length surface normal at point */
|
|
|
149 |
|
|
|
150 |
inline void vnormal (ImplicitFunction* function, POINT* point, POINT* n, float delta)
|
|
|
151 |
{
|
|
|
152 |
float f = function->eval(point->x, point->y, point->z);
|
|
|
153 |
n->x = function->eval(point->x+delta, point->y, point->z)-f;
|
|
|
154 |
n->y = function->eval(point->x, point->y+delta, point->z)-f;
|
|
|
155 |
n->z = function->eval(point->x, point->y, point->z+delta)-f;
|
|
|
156 |
f = sqrt(n->x*n->x + n->y*n->y + n->z*n->z);
|
|
|
157 |
if (f != 0.0) {n->x /= f; n->y /= f; n->z /= f;}
|
|
|
158 |
}
|
|
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
|
162 |
// ----------------------------------------------------------------------
|
|
|
163 |
|
|
|
164 |
class EDGETABLE
|
|
|
165 |
{
|
|
|
166 |
vector<EDGELIST> table; /* edge and vertex id hash table */
|
|
|
167 |
|
|
|
168 |
public:
|
|
|
169 |
|
|
|
170 |
EDGETABLE(): table(2*HASHSIZE) {}
|
|
|
171 |
|
|
|
172 |
void setedge (int i1, int j1, int k1,
|
|
|
173 |
int i2, int j2, int k2, int vid);
|
|
|
174 |
int getedge (int i1, int j1, int k1,
|
|
|
175 |
int i2, int j2, int k2);
|
|
|
176 |
|
|
|
177 |
|
|
|
178 |
};
|
|
|
179 |
|
|
|
180 |
/* setedge: set vertex id for edge */
|
|
|
181 |
void EDGETABLE::setedge (int i1, int j1, int k1,
|
|
|
182 |
int i2, int j2, int k2, int vid)
|
|
|
183 |
{
|
|
|
184 |
unsigned int index;
|
|
|
185 |
|
|
|
186 |
if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
|
|
|
187 |
int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
|
|
|
188 |
}
|
|
|
189 |
index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
|
|
|
190 |
|
|
|
191 |
EDGEELEMENT new_obj;
|
|
|
192 |
new_obj.i1 = i1;
|
|
|
193 |
new_obj.j1 = j1;
|
|
|
194 |
new_obj.k1 = k1;
|
|
|
195 |
new_obj.i2 = i2;
|
|
|
196 |
new_obj.j2 = j2;
|
|
|
197 |
new_obj.k2 = k2;
|
|
|
198 |
new_obj.vid = vid;
|
|
|
199 |
table[index].push_front(new_obj);
|
|
|
200 |
}
|
|
|
201 |
|
|
|
202 |
|
|
|
203 |
/* getedge: return vertex id for edge; return -1 if not set */
|
|
|
204 |
|
|
|
205 |
int EDGETABLE::getedge (int i1, int j1, int k1, int i2, int j2, int k2)
|
|
|
206 |
{
|
|
|
207 |
|
|
|
208 |
if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
|
|
|
209 |
int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
|
|
|
210 |
};
|
|
|
211 |
int hashval = HASH(i1, j1, k1)+HASH(i2, j2, k2);
|
|
|
212 |
EDGELIST::const_iterator q = table[hashval].begin();
|
|
|
213 |
for (; q != table[hashval].end(); ++q)
|
|
|
214 |
if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
|
|
|
215 |
q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
|
|
|
216 |
return q->vid;
|
|
|
217 |
return -1;
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
|
|
|
221 |
// ----------------------------------------------------------------------
|
|
|
222 |
class PROCESS
|
|
|
223 |
{ /* parameters, function, storage */
|
|
|
224 |
|
|
|
225 |
std::vector<NORMAL>* gnormals;
|
|
|
226 |
std::vector<VERTEX>* gvertices;
|
|
|
227 |
std::vector<TRIANGLE> *gtriangles;
|
|
|
228 |
|
|
|
229 |
ImplicitFunction* function; /* implicit surface function */
|
|
|
230 |
|
|
|
231 |
float size, delta; /* cube size, normal delta */
|
|
|
232 |
int bounds; /* cube range within lattice */
|
|
|
233 |
POINT start; /* start point on surface */
|
|
|
234 |
bool use_normals;
|
|
|
235 |
|
|
|
236 |
// Global list of corners (keeps track of memory)
|
|
|
237 |
list<CORNER> corner_lst;
|
|
|
238 |
list<CUBE> cubes; /* active cubes */
|
|
|
239 |
vector<CENTERLIST> centers; /* cube center hash table */
|
|
|
240 |
vector<CORNERLIST> corners; /* corner value hash table */
|
|
|
241 |
EDGETABLE edges;
|
|
|
242 |
|
|
|
243 |
CORNER *setcorner (int i, int j, int k);
|
|
|
244 |
|
|
|
245 |
void testface (int i, int j, int k, CUBE* old,
|
|
|
246 |
int face, int c1, int c2, int c3, int c4);
|
|
|
247 |
|
|
|
248 |
TEST find (int sign, float x, float y, float z);
|
|
|
249 |
|
|
|
250 |
int vertid (CORNER* c1, CORNER* c2);
|
|
|
251 |
|
|
|
252 |
int dotet (CUBE* cube, int c1, int c2, int c3, int c4);
|
|
|
253 |
|
|
|
254 |
int docube (CUBE* cube);
|
|
|
255 |
|
|
|
256 |
int triangle (int i1, int i2, int i3)
|
|
|
257 |
{
|
|
|
258 |
TRIANGLE t;
|
|
|
259 |
t.v0 = i1;
|
|
|
260 |
t.v1 = i2;
|
|
|
261 |
t.v2 = i3;
|
|
|
262 |
(*gtriangles).push_back(t);
|
|
|
263 |
return 1;
|
|
|
264 |
}
|
|
|
265 |
|
|
|
266 |
public:
|
|
|
267 |
PROCESS(ImplicitFunction* _function,
|
|
|
268 |
float _size, float _delta,
|
|
|
269 |
int _bounds,
|
|
|
270 |
vector<VERTEX>& _gvertices,
|
|
|
271 |
vector<NORMAL>& _gnormals,
|
|
|
272 |
vector<TRIANGLE>& _gtriangles,
|
|
|
273 |
bool _compute_normals=false);
|
|
|
274 |
|
|
|
275 |
|
|
|
276 |
~PROCESS() {}
|
|
|
277 |
|
|
|
278 |
void march(int mode, float x, float y, float z);
|
|
|
279 |
|
|
|
280 |
};
|
|
|
281 |
|
|
|
282 |
|
|
|
283 |
/* setcenter: set (i,j,k) entry of table[]
|
|
|
284 |
return 1 if already set; otherwise, set and return 0 */
|
|
|
285 |
int setcenter(vector<CENTERLIST>& table,
|
|
|
286 |
int i, int j, int k)
|
|
|
287 |
{
|
|
|
288 |
int index = HASH(i,j,k);
|
|
|
289 |
CENTERLIST::const_iterator q = table[index].begin();
|
|
|
290 |
for(; q != table[index].end(); ++q)
|
|
|
291 |
if(q->i == i && q->j==j && q->k == k) return 1;
|
|
|
292 |
|
|
|
293 |
CENTERELEMENT elem(i,j,k);
|
|
|
294 |
table[index].push_front(elem);
|
|
|
295 |
return 0;
|
|
|
296 |
}
|
|
|
297 |
|
|
|
298 |
/* setcorner: return corner with the given lattice location
|
|
|
299 |
set (and cache) its function value */
|
|
|
300 |
CORNER* PROCESS::setcorner (int i, int j, int k)
|
|
|
301 |
{
|
|
|
302 |
/* for speed, do corner value caching here */
|
|
|
303 |
corner_lst.push_back(CORNER());
|
|
|
304 |
CORNER *c = &corner_lst.back();
|
|
|
305 |
int index = HASH(i, j, k);
|
|
|
306 |
|
102 |
bj |
307 |
c->i = i; c->x = start.x+((float)i-.5f)*size;
|
|
|
308 |
c->j = j; c->y = start.y+((float)j-.5f)*size;
|
|
|
309 |
c->k = k; c->z = start.z+((float)k-.5f)*size;
|
61 |
jab |
310 |
|
|
|
311 |
CORNERLIST::const_iterator l = corners[index].begin();
|
|
|
312 |
for (; l != corners[index].end(); ++l)
|
|
|
313 |
if (l->i == i && l->j == j && l->k == k) {
|
|
|
314 |
c->value = l->value;
|
|
|
315 |
return c;
|
|
|
316 |
}
|
|
|
317 |
|
|
|
318 |
c->value = function->eval(c->x, c->y, c->z);
|
|
|
319 |
CORNERELEMENT elem(i,j,k,c->value);
|
|
|
320 |
corners[index].push_front(elem);
|
|
|
321 |
return c;
|
|
|
322 |
}
|
|
|
323 |
|
|
|
324 |
|
|
|
325 |
|
|
|
326 |
/* testface: given cube at lattice (i, j, k), and four corners of face,
|
|
|
327 |
* if surface crosses face, compute other four corners of adjacent cube
|
|
|
328 |
* and add new cube to cube stack */
|
|
|
329 |
|
|
|
330 |
inline void PROCESS::testface (int i, int j, int k, CUBE* old,
|
|
|
331 |
int face, int c1, int c2, int c3, int c4)
|
|
|
332 |
{
|
|
|
333 |
CUBE new_obj;
|
|
|
334 |
|
|
|
335 |
static int facebit[6] = {2, 2, 1, 1, 0, 0};
|
|
|
336 |
int n, pos = old->corners[c1]->value > 0.0 ? 1 : 0, bit = facebit[face];
|
|
|
337 |
|
|
|
338 |
/* test if no surface crossing, cube out of bounds, or already visited: */
|
|
|
339 |
if ((old->corners[c2]->value > 0) == pos &&
|
|
|
340 |
(old->corners[c3]->value > 0) == pos &&
|
|
|
341 |
(old->corners[c4]->value > 0) == pos) return;
|
|
|
342 |
if (abs(i) > bounds || abs(j) > bounds || abs(k) > bounds) return;
|
|
|
343 |
if (setcenter(centers, i, j, k)) return;
|
|
|
344 |
|
|
|
345 |
/* create new_obj cube: */
|
|
|
346 |
new_obj.i = i;
|
|
|
347 |
new_obj.j = j;
|
|
|
348 |
new_obj.k = k;
|
|
|
349 |
for (n = 0; n < 8; n++) new_obj.corners[n] = 0;
|
|
|
350 |
new_obj.corners[FLIP(c1, bit)] = old->corners[c1];
|
|
|
351 |
new_obj.corners[FLIP(c2, bit)] = old->corners[c2];
|
|
|
352 |
new_obj.corners[FLIP(c3, bit)] = old->corners[c3];
|
|
|
353 |
new_obj.corners[FLIP(c4, bit)] = old->corners[c4];
|
|
|
354 |
for (n = 0; n < 8; n++)
|
|
|
355 |
if (new_obj.corners[n] == 0)
|
|
|
356 |
new_obj.corners[n] = setcorner(i+BIT(n,2), j+BIT(n,1), k+BIT(n,0));
|
|
|
357 |
|
|
|
358 |
// Add new cube to top of stack
|
|
|
359 |
cubes.push_front(new_obj);
|
|
|
360 |
}
|
|
|
361 |
|
|
|
362 |
/* find: search for point with value of given sign (0: neg, 1: pos) */
|
|
|
363 |
|
|
|
364 |
TEST PROCESS::find (int sign, float x, float y, float z)
|
|
|
365 |
{
|
|
|
366 |
int i;
|
|
|
367 |
TEST test;
|
|
|
368 |
float range = size;
|
|
|
369 |
test.ok = 1;
|
|
|
370 |
for (i = 0; i < 10000; i++) {
|
102 |
bj |
371 |
test.p.x = x+range*(RAND()-0.5f);
|
|
|
372 |
test.p.y = y+range*(RAND()-0.5f);
|
|
|
373 |
test.p.z = z+range*(RAND()-0.5f);
|
61 |
jab |
374 |
test.value = function->eval(test.p.x, test.p.y, test.p.z);
|
|
|
375 |
if (sign == (test.value > 0.0)) return test;
|
102 |
bj |
376 |
range = range*1.0005f; /* slowly expand search outwards */
|
61 |
jab |
377 |
}
|
|
|
378 |
test.ok = 0;
|
|
|
379 |
return test;
|
|
|
380 |
}
|
|
|
381 |
|
|
|
382 |
|
|
|
383 |
/* vertid: return index for vertex on edge:
|
|
|
384 |
* c1->value and c2->value are presumed of different sign
|
|
|
385 |
* return saved index if any; else compute vertex and save */
|
|
|
386 |
|
|
|
387 |
int PROCESS::vertid (CORNER* c1, CORNER* c2)
|
|
|
388 |
{
|
|
|
389 |
VERTEX v;
|
|
|
390 |
NORMAL n;
|
|
|
391 |
POINT a, b;
|
|
|
392 |
int vid = edges.getedge(c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
|
|
|
393 |
if (vid != -1) return vid; /* previously computed */
|
|
|
394 |
a.x = c1->x; a.y = c1->y; a.z = c1->z;
|
|
|
395 |
b.x = c2->x; b.y = c2->y; b.z = c2->z;
|
|
|
396 |
converge(&a, &b, c1->value, function, &v); /* position */
|
|
|
397 |
(*gvertices).push_back(v); /* save vertex */
|
|
|
398 |
if(use_normals)
|
|
|
399 |
{
|
|
|
400 |
vnormal(function, &v, &n, delta); /* normal */
|
|
|
401 |
(*gnormals).push_back(n); /* save vertex */
|
|
|
402 |
}
|
|
|
403 |
vid = gvertices->size()-1;
|
|
|
404 |
edges.setedge(c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
|
|
|
405 |
return vid;
|
|
|
406 |
}
|
|
|
407 |
|
|
|
408 |
|
|
|
409 |
|
|
|
410 |
|
|
|
411 |
/**** Tetrahedral Polygonization ****/
|
|
|
412 |
|
|
|
413 |
|
|
|
414 |
/* dotet: triangulate the tetrahedron
|
|
|
415 |
* b, c, d should appear clockwise when viewed from a
|
|
|
416 |
* return 0 if client aborts, 1 otherwise */
|
|
|
417 |
|
|
|
418 |
int PROCESS::dotet (CUBE* cube, int c1, int c2, int c3, int c4)
|
|
|
419 |
{
|
|
|
420 |
CORNER *a = cube->corners[c1];
|
|
|
421 |
CORNER *b = cube->corners[c2];
|
|
|
422 |
CORNER *c = cube->corners[c3];
|
|
|
423 |
CORNER *d = cube->corners[c4];
|
|
|
424 |
int index = 0, apos, bpos, cpos, dpos, e1, e2, e3, e4, e5, e6;
|
136 |
jab |
425 |
if ((apos = (a->value > 0.0))) index += 8;
|
|
|
426 |
if ((bpos = (b->value > 0.0))) index += 4;
|
|
|
427 |
if ((cpos = (c->value > 0.0))) index += 2;
|
|
|
428 |
if ((dpos = (d->value > 0.0))) index += 1;
|
61 |
jab |
429 |
/* index is now 4-bit number representing one of the 16 possible cases */
|
|
|
430 |
if (apos != bpos) e1 = vertid(a, b);
|
|
|
431 |
if (apos != cpos) e2 = vertid(a, c);
|
|
|
432 |
if (apos != dpos) e3 = vertid(a, d);
|
|
|
433 |
if (bpos != cpos) e4 = vertid(b, c);
|
|
|
434 |
if (bpos != dpos) e5 = vertid(b, d);
|
|
|
435 |
if (cpos != dpos) e6 = vertid(c, d);
|
|
|
436 |
/* 14 productive tetrahedral cases (0000 and 1111 do not yield polygons */
|
|
|
437 |
switch (index) {
|
|
|
438 |
case 1: return triangle(e5, e6, e3);
|
|
|
439 |
case 2: return triangle(e2, e6, e4);
|
|
|
440 |
case 3: return triangle(e3, e5, e4) &&
|
|
|
441 |
triangle(e3, e4, e2);
|
|
|
442 |
case 4: return triangle(e1, e4, e5);
|
|
|
443 |
case 5: return triangle(e3, e1, e4) &&
|
|
|
444 |
triangle(e3, e4, e6);
|
|
|
445 |
case 6: return triangle(e1, e2, e6) &&
|
|
|
446 |
triangle(e1, e6, e5);
|
|
|
447 |
case 7: return triangle(e1, e2, e3);
|
|
|
448 |
case 8: return triangle(e1, e3, e2);
|
|
|
449 |
case 9: return triangle(e1, e5, e6) &&
|
|
|
450 |
triangle(e1, e6, e2);
|
|
|
451 |
case 10: return triangle(e1, e3, e6) &&
|
|
|
452 |
triangle(e1, e6, e4);
|
|
|
453 |
case 11: return triangle(e1, e5, e4);
|
|
|
454 |
case 12: return triangle(e3, e2, e4) &&
|
|
|
455 |
triangle(e3, e4, e5);
|
|
|
456 |
case 13: return triangle(e6, e2, e4);
|
|
|
457 |
case 14: return triangle(e5, e3, e6);
|
|
|
458 |
}
|
|
|
459 |
return 1;
|
|
|
460 |
}
|
|
|
461 |
|
|
|
462 |
|
|
|
463 |
/**** Cubical Polygonization (optional) ****/
|
|
|
464 |
|
|
|
465 |
|
|
|
466 |
const int LB = 0; /* left bottom edge */
|
|
|
467 |
const int LT = 1; /* left top edge */
|
|
|
468 |
const int LN = 2; /* left near edge */
|
|
|
469 |
const int LF = 3; /* left far edge */
|
|
|
470 |
const int RB = 4; /* right bottom edge */
|
|
|
471 |
const int RT = 5; /* right top edge */
|
|
|
472 |
const int RN = 6; /* right near edge */
|
|
|
473 |
const int RF = 7; /* right far edge */
|
|
|
474 |
const int BN = 8; /* bottom near edge */
|
|
|
475 |
const int BF = 9; /* bottom far edge */
|
|
|
476 |
const int TN = 10; /* top near edge */
|
|
|
477 |
const int TF = 11; /* top far edge */
|
|
|
478 |
|
|
|
479 |
|
|
|
480 |
class CUBETABLE
|
|
|
481 |
{
|
|
|
482 |
vector<INTLISTS> ctable;
|
|
|
483 |
int nextcwedge (int edge, int face);
|
|
|
484 |
int otherface (int edge, int face);
|
|
|
485 |
|
|
|
486 |
public:
|
|
|
487 |
|
|
|
488 |
CUBETABLE();
|
|
|
489 |
|
|
|
490 |
const INTLISTS& get_lists(int i) const
|
|
|
491 |
{
|
|
|
492 |
return ctable[i];
|
|
|
493 |
}
|
|
|
494 |
};
|
|
|
495 |
|
|
|
496 |
/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
|
|
|
497 |
const int corner1[12] = {LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF};
|
|
|
498 |
const int corner2[12] = {LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF};
|
|
|
499 |
const int leftface[12] = {B, L, L, F, R, T, N, R, N, B, T, F};
|
|
|
500 |
/* face on left when going corner1 to corner2 */
|
|
|
501 |
const int rightface[12] = {L, T, N, L, B, R, R, F, B, F, N, T};
|
|
|
502 |
/* face on right when going corner1 to corner2 */
|
|
|
503 |
|
|
|
504 |
|
|
|
505 |
/* nextcwedge: return next clockwise edge from given edge around given face */
|
|
|
506 |
|
|
|
507 |
inline int CUBETABLE::nextcwedge (int edge, int face)
|
|
|
508 |
{
|
|
|
509 |
switch (edge) {
|
|
|
510 |
case LB: return (face == L)? LF : BN;
|
|
|
511 |
case LT: return (face == L)? LN : TF;
|
|
|
512 |
case LN: return (face == L)? LB : TN;
|
|
|
513 |
case LF: return (face == L)? LT : BF;
|
|
|
514 |
case RB: return (face == R)? RN : BF;
|
|
|
515 |
case RT: return (face == R)? RF : TN;
|
|
|
516 |
case RN: return (face == R)? RT : BN;
|
|
|
517 |
case RF: return (face == R)? RB : TF;
|
|
|
518 |
case BN: return (face == B)? RB : LN;
|
|
|
519 |
case BF: return (face == B)? LB : RF;
|
|
|
520 |
case TN: return (face == T)? LT : RN;
|
|
|
521 |
case TF: return (face == T)? RT : LF;
|
|
|
522 |
}
|
102 |
bj |
523 |
return -1;
|
61 |
jab |
524 |
}
|
|
|
525 |
|
|
|
526 |
/* otherface: return face adjoining edge that is not the given face */
|
|
|
527 |
|
|
|
528 |
inline int CUBETABLE::otherface (int edge, int face)
|
|
|
529 |
{
|
|
|
530 |
int other = leftface[edge];
|
|
|
531 |
return face == other? rightface[edge] : other;
|
|
|
532 |
}
|
|
|
533 |
|
|
|
534 |
|
|
|
535 |
CUBETABLE::CUBETABLE(): ctable(256)
|
|
|
536 |
{
|
|
|
537 |
int i, e, c, done[12], pos[8];
|
|
|
538 |
for (i = 0; i < 256; i++)
|
|
|
539 |
{
|
|
|
540 |
for (e = 0; e < 12; e++)
|
|
|
541 |
done[e] = 0;
|
|
|
542 |
for (c = 0; c < 8; c++)
|
|
|
543 |
pos[c] = BIT(i, c);
|
|
|
544 |
for (e = 0; e < 12; e++)
|
|
|
545 |
if (!done[e] && (pos[corner1[e]] != pos[corner2[e]]))
|
|
|
546 |
{
|
|
|
547 |
INTLIST ints;
|
|
|
548 |
int start = e, edge = e;
|
|
|
549 |
|
|
|
550 |
/* get face that is to right of edge from pos to neg corner: */
|
|
|
551 |
int face = pos[corner1[e]]? rightface[e] : leftface[e];
|
|
|
552 |
while (1)
|
|
|
553 |
{
|
|
|
554 |
edge = nextcwedge(edge, face);
|
|
|
555 |
done[edge] = 1;
|
|
|
556 |
if (pos[corner1[edge]] != pos[corner2[edge]])
|
|
|
557 |
{
|
|
|
558 |
ints.push_front(edge);
|
|
|
559 |
if (edge == start)
|
|
|
560 |
break;
|
|
|
561 |
face = otherface(edge, face);
|
|
|
562 |
}
|
|
|
563 |
}
|
|
|
564 |
ctable[i].push_front(ints);
|
|
|
565 |
}
|
|
|
566 |
}
|
|
|
567 |
}
|
|
|
568 |
|
|
|
569 |
inline const INTLISTS& get_cubetable_entry(int i)
|
|
|
570 |
{
|
|
|
571 |
static CUBETABLE c;
|
|
|
572 |
return c.get_lists(i);
|
|
|
573 |
}
|
|
|
574 |
|
|
|
575 |
|
|
|
576 |
/* docube: triangulate the cube directly, without decomposition */
|
|
|
577 |
|
|
|
578 |
int PROCESS::docube (CUBE* cube)
|
|
|
579 |
{
|
|
|
580 |
int index = 0;
|
|
|
581 |
for (int i = 0; i < 8; i++)
|
|
|
582 |
if (cube->corners[i]->value > 0.0)
|
|
|
583 |
index += (1<<i);
|
|
|
584 |
|
|
|
585 |
INTLISTS intlists = get_cubetable_entry(index);
|
|
|
586 |
INTLISTS::const_iterator polys = intlists.begin();
|
|
|
587 |
for (; polys != intlists.end(); ++polys)
|
|
|
588 |
{
|
|
|
589 |
INTLIST::const_iterator edges = polys->begin();
|
|
|
590 |
int a = -1, b = -1, count = 0;
|
|
|
591 |
for (; edges != polys->end(); ++edges)
|
|
|
592 |
{
|
|
|
593 |
CORNER *c1 = cube->corners[corner1[(*edges)]];
|
|
|
594 |
CORNER *c2 = cube->corners[corner2[(*edges)]];
|
|
|
595 |
int c = vertid(c1, c2);
|
|
|
596 |
if (++count > 2 && ! triangle(a, b, c))
|
|
|
597 |
return 0;
|
|
|
598 |
if (count < 3)
|
|
|
599 |
a = b;
|
|
|
600 |
b = c;
|
|
|
601 |
}
|
|
|
602 |
}
|
|
|
603 |
return 1;
|
|
|
604 |
}
|
|
|
605 |
|
|
|
606 |
|
|
|
607 |
|
|
|
608 |
|
|
|
609 |
|
|
|
610 |
|
|
|
611 |
|
|
|
612 |
/**** An Implicit Surface Polygonizer ****/
|
|
|
613 |
|
|
|
614 |
|
|
|
615 |
/* polygonize: polygonize the implicit surface function
|
|
|
616 |
* arguments are:
|
|
|
617 |
* ImplicitFunction
|
|
|
618 |
* the implicit surface function
|
|
|
619 |
* return negative for inside, positive for outside
|
|
|
620 |
* float size
|
|
|
621 |
* width of the partitioning cube
|
|
|
622 |
* float delta
|
|
|
623 |
* a small step - used for gradient computation
|
|
|
624 |
* int bounds
|
|
|
625 |
* max. range of cubes (+/- on the three axes) from first cube
|
|
|
626 |
* _gvertices, _gnormals, _gtriangles
|
|
|
627 |
* the data structures into which information is put.
|
|
|
628 |
*/
|
|
|
629 |
|
|
|
630 |
PROCESS::PROCESS(ImplicitFunction* _function,
|
|
|
631 |
float _size, float _delta,
|
|
|
632 |
int _bounds,
|
|
|
633 |
vector<VERTEX>& _gvertices,
|
|
|
634 |
vector<NORMAL>& _gnormals,
|
|
|
635 |
vector<TRIANGLE>& _gtriangles,
|
|
|
636 |
bool _use_normals):
|
|
|
637 |
function(_function), size(_size), delta(_delta), bounds(_bounds),
|
|
|
638 |
centers(HASHSIZE), corners(HASHSIZE),
|
|
|
639 |
gvertices(&_gvertices),
|
|
|
640 |
gnormals(&_gnormals),
|
|
|
641 |
gtriangles(&_gtriangles),
|
|
|
642 |
use_normals(_use_normals)
|
|
|
643 |
{}
|
|
|
644 |
|
|
|
645 |
void PROCESS::march(int mode, float x, float y, float z)
|
|
|
646 |
{
|
|
|
647 |
int noabort;
|
|
|
648 |
TEST in, out;
|
|
|
649 |
|
|
|
650 |
/* find point on surface, beginning search at (x, y, z): */
|
|
|
651 |
srand(1);
|
|
|
652 |
in = find(1, x, y, z);
|
|
|
653 |
out = find(0, x, y, z);
|
|
|
654 |
if (!in.ok || !out.ok)
|
385 |
jab |
655 |
{
|
|
|
656 |
exit(1);
|
|
|
657 |
}
|
61 |
jab |
658 |
converge(&in.p, &out.p, in.value, function, &start);
|
|
|
659 |
|
|
|
660 |
/* push initial cube on stack: */
|
|
|
661 |
CUBE cube;
|
|
|
662 |
cube.i = cube.j = cube.k = 0;
|
|
|
663 |
cubes.push_front(cube);
|
|
|
664 |
|
|
|
665 |
/* set corners of initial cube: */
|
|
|
666 |
for (int n = 0; n < 8; n++)
|
|
|
667 |
cubes.front().corners[n] = setcorner(BIT(n,2), BIT(n,1), BIT(n,0));
|
|
|
668 |
|
|
|
669 |
setcenter(centers, 0, 0, 0);
|
|
|
670 |
|
|
|
671 |
while (cubes.size() != 0)
|
|
|
672 |
{
|
|
|
673 |
/* process active cubes till none left */
|
|
|
674 |
CUBE c = cubes.front();
|
|
|
675 |
|
|
|
676 |
noabort = mode == TET?
|
|
|
677 |
/* either decompose into tetrahedra and polygonize: */
|
|
|
678 |
dotet(&c, LBN, LTN, RBN, LBF) &&
|
|
|
679 |
dotet(&c, RTN, LTN, LBF, RBN) &&
|
|
|
680 |
dotet(&c, RTN, LTN, LTF, LBF) &&
|
|
|
681 |
dotet(&c, RTN, RBN, LBF, RBF) &&
|
|
|
682 |
dotet(&c, RTN, LBF, LTF, RBF) &&
|
|
|
683 |
dotet(&c, RTN, LTF, RTF, RBF)
|
|
|
684 |
:
|
|
|
685 |
/* or polygonize the cube directly: */
|
|
|
686 |
docube(&c);
|
385 |
jab |
687 |
if (! noabort) {
|
|
|
688 |
exit(1);
|
|
|
689 |
}
|
61 |
jab |
690 |
|
|
|
691 |
/* pop current cube from stack */
|
|
|
692 |
cubes.pop_front();
|
|
|
693 |
|
|
|
694 |
/* test six face directions, maybe add to stack: */
|
|
|
695 |
testface(c.i-1, c.j, c.k, &c, L, LBN, LBF, LTN, LTF);
|
|
|
696 |
testface(c.i+1, c.j, c.k, &c, R, RBN, RBF, RTN, RTF);
|
|
|
697 |
testface(c.i, c.j-1, c.k, &c, B, LBN, LBF, RBN, RBF);
|
|
|
698 |
testface(c.i, c.j+1, c.k, &c, T, LTN, LTF, RTN, RTF);
|
|
|
699 |
testface(c.i, c.j, c.k-1, &c, N, LBN, LTN, RBN, RTN);
|
|
|
700 |
testface(c.i, c.j, c.k+1, &c, F, LBF, LTF, RBF, RTF);
|
|
|
701 |
}
|
|
|
702 |
}
|
|
|
703 |
}
|
|
|
704 |
|
|
|
705 |
void Polygonizer::march(float x, float y, float z)
|
|
|
706 |
{
|
|
|
707 |
gvertices.clear();
|
|
|
708 |
gnormals.clear();
|
|
|
709 |
gtriangles.clear();
|
|
|
710 |
PROCESS p(func, size, size/(float)(RES*RES), bounds,
|
|
|
711 |
gvertices, gnormals, gtriangles, use_normals);
|
|
|
712 |
p.march(use_tetra?TET:NOTET,x,y,z);
|
|
|
713 |
}
|
|
|
714 |
|
|
|
715 |
}
|