home *** CD-ROM | disk | FTP | other *** search
- /*
- * rotspline.c
- *
- * Copyright (C) 1991, Gerald Iles.
- * All rights reserved.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- *
- * rotspline.c,v 4.1 1994/08/09 07:59:58 explorer Exp
- *
- * rotspline.c,v
- * Revision 4.1 1994/08/09 07:59:58 explorer
- * Bump version to 4.1
- *
- * Revision 1.1.1.1 1994/08/08 04:52:10 explorer
- * Initial import. This is a prerelease of 4.0.6enh3, or 4.1 possibly.
- *
- */
- #include "geom.h"
- #include "rotspline.h"
-
- static Methods *iRotsplineMethods = NULL;
- static char rotsplineName[] = "rotspline";
-
- unsigned long RotsplineTests, RotsplineHits;
-
- Rotspline *
- RotsplineCreate(bot, x0, d0, top, xw, dw, coeffs)
- Vector *bot, *top;
- Float x0, xw, d0, dw, *coeffs;
- {
- Rotspline *rotspline;
- Float w;
- Vector axis, tmp;
-
- VecSub(*top, *bot, &axis);
- w = VecNormalize(&axis);
- if (w < EPSILON) {
- RLerror(RL_WARN, "Degenerate rotspline.\n");
- return (Rotspline *)NULL;
- }
-
- rotspline = (Rotspline *)Malloc(sizeof(Rotspline));
-
- rotspline->w = w;
-
- if (coeffs == NULL)
- {
- rotspline->k = (Float *)Calloc(4, sizeof(Float));
- rotspline->k[3] = 2.0 * (x0 * x0 - xw * xw + w * x0 * d0 + w * xw * dw) / (w * w * w);
- rotspline->k[2] = (3.0 * (xw * xw - x0 * x0) - 4.0*w*x0*d0 - 2.0*w*xw*dw) / (w * w);
- rotspline->k[1] = 2.0 * x0 * d0;
- rotspline->k[0] = x0 * x0;
- }
- else
- rotspline->k = coeffs;
- CoordSysTransform(bot, &axis, 1.0, 1.0, &rotspline->trans);
-
- return rotspline;
- }
-
- Methods *
- RotsplineMethods()
- {
- if (iRotsplineMethods == (Methods *)NULL) {
- iRotsplineMethods = MethodsCreate();
- iRotsplineMethods->name = RotsplineName;
- iRotsplineMethods->create = (GeomCreateFunc *)RotsplineCreate;
- iRotsplineMethods->methods = RotsplineMethods;
- iRotsplineMethods->intersect = RotsplineIntersect;
- iRotsplineMethods->normal = RotsplineNormal;
- iRotsplineMethods->uv = RotsplineUV;
- iRotsplineMethods->bounds = RotsplineBounds;
- iRotsplineMethods->stats = RotsplineStats;
- iRotsplineMethods->checkbounds = TRUE;
- iRotsplineMethods->closed = FALSE;
- }
- return iRotsplineMethods;
- }
-
- int
- RotsplineIntersect(rotspline, ray, mindist, maxdist)
- Rotspline *rotspline;
- Ray *ray;
- Float mindist, *maxdist;
- {
- double c[4], s[3], pp, pd, pz, dz, tmp, dist;
- Ray newray;
- Vector ndir, npos;
- int num, i;
-
- RotsplineTests++;
-
- newray = *ray;
- (void) RayTransform(&newray, &rotspline->trans.itrans);
- ndir = newray.dir;
- npos = newray.pos;
-
- pp = npos.x*npos.x + npos.y*npos.y +npos.z*npos.z;
- pd = npos.x*ndir.x + npos.y*ndir.y +npos.z*ndir.z;
- pz = npos.z;
- dz = ndir.z;
-
- c[3] = rotspline->k[3] * dz * dz * dz;
- c[2] = dz * dz *(3.0 * rotspline->k[3] * pz + rotspline->k[2] + 1.0) - 1.0;
- c[1] = dz *(pz *(3.0 * rotspline->k[3] * pz + 2.0 * rotspline->k[2] + 2.0) + rotspline->k[1]) - 2.0 * pd;
- c[0] = pz *(pz *(rotspline->k[3] * pz + rotspline->k[2] +1.0) + rotspline->k[1]) + rotspline->k[0] - pp;
-
- if (fabs(c[3]) > EPSILON)
- num = SolveCubic(c, s);
- else if (fabs(c[2]) > EPSILON)
- num = SolveQuadric(c, s);
- else if (fabs(c[1]) > EPSILON)
- {
- s[0] = -c[0]/c[1];
- num = 1;
- }
- else
- num = 0;
-
- if (num==0) return FALSE;
- dist = 0.0;
- for(i=0;i<num;i++)
- {
- if (s[i] > mindist)
- {
- tmp = pz + dz * s[i];
- if (tmp > 0.0 && tmp < rotspline->w)
- {
- if (dist == 0.0)
- dist = s[i];
- else if (s[i] < dist)
- dist = s[i];
- }
- }
- }
- if (dist > mindist && dist < *maxdist) {
- *maxdist = dist;
- RotsplineHits++;
- return TRUE;
- }
- return FALSE;
- }
-
- int
- RotsplineNormal(rotspline, pos, nrm, gnrm)
- Rotspline *rotspline;
- Vector *pos, *nrm, *gnrm;
- {
- Vector npos;
- Float du, r;
-
- npos = *pos;
- PointTransform(&npos, &rotspline->trans.itrans);
-
- du = rotspline->k[3] * 3.0 * npos.z * npos.z
- + rotspline->k[2] * 2.0 * npos.z
- + rotspline->k[1];
-
- r = sqrt(npos.x * npos.x + npos.y * npos.y);
-
- nrm->x = r * npos.x;
- nrm->y = r * npos.y;
- nrm->z = -du / 2.0;
-
- NormalTransform(nrm, &rotspline->trans.itrans);
- *gnrm = *nrm;
- return FALSE;
- }
-
- void
- RotsplineUV(rotspline, pos, norm, uv, dpdu, dpdv)
- Rotspline *rotspline;
- Vector *pos, *norm, *dpdu, *dpdv;
- Vec2d *uv;
- {
- Vector npos;
- Float val, d;
-
- npos = *pos;
- PointTransform(&npos, &rotspline->trans.itrans);
-
- uv->v = npos.z / rotspline->w;
- d = sqrt(npos.x * npos.x + npos.y * npos.y);
- if (d < EPSILON)
- uv->u = 0.;
- else
- {
- val = npos.x / d;
- if (val > 1.)
- uv->u = 0.;
- else if (val < -1.)
- uv->u = 0.5;
- else
- {
- uv->u = acos(val) / TWOPI;
- if (npos.y < 0.)
- uv->u = 1. - uv->u;
- }
- }
-
- if (dpdu)
- {
- dpdu->x = -npos.y;
- dpdu->y = npos.x;
- dpdu->z = 0.;
- dpdv->x = rotspline->k[3] * 3.0 * npos.z * npos.z
- + rotspline->k[2] * 2.0 * npos.z
- + rotspline->k[1];
- dpdv->y = 0.;
- dpdv->z = (d < EPSILON)?0.:d;
- VecTransform(dpdu, &rotspline->trans.trans);
- VecTransform(dpdv, &rotspline->trans.trans);
- (void)VecNormalize(dpdu);
- (void)VecNormalize(dpdv);
- }
- }
-
- void
- RotsplineBounds(rotspline, bounds)
- Rotspline *rotspline;
- Float bounds[2][3];
- {
- Float r0, rw, rmax, d, z, rz;
-
- r0 = (rotspline->k[0] < EPSILON ? 0.0 : sqrt(rotspline->k[0]));
- rw = EvalSpline(rotspline->k, rotspline->w);
- rw = (rw < EPSILON ? 0.0 : sqrt(rw));
- rmax = max(r0, rw);
- d = 4.*rotspline->k[2]*rotspline->k[2] - 12.*rotspline->k[3]*rotspline->k[1];
- if (d > 0.)
- {
- z = (-2. * rotspline->k[2] + sqrt(d))/(6. * rotspline->k[3]);
- if (z > 0. && z < rotspline->w)
- {
- rz = EvalSpline(rotspline->k, z);
- rz = (rz < EPSILON ? 0.0 : sqrt(rz));
- rmax = max(rmax, rz);
- }
- z = (-2. * rotspline->k[2] - sqrt(d))/(6. * rotspline->k[3]);
- if (z > 0. && z < rotspline->w)
- {
- rz = EvalSpline(rotspline->k, z);
- rz = (rz < EPSILON ? 0.0 : sqrt(rz));
- rmax = max(rmax, rz);
- }
- }
- bounds[LOW][X] = bounds[LOW][Y] = -rmax;
- bounds[HIGH][X] = bounds[HIGH][Y] = rmax;
- bounds[LOW][Z] = 0.;
- bounds[HIGH][Z] = rotspline->w;
- BoundsTransform(&rotspline->trans.trans, bounds);
- }
-
- char *
- RotsplineName()
- {
- return rotsplineName;
- }
-
- void
- RotsplineStats(tests, hits)
- unsigned long *tests, *hits;
- {
- *tests = RotsplineTests;
- *hits = RotsplineHits;
- }
-