home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
RADIANCE
/
SRC
/
COMMON
/
FACE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-07
|
3KB
|
139 lines
/* Copyright (c) 1991 Regents of the University of California */
#ifndef lint
static char SCCSid[] = "@(#)face.c 2.2 10/2/92 LBL";
#endif
/*
* face.c - routines dealing with polygonal faces.
*
* 8/30/85
*/
#include "standard.h"
#include "object.h"
#include "face.h"
/*
* A face is given as a list of 3D vertices. The normal
* direction and therefore the surface orientation is determined
* by the ordering of the vertices. Looking in the direction opposite
* the normal (at the front of the face), the vertices will be
* listed in counter-clockwise order.
* There is no checking done to insure that the edges do not cross
* one another. This was considered too expensive and should be unnecessary.
* The last vertex is automatically connected to the first.
*/
#define VERTEPS 1e-4 /* allowed vertex error */
FACE *
getface(o) /* get arguments for a face */
OBJREC *o;
{
double d1;
int badvert;
FVECT v1, v2, v3;
register FACE *f;
register int i;
if ((f = (FACE *)o->os) != NULL)
return(f); /* already done */
f = (FACE *)malloc(sizeof(FACE));
if (f == NULL)
error(SYSTEM, "out of memory in makeface");
if (o->oargs.nfargs < 9 || o->oargs.nfargs % 3)
objerror(o, USER, "bad # arguments");
o->os = (char *)f; /* save face */
f->va = o->oargs.farg;
f->nv = o->oargs.nfargs / 3;
/* compute area and normal */
f->norm[0] = f->norm[1] = f->norm[2] = 0.0;
v1[0] = v1[1] = v1[2] = 0.0;
for (i = 1; i < f->nv; i++) {
v2[0] = VERTEX(f,i)[0] - VERTEX(f,0)[0];
v2[1] = VERTEX(f,i)[1] - VERTEX(f,0)[1];
v2[2] = VERTEX(f,i)[2] - VERTEX(f,0)[2];
fcross(v3, v1, v2);
f->norm[0] += v3[0];
f->norm[1] += v3[1];
f->norm[2] += v3[2];
VCOPY(v1, v2);
}
f->area = normalize(f->norm);
if (f->area == 0.0) {
objerror(o, WARNING, "zero area"); /* used to be fatal */
f->offset = 0.0;
f->ax = 0;
return(f);
}
f->area *= 0.5;
/* compute offset */
badvert = 0;
f->offset = DOT(f->norm, VERTEX(f,0));
for (i = 1; i < f->nv; i++) {
d1 = DOT(f->norm, VERTEX(f,i));
badvert += fabs(d1 - f->offset/i) > VERTEPS;
f->offset += d1;
}
f->offset /= (double)f->nv;
if (badvert)
objerror(o, WARNING, "non-planar vertex");
/* find axis */
f->ax = fabs(f->norm[0]) > fabs(f->norm[1]) ? 0 : 1;
if (fabs(f->norm[2]) > fabs(f->norm[f->ax]))
f->ax = 2;
return(f);
}
freeface(o) /* free memory associated with face */
OBJREC *o;
{
if (o->os == NULL)
return;
free(o->os);
o->os = NULL;
}
inface(p, f) /* determine if point is in face */
FVECT p;
FACE *f;
{
int ncross, n;
double x, y;
register int xi, yi;
register FLOAT *p0, *p1;
xi = (f->ax+1)%3;
yi = (f->ax+2)%3;
x = p[xi];
y = p[yi];
n = f->nv;
p0 = f->va + 3*(n-1); /* connect last to first */
p1 = f->va;
ncross = 0;
/* positive x axis cross test */
while (n--) {
if ((p0[yi] > y) ^ (p1[yi] > y))
if (p0[xi] > x && p1[xi] > x)
ncross++;
else if (p0[xi] > x || p1[xi] > x)
ncross += (p1[yi] > p0[yi]) ^
((p0[yi]-y)*(p1[xi]-x) >
(p0[xi]-x)*(p1[yi]-y));
p0 = p1;
p1 += 3;
}
return(ncross & 01);
}