📄 bloomenthal.cpp
字号:
if (l->i == i && l->j == j && l->k == k) {
c->value = l->value;
return c;
}
l = (CORNERLIST *) mycalloc(1, sizeof(CORNERLIST));
l->i = i; l->j = j; l->k = k;
l->value = c->value = function(c->x, c->y, c->z);
l->next = p->corners[index];
p->corners[index] = l;
return c;
}
/* find: search for point with value of given sign (0: neg, 1: pos) */
Bloomenthal::TEST Bloomenthal::find1(int sign, PROCESS *p, double x, double y, double z)
{
int i;
TEST test;
double range = p->size;
test.ok = 1;
for (i = 0; i < 10000; i++) {
test.p.x = x+range*(RAND()-0.5);
test.p.y = y+range*(RAND()-0.5);
test.p.z = z+range*(RAND()-0.5);
test.value = function(test.p.x, test.p.y, test.p.z);
if (sign == (test.value > 0.0)) return test;
range = range*1.0005; /* slowly expand search outwards */
}
test.ok = 0;
return test;
}
/**** Tetrahedral Polygonization ****/
/* dotet: triangulate the tetrahedron
* b, c, d should appear clockwise when viewed from a
* return 0 if client aborts, 1 otherwise */
int Bloomenthal::dotet(CUBE *cube, int c1, int c2, int c3, int c4, PROCESS *p)
{
CORNER *a = cube->corners[c1];
CORNER *b = cube->corners[c2];
CORNER *c = cube->corners[c3];
CORNER *d = cube->corners[c4];
int index = 0, apos, bpos, cpos, dpos, e1, e2, e3, e4, e5, e6;
if (apos = (a->value > 0.0)) index += 8;
if (bpos = (b->value > 0.0)) index += 4;
if (cpos = (c->value > 0.0)) index += 2;
if (dpos = (d->value > 0.0)) index += 1;
/* index is now 4-bit number representing one of the 16 possible cases */
if (apos != bpos) e1 = vertid(a, b, p);
if (apos != cpos) e2 = vertid(a, c, p);
if (apos != dpos) e3 = vertid(a, d, p);
if (bpos != cpos) e4 = vertid(b, c, p);
if (bpos != dpos) e5 = vertid(b, d, p);
if (cpos != dpos) e6 = vertid(c, d, p);
/* 14 productive tetrahedral cases (0000 and 1111 do not yield polygons */
switch (index) {
case 1: return triproc(e5, e6, e3, p->vertices);
case 2: return triproc(e2, e6, e4, p->vertices);
case 3: return triproc(e3, e5, e4, p->vertices) &&
triproc(e3, e4, e2, p->vertices);
case 4: return triproc(e1, e4, e5, p->vertices);
case 5: return triproc(e3, e1, e4, p->vertices) &&
triproc(e3, e4, e6, p->vertices);
case 6: return triproc(e1, e2, e6, p->vertices) &&
triproc(e1, e6, e5, p->vertices);
case 7: return triproc(e1, e2, e3, p->vertices);
case 8: return triproc(e1, e3, e2, p->vertices);
case 9: return triproc(e1, e5, e6, p->vertices) &&
triproc(e1, e6, e2, p->vertices);
case 10: return triproc(e1, e3, e6, p->vertices) &&
triproc(e1, e6, e4, p->vertices);
case 11: return triproc(e1, e5, e4, p->vertices);
case 12: return triproc(e3, e2, e4, p->vertices) &&
triproc(e3, e4, e5, p->vertices);
case 13: return triproc(e6, e2, e4, p->vertices);
case 14: return triproc(e5, e3, e6, p->vertices);
}
return 1;
}
/**** Cubical Polygonization (optional) ****/
/* docube: triangulate the cube directly, without decomposition */
int Bloomenthal::docube(CUBE *cube, PROCESS *p)
{
INTLISTS *polys;
int i, index = 0;
for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0) index += (1<<i);
for (polys = cubetable[index]; polys; polys = polys->next) {
INTLIST *edges;
int a = -1, b = -1, count = 0;
for (edges = polys->list; edges; edges = edges->next) {
CORNER *c1 = cube->corners[corner1[edges->i]];
CORNER *c2 = cube->corners[corner2[edges->i]];
int c = vertid(c1, c2, p);
if (++count > 2 && ! triproc(a, b, c, p->vertices)) return 0;
if (count < 3) a = b;
b = c;
}
}
return 1;
}
/* nextcwedge: return next clockwise edge from given edge around given face */
Bloomenthal::nextcwedge(int edge, int face)
{
switch (edge) {
case LB: return (face == L)? LF : BN;
case LT: return (face == L)? LN : TF;
case LN: return (face == L)? LB : TN;
case LF: return (face == L)? LT : BF;
case RB: return (face == R)? RN : BF;
case RT: return (face == R)? RF : TN;
case RN: return (face == R)? RT : BN;
case RF: return (face == R)? RB : TF;
case BN: return (face == B)? RB : LN;
case BF: return (face == B)? LB : RF;
case TN: return (face == T)? LT : RN;
case TF: return (face == T)? RT : LF;
default: return 0;
}
}
/* otherface: return face adjoining edge that is not the given face */
int Bloomenthal::otherface(int edge, int face)
{
int other = leftface[edge];
return face == other? rightface[edge] : other;
}
/* makecubetable: create the 256 entry table for cubical polygonization */
void Bloomenthal::makecubetable()
{
static int visited = 0;
if (visited)
return;
visited = 1;
int i, e, c, done[12], pos[8];
for (i = 0; i < 256; i++) {
for (e = 0; e < 12; e++) done[e] = 0;
for (c = 0; c < 8; c++) pos[c] = BIT(i, c);
for (e = 0; e < 12; e++)
if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
INTLIST *ints = 0;
INTLISTS *lists = (INTLISTS *) mycalloc(1, sizeof(INTLISTS));
int start = e, edge = e;
/* get face that is to right of edge from pos to neg corner: */
int face = pos[corner1[e]]? rightface[e] : leftface[e];
while (1) {
edge = nextcwedge(edge, face);
done[edge] = 1;
if (pos[corner1[edge]] != pos[corner2[edge]]) {
INTLIST *tmp = ints;
ints = (INTLIST *) mycalloc(1, sizeof(INTLIST));
ints->i = edge;
ints->next = tmp; /* add edge to head of list */
if (edge == start) break;
face = otherface(edge, face);
}
}
lists->list = ints; /* add ints to head of table entry */
lists->next = cubetable[i];
cubetable[i] = lists;
}
}
}
/**** Storage ****/
/* mycalloc: return successful calloc or exit program */
char * Bloomenthal::mycalloc(int nitems, int nbytes)
{
char *ptr = (char*)calloc(nitems, nbytes);
if (ptr != NULL) return ptr;
fprintf(stderr, "can't calloc %d bytes\n", nitems*nbytes);
exit(1);
}
/* setcenter: set (i,j,k) entry of table[]
* return 1 if already set; otherwise, set and return 0 */
int Bloomenthal::setcenter(CENTERLIST *table[], int i, int j, int k)
{
int index = HASH(i, j, k);
CENTERLIST *new1, *l, *q = table[index];
for (l = q; l != NULL; l = l->next)
if (l->i == i && l->j == j && l->k == k) return 1;
new1 = (CENTERLIST *) mycalloc(1, sizeof(CENTERLIST));
new1->i = i; new1->j = j; new1->k = k; new1->next = q;
table[index] = new1;
return 0;
}
/* setedge: set vertex id for edge */
void Bloomenthal::setedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2, int vid)
{
unsigned int index;
EDGELIST *new1;
if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
}
index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
new1 = (EDGELIST *) mycalloc(1, sizeof(EDGELIST));
new1->i1 = i1; new1->j1 = j1; new1->k1 = k1;
new1->i2 = i2; new1->j2 = j2; new1->k2 = k2;
new1->vid = vid;
new1->next = table[index];
table[index] = new1;
}
/* getedge: return vertex id for edge; return -1 if not set */
int Bloomenthal::getedge(EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2)
{
EDGELIST *q;
if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
};
q = table[HASH(i1, j1, k1)+HASH(i2, j2, k2)];
for (; q != NULL; q = q->next)
if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
return q->vid;
return -1;
}
/**** Vertices ****/
/* vertid: return index for vertex on edge:
* c1->value and c2->value are presumed of different sign
* return saved index if any; else compute vertex and save */
int Bloomenthal::vertid(CORNER *c1, CORNER *c2, PROCESS *p)
{
VERTEX v;
POINT1 a, b;
int vid = getedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
if (vid != -1) return vid; /* previously computed */
a.x = c1->x; a.y = c1->y; a.z = c1->z;
b.x = c2->x; b.y = c2->y; b.z = c2->z;
double x1, y1, z1, x2, y2, z2, f1, f2;
if(c1->value > 0){
f1 = c1->value;
x1 = c1->x; y1 = c1->y; z1 = c1->z;
f2 = c2->value;
x2 = c2->x; y2 = c2->y; z2 = c2->z;
}
else{
f1 = c2->value;
x1 = c2->x; y1 = c2->y; z1 = c2->z;
f2 = c1->value;
x2 = c1->x; y2 = c1->y; z2 = c1->z;
}
//Repeated Linear Interpolation
double x, y, z, f;
for(int i=0; i<10; i++){
double w1 = fabs(f1);
double w2 = fabs(f2);
x = (w2*x1 + w1*x2)/(w1+w2);
y = (w2*y1 + w1*y2)/(w1+w2);
z = (w2*z1 + w1*z2)/(w1+w2);
break;
f = function(x,y,z);
if(fabs(f) < 0.00001)
break;
if(f > 0){
f1 = f;
x1 = x; y1 = y; z1 = z;
}
else{
f2 = f;
x2 = x; y2 = y; z2 = z;
}
}
v.position.x = x;
v.position.y = y;
v.position.z = z;
//converge(&a, &b, c1->value, &v.position); /* position */
//vnormal(&v.position, p, &v.normal); /* normal */
addtovertices(&p->vertices, v); /* save vertex */
vid = p->vertices.count-1;
setedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
return vid;
}
/* addtovertices: add v to sequence of vertices */
void Bloomenthal::addtovertices(VERTICES *vertices, VERTEX v)
{
if(FILEOUT){
fprintf(ver_file, "%f %f %f\n", v.position.x, v.position.y, v.position.z);
vertices->count++;
}
else{
if(vertices->count == vertices->max) {
int i;
VERTEX *new1;
vertices->max = vertices->count == 0 ? 10 : 2*vertices->count;
new1 = (VERTEX *) mycalloc((unsigned) vertices->max, sizeof(VERTEX));
for (i = 0; i < vertices->count; i++) new1[i] = vertices->ptr[i];
if (vertices->ptr != NULL) free((char *)vertices->ptr);
vertices->ptr = new1;
}
vertices->ptr[vertices->count++] = v;
}
}
/* vnormal: compute unit length surface normal at point */
void Bloomenthal::vnormal(POINT1 *point, PROCESS *p, POINT1 *v)
{
double f = function(point->x, point->y, point->z);
v->x = function(point->x+p->delta, point->y, point->z)-f;
v->y = function(point->x, point->y+p->delta, point->z)-f;
v->z = function(point->x, point->y, point->z+p->delta)-f;
f = sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
if (f != 0.0) {v->x /= f; v->y /= f; v->z /= f;}
}
/* converge: from two points of differing sign, converge to zero crossing */
void Bloomenthal::converge(POINT1 *p1, POINT1 *p2, double v, POINT1 *p)
{
int i = 0;
POINT1 pos, neg;
if (v < 0) {
pos.x = p2->x; pos.y = p2->y; pos.z = p2->z;
neg.x = p1->x; neg.y = p1->y; neg.z = p1->z;
}
else {
pos.x = p1->x; pos.y = p1->y; pos.z = p1->z;
neg.x = p2->x; neg.y = p2->y; neg.z = p2->z;
}
while (1) {
p->x = 0.5*(pos.x + neg.x);
p->y = 0.5*(pos.y + neg.y);
p->z = 0.5*(pos.z + neg.z);
if (i++ == RES) return;
if ((function(p->x, p->y, p->z)) > 0.0)
{pos.x = p->x; pos.y = p->y; pos.z = p->z;}
else {neg.x = p->x; neg.y = p->y; neg.z = p->z;}
}
}
double Bloomenthal::function(double x, double y, double z)
{
return func->GetValue((float)x, (float)y, (float)z);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -