Back to index

radiance  4R0+20100331
face.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: face.c,v 2.12 2006/03/02 16:51:54 greg Exp $";
00003 #endif
00004 /*
00005  *  face.c - routines dealing with polygonal faces.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include  "standard.h"
00011 
00012 #include  "object.h"
00013 
00014 #include  "face.h"
00015 
00016 /*
00017  *     A face is given as a list of 3D vertices.  The normal
00018  *  direction and therefore the surface orientation is determined
00019  *  by the ordering of the vertices.  Looking in the direction opposite
00020  *  the normal (at the front of the face), the vertices will be
00021  *  listed in counter-clockwise order.
00022  *     There is no checking done to insure that the edges do not cross
00023  *  one another.  This was considered too expensive and should be unnecessary.
00024  *  The last vertex is automatically connected to the first.
00025  */
00026 
00027 #ifdef  SMLFLT
00028 #define  VERTEPS     1e-3          /* allowed vertex error */
00029 #else
00030 #define  VERTEPS     1e-5          /* allowed vertex error */
00031 #endif
00032 
00033 
00034 FACE *
00035 getface(o)                  /* get arguments for a face */
00036 OBJREC  *o;
00037 {
00038        double  d1;
00039        int  smalloff, badvert;
00040        FVECT  v1, v2, v3;
00041        register FACE  *f;
00042        register int  i;
00043 
00044        if ((f = (FACE *)o->os) != NULL)
00045               return(f);                  /* already done */
00046 
00047        f = (FACE *)malloc(sizeof(FACE));
00048        if (f == NULL)
00049               error(SYSTEM, "out of memory in makeface");
00050 
00051        if (o->oargs.nfargs < 9 || o->oargs.nfargs % 3)
00052               objerror(o, USER, "bad # arguments");
00053 
00054        o->os = (char *)f;                 /* save face */
00055 
00056        f->va = o->oargs.farg;
00057        f->nv = o->oargs.nfargs / 3;
00058                                           /* check for last==first */
00059        if (dist2(VERTEX(f,0),VERTEX(f,f->nv-1)) <= FTINY*FTINY)
00060               f->nv--;
00061                                           /* compute area and normal */
00062        f->norm[0] = f->norm[1] = f->norm[2] = 0.0;
00063        v1[0] = VERTEX(f,1)[0] - VERTEX(f,0)[0];
00064        v1[1] = VERTEX(f,1)[1] - VERTEX(f,0)[1];
00065        v1[2] = VERTEX(f,1)[2] - VERTEX(f,0)[2];
00066        for (i = 2; i < f->nv; i++) {
00067               v2[0] = VERTEX(f,i)[0] - VERTEX(f,0)[0];
00068               v2[1] = VERTEX(f,i)[1] - VERTEX(f,0)[1];
00069               v2[2] = VERTEX(f,i)[2] - VERTEX(f,0)[2];
00070               fcross(v3, v1, v2);
00071               f->norm[0] += v3[0];
00072               f->norm[1] += v3[1];
00073               f->norm[2] += v3[2];
00074               VCOPY(v1, v2);
00075        }
00076        f->area = normalize(f->norm);
00077        if (f->area == 0.0) {
00078               objerror(o, WARNING, "zero area"); /* used to be fatal */
00079               f->offset = 0.0;
00080               f->ax = 0;
00081               return(f);
00082        }
00083        f->area *= 0.5;
00084                                           /* compute offset */
00085        badvert = 0;
00086        f->offset = DOT(f->norm, VERTEX(f,0));
00087        smalloff = fabs(f->offset) <= VERTEPS;
00088        for (i = 1; i < f->nv; i++) {
00089               d1 = DOT(f->norm, VERTEX(f,i));
00090               if (smalloff)
00091                      badvert += fabs(d1 - f->offset/i) > VERTEPS;
00092               else
00093                      badvert += fabs(1.0 - d1*i/f->offset) > VERTEPS;
00094               f->offset += d1;
00095        }
00096        f->offset /= (double)f->nv;
00097        if (f->nv > 3 && badvert)
00098               objerror(o, WARNING, "non-planar vertex");
00099                                           /* find axis */
00100        f->ax = fabs(f->norm[0]) > fabs(f->norm[1]) ? 0 : 1;
00101        if (fabs(f->norm[2]) > fabs(f->norm[f->ax]))
00102               f->ax = 2;
00103 
00104        return(f);
00105 }
00106 
00107 
00108 void
00109 freeface(o)                 /* free memory associated with face */
00110 OBJREC  *o;
00111 {
00112        if (o->os == NULL)
00113               return;
00114        free(o->os);
00115        o->os = NULL;
00116 }
00117 
00118 
00119 int
00120 inface(p, f)                /* determine if point is in face */
00121 FVECT  p;
00122 FACE  *f;
00123 {
00124        int  ncross, n;
00125        double  x, y;
00126        int  tst;
00127        register int  xi, yi;
00128        register RREAL  *p0, *p1;
00129 
00130        if ((xi = f->ax + 1) >= 3) xi -= 3;
00131        if ((yi = xi + 1) >= 3) yi -= 3;
00132        x = p[xi];
00133        y = p[yi];
00134        n = f->nv;
00135        p0 = f->va + 3*(n-1);              /* connect last to first */
00136        p1 = f->va;
00137        ncross = 0;
00138                                    /* positive x axis cross test */
00139        while (n--) {
00140               if ((p0[yi] > y) ^ (p1[yi] > y)) {
00141                      tst = (p0[xi] > x) + (p1[xi] > x);
00142                      if (tst == 2)
00143                             ncross++;
00144                      else if (tst)
00145                             ncross += (p1[yi] > p0[yi]) ^
00146                                           ((p0[yi]-y)*(p1[xi]-x) >
00147                                           (p0[xi]-x)*(p1[yi]-y));
00148               }
00149               p0 = p1;
00150               p1 += 3;
00151        }
00152        return(ncross & 01);
00153 }