home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
RISC DISC 3
/
RISC_DISC_3.iso
/
resources
/
etexts
/
gems
/
gemsv
/
ch5_2
/
quad_gg.c
next >
Wrap
C/C++ Source or Header
|
1994-11-22
|
5KB
|
141 lines
/* ------------------------------------------------------------------------- *\
QUAD_GG.C :
by Christophe Schlick and Gilles Subrenat (15 May 1994)
"Ray Intersection of Tessellated Surfaces : Quadrangles versus Triangles"
in Graphics Gems V (edited by A. Paeth), Academic Press
\* ------------------------------------------------------------------------- */
#include "quad_gg.h"
/*********************
* macro definitions *
*********************/
#define EPSILON ((REAL) 0.0001)
#define DETERMINANT(A,B) ((REAL) ((A).x * (B).y - (A).y * (B).x))
#define V3_LIN(R,A,k,B) ((R).x = (A).x + k * (B).x, \
(R).y = (A).y + k * (B).y, \
(R).z = (A).z + k * (B).z)
#define LARGEST_COMPONENT(A) (ABS((A).x) > ABS((A).y) ? \
(ABS((A).x) > ABS((A).z) ? 'x' : 'z') : \
(ABS((A).y) > ABS((A).z) ? 'y' : 'z'))
/*
** Compute uv-coordinates of the point
** Return TRUE if the point is in the quadrangle
*/
static boolean point_in_quad (QUAD *Quad, HIT *Hit)
{
char LargestComponent; /* of the normal vector */
Point2 A, B, C, D; /* Projected vertices */
Point2 M; /* Projected intersection point */
Vector2 AB, BC, CD, AD, AM, AE; /* AE = DC - AB = DA - CB */
REAL u, v; /* Parametric coordinates */
REAL a, b, c, SqrtDelta; /* for the quadratic equation */
boolean IsInside = FALSE; /* if u and v are inside */
Vector2 Vector; /* temporary 2D-vector */
/*
** Projection on the plane that is most parallel to the facet
*/
LargestComponent = LARGEST_COMPONENT(Quad->Normal);
if (LargestComponent == 'x') {
A.x = Quad->A.y; B.x = Quad->B.y; C.x = Quad->C.y; D.x = Quad->D.y;
M.x = Hit->Point.y;
}
else {
A.x = Quad->A.x; B.x = Quad->B.x; C.x = Quad->C.x; D.x = Quad->D.x;
M.x = Hit->Point.x;
}
if (LargestComponent == 'z') {
A.y = Quad->A.y; B.y = Quad->B.y; C.y = Quad->C.y; D.y = Quad->D.y;
M.y = Hit->Point.y;
}
else {
A.y = Quad->A.z; B.y = Quad->B.z; C.y = Quad->C.z; D.y = Quad->D.z;
M.y = Hit->Point.z;
}
V2Sub (&B, &A, &AB); V2Sub (&C, &B, &BC);
V2Sub (&D, &C, &CD); V2Sub (&D, &A, &AD);
V2Add (&CD, &AB, &AE); V2Negate (&AE); V2Sub (&M, &A, &AM);
if (fabs(DETERMINANT(AB, CD)) < EPSILON) /* case AB // CD */
{
V2Sub (&AB, &CD, &Vector);
v = DETERMINANT(AM, Vector) / DETERMINANT(AD, Vector);
if ((v >= 0.0) && (v <= 1.0)) {
b = DETERMINANT(AB, AD) - DETERMINANT(AM, AE);
c = DETERMINANT (AM, AD);
u = ABS(b) < EPSILON ? -1 : c/b;
IsInside = ((u >= 0.0) && (u <= 1.0));
}
}
else if (fabs(DETERMINANT(BC, AD)) < EPSILON) /* case AD // BC */
{
V2Add (&AD, &BC, &Vector);
u = DETERMINANT(AM, Vector) / DETERMINANT(AB, Vector);
if ((u >= 0.0) && (u <= 1.0)) {
b = DETERMINANT(AD, AB) - DETERMINANT(AM, AE);
c = DETERMINANT (AM, AB);
v = ABS(b) < EPSILON ? -1 : c/b;
IsInside = ((v >= 0.0) && (v <= 1.0));
}
}
else /* general case */
{
a = DETERMINANT(AB, AE); c = - DETERMINANT (AM,AD);
b = DETERMINANT(AB, AD) - DETERMINANT(AM, AE);
a = -0.5/a; b *= a; c *= (a + a); SqrtDelta = b*b + c;
if (SqrtDelta >= 0.0) {
SqrtDelta = sqrt(SqrtDelta);
u = b - SqrtDelta;
if ((u < 0.0) || (u > 1.0)) /* to choose u between 0 and 1 */
u = b + SqrtDelta;
if ((u >= 0.0) && (u <= 1.0)) {
v = AD.x + u * AE.x;
if (ABS(v) < EPSILON)
v = (AM.y - u * AB.y) / (AD.y + u * AE.y);
else
v = (AM.x - u * AB.x) / v;
IsInside = ((v >= 0.0) && (v <= 1.0));
}
}
}
if (IsInside) {
Hit->u = u;
Hit->v = v;
}
return (IsInside);
}
/*
** Search for an intersection between a facet and a ray
*/
boolean hit_ray_quad (RAY *Ray, QUAD *Quad, HIT *Hit)
{
Point3 Point;
/* if the ray is parallel to the facet, there is no intersection */
Hit->Distance = V3Dot (&(Ray->Vector), &(Quad->Normal));
if (ABS(Hit->Distance) < EPSILON) return (FALSE);
/* compute ray intersection with the plane of the facet */
V3Sub (&(Quad->A), &(Ray->Point), &Point);
Hit->Distance = V3Dot (&Point, &(Quad->Normal)) / Hit->Distance;
V3_LIN (Hit->Point, Ray->Point, Hit->Distance, Ray->Vector);
/* is the intersection point inside the facet */
return (point_in_quad(Quad, Hit));
}
/* ------------------------------------------------------------------------- */