home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- *
- *
- * sweptsph.c
- *
- *
- * Copyright (C) 1992 by Lawrence K. Coffin, Craig Colb
- * 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".
- *
- * 06/20/92 Larry Coffin
- * Initial version.
- *
- */
-
- /*
- * This primative is from "Ray Tracing Objects Defined by Sweeping a
- * Sphere" by J.J. van Wijk in Eurographics '84, pg 73. It is defined by
- * a sphere of variying radius that is swept or extruded through space along a
- * parametricly defined curve. The equations for the x,y,z components of the
- * curve and the radius of the sphere are defined by third order equations.
- * This allows for the curve to be defined as the actual equation, as a bezier
- * curve, and perhaps several other curves such as splines.
- *
- * The equation for the primitive is the parametric equation:
- *
- * f(xyz,u) = |xyz - c(u)|^2 - r(u)^2 -- where xyz = {x,y,z} and
- * c(u) = {x(u),y(u),z(u)} for umin <= u <= umax.
- *
- *
- * Substituting the parametric form of a ray (xyz = Vt + P) where P is the
- * ray position (ray->pos), and V is the ray direction (ray->dir) we get an
- * equation
- *
- * g(u,t) = f2 * t^2 + f1 * t^1 + f0
- *
- * Where:
- * f2 = |V|^2 = dotp<ray->dir,ray->dir> = 1 since the ray direction is
- * a unit vector.
- *
- * f1 = 2*dotp<(P - c(u)),V)>
- *
- * f0 = |P - c(u)|^2 - r(u)^2
- *
- * Differentiating g(u,t) = 0 with respect to u gives us:
- *
- * 2*f2*t*t' + f1'*t + f1*t' + f0' = 0
- *
- * Setting t' = 0 gives us:
- *
- * f1'*t + f0' = 0
- *
- * Which gives us t = -f1'/f0'
- *
- * Substituting this back into g(u,t) gives us
- *
- * g(u) = f2*f0'*f0' - f1*f1'*f0' + f1'*f1'*f0
- *
- * working this out we get an equation in u of 2*(2*n -1) degree when starting
- * with center or radius equations of nth degree (10th degree for 3rd degree
- * center and radius equations).
- *
- * After solving for u = 0, we can find t from t = -f1'/f0' and keep
- * the shortest t as our distance of closest intersection. We must also check
- * the case where u = umin and u = umax to see if we intersect the sphere at
- * either end.
- *
- */
-
-
- #include "geom.h"
- #include "sweptsph.h"
-
- #define BIGNUM 9.9e6 /* used as the min and max values for the root finding
- intervals */
- #define SMALLNUM .1e-6 /* a number close enough to zero */
- #define DBL_EPS 2.2204460492503131e-10 /* larger than the accuracy of
- the machine's Floats */
- #define COUNT 8 /* maximum number of iterations for the Newton's method
- root finder */ /* 8 best for linear start */
- #define COUNT2 200
-
- #define sign(x) ((x) < 0 ? (-1) : (1))
-
-
- static Methods *iSweptSphMethods = NULL;
- static char sweptsphName[] = "sweptsph";
-
- unsigned long SweptSphTests, SweptSphHits, maxcount;
- Float SweptSphRoot; /* This holds the value for u for the most recent hit
- This is neccecary inorder to calculate the normal */
- int steps[20];
- unsigned long int bichecks, bitests, newtons, newchecks;
-
- FILE *sweptspherror;
-
- /*
- * SweptSphCreate expects two prameters: the equations for the center and the
- * equation for the radius. The center equations are passed as an array of
- * four vectors. The center is defined by parametric equations such that
- *
- * x(u) = cent[0].x + cent[1].x * u + cent[2].x * u^2 + cent[3].x * u^3
- * y(u) = cent[0].y + cent[1].y * u + cent[2].y * u^2 + cent[3].y * u^3
- * z(u) = cent[0].z + cent[1].z * u + cent[2].z * u^2 + cent[3].z * u^3
- *
- * Likewise the radius is defined as:
- *
- * r(u) = rad[0] + rad[1] * u + rad[2] * u^2 + rad[3] * u^3
- *
- */
-
-
- SweptSph *
- SweptSphCreate(cent, rad)
- Vector cent[4];
- Float rad[4];
- {
- SweptSph *sweptsph;
- int i;
-
- sweptsph = (SweptSph *)share_malloc(sizeof(SweptSph));
-
- for (i = 0; i < 4; i++){
- if (fabs(cent[i].x) < DBL_EPS) cent[i].x = 0.0;
- if (fabs(cent[i].y) < DBL_EPS) cent[i].y = 0.0;
- if (fabs(cent[i].z) < DBL_EPS) cent[i].z = 0.0;
- if (fabs(rad[i]) < DBL_EPS) rad[i] = 0.0;
- }
-
- sweptsph->a0 = cent[0];
- sweptsph->a1 = cent[1];
- sweptsph->a2 = cent[2];
- sweptsph->a3 = cent[3];
-
- sweptsph->rad[0] = rad[0];
- sweptsph->rad[1] = rad[1];
- sweptsph->rad[2] = rad[2];
- sweptsph->rad[3] = rad[3];
-
- sweptsph->pb[0] = dotp(&(sweptsph->a0),&(sweptsph->a0)) - rad[0]*rad[0];
- sweptsph->pb[1] = 2*dotp(&(sweptsph->a0),&(sweptsph->a1)) - 2*rad[0]*rad[1];
- sweptsph->pb[2] = 2*dotp(&(sweptsph->a0),&(sweptsph->a2)) + dotp(&(sweptsph->a1),&(sweptsph->a1)) - 2*rad[0]*rad[2] - rad[1]*rad[1];
- sweptsph->pb[3] = 2*dotp(&(sweptsph->a0),&(sweptsph->a3)) + 2*dotp(&(sweptsph->a1),&(sweptsph->a2)) - 2*rad[0]*rad[3] - 2*rad[1]*rad[2];
- sweptsph->pb[4] = 2*dotp(&(sweptsph->a1),&(sweptsph->a3)) + dotp(&(sweptsph->a2),&(sweptsph->a2)) - 2*rad[1]*rad[3] - rad[2]*rad[2];
- sweptsph->pb[5] = 2*dotp(&(sweptsph->a2),&(sweptsph->a3)) - 2*rad[2]*rad[3];
- sweptsph->pb[6] = dotp(&(sweptsph->a3),&(sweptsph->a3)) - rad[3]*rad[3];
-
- sweptsph->pd[0] = 16*(sweptsph->pb[4])*(sweptsph->pb[4]);
- sweptsph->pd[1] = 40*(sweptsph->pb[4])*(sweptsph->pb[5]);
- sweptsph->pd[2] = 48*(sweptsph->pb[4])*(sweptsph->pb[6]) + 25*(sweptsph->pb[5])*(sweptsph->pb[5]);
- sweptsph->pd[3] = 60*(sweptsph->pb[5])*(sweptsph->pb[6]);
- sweptsph->pd[4] = 36*(sweptsph->pb[6])*(sweptsph->pb[6]);
-
- /* if ((sweptspherror = fopen("/usr/people/c/lcoffin/sweptsph.stat","w")) == NULL){
- fprintf(stderr,"Unable to open stat file for sweptsph\n");
- exit(1);
- }
- */
- return sweptsph;
- }
-
- Methods *
- SweptSphMethods()
- {
- if (iSweptSphMethods == (Methods *)NULL) {
- iSweptSphMethods = MethodsCreate();
- iSweptSphMethods->create = (GeomCreateFunc *)SweptSphCreate;
- iSweptSphMethods->methods = SweptSphMethods;
- iSweptSphMethods->name = SweptSphName;
- iSweptSphMethods->intersect = SweptSphIntersect;
- iSweptSphMethods->normal = SweptSphNormal;
- iSweptSphMethods->bounds = SweptSphBounds;
- iSweptSphMethods->stats = SweptSphStats;
- iSweptSphMethods->checkbounds = TRUE;
- iSweptSphMethods->closed = TRUE;
- }
- return iSweptSphMethods;
- }
-
- int
- SweptSphIntersect(sweptsph, ray, mindist, maxdist)
- SweptSph *sweptsph;
- Ray *ray;
- Float mindist, *maxdist;
- {
- Vector a0, a1, a2, a3, dir, pos;
- Float b[7],c[4], d[11], e[6], h[5], i[11], j[11], g[11], roots[10], t;
- Float rad[4], div, radic, root;
- int num, hit, x, k;
-
- SweptSphTests++;
-
- dir = ray->dir;
- pos = ray->pos;
-
- rad[0] = sweptsph->rad[0];
- rad[1] = sweptsph->rad[1];
- rad[2] = sweptsph->rad[2];
- rad[3] = sweptsph->rad[3];
-
- a0 = sweptsph->a0;
- a1 = sweptsph->a1;
- a2 = sweptsph->a2;
- a3 = sweptsph->a3;
-
- /* b[] = f0 */
- b[0] = dotp(&pos,&pos) - 2*dotp(&pos,&a0) + sweptsph->pb[0];
- b[1] = -2*dotp(&pos,&a1 ) + sweptsph->pb[1];
- b[2] = -2*dotp(&pos,&a2 ) + sweptsph->pb[2];
- b[3] = -2*dotp(&pos,&a3 ) + sweptsph->pb[3];
- b[4] = sweptsph->pb[4];
- b[5] = sweptsph->pb[5];
- b[6] = sweptsph->pb[6];
-
- /* c[] = f1 */
- c[0] = 2*dotp(&pos,&dir) - 2*dotp(&a0,&dir);
- c[1] = -2*dotp(&a1 ,&dir);
- c[2] = -2*dotp(&a2 ,&dir);
- c[3] = -2*dotp(&a3 ,&dir);
-
- /* d[] = f0'*f0' which also equals f2*f0'*f0' since our ray->dir is
- a unit vector */
- d[0] = b[1]*b[1];
- d[1] = 4*b[1]*b[2];
- d[2] = 6*b[1]*b[3] + 4*b[2]*b[2];
- d[3] = 8*b[1]*b[4] + 12*b[2]*b[3];
- d[4] = 10*b[1]*b[5] + 16*b[2]*b[4] + 9*b[3]*b[3];
- d[5] = 12*b[1]*b[6] + 20*b[2]*b[5] + 24*b[3]*b[4];
- d[6] = 24*b[2]*b[6] + 30*b[3]*b[5] + sweptsph->pd[0];
- d[7] = 36*b[3]*b[6] + sweptsph->pd[1];
- d[8] = sweptsph->pd[2];
- d[9] = sweptsph->pd[3];
- d[10] = sweptsph->pd[4];
-
- /* e = f1*f1' */
- e[0] = c[0]*c[1];
- e[1] = 2*c[0]*c[2] + c[1]*c[1];
- e[2] = 3*c[0]*c[3] + 3*c[1]*c[2];
- e[3] = 4*c[1]*c[3] + 2*c[2]*c[2];
- e[4] = 5*c[2]*c[3];
- e[5] = 3*c[3]*c[3];
-
- /* h[] = f1'*f1' */
- h[0] = c[1]*c[1];
- h[1] = 4*c[1]*c[2];
- h[2] = 6*c[1]*c[3] + 4*c[2]*c[2];
- h[3] = 12*c[2]*c[3];
- h[4] = 9*c[3]*c[3];
-
- /* i[] = f1*f1'*f0' */
- i[0] = e[0]*b[1];
- i[1] = 2*e[0]*b[2] + e[1]*b[1];
- i[2] = 3*e[0]*b[3] + 2*e[1]*b[2] + e[2]*b[1];
- i[3] = 4*e[0]*b[4] + 3*e[1]*b[3] + 2*e[2]*b[2] + e[3]*b[1];
- i[4] = 5*e[0]*b[5] + 4*e[1]*b[4] + 3*e[2]*b[3] + 2*e[3]*b[2] + e[4]*b[1];
- i[5] = 6*e[0]*b[6] + 5*e[1]*b[5] + 4*e[2]*b[4] + 3*e[3]*b[3] + 2*e[4]*b[2] + e[5]*b[1];
- i[6] = 6*e[1]*b[6] + 5*e[2]*b[5] + 4*e[3]*b[4] + 3*e[4]*b[3] + 2*e[5]*b[2];
- i[7] = 6*e[2]*b[6] + 5*e[3]*b[5] + 4*e[4]*b[4] + 3*e[5]*b[3];
- i[8] = 6*e[3]*b[6] + 5*e[4]*b[5] + 4*e[5]*b[4];
- i[9] = 6*e[4]*b[6] + 5*e[5]*b[5];
- i[10] = 6*e[5]*b[6];
-
- /* j[] = f1'*f1'*f0 */
- j[0] = h[0]*b[0];
- j[1] = h[0]*b[1] + h[1]*b[0];
- j[2] = h[0]*b[2] + h[1]*b[1] + h[2]*b[0];
- j[3] = h[0]*b[3] + h[1]*b[2] + h[2]*b[1] + h[3]*b[0];
- j[4] = h[0]*b[4] + h[1]*b[3] + h[2]*b[2] + h[3]*b[1] + h[4]*b[0];
- j[5] = h[0]*b[5] + h[1]*b[4] + h[2]*b[3] + h[3]*b[2] + h[4]*b[1];
- j[6] = h[0]*b[6] + h[1]*b[5] + h[2]*b[4] + h[3]*b[3] + h[4]*b[2];
- j[7] = h[1]*b[6] + h[2]*b[5] + h[3]*b[4] + h[4]*b[3];
- j[8] = h[2]*b[6] + h[3]*b[5] + h[4]*b[4];
- j[9] = h[3]*b[6] + h[4]*b[5];
- j[10] = h[4]*b[6];
-
- /* g[] = f2*f0'*f0' - f1*f1'*f0' + f1'*f1'*f0 */
- for (x = 0; x <= 10; x++){
- g[x] = d[x] - i[x] + j[x];
- }
-
- /* find the roots */
- num = FindRoots(g,10,0.0,1.0,roots);
-
- hit = FALSE;
-
- /* check each root */
- for (k = 0; k < num; k++){
- /* check to see if f1' = 0 */
- div = (c[1] + (2*c[2] + 3*c[3]*roots[k])*roots[k]);
-
- if (div){
- /* find t = -f0'/f1' */
- t = -(b[1] + (2*b[2] + (3*b[3] + (4*b[4] + (5*b[5]
- + 6*b[6]*roots[k])*roots[k])*roots[k])*roots[k])*roots[k])/div;
- /* set maxdist = t if t is smaller than our
- maximum distance */
- if (t > mindist + .0001){
- if (t < *maxdist){
- SweptSphRoot = roots[k];
- *maxdist = t;
- hit = TRUE;
- }
- }
- }
- }
-
- /* check intersection with the end spheres */
- g[2] = 1;
- g[1] = c[0];
- g[0] = b[0];
-
- radic = g[1]*g[1] - 4*g[0];
-
- if (radic > 0){
- radic = sqrt(radic);
- root = (-g[1] - radic)/2.0;
-
- if (root > mindist + .0001 && root < *maxdist){
- SweptSphRoot = 0.0;
- *maxdist = root;
- hit = TRUE;
- }
-
- root = (-g[1] + radic)/2.0;
-
- if (root > mindist + .0001 && root < *maxdist){
- SweptSphRoot = 0.0;
- *maxdist = root;
- hit = TRUE;
- }
- }
- else if (radic == 0){
- root = -g[1]/2.0;
- if (root > mindist + .0001 && root < *maxdist){
- SweptSphRoot = 0.0;
- *maxdist = root;
- hit = TRUE;
- }
- }
-
-
- g[2] = 1;
- g[1] = c[0]+c[1]+c[2]+c[3];
- g[0] = b[0]+b[1]+b[2]+b[3]+b[4]+b[5]+b[6];
-
- radic = g[1]*g[1] - 4*g[0];
-
- if (radic > 0){
- radic = sqrt(radic);
- root = (-g[1] - radic)/2.0;
-
- if (root > mindist + .0001 && root < *maxdist){
- SweptSphRoot = 1.0;
- *maxdist = root;
- hit = TRUE;
- }
-
- root = (-g[1] + radic)/2.0;
-
- if (root > mindist + .0001 && root < *maxdist){
- SweptSphRoot = 1.0;
- *maxdist = root;
- hit = TRUE;
- }
- }
- else if (radic == 0){
- root = -g[1]/2.0;
- if (root > mindist + .0001 && root < *maxdist){
- SweptSphRoot = 1.0;
- *maxdist = root;
- hit = TRUE;
- }
- }
-
- if (hit == TRUE){
- SweptSphHits++;
- }
- return hit;
- }
-
-
- int
- SweptSphNormal(sweptsph, pos, nrm, gnrm)
- SweptSph *sweptsph;
- Vector *pos, *nrm, *gnrm;
- {
- Vector a0, a1, a2, a3;
-
- a0 = sweptsph->a0;
- a1 = sweptsph->a1;
- a2 = sweptsph->a2;
- a3 = sweptsph->a3;
-
- /* normal is simply the normal to the sphere at c(u): u = SweptSphRoot */
- nrm->x = pos->x - a0.x - (a1.x + (a2.x + a3.x*SweptSphRoot)*SweptSphRoot)*SweptSphRoot;
- nrm->y = pos->y - a0.y - (a1.y + (a2.y + a3.y*SweptSphRoot)*SweptSphRoot)*SweptSphRoot;
- nrm->z = pos->z - a0.z - (a1.z + (a2.z + a3.z*SweptSphRoot)*SweptSphRoot)*SweptSphRoot;
-
- VecNormalize(nrm);
- *gnrm = *nrm;
-
- return FALSE;
- }
-
- void
- SweptSphBounds(sweptsph, bounds)
- SweptSph *sweptsph;
- Float bounds[2][3];
- {
- Float a[4], aprime[3],root, val, rad, radimax;
-
- /* for the bounding boxes, calculate the maximum radius of the swept
- sphere then set the bounding box to the max and min of the
- center curve plus or minus the maximum radius of the sphere
- */
-
- /* find the maximum radius */
-
- radimax = 0;
-
- a[0] = sweptsph->rad[0];
- a[1] = sweptsph->rad[1];
- a[2] = sweptsph->rad[2];
- a[3] = sweptsph->rad[3];
-
- aprime[0] = a[1];
- aprime[1] = 2.0*a[2];
- aprime[2] = 3.0*a[3];
-
- if (aprime[2] == 0){
- if (aprime[1] != 0){
- root = -aprime[0]/aprime[1];
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val > radimax){
- radimax = val;
- }
- }
- }
- }
- else {
- rad = aprime[1]*aprime[1] - 4.0 * aprime[2] * aprime[0];
- if (rad == 0) {
- root = -aprime[1]/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val > radimax){
- radimax = val;
- }
- }
- }
- else if (rad > 0){
- rad = sqrt(rad);
-
- root = (-aprime[1] - rad)/(2.0*aprime[2]);
-
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val > radimax){
- radimax = val;
- }
- }
-
- root = (-aprime[1] + rad)/(2.0*aprime[2]);
-
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val > radimax){
- radimax = val;
- }
- }
- }
- }
-
- val = a[0];
- if (val > radimax){
- radimax = val;
- }
-
- val = a[0] + a[1] + a[2] + a[3];
- if (val > radimax){
- radimax = val;
- }
-
-
- /* find the x bounds of the curve */
- a[0] = sweptsph->a0.x;
- a[1] = sweptsph->a1.x;
- a[2] = sweptsph->a2.x;
- a[3] = sweptsph->a3.x;
-
- aprime[0] = a[1];
- aprime[1] = 2.0*a[2];
- aprime[2] = 3.0*a[3];
-
-
- if (aprime[2] == 0){
- if (aprime[1] != 0){
- root = -aprime[0]/aprime[1];
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][X]){
- bounds[LOW][X] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][X]){
- bounds[HIGH][X] = val + radimax;
- }
- }
- }
- }
- else {
- rad = aprime[1]*aprime[1] - 4.0 * aprime[2] * aprime[0];
-
- if (rad == 0) {
- root = -aprime[1]/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][X]){
- bounds[LOW][X] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][X]){
- bounds[HIGH][X] = val + radimax;
- }
- }
- }
- else if (rad > 0){
- rad = sqrt(rad);
-
- root = (-aprime[1] - rad)/(2.0*aprime[2]);
-
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][X]){
- bounds[LOW][X] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][X]){
- bounds[HIGH][X] = val + radimax;
- }
- }
-
- root = (-aprime[1] + rad)/(2.0*aprime[2]);
-
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][X]){
- bounds[LOW][X] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][X]){
- bounds[HIGH][X] = val + radimax;
- }
- }
- }
- }
-
- val = a[0];
- if (val - radimax < bounds[LOW][X]){
- bounds[LOW][X] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][X]){
- bounds[HIGH][X] = val + radimax;
- }
- val = a[0] + a[1] + a[2] + a[3];
- if (val - radimax < bounds[LOW][X]){
- bounds[LOW][X] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][X]){
- bounds[HIGH][X] = val + radimax;
- }
-
-
- /* find the y bounds of the curve */
- a[0] = sweptsph->a0.y;
- a[1] = sweptsph->a1.y;
- a[2] = sweptsph->a2.y;
- a[3] = sweptsph->a3.y;
-
- aprime[0] = a[1];
- aprime[1] = 2.0*a[2];
- aprime[2] = 3.0*a[3];
-
- if (aprime[2] == 0){
- if (aprime[1] != 0){
- root = -aprime[0]/aprime[1];
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Y]){
- bounds[LOW][Y] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Y]){
- bounds[HIGH][Y] = val + radimax;
- }
- }
- }
- }
- else {
- rad = aprime[1]*aprime[1] - 4.0 * aprime[2] * aprime[0];
- if (rad == 0) {
- root = -aprime[1]/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Y]){
- bounds[LOW][Y] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Y]){
- bounds[HIGH][Y] = val + radimax;
- }
- }
- }
- else if (rad > 0){
- rad = sqrt(rad);
- root = (-aprime[1] - rad)/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Y]){
- bounds[LOW][Y] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Y]){
- bounds[HIGH][Y] = val + radimax;
- }
- }
- root = (-aprime[1] + rad)/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Y]){
- bounds[LOW][Y] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Y]){
- bounds[HIGH][Y] = val + radimax;
- }
- }
- }
- }
-
- val = a[0];
- if (val - radimax < bounds[LOW][Y]){
- bounds[LOW][Y] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Y]){
- bounds[HIGH][Y] = val + radimax;
- }
- val = a[0] + a[1] + a[2] + a[3];
- if (val - radimax < bounds[LOW][Y]){
- bounds[LOW][Y] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Y]){
- bounds[HIGH][Y] = val + radimax;
- }
-
-
- /* find the z bounds of the curve */
- a[0] = sweptsph->a0.z;
- a[1] = sweptsph->a1.z;
- a[2] = sweptsph->a2.z;
- a[3] = sweptsph->a3.z;
-
- aprime[0] = a[1];
- aprime[1] = 2.0*a[2];
- aprime[2] = 3.0*a[3];
-
- if (aprime[2] == 0){
- if (aprime[1] != 0){
- root = -aprime[0]/aprime[1];
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Z]){
- bounds[LOW][Z] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Z]){
- bounds[HIGH][Z] = val + radimax;
- }
- }
- }
- }
- else {
- rad = aprime[1]*aprime[1] - 4.0 * aprime[2] * aprime[0];
-
- if (rad == 0) {
- root = -aprime[1]/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Z]){
- bounds[LOW][Z] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Z]){
- bounds[HIGH][Z] = val + radimax;
- }
- }
- }
- else if (rad > 0){
- rad = sqrt(rad);
- root = (-aprime[1] - rad)/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Z]){
- bounds[LOW][Z] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Z]){
- bounds[HIGH][Z] = val + radimax;
- }
- }
- root = (-aprime[1] + rad)/(2.0*aprime[2]);
- if (root > 0.0 && root < 1.0){
- val = a[0] + (a[1] + (a[2] + a[3]*root)*root)*root;
-
- if (val - radimax < bounds[LOW][Z]){
- bounds[LOW][Z] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Z]){
- bounds[HIGH][Z] = val + radimax;
- }
- }
- }
- }
-
- val = a[0];
- if (val - radimax < bounds[LOW][Z]){
- bounds[LOW][Z] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Z]){
- bounds[HIGH][Z] = val + radimax;
- }
- val = a[0] + a[1] + a[2] + a[3];
- if (val - radimax < bounds[LOW][Z]){
- bounds[LOW][Z] = val - radimax;
- }
- if (val + radimax > bounds[HIGH][Z]){
- bounds[HIGH][Z] = val + radimax;
- }
-
-
- }
-
- void
- SweptSphStats(tests, hits)
- unsigned long *tests, *hits;
- {
- *tests = SweptSphTests;
- *hits = SweptSphHits;
- }
-
- char *SweptSphName()
- {
- return sweptsphName;
- }
-
- /* evaluate a polynomial at x */
-
- Float evalpoly(p,order,x)
- Float *p,x;
- int order;
- {
- Float val;
- int i;
-
- val = p[order];
-
- for (i = order - 1; i >= 0; i--){
- val = p[i] + val*x;
- }
- return val;
-
- }
-
- /* use bisection to find the root */
- int findit(p,order,minx,maxx,root)
- Float *p,minx,maxx,*root;
- int order;
- {
- Float minval, val, midx;
- int i;
-
- minval = evalpoly(p,order,minx);
-
- /* bichecks++;
-
- if((newchecks+bichecks)%10000 == 0){
- fprintf(stderr,"Checks: %i(%i) Bisection: %.2f Newton: %.2f Both %.2f (%.2f) \n",bichecks+newchecks,newchecks, (Float)bitests/(Float)bichecks,(Float)newtons/(Float)newchecks,(Float)(bitests+newtons)/(Float)(bichecks+newchecks),(Float)(bitests+newtons)/(Float)newchecks);
- fflush(stderr);
- }
- */
- i = 0;
- while(fabs(minx-maxx) > DBL_EPS){
-
- midx = (maxx + minx)/2.0;
-
- val = evalpoly(p,order,midx);
-
- if (fabs(val) < SMALLNUM) break;
-
- if(val*minval < 0){
- maxx = midx;
- }
- else {
- minx = midx;
- minval = val;
- }
- /* bitests++;
- */ i++;
- if (i > COUNT2) {
- maxcount++;
- break;
- }
- }
-
- *root = midx;
- return TRUE;
-
- }
-
- /* use Newton's method to find the root */
-
- int newtonit(p,order,minx,maxx,root)
- Float *p,minx,maxx,*root;
- int order;
- {
- Float val, x, *pprime, oldval, oldx, m;
- int i;
-
- /*
- newchecks++;
-
- if((newchecks+bichecks)%10000 == 0){
- fprintf(stderr,"Checks: %i(%i) Bisection: %.2f Newton: %.2f Both %.2f (%.2f) \n",bichecks+newchecks,newchecks, (Float)bitests/(Float)bichecks,(Float)newtons/(Float)newchecks,(Float)(bitests+newtons)/(Float)(bichecks+newchecks),(Float)(bitests+newtons)/(Float)newchecks);
- fflush(stderr);
- }
- */
- pprime = (Float *)malloc(order*sizeof(Float));
-
- for (i = 0; i < order; i++){
- pprime[i] = (i+1)*p[i+1];
- }
-
- oldx = maxx;
- oldval = evalpoly(p,order,maxx);
-
- /* first point is where the line through the interval end points
- equals zero */
- m = (oldval - evalpoly(p,order,minx))/(maxx - minx);
- x = (m*maxx - oldval)/m;
- val = evalpoly(p,order,x);
-
-
- i = 0;
-
- while(fabs(val) > SMALLNUM || fabs(oldx-x) > DBL_EPS){
- oldx = x;
- oldval = val;
- x = x - val/evalpoly(pprime,order-1,x);
- val = evalpoly(p,order,x);
- /* exit if the new x is outside [umin,umax] */
- if (x > maxx || x < minx){
- free(pprime);
- return FALSE;
- }
- /* newtons++;
- */ i++;
- /* exit if we haven't found the root after COUNT iterations
- (in case we are at a point where we are bouncing
- back and forth without getting closer to the root.
- Perhaps a different test would be better)
- */
- if (i > COUNT){
- free(pprime);
- return FALSE;
- }
- }
-
- free(pprime);
- *root = x;
- return TRUE;
-
- }
-
-
-
- /* FindRoots finds the roots to a polynomial by reducing the polynomial
- down to it's 2nd order derivative then using the roots of the derivative
- as the max,min points between which there can be only one zero point, if
- any, for the next higher derivative.
-
- Roots for greater than 2nd order polynomials are found by first trying
- Newton's method and if that fails, then using bisection.
-
- This algorithm probably could use alot of work to make it faster than
- it currently is. I was not particularly sure what to use as determining
- factors for the Newton's methods failure. One was finding a new x value
- outside the current search range, which would result in finding the
- wrong root, the other was an upper limit on the number of iterations
- performed. This last test was to insure that we did not get caught in
- a loop where each sucssesive iteration returned us to the previous x
- value.
- */
-
- int FindRoots(p,order,lower,upper,roots)
- Float *p,lower, upper;
- int order;
- Float *roots;
- {
- Float *pprime, *droots, rad, root, lowerval,upperval, rootval, oldrootval;
- int num, i, j, minindex, found;
-
- if (p[order] < SMALLNUM){
- return FindRoots(p,order-1,lower,upper,roots);
- }
- if (order == 0) return 0;
- if (order == 1){
- root = -p[0]/p[1];
- if (root > lower && root < upper){
- roots[0] = root;
- return 1;
- }
- return 0;
- }
-
- found = 0;
- if (order == 2) {
- rad = p[1]*p[1] - 4*p[0]*p[2];
- if (rad < 0) return 0;
- if (rad == 0) {
- root = -p[1]/(2.0*p[2]);
- if (root > lower && root < upper){
- roots[0] = root;
- return 1;
- }
- return 0;
- }
-
- rad = sqrt(rad);
- root = (-p[1]-rad)/(2.0*p[2]);
- if (root > lower && root < upper){
- roots[found] = root;
- found++;
- }
- root = (-p[1]+rad)/(2.0*p[2]);
- if (root > lower && root < upper){
- roots[found] = root;
- found++;
- }
- if (found == 2){
- if (roots[0] > roots[1]){
- root = roots[0];
- roots[0] = roots[1];
- roots[1] = root;
- }
- }
- return found;
- }
-
- droots = (Float*)malloc((order-1)*sizeof(Float));
- pprime = (Float*)malloc((order)*sizeof(Float));
-
- if (droots == NULL || pprime == NULL){
- fprintf(stderr,"\n\nNot enough memory\n\n");
- exit (1);
- }
-
- pprime[0] = p[1];
-
- /* calculate the derivative of p */
- for (i = 1; i < order; i++){
- pprime[i] = (i+1)*p[i+1];
- }
-
- /* find the roots of the derivative which will be p's max and min
- points */
- num = FindRoots(pprime,order-1, lower, upper,droots);
-
- free(pprime);
-
- lowerval = evalpoly(p,order,lower);
- upperval = evalpoly(p,order,upper);
-
- /* no max,min found check the interval (lower,upper) */
- if (num == 0){
- free(droots);
- if (lowerval*upperval < 0){
- if (newtonit(p,order,lower,upper,&roots[0]) == FALSE){
- if (findit(p,order,lower,upper,&roots[0]) == FALSE){
- fprintf(stderr,"Neither found the root!!");
- return 0;
- }
- else {
- return 1;
- }
- }
- return 1;
- }
- return 0;
- }
-
- found = 0;
-
- /* check the interval (lower,1st_root] */
- rootval = evalpoly(p,order,droots[0]);
-
- if (fabs(rootval) < SMALLNUM){
- roots[found] = droots[0];
- found++;
- }
- else if (lowerval*rootval < 0){
- if (newtonit(p,order,lower,droots[0],&root) == TRUE) {
- roots[found] = root;
- found++;
- }
- else if (findit(p,order,lower,droots[0],&root) == TRUE) {
- roots[found] = root;
- found++;
- }
-
- }
-
- /* check the intervals (nth_root,(n+1)th_root] for n = 1 to (num - 1) */
- for(i = 1 ; i < num; i++){
- oldrootval = rootval;
- rootval = evalpoly(p,order,droots[i]);
- if (fabs(rootval) < SMALLNUM){
- roots[found] = droots[i];
- found++;
- }
- else if (rootval*oldrootval < 0){
- if (newtonit(p,order,droots[i-1],droots[i],&root) == TRUE) {
- roots[found] = root;
- found++;
- }
- else if (findit(p,order,droots[i-1],droots[i],&root) == TRUE) {
- roots[found] = root;
- found++;
- }
- }
- }
-
- /* check the interval ((num)th_root,upper) */
- if (fabs(rootval) > SMALLNUM){
- if (rootval*upperval < 0){
- if (newtonit(p,order,droots[num-1],upper,&root) == TRUE) {
- roots[found] = root;
- found++;
- }
- else if (findit(p,order,droots[num-1],upper,&root) == TRUE) {
- roots[found] = root;
- found++;
- }
- }
- }
-
- free(droots);
- return found;
-
- }
-