/* Copyright (c) 1986 Regents of the University of California */

#ifndef lint
static char SCCSid[] = "@(#)o_face.c 2.1 11/12/91 LBL";
#endif

/*
 *  o_face.c - routines for creating octrees for polygonal faces.
 *
 *     8/27/85
 */

#include  "standard.h"

#include  "octree.h"

#include  "object.h"

#include  "face.h"

#include  "plocate.h"

/*
 *	The algorithm for determining a face's intersection
 *  with a cube is relatively straightforward:
 *
 *	1) Check to see if any vertices are inside the cube
 *	   (intersection).
 *
 *	2) Check to see if all vertices are to one side of
 *	   cube (no intersection).
 *
 *	3) Check to see if any portion of any edge is inside
 *	   cube (intersection).
 *
 *	4) Check to see if the cube cuts the plane of the
 *	   face and one of its edges passes through
 *	   the face (intersection).
 *
 *	5) If test 4 fails, we have no intersection.
 */


o_face(o, cu)			/* determine if face intersects cube */
OBJREC  *o;
CUBE  *cu;
{
	FVECT  cumin, cumax;
	FVECT  v1, v2;
	double  d1, d2;
	int  vloc;
	register FACE  *f;
	register int  i, j;
				/* get face arguments */
	f = getface(o);
	if (f->area == 0.0)		/* empty face */
		return(O_MISS);
					/* compute cube boundaries */
	for (j = 0; j < 3; j++)
		cumax[j] = (cumin[j] = cu->cuorg[j]-FTINY)
				+ cu->cusize + 2.0*FTINY;

	vloc = ABOVE | BELOW;		/* check vertices */
	for (i = 0; i < f->nv; i++)
		if (j = plocate(VERTEX(f,i), cumin, cumax))
			vloc &= j;
		else
			return(O_HIT);	/* vertex inside */

	if (vloc)			/* all to one side */
		return(O_MISS);
	
	for (i = 0; i < f->nv; i++) {	/* check edges */
		if ((j = i + 1) >= f->nv)
			j = 0;			/* wrap around */
		VCOPY(v1, VERTEX(f,i));		/* clip modifies */
		VCOPY(v2, VERTEX(f,j));		/* the vertices! */
		if (clip(v1, v2, cumin, cumax))
			return(O_HIT);		/* edge inside */
	}
					/* see if cube cuts plane */
	for (j = 0; j < 3; j++)
		if (f->norm[j] > 0.0) {
			v1[j] = cumin[j];
			v2[j] = cumax[j];
		} else {
			v1[j] = cumax[j];
			v2[j] = cumin[j];
		}
	if ((d1 = DOT(v1, f->norm) - f->offset) > FTINY)
		return(O_MISS);
	if ((d2 = DOT(v2, f->norm) - f->offset) < -FTINY)
		return(O_MISS);
					/* intersect face */
	for (j = 0; j < 3; j++)
		v1[j] = (v1[j]*d2 - v2[j]*d1)/(d2 - d1);
	if (inface(v1, f))
		return(O_HIT);
	
	return(O_MISS);		/* no intersection */
}
