home *** CD-ROM | disk | FTP | other *** search
- /* ****************************************************************
- * geo.c
- * ****************************************************************
- * MODULE PURPOSE:
- * This module contains routines that preform common
- * geometric manipulations for image synthesis.
- *
- * MODULE CONTENTS:
- * geo_dot - vector dot product
- * geo_cross - vector cross product
- * geo_norm - vector normalization
- * geo_line - generate a line
- * geo_rfl - compute the reflected vector
- * geo_rfr - compute the refracted vector
- * geo_H - compute H vector
- * geo_Ht - compute the H' vector
- */
- #include <stdio.h>
- #include <math.h>
- #include "geo.h"
-
- /* ****************************************************************
- * double geo_dot (v0, v1)
- * DIR_VECT *v0, *v1 (in) normalized direction vectors
- *
- * Returns the dot product of two direction vectors, ref
- * Eq.(\*(rK). Note that the dot product is the cosine
- * between the direction vectors because the direction
- * vectors are normalized.
- */
- double geo_dot (v0, v1)
- DIR_VECT *v0, *v1;
- { return (v0->i * v1->i) + (v0->j * v1->j) + (v0->k * v1->k);
- }
-
- /* ****************************************************************
- * DIR_VECT geo_cross (v0, v1)
- * DIR_VECT *v0, *v1 (in) normalized direction vectors
- *
- * Returns the cross product of two direction vectors, refer
- * to Eq.(\*(rL).
- */
- DIR_VECT geo_cross (v0, v1)
- DIR_VECT *v0, *v1;
- { DIR_VECT v2;
- v2.i = (v0->j * v1->k) - (v0->k * v1->j);
- v2.j = (v0->k * v1->i) - (v0->i * v1->k);
- v2.k = (v0->i * v1->j) - (v0->j * v1->i);
- return v2;
- }
-
- /* ****************************************************************
- * double geo_norm (*v0)
- * DIR_VECT *v0 (mod) vector to be normalized
- *
- * Returns the length of the vector before normalization.
- * Returns zero if the vector could not be normalized.
- * Note that the input vector is modified.
- */
- double geo_norm (v0)
- DIR_VECT *v0;
- { double len;
- if ((len = geo_dot(v0, v0)) <= 0.0) return FALSE;
- len = sqrt((double)len);
- v0->i /= len;
- v0->j /= len;
- v0->k /= len;
- return TRUE;
- }
-
- /* ****************************************************************
- * double geo_line (*p0, *p1, *v)
- * POINT3 *p0, *p1 (in) from, to points
- * LINE *v (out) generated line
- *
- * Returns the distance from p0 to p1. Returns 0.0
- * on error (p0=p1). The line is expressed in parametric
- * form with a start point (p0) and a normalized direction
- * vector. The vector direction of the line is normalized.
- */
- double geo_line (p0, p1, v)
- POINT3 *p0, *p1;
- LINE *v;
- { v->start = *p0;
- v->dir.i = p1->x - p0->x;
- v->dir.j = p1->y - p0->y;
- v->dir.k = p1->z - p0->z;
- return geo_norm(&v->dir);
- }
-
- /* ****************************************************************
- * DIR_VECT *geo_rfl (V, N)
- * DIR_VECT *V (in) incident vector
- * DIR_VECT *N (in) surface normal
- *
- * Returns the reflected direction vector. The reflected
- * direction is computed using the method given by Whitted
- * (1980), refer to Eq.(\*(rM).
- */
- DIR_VECT *geo_rfl (V, N)
- DIR_VECT *V;
- DIR_VECT *N;
- { double N_dot_V;
- static DIR_VECT rfl;
- N_dot_V = geo_dot (N,V);
- rfl.i = (2.0 * N_dot_V * N->i) - V->i;
- rfl.j = (2.0 * N_dot_V * N->j) - V->j;
- rfl.k = (2.0 * N_dot_V * N->k) - V->k;
- return &rfl;
- }
-
- /* ****************************************************************
- * DIR_VECT *geo_rfr (V, N, ni, nt)
- * DIR_VECT *V (in) incident vector
- * DIR_VECT *N (in) surface normal
- * double ni (in) index of refraction for the
- * material on the front of the
- * interface (same side as N)
- * double nt (in) index of refraction for the
- * material on the back of the
- * interface (opposite size as N)
- *
- * Returns the refracted vector, if there complete internal
- * refracted (no refracted vector) then a NULL vector is
- * NULL is returned. The vector is computed using the
- * method given by Hall (1983) with enhancements as
- * described in Appendix III.
- */
- DIR_VECT *geo_rfr (V, N, ni, nt)
- DIR_VECT *V;
- DIR_VECT *N;
- double ni;
- double nt;
- { static DIR_VECT T; /* the refracted vector */
- DIR_VECT sin_T; /* sin vect of the refracted vect */
- DIR_VECT cos_V; /* cos vect of the incident vect */
- double len_sin_T; /* length of sin T squared */
- double n_mult; /* ni over nt */
- double N_dot_V;
- double N_dot_T;
- if ((N_dot_V = geo_dot(N,V)) > 0.0) n_mult = ni / nt;
- else n_mult = nt / ni;
- cos_V.i = N_dot_V * N->i;
- cos_V.j = N_dot_V * N->j;
- cos_V.k = N_dot_V * N->k;
- sin_T.i = (n_mult) * (cos_V.i - V->i);
- sin_T.j = (n_mult) * (cos_V.j - V->j);
- sin_T.k = (n_mult) * (cos_V.k - V->k);
- if ((len_sin_T = geo_dot(&sin_T, &sin_T)) >= 1.0)
- return NULL; /* internal reflection */
- N_dot_T = sqrt(1.0 - len_sin_T);
- if (N_dot_V < 0.0) N_dot_T = -N_dot_T;
- T.i = sin_T.i - (N->i * N_dot_T);
- T.j = sin_T.j - (N->j * N_dot_T);
- T.k = sin_T.k - (N->k * N_dot_T);
- return &T;
- }
-
- /* ****************************************************************
- * DIR_VECT *geo_H (L, V)
- * DIR_VECT *L (in) incident vector
- * DIR_VECT *V (in) reflected vector
- *
- * Returns H, NULL on error (if L+H = 0). Refer
- * to Eq.(\*(rO).
- */
- DIR_VECT *geo_H (L, V)
- DIR_VECT *L;
- DIR_VECT *V;
- { static DIR_VECT H;
- H.i = L->i + V->i;
- H.j = L->j + V->j;
- H.k = L->k + V->k;
- if (!geo_norm(&H)) return NULL;
- return &H;
- }
-
- /* ****************************************************************
- * DIR_VECT *geo_Ht(L, T, ni, nt)
- * DIR_VECT *L (in) incident vector
- * DIR_VECT *T (in) transmitted hector
- * double ni (in) incident index
- * double nt (in) transmitted index
- *
- * Returns H' oriented to the same side of the surface
- * as L computed using the method suggested by
- * Hall (1983). Returns NULL on error (if the angle
- * between V and L is less than the critical angle).
- */
- DIR_VECT *geo_Ht (L, T, ni, nt)
- DIR_VECT *L;
- DIR_VECT *T;
- double ni;
- double nt;
- {
- float L_dot_T;
- float divisor;
- static DIR_VECT Ht;
-
- L_dot_T = -(geo_dot(L,T));
- /* check for special cases */
- if (ni == nt) {
- if (L_dot_T == 1.0) return L;
- else return NULL;
- }
- if (ni < nt) {
- if (L_dot_T < ni/nt) return NULL;
- divisor = (nt / ni) - 1.0;
- Ht.i = -(((L->i + T->i) / divisor) + T->i);
- Ht.j = -(((L->j + T->j) / divisor) + T->j);
- Ht.k = -(((L->k + T->k) / divisor) + T->k);
- }
- else
- { if (L_dot_T < nt/ni) return NULL;
- divisor = (ni / nt) - 1.0;
- Ht.i = ((L->i + T->i) / divisor) + L->i;
- Ht.j = ((L->j + T->j) / divisor) + L->j;
- Ht.k = ((L->k + T->k) / divisor) + L->k;
- }
- (void)geo_norm(&Ht);
- return &Ht;
- }
- /* ************************************************************* */
-