IMPLICIT.C

Go to the documentation of this file.
00001 /* --
00002 OpenFX version 2.0 - Modelling, Animation and Rendering Package
00003 Copyright (C) 2000 -  OpenFX Development Team
00004 -- */
00005 
00006 /*  IMPLICIT.C  */
00007 
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <math.h>
00011 #include <windows.h>
00012 #include <sys/types.h>
00013 
00014 #include "struct.h"
00015 #include "dstruct.h"
00016 
00017 #include "reverse.h"
00018 
00019 #define DESELECTED 0
00020 #define SELECTED   1
00021 #define UNIT       32768.0
00022 
00023 
00024 static HWND      hParent;
00025 static HINSTANCE hThisInstance;
00026 
00027 
00028 #if __WATCOMC__
00029 int APIENTRY LibMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
00030 #else
00031 BOOL WINAPI DllMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
00032 #endif
00033   switch (dwReason) {
00034     case DLL_PROCESS_ATTACH: {
00035       hThisInstance=hDLL;
00036       if(hDLL == NULL)MessageBox ( GetFocus()," NULL instance",NULL, MB_OK);
00037       break;
00038     }
00039     case DLL_PROCESS_DETACH:
00040       break;
00041   }
00042   return TRUE;
00043 }
00044 
00045 #if __SC__
00046 #pragma startaddress(DllMain)
00047 #endif
00048 
00049 void ImplicitPolygon(void);
00050 
00051 BOOL _Xmodeler
00052  (HWND parent_window,HWND info_window,X__STRUCTURE *lpevi){
00053  char text_string[255],name_string[255];
00054  lpEVI=lpevi;
00055  hParent=parent_window;
00056  LoadString(hThisInstance,IDX_STRING2,text_string,256);
00057  LoadString(hThisInstance,IDX_STRING1,name_string,256);
00058  if(MessageBox(hParent,text_string,name_string,MB_OKCANCEL)
00059                == IDCANCEL)return FALSE;
00060  else{
00061    HCURSOR hSave;
00062    hSave=SetCursor(LoadCursor(NULL,IDC_WAIT));
00063    ImplicitPolygon();
00064    SetCursor(hSave);
00065  }
00066  return TRUE;
00067 }
00068 
00070 
00071 #define TET   0  /* use tetrahedral decomposition */
00072 #define NOTET   1  /* no tetrahedral decomposition  */
00073 
00074 #define RES   10 /* # converge iterations    */
00075 
00076 #define L   0    /* left direction:   -x, -i */
00077 #define R   1    /* right direction:  +x, +i */
00078 #define B   2    /* bottom direction: -y, -j */
00079 #define T   3    /* top direction:   +y, +j  */
00080 #define N   4    /* near direction:   -z, -k */
00081 #define F   5    /* far direction:   +z, +k  */
00082 #define LBN   0  /* left bottom near corner  */
00083 #define LBF   1  /* left bottom far corner   */
00084 #define LTN   2  /* left top near corner     */
00085 #define LTF   3  /* left top far corner      */
00086 #define RBN   4  /* right bottom near corner */
00087 #define RBF   5  /* right bottom far corner  */
00088 #define RTN   6  /* right top near corner    */
00089 #define RTF   7  /* right top far corner     */
00090 
00091 /* the LBN corner of cube (i, j, k), corresponds with location
00092  * (start.x+(i-.5)*size, start.y+(j-.5)*size, start.z+(k-.5)*size) */
00093 
00094 #define RAND()       ((rand()&32767)/32767.)    /* random number between 0 and 1 */
00095 #define HASHBIT       (5)
00096 #define HASHSIZE    (size_t)(1<<(3*HASHBIT))   /* hash table size (32768) */
00097 #define MASK       ((1<<HASHBIT)-1)
00098 #define HASH(i,j,k) ((((((i)&MASK)<<HASHBIT)|((j)&MASK))<<HASHBIT)|((k)&MASK))
00099 #define BIT(i, bit) (((i)>>(bit))&1)
00100 #define FLIP(i,bit) ((i)^1<<(bit)) /* flip the given bit of i */
00101 
00102 typedef struct ipt {         /* a three-dimensional point */
00103     double x, y, z;          /* its coordinates */
00104 } IPOINT;
00105 
00106 typedef struct test {         /* test the function for a signed value */
00107     IPOINT p;                 /* location of test */
00108     double value;             /* function value at p */
00109     int ok;                   /* if value is of correct sign */
00110 } TEST;
00111 
00112 typedef struct pvert {            /* surface vertex */
00113     IPOINT position, normal;      /* position and surface normal */
00114 } IVERTEX;
00115 
00116 typedef struct pverts {      /* list of vertices in polygonization */
00117     int count, max;          /* # vertices, max # allowed */
00118     IVERTEX *ptr;            /* dynamically allocated */
00119 } IVERTICES;
00120 
00121 typedef struct corner {         /* corner of a cube */
00122     int i, j, k;                /* (i, j, k) is index within lattice */
00123     double x, y, z, value;      /* location and function value */
00124 } CORNER;
00125 
00126 typedef struct cube {         /* partitioning cell (cube) */
00127     int i, j, k;              /* lattice location of cube */
00128     CORNER *corners[8];       /* eight corners */
00129 } CUBE;
00130 
00131 typedef struct cubes {         /* linked list of cubes acting as stack */
00132     CUBE cube;                 /* a single cube */
00133     struct cubes *next;        /* remaining elements */
00134 } CUBES;
00135 
00136 typedef struct centerlist {      /* list of cube locations */
00137     int i, j, k;                 /* cube location */
00138     struct centerlist *next;     /* remaining elements */
00139 } CENTERLIST;
00140 
00141 typedef struct cornerlist {      /* list of corners */
00142     int i, j, k;                 /* corner id */
00143     double value;                /* corner value */
00144     struct cornerlist *next;     /* remaining elements */
00145 } CORNERLIST;
00146 
00147 typedef struct edgelist {            /* list of edges */
00148     int i1, j1, k1, i2, j2, k2;      /* edge corner ids */
00149     int vid;                         /* vertex id */
00150     struct edgelist *next;           /* remaining elements */
00151 } EDGELIST;
00152 
00153 typedef struct intlist {       /* list of integers */
00154     int i;                     /* an integer */
00155     struct intlist *next;      /* remaining elements */
00156 } INTLIST;
00157 
00158 typedef struct intlists {      /* list of list of integers */
00159     INTLIST *list;             /* a list of integers */
00160     struct intlists *next;     /* remaining elements */
00161 } INTLISTS;
00162 
00163 typedef struct process {      /* parameters, function, storage */
00164     double (*function)();     /* implicit surface function */
00165     int (*triproc)();         /* triangle output function */
00166     double size, delta;       /* cube size, normal delta */
00167     int bounds;               /* cube range within lattice */
00168     IPOINT start;             /* start point on surface */
00169     CUBES *cubes;             /* active cubes */
00170     IVERTICES vertices;       /* surface vertices */
00171     CENTERLIST **centers;     /* cube center hash table */
00172     CORNERLIST **corners;     /* corner value hash table */
00173     EDGELIST **edges;         /* edge and vertex id hash table */
00174 } PROCESS;
00175 
00176 typedef struct _threeints {
00177  long i1,i2,i3;
00178 } THREEINTS;
00179 
00180 void *calloc();
00181 char *mycalloc();
00182 
00183 
00184 /**** A Test Program ****/
00185 
00186 
00187 /* torus: a torus with major, minor radii = 0.5, 0.1, try size = .05 */
00188 
00189 double torus (x, y, z)
00190 double x, y, z;
00191 {
00192     double x2 = x*x, y2 = y*y, z2 = z*z;
00193     double a = x2+y2+z2+(0.5*0.5)-(0.1*0.1);
00194     return a*a-4.0*(0.5*0.5)*(y2+z2);
00195 }
00196 
00197 
00198 /* sphere: an inverse square function (always positive) */
00199 
00200 double sphere (x, y, z)
00201 double x, y, z;
00202 {
00203     double rsq = x*x+y*y+z*z;
00204     return 1.0/(rsq < 0.00001? 0.00001 : rsq);
00205 }
00206 
00207 
00208 /* blob: a three-pole blend function, try size = .1 */
00209 
00210 double blob (x, y, z)
00211 double x, y, z;
00212 {
00213     return 4.0-sphere(x+1.0,y,z)-sphere(x,y+1.0,z)-sphere(x,y,z+1.0);
00214 }
00215 
00216 double sphere1(double x, double y, double z){
00217   return (x*x+y*y+z*z)-1.0;
00218 }
00219 
00220 
00221 int gntris;           /* global needed by application */
00222 IVERTICES gvertices;  /* global needed by application */
00223 THREEINTS *listf;
00224 
00225 /* triangle: called by polygonize() for each triangle; write to stdout */
00226 
00227 triangle (i1, i2, i3, vertices)
00228 int i1, i2, i3;
00229 IVERTICES vertices;
00230 {
00231     gvertices=vertices;
00232     gntris++;
00233     if(listf == NULL){
00234       if((listf=(THREEINTS *)malloc(sizeof(THREEINTS))) != NULL){
00235         listf[0].i1=i1;
00236         listf[0].i2=i2;
00237         listf[0].i3=i3;
00238       }
00239     }
00240     else{
00241       if((listf=(THREEINTS *)realloc(listf,sizeof(THREEINTS)*gntris)) != NULL){
00242         listf[gntris-1].i1=i1;
00243         listf[gntris-1].i2=i2;
00244         listf[gntris-1].i3=i3;
00245       }
00246     }
00247     return 1;
00248 }
00249 
00251 
00252 void InsertInVertexList(long base, long Vj, long Vi){
00253  vertex *vj,*vi;
00254  long *list,i,j;
00255  vj=(MainVp+base+Vj);
00256  vi=(MainVp+base+Vi);
00257  list = (long *)vi->sp;
00258  if(vi->id > 0)for(i=0;i<vi->id;i++)if(list[i] == Vj)return;
00259  list = (long *)vj->sp;
00260  if(vj->id > 0)for(j=0;j<vj->id;j++)if(list[j] == Vi)return;
00261  if(vi->id == 0){
00262    if((list = (long *)X__Malloc((vi->id + 1)*sizeof(long))) == NULL){
00263      return;
00264    }
00265    vi->sp=(struct SKELETON *)list;
00266  }
00267  else{
00268    list = (long *)vi->sp;
00269    if((list = (long *)X__Realloc(list,(vi->id + 1)*sizeof(long))) == NULL){
00270      return;
00271    }
00272    vi->sp=(struct SKELETON *)list;
00273  }
00274  list[vi->id] = base+Vj;
00275  (vi->id)++;
00276 }
00277 
00278 void BuildEdges(long base){
00279  long n,j,i,*list;
00280  vertex *vp;
00281  vp=(MainVp+base);
00282  for(j=base;j<Nvert;j++){
00283    if(vp->id != 0 && vp->sp != NULL){
00284      if(!UpdateEdgeHeap(Nedge+vp->id))return;
00285      list = (long *)vp->sp;
00286      for(i=0;i<vp->id;i++)CreateEdge(j,list[i]);
00287      X__Free(vp->sp); vp->sp=NULL; vp->id=0;
00288    }
00289    vp++;
00290  }
00291 }
00292 
00293 void ImplicitPolygon(void){
00294     int i,id1,id2,id3;
00295     char *err, *polygonize();
00296     vertex *Vp;
00297     gntris = 0;
00298     gvertices.ptr=NULL;
00299     listf=NULL;
00300 //    if ((err = polygonize(torus, .05, 20, 0.,0.,0., triangle, TET)) != NULL) {
00301     if ((err = polygonize(torus, .1, 10, 0.,0.,0., triangle, NOTET)) != NULL) {
00302 //    if ((err = polygonize(blob, .05, 20, 0.,0.,0., triangle, NOTET)) != NULL) {
00303 //    if ((err = polygonize(blob, .1, 10, 0.,0.,0., triangle, NOTET)) != NULL) {
00304 
00305 //    if ((err = polygonize(blob, .2, 5, 0.,0.,0., triangle, NOTET)) != NULL) {
00306 //    if ((err = polygonize(sphere1, .2, 8, 0.,0.,0., triangle, NOTET)) != NULL) {
00307       goto FREEPOINT;
00308     }
00309     if(gvertices.ptr != NULL && listf != NULL){
00310       if(UpdateVertexHeap(Nvert+gvertices.count)){
00311         long BaseVert=Nvert;
00312         for(i = 0;i<gvertices.count;i++) {
00313           IVERTEX v;
00314           v = gvertices.ptr[i];
00315           CreateVertex();
00316           Vp=(MainVp+Nvert-1);
00317           Vp->id=0;
00318           Vp->xyz[0]=(long)(v.position.x * UNIT);
00319           Vp->xyz[1]=(long)(v.position.y * UNIT);
00320           Vp->xyz[2]=(long)(v.position.z * UNIT);
00321         }
00322         if(UpdateFaceHeap(Nface+gntris)){
00323           for(i=0;i<gntris;i++){
00324             id1=listf[i].i1; id2=listf[i].i2; id3=listf[i].i3;
00325             CreateFace(BaseVert+id1,
00326                        BaseVert+id2,
00327                        BaseVert+id3);
00328 //            (MainFp+Nface-1)->attrib |= 0x80; // smooth
00329 //            (MainFp+Nface-1)->attrib |= 0x20; // gloss
00330             InsertInVertexList(BaseVert,id1,id2);
00331             InsertInVertexList(BaseVert,id2,id3);
00332             InsertInVertexList(BaseVert,id3,id1);
00333           }
00334           BuildEdges(BaseVert);
00335         }
00336       }
00337     }
00338     FREEPOINT:
00339     if(listf != NULL)free(listf);
00340     if(gvertices.ptr != NULL)free(gvertices.ptr);
00341 MessageBox(NULL,"DONE","Debug",MB_OK);
00342     return;
00343 }
00344 
00345 
00346 /**** An Implicit Surface Polygonizer ****/
00347 static void testface (int i, int j, int k, CUBE *old, int ipface, int c1,
00348                int c2, int c3, int c4, PROCESS *p);
00349 static void converge (IPOINT *p1, IPOINT *p2,  double v,
00350                       double (*function)(), IPOINT *p);
00351 void makecubetable(void);
00352 void freecubetable(void);
00353 
00354 /* polygonize: polygonize the implicit surface function
00355  *   arguments are:
00356  *    double function (x, y, z)
00357  *       double x, y, z (an arbitrary 3D point)
00358  *        the implicit surface function
00359  *        return negative for inside, positive for outside
00360  *    double size
00361  *        width of the partitioning cube
00362  *    int bounds
00363  *        max. range of cubes (+/- on the three axes) from first cube
00364  *    double x, y, z
00365  *        coordinates of a starting point on or near the surface
00366  *        may be defaulted to 0., 0., 0.
00367  *    int triproc (i1, i2, i3, vertices)
00368  *       int i1, i2, i3 (indices into the vertex array)
00369  *       IVERTICES vertices (the vertex array, indexed from 0)
00370  *        called for each triangle
00371  *        the triangle coordinates are (for i = i1, i2, i3):
00372  *       vertices.ptr[i].position.x, .y, and .z
00373  *        vertices are ccw when viewed from the out (positive) side
00374  *       in a left-handed coordinate system
00375  *        vertex normals point outwards
00376  *        return 1 to continue, 0 to abort
00377  *    int mode
00378  *        TET: decompose cube and polygonize six tetrahedra
00379  *        NOTET: polygonize cube directly
00380  *   returns error or NULL
00381  */
00382 
00383 char *polygonize (function, size, bounds, x, y, z, triproc, mode)
00384 double (*function)(), size, x, y, z;
00385 int bounds, (*triproc)(), mode;
00386 {
00387     PROCESS p;
00388     int n, noabort;
00389     CORNER *setcorner();
00390     TEST in, out, find();
00391 
00392     p.function = function;
00393     p.triproc = triproc;
00394     p.size = size;
00395     p.bounds = bounds;
00396     p.delta = size/(double)(RES*RES);
00397 
00398     /* allocate hash tables and build cube polygon table: */
00399 
00400     p.centers = (CENTERLIST **) mycalloc(HASHSIZE,sizeof(CENTERLIST *));
00401     p.corners = (CORNERLIST **) mycalloc(HASHSIZE,sizeof(CORNERLIST *));
00402     p.edges   = (EDGELIST **) mycalloc(2*HASHSIZE,sizeof(EDGELIST *));
00403     memset(p.centers,0,HASHSIZE*sizeof(CENTERLIST *));
00404     memset(p.corners,0,HASHSIZE*sizeof(CORNERLIST *));
00405     memset(p.edges,0,2*HASHSIZE*sizeof(EDGELIST *));
00406 
00407     makecubetable();
00408 
00409     /* find point on surface, beginning search at (x, y, z): */
00410     srand(1);
00411     in = find(1, &p, x, y, z);
00412     out = find(0, &p, x, y, z);
00413     if (!in.ok || !out.ok) return "can't find starting point";
00414     converge(&in.p, &out.p, in.value, p.function, &p.start);
00415 
00416     /* push initial cube on stack: */
00417     p.cubes = (CUBES *) mycalloc(1, sizeof(CUBES)); /* list of 1 */
00418     p.cubes->cube.i = p.cubes->cube.j = p.cubes->cube.k = 0;
00419     p.cubes->next = NULL;
00420 
00421     /* set corners of initial cube: */
00422     for (n = 0; n < 8; n++)
00423       p.cubes->cube.corners[n] = setcorner(&p, BIT(n,2), BIT(n,1), BIT(n,0));
00424 
00425     p.vertices.count = p.vertices.max = 0; /* no vertices yet */
00426     p.vertices.ptr = NULL;
00427 
00428     setcenter(p.centers, 0, 0, 0);
00429 
00430     while (p.cubes != NULL) { /* process active cubes till none left */
00431       CUBE c;
00432       CUBES *temp = p.cubes;
00433       c = p.cubes->cube;
00434 
00435       noabort = mode == TET?
00436           /* either decompose into tetrahedra and polygonize: */
00437           dotet(&c, LBN, LTN, RBN, LBF, &p) &&
00438           dotet(&c, RTN, LTN, LBF, RBN, &p) &&
00439           dotet(&c, RTN, LTN, LTF, LBF, &p) &&
00440           dotet(&c, RTN, RBN, LBF, RBF, &p) &&
00441           dotet(&c, RTN, LBF, LTF, RBF, &p) &&
00442           dotet(&c, RTN, LTF, RTF, RBF, &p)
00443           :
00444           /* or polygonize the cube directly: */
00445           docube(&c, &p);
00446       if (! noabort) return "aborted";
00447 
00448       /* pop current cube from stack */
00449       p.cubes = p.cubes->next;
00450       /* test six face directions, maybe add to stack: */
00451       testface(c.i-1, c.j, c.k, &c, L, LBN, LBF, LTN, LTF, &p);
00452       testface(c.i+1, c.j, c.k, &c, R, RBN, RBF, RTN, RTF, &p);
00453       testface(c.i, c.j-1, c.k, &c, B, LBN, LBF, RBN, RBF, &p);
00454       testface(c.i, c.j+1, c.k, &c, T, LTN, LTF, RTN, RTF, &p);
00455       testface(c.i, c.j, c.k-1, &c, N, LBN, LTN, RBN, RTN, &p);
00456       testface(c.i, c.j, c.k+1, &c, F, LBF, LTF, RBF, RTF, &p);
00457       // free up cube
00458       for(n=0;n<8;n++){
00459         if(temp->cube.corners[n] != NULL)free(temp->cube.corners[n]);
00460       }
00461       free((char *) temp);
00462     }
00463     {
00464      CUBES *pc,*temppc;
00465      if((pc=p.cubes) != NULL){
00466        while(pc != NULL){
00467          temppc=pc;
00468          pc=pc->next;
00469          for(n=0;n<8;n++){
00470            if(temppc->cube.corners[n] != NULL)free(temppc->cube.corners[n]);
00471          }
00472          free((char *)temppc);
00473        }
00474      }
00475     }
00476     if(p.centers != NULL){
00477       for(n=0;n<HASHSIZE;n++){
00478         CENTERLIST *xx,*tempxx;
00479         if((xx=p.centers[n]) != NULL){
00480           while(xx != NULL){
00481             tempxx=xx;
00482             xx=xx->next;
00483             free(tempxx);
00484           }
00485         }
00486       }
00487       free(p.centers);
00488     }
00489     if(p.corners != NULL){
00490       for(n=0;n<HASHSIZE;n++){
00491         CORNERLIST *xx,*tempxx;
00492         if((xx=p.corners[n]) != NULL){
00493           while(xx != NULL){
00494             tempxx=xx;
00495             xx=xx->next;
00496             free(tempxx);
00497           }
00498         }
00499       }
00500       free(p.corners);
00501     }
00502     if(p.edges != NULL){
00503       for(n=0;n<2*HASHSIZE;n++){
00504         EDGELIST *xx,*tempxx;
00505         if((xx=p.edges[n]) != NULL){
00506           while(xx != NULL){
00507             tempxx=xx;
00508             xx=xx->next;
00509             free(tempxx);
00510           }
00511         }
00512       }
00513       free(p.edges);
00514     }
00515     freecubetable();
00516     return NULL;
00517 }
00518 
00519 
00520 /* testface: given cube at lattice (i, j, k), and four corners of face,
00521  * if surface crosses face, compute other four corners of adjacent cube
00522  * and add new cube to cube stack */
00523 
00524 static void testface (int i, int j, int k, CUBE *old, int ipface, int c1,
00525                int c2, int c3, int c4, PROCESS *p){
00526     CUBE new;
00527     CUBES *oldcubes = p->cubes;
00528     CORNER *setcorner();
00529     static int ipfacebit[6] = {2, 2, 1, 1, 0, 0};
00530     int n, pos = old->corners[c1]->value > 0.0 ? 1 : 0, bit = ipfacebit[ipface];
00531 
00532     /* test if no surface crossing, cube out of bounds, or already visited: */
00533     if ((old->corners[c2]->value > 0) == pos &&
00534    (old->corners[c3]->value > 0) == pos &&
00535    (old->corners[c4]->value > 0) == pos) return;
00536     if (abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;
00537     if (setcenter(p->centers, i, j, k)) return;
00538 
00539     /* create new cube: */
00540     new.i = i;
00541     new.j = j;
00542     new.k = k;
00543     for (n = 0; n < 8; n++) new.corners[n] = NULL;
00544 //    new.corners[FLIP(c1, bit)] = old->corners[c1];
00545 //    new.corners[FLIP(c2, bit)] = old->corners[c2];
00546 //    new.corners[FLIP(c3, bit)] = old->corners[c3];
00547 //    new.corners[FLIP(c4, bit)] = old->corners[c4];
00548     new.corners[FLIP(c1, bit)] = (CORNER *) mycalloc(1, sizeof(CORNER));
00549     memcpy(new.corners[FLIP(c1,bit)],old->corners[c1],sizeof(CORNER));
00550     new.corners[FLIP(c2, bit)] = (CORNER *) mycalloc(1, sizeof(CORNER));
00551     memcpy(new.corners[FLIP(c2,bit)],old->corners[c2],sizeof(CORNER));
00552     new.corners[FLIP(c3, bit)] = (CORNER *) mycalloc(1, sizeof(CORNER));
00553     memcpy(new.corners[FLIP(c3,bit)],old->corners[c3],sizeof(CORNER));
00554     new.corners[FLIP(c4, bit)] = (CORNER *) mycalloc(1, sizeof(CORNER));
00555     memcpy(new.corners[FLIP(c4,bit)],old->corners[c4],sizeof(CORNER));
00556 
00557     for (n = 0; n < 8; n++)
00558       if (new.corners[n] == NULL)
00559         new.corners[n] = setcorner(p, i+BIT(n,2), j+BIT(n,1), k+BIT(n,0));
00560 
00561     /*add cube to top of stack: */
00562     p->cubes = (CUBES *) mycalloc(1, sizeof(CUBES));
00563     p->cubes->cube = new;
00564     p->cubes->next = oldcubes;
00565 }
00566 
00567 
00568 /* setcorner: return corner with the given lattice location
00569    set (and cache) its function value */
00570 
00571 CORNER *setcorner (p, i, j, k)
00572 int i, j, k;
00573 PROCESS *p;
00574 {
00575     /* for speed, do corner value caching here */
00576     CORNER *c = (CORNER *) mycalloc(1, sizeof(CORNER));
00577     int index = HASH(i, j, k);
00578     CORNERLIST *l = p->corners[index];
00579     c->i = i; c->x = p->start.x+((double)i-.5)*p->size;
00580     c->j = j; c->y = p->start.y+((double)j-.5)*p->size;
00581     c->k = k; c->z = p->start.z+((double)k-.5)*p->size;
00582     for (; l != NULL; l = l->next)
00583    if (l->i == i && l->j == j && l->k == k) {
00584        c->value = l->value;
00585        return c;
00586        }
00587     l = (CORNERLIST *) mycalloc(1, sizeof(CORNERLIST));
00588     l->i = i; l->j = j; l->k = k;
00589     l->value = c->value = p->function(c->x, c->y, c->z);
00590     l->next = p->corners[index];
00591     p->corners[index] = l;
00592     return c;
00593 }
00594 
00595 /* find: search for point with value of given sign (0: neg, 1: pos) */
00596 
00597 TEST find (sign, p, x, y, z)
00598 int sign;
00599 PROCESS *p;
00600 double x, y, z;
00601 {
00602     int i;
00603     TEST test;
00604     double range = p->size;
00605     test.ok = 1;
00606     for (i = 0; i < 10000; i++) {
00607    test.p.x = x+range*(RAND()-0.5);
00608    test.p.y = y+range*(RAND()-0.5);
00609    test.p.z = z+range*(RAND()-0.5);
00610    test.value = p->function(test.p.x, test.p.y, test.p.z);
00611    if (sign == (test.value > 0.0)) return test;
00612    range = range*1.0005; /* slowly expand search outwards */
00613     }
00614     test.ok = 0;
00615     return test;
00616 }
00617 
00618 
00619 /**** Tetrahedral Polygonization ****/
00620 
00621 
00622 /* dotet: triangulate the tetrahedron
00623  * b, c, d should appear clockwise when viewed from a
00624  * return 0 if client aborts, 1 otherwise */
00625 
00626 int dotet (cube, c1, c2, c3, c4, p)
00627 CUBE *cube;
00628 int c1, c2, c3, c4;
00629 PROCESS *p;
00630 {
00631     CORNER *a = cube->corners[c1];
00632     CORNER *b = cube->corners[c2];
00633     CORNER *c = cube->corners[c3];
00634     CORNER *d = cube->corners[c4];
00635     int index = 0, apos, bpos, cpos, dpos, e1, e2, e3, e4, e5, e6;
00636     if (apos = (a->value > 0.0)) index += 8;
00637     if (bpos = (b->value > 0.0)) index += 4;
00638     if (cpos = (c->value > 0.0)) index += 2;
00639     if (dpos = (d->value > 0.0)) index += 1;
00640     /* index is now 4-bit number representing one of the 16 possible cases */
00641     if (apos != bpos) e1 = vertid(a, b, p);
00642     if (apos != cpos) e2 = vertid(a, c, p);
00643     if (apos != dpos) e3 = vertid(a, d, p);
00644     if (bpos != cpos) e4 = vertid(b, c, p);
00645     if (bpos != dpos) e5 = vertid(b, d, p);
00646     if (cpos != dpos) e6 = vertid(c, d, p);
00647     /* 14 productive tetrahedral cases (0000 and 1111 do not yield polygons */
00648     switch (index) {
00649        case 1:    return p->triproc(e5, e6, e3, p->vertices);
00650        case 2:    return p->triproc(e2, e6, e4, p->vertices);
00651        case 3:    return p->triproc(e3, e5, e4, p->vertices) &&
00652                          p->triproc(e3, e4, e2, p->vertices);
00653        case 4:    return p->triproc(e1, e4, e5, p->vertices);
00654        case 5:    return p->triproc(e3, e1, e4, p->vertices) &&
00655                          p->triproc(e3, e4, e6, p->vertices);
00656        case 6:    return p->triproc(e1, e2, e6, p->vertices) &&
00657                          p->triproc(e1, e6, e5, p->vertices);
00658        case 7:    return p->triproc(e1, e2, e3, p->vertices);
00659        case 8:    return p->triproc(e1, e3, e2, p->vertices);
00660        case 9:    return p->triproc(e1, e5, e6, p->vertices) &&
00661                          p->triproc(e1, e6, e2, p->vertices);
00662        case 10: return p->triproc(e1, e3, e6, p->vertices) &&
00663                          p->triproc(e1, e6, e4, p->vertices);
00664        case 11: return p->triproc(e1, e5, e4, p->vertices);
00665        case 12: return p->triproc(e3, e2, e4, p->vertices) &&
00666                          p->triproc(e3, e4, e5, p->vertices);
00667        case 13: return p->triproc(e6, e2, e4, p->vertices);
00668        case 14: return p->triproc(e5, e3, e6, p->vertices);
00669     }
00670     return 1;
00671 }
00672 
00673 /**** Cubical Polygonization (optional) ****/
00674 
00675 #define LB   0  /* left bottom edge   */
00676 #define LT   1  /* left top edge   */
00677 #define LN   2  /* left near edge   */
00678 #define LF   3  /* left far edge   */
00679 #define RB   4  /* right bottom edge */
00680 #define RT   5  /* right top edge   */
00681 #define RN   6  /* right near edge   */
00682 #define RF   7  /* right far edge   */
00683 #define BN   8  /* bottom near edge   */
00684 #define BF   9  /* bottom far edge   */
00685 #define TN   10 /* top near edge   */
00686 #define TF   11 /* top far edge   */
00687 
00688 static INTLISTS *cubetable[256];
00689 
00690 /*         edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
00691 static int corner1[12]      = {LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF};
00692 static int corner2[12]      = {LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF};
00693 static int leftface[12]     = {B,  L,  L,  F,  R,  T,  N,  R,  N,  B,  T,  F};
00694               /* face on left when going corner1 to corner2 */
00695 static int rightface[12]    = {L,  T,  N,  L,  B,  R,  R,  F,  B,  F,  N,  T};
00696               /* face on right when going corner1 to corner2 */
00697 
00698 
00699 /* docube: triangulate the cube directly, without decomposition */
00700 
00701 int docube (cube, p)
00702 CUBE *cube;
00703 PROCESS *p;
00704 {
00705    INTLISTS *polys;
00706    int i, index = 0;
00707    for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0) index += (1<<i);
00708    for (polys = cubetable[index]; polys; polys = polys->next) {
00709      INTLIST *edges;
00710      int a = -1, b = -1, count = 0;
00711      for (edges = polys->list; edges; edges = edges->next) {
00712        CORNER *c1 = cube->corners[corner1[edges->i]];
00713        CORNER *c2 = cube->corners[corner2[edges->i]];
00714        int c = vertid(c1, c2, p);
00715        if (++count > 2 && ! p->triproc(a, b, c, p->vertices)) return 0;
00716        if (count < 3) a = b;
00717        b = c;
00718      }
00719    }
00720    return 1;
00721 }
00722 
00723 
00724 /* nextcwedge: return next clockwise edge from given edge around given face */
00725 
00726 int nextcwedge (ipedge, ipface)
00727 int ipedge, ipface;
00728 {
00729     switch (ipedge) {
00730    case LB: return (ipface == L)? LF : BN;
00731    case LT: return (ipface == L)? LN : TF;
00732    case LN: return (ipface == L)? LB : TN;
00733    case LF: return (ipface == L)? LT : BF;
00734    case RB: return (ipface == R)? RN : BF;
00735    case RT: return (ipface == R)? RF : TN;
00736    case RN: return (ipface == R)? RT : BN;
00737    case RF: return (ipface == R)? RB : TF;
00738    case BN: return (ipface == B)? RB : LN;
00739    case BF: return (ipface == B)? LB : RF;
00740    case TN: return (ipface == T)? LT : RN;
00741    case TF: return (ipface == T)? RT : LF;
00742     }
00743 }
00744 
00745 
00746 /* otherface: return face adjoining edge that is not the given face */
00747 
00748 int otherface (ipedge, ipface)
00749 int ipedge, ipface;
00750 {
00751     int other = leftface[ipedge];
00752     return ipface == other? rightface[ipedge] : other;
00753 }
00754 
00755 
00756 /* makecubetable: create the 256 entry table for cubical polygonization */
00757 
00758 void makecubetable (void){
00759  int i, e, c, done[12], pos[8];
00760  for (i = 0; i < 256; i++) {
00761    cubetable[i]=NULL;
00762    for (e = 0; e < 12; e++) done[e] = 0;
00763    for (c = 0; c < 8; c++) pos[c] = BIT(i, c);
00764    for (e = 0; e < 12; e++)
00765    if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
00766      INTLIST *ints = 0;
00767      INTLISTS *lists = (INTLISTS *) mycalloc(1, sizeof(INTLISTS));
00768      int start = e, ipedge = e;
00769      /* get face that is to right of edge from pos to neg corner: */
00770      int ipface = pos[corner1[e]]? rightface[e] : leftface[e];
00771      while (1) {
00772        ipedge = nextcwedge(ipedge, ipface);
00773        done[ipedge] = 1;
00774        if (pos[corner1[ipedge]] != pos[corner2[ipedge]]) {
00775          INTLIST *tmp = ints;
00776          ints = (INTLIST *) mycalloc(1, sizeof(INTLIST));
00777          ints->i = ipedge;
00778          ints->next = tmp; /* add edge to head of list */
00779          if (ipedge == start) break;
00780          ipface = otherface(ipedge, ipface);
00781        }
00782      }
00783      lists->list = ints; /* add ints to head of table entry */
00784      lists->next = cubetable[i];
00785      cubetable[i] = lists;
00786    }
00787  }
00788 }
00789 
00790 void freecubetable(void){
00791  int i;
00792  INTLIST *il,*tempil;
00793  INTLISTS *ils,*tempils;
00794  for(i=0;i<256;i++){
00795    if((ils=cubetable[i]) != NULL){
00796      while(ils != NULL){
00797        tempils=ils;
00798        if((il=ils->list) !=NULL){
00799          while(il != NULL){
00800            tempil=il;
00801            il=il->next;
00802            free(tempil);
00803          }
00804        }
00805        ils=ils->next;
00806        free(tempils);
00807      }
00808    }
00809  }
00810 }
00811 
00812 /**** Storage ****/
00813 
00814 /* mycalloc: return successful calloc or exit program */
00815 
00816 char *mycalloc (nitems, nbytes)
00817 int nitems, nbytes;
00818 {
00819    char *ptr = calloc(nitems, nbytes);
00820    if (ptr != NULL) return ptr;
00821 MessageBox(NULL,"Memory Error",NULL,MB_OK);
00822    return NULL;
00823 }
00824 
00825 
00826 /* setcenter: set (i,j,k) entry of table[]
00827  * return 1 if already set; otherwise, set and return 0 */
00828 
00829 int setcenter(table, i, j, k)
00830 CENTERLIST *table[];
00831 int i, j, k;
00832 {
00833  int index = HASH(i, j, k);
00834  CENTERLIST *new, *l, *q = table[index];
00835  for (l = q; l != NULL; l = l->next)
00836    if (l->i == i && l->j == j && l->k == k) return 1;
00837  new = (CENTERLIST *) mycalloc(1, sizeof(CENTERLIST));
00838  new->i = i; new->j = j; new->k = k; new->next = q;
00839  table[index] = new;
00840  return 0;
00841 }
00842 
00843 
00844 /* setedge: set vertex id for edge */
00845 
00846 setedge (table, i1, j1, k1, i2, j2, k2, vid)
00847 EDGELIST *table[];
00848 int i1, j1, k1, i2, j2, k2, vid;
00849 {
00850  unsigned int index;
00851  EDGELIST *new;
00852  if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
00853    int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
00854   }
00855   index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
00856   new = (EDGELIST *) mycalloc(1, sizeof(EDGELIST));
00857   new->i1 = i1; new->j1 = j1; new->k1 = k1;
00858   new->i2 = i2; new->j2 = j2; new->k2 = k2;
00859   new->vid = vid;
00860   new->next = table[index];
00861   table[index] = new;
00862 }
00863 
00864 /* getedge: return vertex id for edge; return -1 if not set */
00865 
00866 int getedge (table, i1, j1, k1, i2, j2, k2)
00867 EDGELIST *table[];
00868 int i1, j1, k1, i2, j2, k2;
00869 {
00870  EDGELIST *q;
00871  if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
00872    int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
00873  };
00874  q = table[HASH(i1, j1, k1)+HASH(i2, j2, k2)];
00875  for (; q != NULL; q = q->next)
00876    if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
00877        q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
00878       return q->vid;
00879  return -1;
00880 }
00881 
00882 
00883 /**** Vertices ****/
00884 
00885 
00886 /* vertid: return index for vertex on edge:
00887  * c1->value and c2->value are presumed of different sign
00888  * return saved index if any; else compute vertex and save */
00889 
00890 int vertid (c1, c2, p)
00891 CORNER *c1, *c2;
00892 PROCESS *p;
00893 {
00894     IVERTEX v;
00895     IPOINT a, b;
00896     int vid = getedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
00897     if (vid != -1) return vid;              /* previously computed */
00898     a.x = c1->x; a.y = c1->y; a.z = c1->z;
00899     b.x = c2->x; b.y = c2->y; b.z = c2->z;
00900     converge(&a, &b, c1->value, p->function, &v.position); /* position */
00901     vnormal(&v.position, p, &v.normal);        /* normal      */
00902     addtovertices(&p->vertices, v);            /* save vertex */
00903     vid = p->vertices.count-1;
00904     setedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
00905     return vid;
00906 }
00907 
00908 
00909 /* addtovertices: add v to sequence of vertices */
00910 
00911 addtovertices (vertices, v)
00912 IVERTICES *vertices;
00913 IVERTEX v;
00914 {
00915  if (vertices->count == vertices->max) {
00916    int i;
00917    IVERTEX *new;
00918    vertices->max = vertices->count == 0 ? 10 : 2*vertices->count;
00919    new = (IVERTEX *) mycalloc(vertices->max, sizeof(IVERTEX));
00920    for (i = 0; i < vertices->count; i++) new[i] = vertices->ptr[i];
00921    if (vertices->ptr != NULL) free((char *) vertices->ptr);
00922    vertices->ptr = new;
00923  }
00924  vertices->ptr[vertices->count++] = v;
00925 }
00926 
00927 
00928 /* vnormal: compute unit length surface normal at point */
00929 
00930 vnormal (ipt, p, v)
00931 IPOINT *ipt, *v;
00932 PROCESS *p;
00933 {
00934     double f = p->function(ipt->x, ipt->y, ipt->z);
00935     v->x = p->function(ipt->x+p->delta, ipt->y, ipt->z)-f;
00936     v->y = p->function(ipt->x, ipt->y+p->delta, ipt->z)-f;
00937     v->z = p->function(ipt->x, ipt->y, ipt->z+p->delta)-f;
00938     f = sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
00939     if (f != 0.0) {v->x /= f; v->y /= f; v->z /= f;}
00940 }
00941 
00942 
00943 /* converge: from two points of differing sign, converge to zero crossing */
00944 
00945 static void converge (IPOINT *p1, IPOINT *p2,  double v,
00946                       double (*function)(), IPOINT *p){
00947     int i = 0;
00948     IPOINT pos, neg;
00949     if (v < 0) {
00950    pos.x = p2->x; pos.y = p2->y; pos.z = p2->z;
00951    neg.x = p1->x; neg.y = p1->y; neg.z = p1->z;
00952     }
00953     else {
00954    pos.x = p1->x; pos.y = p1->y; pos.z = p1->z;
00955    neg.x = p2->x; neg.y = p2->y; neg.z = p2->z;
00956     }
00957     while (1) {
00958    p->x = 0.5*(pos.x + neg.x);
00959    p->y = 0.5*(pos.y + neg.y);
00960    p->z = 0.5*(pos.z + neg.z);
00961    if (i++ == RES) return;
00962    if ((function(p->x, p->y, p->z)) > 0.0)
00963         {pos.x = p->x; pos.y = p->y; pos.z = p->z;}
00964    else {neg.x = p->x; neg.y = p->y; neg.z = p->z;}
00965     }
00966 }

Generated on Sun Apr 27 14:20:11 2014 for OpenFX by  doxygen 1.5.6