📄 implicit.c
字号:
/* create new cube: */ new.i = i; new.j = j; new.k = k; /* CLJ: changed this to make memory management possible. *//* for (n = 0; n < 8; n++) new.corners[n] = NULL; *//* new.corners[FLIP(c1, bit)] = old->corners[c1]; *//* new.corners[FLIP(c2, bit)] = old->corners[c2]; *//* new.corners[FLIP(c3, bit)] = old->corners[c3]; *//* new.corners[FLIP(c4, bit)] = old->corners[c4]; *//* for (n = 0; n < 8; n++) *//* if (new.corners[n] == NULL) *//* new.corners[n] = setcorner(p, i+BIT(n,2), j+BIT(n,1), k+BIT(n,0)); */ for (n = 0; n < 8; n++) new.corners[n] = setcorner(p, i+BIT(n,2), j+BIT(n,1), k+BIT(n,0)); /*add cube to top of stack: */ p->cubes = (CUBES *) mycalloc(1, sizeof(CUBES)); p->cubes->cube = new; p->cubes->next = oldcubes;}/* setcorner: return corner with the given lattice location set (and cache) its function value */static CORNER *setcorner (p, i, j, k)int i, j, k;PROCESS *p;{ /* for speed, do corner value caching here */ CORNER *c = (CORNER *) mycalloc(1, sizeof(CORNER)); int index = HASH(i, j, k); CORNERLIST *l = p->corners[index]; c->i = i; c->x = p->start.x+((double)i-.5)*p->size; c->j = j; c->y = p->start.y+((double)j-.5)*p->size; c->k = k; c->z = p->start.z+((double)k-.5)*p->size; for (; l != NULL; l = l->next) 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 = p->function(c->x, c->y, c->z); if (c->value > 100.0 || c->value < -100.0) { fprintf(stderr,"suspicious\n"); abort(); } l->next = p->corners[index]; p->corners[index] = l; return c;}/* find: search for point with value of given sign (0: neg, 1: pos) */static TEST find (sign, p, x, y, z)int sign;PROCESS *p;double x, y, 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 = p->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 */static int dotet (cube, c1, c2, c3, c4, p)CUBE *cube;int c1, c2, c3, 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=0, e2=0, e3=0, e4=0, e5=0, e6=0; 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 p->triproc(e5, e6, e3, p->vertices); case 2: return p->triproc(e2, e6, e4, p->vertices); case 3: return p->triproc(e3, e5, e4, p->vertices) && p->triproc(e3, e4, e2, p->vertices); case 4: return p->triproc(e1, e4, e5, p->vertices); case 5: return p->triproc(e3, e1, e4, p->vertices) && p->triproc(e3, e4, e6, p->vertices); case 6: return p->triproc(e1, e2, e6, p->vertices) && p->triproc(e1, e6, e5, p->vertices); case 7: return p->triproc(e1, e2, e3, p->vertices); case 8: return p->triproc(e1, e3, e2, p->vertices); case 9: return p->triproc(e1, e5, e6, p->vertices) && p->triproc(e1, e6, e2, p->vertices); case 10: return p->triproc(e1, e3, e6, p->vertices) && p->triproc(e1, e6, e4, p->vertices); case 11: return p->triproc(e1, e5, e4, p->vertices); case 12: return p->triproc(e3, e2, e4, p->vertices) && p->triproc(e3, e4, e5, p->vertices); case 13: return p->triproc(e6, e2, e4, p->vertices); case 14: return p->triproc(e5, e3, e6, p->vertices); } return 1;}/**** Cubical Polygonization (optional) ****/#define LB 0 /* left bottom edge */#define LT 1 /* left top edge */#define LN 2 /* left near edge */#define LF 3 /* left far edge */#define RB 4 /* right bottom edge */#define RT 5 /* right top edge */#define RN 6 /* right near edge */#define RF 7 /* right far edge */#define BN 8 /* bottom near edge */#define BF 9 /* bottom far edge */#define TN 10 /* top near edge */#define TF 11 /* top far edge */static INTLISTS *cubetable[256];/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */static int corner1[12] = {LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF};static int corner2[12] = {LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF};static int leftface[12] = {B, L, L, F, R, T, N, R, N, B, T, F}; /* face on left when going corner1 to corner2 */static int rightface[12] = {L, T, N, L, B, R, R, F, B, F, N, T}; /* face on right when going corner1 to corner2 *//* docube: triangulate the cube directly, without decomposition */static int docube (cube, p)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 && ! p->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 */static int nextcwedge (edge, face)int edge, 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; } return -1;}/* otherface: return face adjoining edge that is not the given face */static int otherface (edge, face)int edge, face;{ int other = leftface[edge]; return face == other? rightface[edge] : other;}/* makecubetable: create the 256 entry table for cubical polygonization */static void makecubetable (){ int i, e, c, done[12], pos[8]; memset(cubetable, 0, sizeof(cubetable)); 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; } }}static voidfree_cubetable(){ int i; for (i=0; i<256; i++) { INTLISTS *l,*nextl; for (l=cubetable[i]; l; l=nextl) { INTLIST *m, *nextm; for (m=l->list; m; m=nextm) { nextm = m->next; myfree(m); } nextl = l->next; myfree(l); } }}/**** Storage ****/#undef CHECK_MALLOC#ifdef CHECK_MALLOCstatic char allocwarn[10000];static char delwarn[10000];#endif/* mycalloc: return successful calloc or exit program */typedef struct mallocdata { int lineno; char* ptr; size_t size; struct mallocdata* next;} MALLOCDATA;#ifdef CHECK_MALLOCstatic MALLOCDATA *malloc_list;static void add_mallocdata(char* ptr, int lineno, size_t size){ MALLOCDATA * old = malloc_list; malloc_list = (MALLOCDATA*) malloc(sizeof(MALLOCDATA)); malloc_list->next = old; malloc_list->ptr = ptr; malloc_list->size = size; malloc_list->lineno = lineno;}static size_t del_mallocdata(char* ptr,int lineno){ MALLOCDATA *i, *ilast = 0; int size; for (i=malloc_list; i; ilast=i,i=i->next) { if (i->ptr == ptr) { if (ilast) { MALLOCDATA * tmp = i->next; ilast->next = i->next; } else { malloc_list = i->next; } size = i->size; free(i); return size; } } if (!delwarn[lineno]) { fprintf(stderr,"tried to delete unknown data at line %d\n",lineno); delwarn[lineno] = 1; } return 0;}#endifstatic void clean_malloc(){#ifdef CHECK_MALLOC MALLOCDATA*i; int count=0; for (i=malloc_list; i; i=i->next) { if (!allocwarn[i->lineno]) { fprintf(stderr,"have memory allocated from line %d\n",i->lineno); allocwarn[i->lineno] = 1; } count++; } fprintf(stderr,"%d allocated pieces of memory remain\n",count);#endif}static char *_mycalloc (nitems, nbytes, line)int nitems, nbytes, line;{ char *ptr = calloc(nitems, nbytes);#ifdef CHECK_MALLOC add_mallocdata(ptr,line,nitems*nbytes);#endif if (ptr != NULL) return ptr; fprintf(stderr, "can't calloc %d bytes\n", nitems*nbytes); abort(); return 0;}static void _myfree(ptr, lineno) void* ptr; int lineno;{#ifdef CHECK_MALLOC size_t size = del_mallocdata(ptr,lineno); char*tmp = ptr; for (int i=0; i<size; i++) { *tmp++ = 0x00; }#endif free(ptr);}/* setcenter: set (i,j,k) entry of table[] * return 1 if already set; otherwise, set and return 0 */static int setcenter(table, i, j, k)CENTERLIST *table[];int i, j, k;{ int index = HASH(i, j, k); CENTERLIST *new, *l, *q = table[index]; for (l = q; l != NULL; l = l->next) if (l->i == i && l->j == j && l->k == k) return 1; new = (CENTERLIST *) mycalloc(1, sizeof(CENTERLIST)); new->i = i; new->j = j; new->k = k; new->next = q; table[index] = new; return 0;}/* setedge: set vertex id for edge */static void setedge (table, i1, j1, k1, i2, j2, k2, vid)EDGELIST *table[];int i1, j1, k1, i2, j2, k2, vid;{ unsigned int index; EDGELIST *new; 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); new = (EDGELIST *) mycalloc(1, sizeof(EDGELIST)); new->i1 = i1; new->j1 = j1; new->k1 = k1; new->i2 = i2; new->j2 = j2; new->k2 = k2; new->vid = vid; new->next = table[index]; table[index] = new;}/* getedge: return vertex id for edge; return -1 if not set */static int getedge (table, i1, j1, k1, i2, j2, k2)EDGELIST *table[];int i1, j1, k1, i2, j2, 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 */static int vertid (c1, c2, p)CORNER *c1, *c2;PROCESS *p;{ VERTEX v; POINT 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; converge(&a, &b, c1->value, p->function, &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 */static void addtovertices (vertices, v)VERTICES *vertices;VERTEX v;{ if (vertices->count == vertices->max) { int i; VERTEX *new; vertices->max = vertices->count == 0 ? 10 : 2*vertices->count; new = (VERTEX *) mycalloc(vertices->max, sizeof(VERTEX)); for (i = 0; i < vertices->count; i++) new[i] = vertices->ptr[i]; if (vertices->ptr != NULL) myfree(vertices->ptr); vertices->ptr = new; } vertices->ptr[vertices->count++] = v;}/* vnormal: compute unit length surface normal at point */static void vnormal (point, p, v)POINT *point, *v;PROCESS *p;{ double f = p->function(point->x, point->y, point->z); v->x = p->function(point->x+p->delta, point->y, point->z)-f; v->y = p->function(point->x, point->y+p->delta, point->z)-f; v->z = p->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 */static void converge (p1, p2, v, function, p)double v;double (*function)();POINT *p1, *p2, *p;{ int i = 0; POINT 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;} }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -