/**************************************************************************** * lathe.c * * This module implements functions that manipulate lathes. * * This module was written by Dieter Bayer [DB]. * * from Persistence of Vision(tm) Ray Tracer * Copyright 1996 Persistence of Vision Team *--------------------------------------------------------------------------- * NOTICE: This source code file is provided so that users may experiment * with enhancements to POV-Ray and to port the software to platforms other * than those supported by the POV-Ray Team. There are strict rules under * which you are permitted to use this file. The rules are in the file * named POVLEGAL.DOC which should be distributed with this file. If * POVLEGAL.DOC is not available or for more info please contact the POV-Ray * Team Coordinator by leaving a message in CompuServe's Graphics Developer's * Forum. The latest version of POV-Ray may be found there as well. * * This program is based on the popular DKB raytracer version 2.12. * DKBTrace was originally written by David K. Buck. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. * *****************************************************************************/ /**************************************************************************** * * Explanation: * * The lathe primitive is defined by a set of points in 2d space which * are interpolated by linear, quadratic, or cubic splines. The resulting * 2d curve is rotated about an axis to form the final lathe object. * * All calculations are done in the object's (u,v,w)-coordinate system * with the (w)-axis being the rotation axis. * * One spline segment in the (r,w)-plane is given by the equations * * fw(t) = Aw * t^3 + Bw * t^2 + Cw * t + Dw and * fr(t) = Ar * t^3 + Br * t^2 + Cr * t + Dr, * * with the parameter t ranging from 0 to 1 and r = sqrt(u*u+v*v). * * To intersect a ray R = P + k * D transformed into the object's * coordinate system with the lathe object, the equations * * (Pu + k * Du)^2 + (Pv + k * Dv)^2 = (fr(t))^2 * (Pw + k * Dw) = fw(t) * * have to be solved for t. For valid intersections (0 <= t <= 1) * the corresponding k can be calculated from one of the above equations. * * Note that the degree of the polynomal to solve is two times the * degree of the spline segments used. * * Note that Pu, Pv, Pw and Du, Dv, Dw denote the coordinates * of the vectors P and D. * * Syntax: * * lathe * { * [ linear_spline | quadratic_spline | cubic_spline ] * * number_of_points, * * , * * [ sturm ] * } * * Note that the P[i] are 2d vectors. * * Linear interpolation is used by default. In this case all n Points * are used. In the quadratic case the first point is used to determine * the derivates at the starting point P[1]. In the cubic case * the first and last points are used to determine the derivatives at * the starting point P[1] and ending point P[n-2]. * * To get a closed (and smooth) curve you have make sure that * * P[0] = P[n-1] in the linear case, * * P[0] = P[n-2] and P[1] = P[n-1] in the quadratic case, and * * P[0] = P[n-3] and P[1] = P[n-2] and P[2] = P[n-1] in the cubic case. * * Note that the x coordinate of a point corresponds to the r coordinate * and the y coordinate to the w coordinate; * * --- * * Ideas for the lathe were taken from: * * P. Burger and D. Gillies, "Rapid Ray Tracing of General Surfaces * of Revolution", New Advances in Computer Graphics, Proceedings * of CG International '89, R. A. Earnshaw, B. Wyvill (Eds.), * Springer, ..., pp. 523-531 * * P. Burger and D. Gillies, "Swept Surfaces", Interactive Computer * Graphics, Addison-Wesley, 1989, pp. 376-380 * * --- * * Jun 1994 : Creation. [DB] * *****************************************************************************/ #include "frame.h" #include "povray.h" #include "vector.h" #include "povproto.h" #include "bbox.h" #include "lathe.h" #include "polysolv.h" #include "matrices.h" #include "objects.h" #include "torus.h" /***************************************************************************** * Local preprocessor defines ******************************************************************************/ /* Minimal intersection depth for a valid intersection. */ #define DEPTH_TOLERANCE 1.0e-4 /* Max. number of intersecions per spline segment. */ #define MAX_INTERSECTIONS_PER_SEGMENT 4 /***************************************************************************** * Local typedefs ******************************************************************************/ /***************************************************************************** * Static functions ******************************************************************************/ static int intersect_lathe PARAMS((RAY *Ray, LATHE *Lathe, ISTACK *Depth_Stack)); static int All_Lathe_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)); static int Inside_Lathe PARAMS((VECTOR point, OBJECT *Object)); static void Lathe_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter)); static void *Copy_Lathe PARAMS((OBJECT *Object)); static void Translate_Lathe PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Rotate_Lathe PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Scale_Lathe PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Transform_Lathe PARAMS((OBJECT *Object, TRANSFORM *Trans)); static void Invert_Lathe PARAMS((OBJECT *Object)); static void Destroy_Lathe PARAMS((OBJECT *Object)); static int test_hit PARAMS((LATHE *, RAY *, ISTACK *, DBL, DBL, int)); /***************************************************************************** * Local variables ******************************************************************************/ static METHODS Lathe_Methods = { All_Lathe_Intersections, Inside_Lathe, Lathe_Normal, Copy_Lathe, Translate_Lathe, Rotate_Lathe, Scale_Lathe, Transform_Lathe, Invert_Lathe, Destroy_Lathe }; /***************************************************************************** * * FUNCTION * * All_Lathe_Intersections * * INPUT * * Object - Object * Ray - Ray * Depth_Stack - Intersection stack * * OUTPUT * * Depth_Stack * * RETURNS * * int - TRUE, if a intersection was found * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Determine ray/lathe intersection and clip intersection found. * * CHANGES * * Jun 1994 : Creation. * Oct 1996 : Changed code to include faster version. [DB] * ******************************************************************************/ static int All_Lathe_Intersections(Object, Ray, Depth_Stack) OBJECT *Object; RAY *Ray; ISTACK *Depth_Stack; { Increase_Counter(stats[Ray_Lathe_Tests]); if (intersect_lathe(Ray, (LATHE *)Object, Depth_Stack)) { Increase_Counter(stats[Ray_Lathe_Tests_Succeeded]); return(TRUE); } return(FALSE); } /***************************************************************************** * * FUNCTION * * intersect_lathe * * INPUT * * Ray - Ray * Lathe - Lathe * Intersection - Lathe intersection structure * * OUTPUT * * Intersection * * RETURNS * * int - Number of intersections found * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Determine ray/lathe intersection. * * NOTE: The curve is rotated about the y-axis! * Order of the polynomial must not be used! * * CHANGES * * Jun 1994 : Creation. * Oct 1996 : Changed code to include faster version. [DB] * ******************************************************************************/ static int intersect_lathe(Ray, Lathe, Depth_Stack) RAY *Ray; LATHE *Lathe; ISTACK *Depth_Stack; { int cnt; int found, j, n1, n2; DBL k, len, r, m, w, Dy2, r0; DBL x1[7], x2[3], y1[6], y2[2]; DBL best; VECTOR P, D; BCYL_INT *intervals; LATHE_SPLINE_ENTRY *Entry; /* Transform the ray into the lathe space. */ MInvTransPoint(P, Ray->Initial, Lathe->Trans); MInvTransDirection(D, Ray->Direction, Lathe->Trans); VLength(len, D); VInverseScaleEq(D, len); /* Test if ray misses lathe's cylindrical bound. */ #ifdef LATHE_EXTRA_STATS Increase_Counter(stats[Lathe_Bound_Tests]); #endif if (((D[Y] >= 0.0) && (P[Y] > Lathe->Height2)) || ((D[Y] <= 0.0) && (P[Y] < Lathe->Height1)) || ((D[X] >= 0.0) && (P[X] > Lathe->Radius2)) || ((D[X] <= 0.0) && (P[X] < -Lathe->Radius2))) { return(FALSE); } /* Get distance r0 of the ray from rotation axis (i.e. y axis). */ r0 = fabs(P[X] * D[Z] - P[Z] * D[X]); r = D[X] * D[X] + D[Z] * D[Z]; if (r > 0.0) { r0 /= sqrt(r); } /* Test if ray misses lathe's cylindrical bound. */ if (r0 > Lathe->Radius2) { return(FALSE); } /* Intersect all cylindrical bounds. */ if ((cnt = Intersect_BCyl(Lathe->Spline->BCyl, P, D)) == 0) { return(FALSE); } #ifdef LATHE_EXTRA_STATS Increase_Counter(stats[Lathe_Bound_Tests_Succeeded]); #endif /* Precalculate some constants that are ray-dependant only. */ m = D[X] * P[X] + D[Z] * P[Z]; Dy2 = D[Y] * D[Y]; /* Step through the list of intersections. */ found = FALSE; best = BOUND_HUGE; intervals = Lathe->Spline->BCyl->intervals; for (j = 0; j < cnt; j++) { /* Get current segment. */ Entry = &Lathe->Spline->Entry[intervals[j].n]; /* If we already have the best intersection we may exit. */ if (!(Lathe->Type & IS_CHILD_OBJECT) && (intervals[j].d[0] > best)) { break; } /* Init number of roots found. */ n1 = 0; /* Intersect segment. */ switch (Lathe->Spline_Type) { /*********************************************************************** * Linear spline. ************************************************************************/ case LINEAR_SPLINE: /* Solve 2th order polynomial. */ x1[0] = Entry->C[Y] * Entry->C[Y] * r - Entry->C[X] * Entry->C[X] * Dy2; x1[1] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2); x1[2] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]); n1 = Solve_Polynomial(2, x1, y1, FALSE, 0.0); break; /*********************************************************************** * Quadratic spline. ************************************************************************/ case QUADRATIC_SPLINE: /* Solve 4th order polynomial. */ x1[0] = Entry->B[Y] * Entry->B[Y] * r - Entry->B[X] * Entry->B[X] * Dy2; x1[1] = 2.0 * (Entry->B[Y] * Entry->C[Y] * r - Entry->B[X] * Entry->C[X] * Dy2); x1[2] = r * (2.0 * Entry->B[Y] * (Entry->D[Y] - P[Y]) + Entry->C[Y] * Entry->C[Y]) + 2.0 * Entry->B[Y] * D[Y] * m - (2.0 * Entry->B[X] * Entry->D[X] + Entry->C[X] * Entry->C[X]) * Dy2; x1[3] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2); x1[4] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]); n1 = Solve_Polynomial(4, x1, y1, Test_Flag(Lathe, STURM_FLAG), 0.0); break; /*********************************************************************** * Cubic spline. ************************************************************************/ case CUBIC_SPLINE: /* Solve 6th order polynomial. */ x1[0] = Entry->A[Y] * Entry->A[Y] * r - Entry->A[X] * Entry->A[X] * Dy2; x1[1] = 2.0 * (Entry->A[Y] * Entry->B[Y] * r - Entry->A[X] * Entry->B[X] * Dy2); x1[2] = (2.0 * Entry->A[Y] * Entry->C[Y] + Entry->B[Y] * Entry->B[Y]) * r - (2.0 * Entry->A[X] * Entry->C[X] + Entry->B[X] * Entry->B[X]) * Dy2; x1[3] = 2.0 * ((Entry->A[Y] * Entry->D[Y] + Entry->B[Y] * Entry->C[Y] - Entry->A[Y] * P[Y]) * r + Entry->A[Y] * D[Y] * m - (Entry->A[X] * Entry->D[X] + Entry->B[X] * Entry->C[X]) * Dy2); x1[4] = (2.0 * Entry->B[Y] * (Entry->D[Y] - P[Y]) + Entry->C[Y] * Entry->C[Y]) * r + 2.0 * Entry->B[Y] * D[Y] * m - (2.0 * Entry->B[X] * Entry->D[X] + Entry->C[X] * Entry->C[X]) * Dy2; x1[5] = 2.0 * (Entry->C[Y] * ((Entry->D[Y] - P[Y]) * r + D[Y] * m) - Entry->C[X] * Entry->D[X] * Dy2); x1[6] = (Entry->D[Y] - P[Y]) * ((Entry->D[Y] - P[Y]) * r + 2.0 * D[Y] * m) + Dy2 * (P[X] * P[X] + P[Z] * P[Z] - Entry->D[X] * Entry->D[X]); n1 = Solve_Polynomial(6, x1, y1, Test_Flag(Lathe, STURM_FLAG), 0.0); break; } /* Test roots for valid intersections. */ while (n1--) { w = y1[n1]; if ((w >= 0.0) && (w <= 1.0)) { if (fabs(D[Y]) > EPSILON) { k = (w * (w * (w * Entry->A[Y] + Entry->B[Y]) + Entry->C[Y]) + Entry->D[Y] - P[Y]) / D[Y]; if (test_hit(Lathe, Ray, Depth_Stack, k / len, w, intervals[j].n)) { found = TRUE; if (k < best) { best = k; } } } else { k = w * (w * (w * Entry->A[X] + Entry->B[X]) + Entry->C[X]) + Entry->D[X]; x2[0] = r; x2[1] = 2.0 * m; x2[2] = P[X] * P[X] + P[Z] * P[Z] - k * k; n2 = Solve_Polynomial(2, x2, y2, FALSE, 0.0); while (n2--) { k = y2[n2]; if (test_hit(Lathe, Ray, Depth_Stack, k / len, w, intervals[j].n)) { found = TRUE; if (k < best) { best = k; } } } } } } } return(found); } /***************************************************************************** * * FUNCTION * * Inside_Lathe * * INPUT * * IPoint - Intersection point * Object - Object * * OUTPUT * * RETURNS * * int - TRUE if inside * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Test if a point lies inside the lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static int Inside_Lathe(IPoint, Object) VECTOR IPoint; OBJECT *Object; { int i, n, NC; DBL r, k, w; DBL x[4], y[3]; DBL *height, *radius; VECTOR P; BCYL_ENTRY *entry; LATHE_SPLINE_ENTRY *Entry; LATHE *Lathe = (LATHE *)Object; height = Lathe->Spline->BCyl->height; radius = Lathe->Spline->BCyl->radius; entry = Lathe->Spline->BCyl->entry; /* Transform the point into the lathe space. */ MInvTransPoint(P, IPoint, Lathe->Trans); /* Number of crossings. */ NC = 0; if ((P[Y] >= Lathe->Height1) && (P[Y] <= Lathe->Height2)) { r = sqrt(P[X] * P[X] + P[Z] * P[Z]); if ((r >= Lathe->Radius1) && (r <= Lathe->Radius2)) { for (i = 0; i < Lathe->Number; i++) { Entry = &Lathe->Spline->Entry[i]; /* Test if we are inside the segments cylindrical bound. */ if ((P[Y] >= height[entry[i].h1] - EPSILON) && (P[Y] <= height[entry[i].h2] + EPSILON)) { x[0] = Entry->A[Y]; x[1] = Entry->B[Y]; x[2] = Entry->C[Y]; x[3] = Entry->D[Y] - P[Y]; n = Solve_Polynomial(3, x, y, Test_Flag(Lathe, STURM_FLAG), 0.0); while (n--) { w = y[n]; if ((w >= 0.0) && (w <= 1.0)) { k = w * (w * (w * Entry->A[X] + Entry->B[X]) + Entry->C[X]) + Entry->D[X] - r; if (k >= 0.0) { NC++; } } } } } } } if (NC & 1) { return(!Test_Flag(Lathe, INVERTED_FLAG)); } else { return(Test_Flag(Lathe, INVERTED_FLAG)); } } /***************************************************************************** * * FUNCTION * * Lathe_Normal * * INPUT * * Result - Normal vector * Object - Object * Inter - Intersection found * * OUTPUT * * Result * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Calculate the normal of the lathe in a given point. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static void Lathe_Normal(Result, Object, Inter) OBJECT *Object; VECTOR Result; INTERSECTION *Inter; { DBL r, dx, dy; VECTOR P, N; LATHE *Lathe = (LATHE *)Object; LATHE_SPLINE_ENTRY *Entry; Entry = &Lathe->Spline->Entry[Inter->i1]; /* Transform the point into the lathe space. */ MInvTransPoint(P, Inter->IPoint, Lathe->Trans); /* Get distance from rotation axis. */ r = P[X] * P[X] + P[Z] * P[Z]; if (r > EPSILON) { r = sqrt(r); /* Get derivatives. */ dx = Inter->d1 * (3.0 * Entry->A[X] * Inter->d1 + 2.0 * Entry->B[X]) + Entry->C[X]; dy = Inter->d1 * (3.0 * Entry->A[Y] * Inter->d1 + 2.0 * Entry->B[Y]) + Entry->C[Y]; /* Get normal by rotation. */ N[X] = dy * P[X]; N[Y] = -dx * r; N[Z] = dy * P[Z]; } else { N[X] = N[Z] = 0.0; N[Y] = 1.0; } /* Transform the normalt out of the lathe space. */ MTransNormal(Result, N, Lathe->Trans); VNormalize(Result, Result); } /***************************************************************************** * * FUNCTION * * Translate_Lathe * * INPUT * * Object - Object * Vector - Translation vector * * OUTPUT * * Object * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Translate a lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static void Translate_Lathe(Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { Transform_Lathe(Object, Trans); } /***************************************************************************** * * FUNCTION * * Rotate_Lathe * * INPUT * * Object - Object * Vector - Rotation vector * * OUTPUT * * Object * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Rotate a lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static void Rotate_Lathe(Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { Transform_Lathe(Object, Trans); } /***************************************************************************** * * FUNCTION * * Scale_Lathe * * INPUT * * Object - Object * Vector - Scaling vector * * OUTPUT * * Object * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Scale a lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static void Scale_Lathe(Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { Transform_Lathe(Object, Trans); } /***************************************************************************** * * FUNCTION * * Transform_Lathe * * INPUT * * Object - Object * Trans - Transformation to apply * * OUTPUT * * Object * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Transform a lathe and recalculate its bounding box. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static void Transform_Lathe(Object, Trans) OBJECT *Object; TRANSFORM *Trans; { Compose_Transforms(((LATHE *)Object)->Trans, Trans); Compute_Lathe_BBox((LATHE *)Object); } /***************************************************************************** * * FUNCTION * * Invert_Lathe * * INPUT * * Object - Object * * OUTPUT * * Object * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Invert a lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ static void Invert_Lathe(Object) OBJECT *Object; { Invert_Flag(Object, INVERTED_FLAG); } /***************************************************************************** * * FUNCTION * * Create_Lathe * * INPUT * * OUTPUT * * RETURNS * * LATHE * - new lathe * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Create a new lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ LATHE *Create_Lathe() { LATHE *New; New = (LATHE *)POV_MALLOC(sizeof(LATHE), "lathe"); INIT_OBJECT_FIELDS(New,LATHE_OBJECT,&Lathe_Methods) New->Trans = Create_Transform(); New->Spline_Type = LINEAR_SPLINE; New->Number = 0; New->Spline = NULL; New->Radius1 = New->Radius2 = New->Height1 = New->Height2 = 0.0; return(New); } /***************************************************************************** * * FUNCTION * * Copy_Lathe * * INPUT * * Object - Object * * OUTPUT * * RETURNS * * void * - New lathe * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Copy a lathe structure. * * NOTE: The splines are not copied, only the number of references is * counted, so that Destray_Lathe() knows if they can be destroyed. * * CHANGES * * Jun 1994 : Creation. * * Sep 1994 : Fixed memory leakage bug. [DB] * ******************************************************************************/ static void *Copy_Lathe(Object) OBJECT *Object; { LATHE *New, *Lathe = (LATHE *)Object; New = Create_Lathe(); /* Get rid of the transformation created in Create_Lathe(). */ Destroy_Transform(New->Trans); /* Copy lathe. */ *New = *Lathe; New->Trans = Copy_Transform(Lathe->Trans); New->Spline->References++; return(New); } /***************************************************************************** * * FUNCTION * * Destroy_Lathe * * INPUT * * Object - Object * * OUTPUT * * Object * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Destroy a lathe. * * NOTE: The splines are destroyed if they are no longer used by any copy. * * CHANGES * * Jun 1994 : Creation. * Oct 1996 : Changed code to include faster version. [DB] * ******************************************************************************/ static void Destroy_Lathe(Object) OBJECT *Object; { LATHE *Lathe = (LATHE *)Object; Destroy_Transform(Lathe->Trans); if (--(Lathe->Spline->References) == 0) { Destroy_BCyl(Lathe->Spline->BCyl); POV_FREE(Lathe->Spline->Entry); POV_FREE(Lathe->Spline); } POV_FREE (Object); } /***************************************************************************** * * FUNCTION * * Compute_Lathe_BBox * * INPUT * * Lathe - Lathe * * OUTPUT * * Lathe * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Calculate the bounding box of a lathe. * * CHANGES * * Jun 1994 : Creation. * ******************************************************************************/ void Compute_Lathe_BBox(Lathe) LATHE *Lathe; { Make_BBox(Lathe->BBox, -Lathe->Radius2, Lathe->Height1, -Lathe->Radius2, 2.0 * Lathe->Radius2, Lathe->Height2 - Lathe->Height1, 2.0 * Lathe->Radius2); Recompute_BBox(&Lathe->BBox, Lathe->Trans); } /***************************************************************************** * * FUNCTION * * Compute_Lathe * * INPUT * * Lathe - Lathe * P - Points defining lathe * * OUTPUT * * Lathe * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Calculate the spline segments of a lathe from a set of points. * * Note that the number of points in the lathe has to be set. * * CHANGES * * Jun 1994 : Creation. * Oct 1996 : Changed code to include faster version. [DB] * ******************************************************************************/ void Compute_Lathe(Lathe, P) LATHE *Lathe; UV_VECT *P; { int i, n; DBL x[4], xmin, xmax; DBL y[4], ymin, ymax; DBL c[3], r[2]; DBL *tmp_r1; DBL *tmp_r2; DBL *tmp_h1; DBL *tmp_h2; UV_VECT A, B, C, D; /* Allocate Lathe->Number segments. */ if (Lathe->Spline == NULL) { Lathe->Spline = (LATHE_SPLINE *)POV_MALLOC(sizeof(LATHE_SPLINE), "spline segments of lathe"); /* Init spline. */ Lathe->Spline->References = 1; Lathe->Spline->Entry = (LATHE_SPLINE_ENTRY *)POV_MALLOC(Lathe->Number*sizeof(LATHE_SPLINE_ENTRY), "spline segments of lathe"); } else { /* This should never happen! */ Error("Lathe segments are already defined.\n"); } /* Allocate temporary lists. */ tmp_r1 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data"); tmp_r2 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data"); tmp_h1 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data"); tmp_h2 = (DBL *)POV_MALLOC(Lathe->Number * sizeof(DBL), "temp lathe data"); /*************************************************************************** * Calculate segments. ****************************************************************************/ /* We want to know the size of the overall bounding cylinder. */ xmax = ymax = -BOUND_HUGE; xmin = ymin = BOUND_HUGE; for (i = 0; i < Lathe->Number; i++) { switch (Lathe->Spline_Type) { /************************************************************************* * Linear spline (nothing more than a simple polygon). **************************************************************************/ case LINEAR_SPLINE: /* Use linear interpolation. */ A[X] = 0.0; B[X] = 0.0; C[X] = -1.0 * P[i][X] + 1.0 * P[i+1][X]; D[X] = 1.0 * P[i][X]; A[Y] = 0.0; B[Y] = 0.0; C[Y] = -1.0 * P[i][Y] + 1.0 * P[i+1][Y]; D[Y] = 1.0 * P[i][Y]; /* Get maximum coordinates in current segment. */ x[0] = x[2] = P[i][X]; x[1] = x[3] = P[i+1][X]; y[0] = y[2] = P[i][Y]; y[1] = y[3] = P[i+1][Y]; break; /************************************************************************* * Quadratic spline. **************************************************************************/ case QUADRATIC_SPLINE: /* Use quadratic interpolation. */ A[X] = 0.0; B[X] = 0.5 * P[i][X] - 1.0 * P[i+1][X] + 0.5 * P[i+2][X]; C[X] = -0.5 * P[i][X] + 0.5 * P[i+2][X]; D[X] = 1.0 * P[i+1][X]; A[Y] = 0.0; B[Y] = 0.5 * P[i][Y] - 1.0 * P[i+1][Y] + 0.5 * P[i+2][Y]; C[Y] = -0.5 * P[i][Y] + 0.5 * P[i+2][Y]; D[Y] = 1.0 * P[i+1][Y]; /* Get maximum coordinates in current segment. */ x[0] = x[2] = P[i+1][X]; x[1] = x[3] = P[i+2][X]; y[0] = y[2] = P[i+1][Y]; y[1] = y[3] = P[i+2][Y]; break; /************************************************************************* * Cubic spline. **************************************************************************/ case CUBIC_SPLINE: /* Use cubic interpolation. */ A[X] = -0.5 * P[i][X] + 1.5 * P[i+1][X] - 1.5 * P[i+2][X] + 0.5 * P[i+3][X]; B[X] = P[i][X] - 2.5 * P[i+1][X] + 2.0 * P[i+2][X] - 0.5 * P[i+3][X]; C[X] = -0.5 * P[i][X] + 0.5 * P[i+2][X]; D[X] = P[i+1][X]; A[Y] = -0.5 * P[i][Y] + 1.5 * P[i+1][Y] - 1.5 * P[i+2][Y] + 0.5 * P[i+3][Y]; B[Y] = P[i][Y] - 2.5 * P[i+1][Y] + 2.0 * P[i+2][Y] - 0.5 * P[i+3][Y]; C[Y] = -0.5 * P[i][Y] + 0.5 * P[i+2][Y]; D[Y] = P[i+1][Y]; /* Get maximum coordinates in current segment. */ x[0] = x[2] = P[i+1][X]; x[1] = x[3] = P[i+2][X]; y[0] = y[2] = P[i+1][Y]; y[1] = y[3] = P[i+2][Y]; break; default: Error("Unknown lathe type in Compute_Lathe().\n"); } Assign_UV_Vect(Lathe->Spline->Entry[i].A, A); Assign_UV_Vect(Lathe->Spline->Entry[i].B, B); Assign_UV_Vect(Lathe->Spline->Entry[i].C, C); Assign_UV_Vect(Lathe->Spline->Entry[i].D, D); /* Get maximum coordinates in current segment. */ c[0] = 3.0 * A[X]; c[1] = 2.0 * B[X]; c[2] = C[X]; n = Solve_Polynomial(2, c, r, FALSE, 0.0); while (n--) { if ((r[n] >= 0.0) && (r[n] <= 1.0)) { x[n] = r[n] * (r[n] * (r[n] * A[X] + B[X]) + C[X]) + D[X]; } } c[0] = 3.0 * A[Y]; c[1] = 2.0 * B[Y]; c[2] = C[Y]; n = Solve_Polynomial(2, c, r, FALSE, 0.0); while (n--) { if ((r[n] >= 0.0) && (r[n] <= 1.0)) { y[n] = r[n] * (r[n] * (r[n] * A[Y] + B[Y]) + C[Y]) + D[Y]; } } /* Set current segment's bounding cylinder. */ tmp_r1[i] = min(min(x[0], x[1]), min(x[2], x[3])); tmp_r2[i] = max(max(x[0], x[1]), max(x[2], x[3])); tmp_h1[i] = min(min(y[0], y[1]), min(y[2], y[3])); tmp_h2[i] = max(max(y[0], y[1]), max(y[2], y[3])); /* Keep track of overall bounding cylinder. */ xmin = min(xmin, tmp_r1[i]); xmax = max(xmax, tmp_r2[i]); ymin = min(ymin, tmp_h1[i]); ymax = max(ymax, tmp_h2[i]); /* fprintf(stderr, "bound spline segment %d: ", i); fprintf(stderr, "r = %f - %f, h = %f - %f\n", tmp_r1[i], tmp_r2[i], tmp_h1[i], tmp_h2[i]); */ } /* Set overall bounding cylinder. */ Lathe->Radius1 = xmin; Lathe->Radius2 = xmax; Lathe->Height1 = ymin; Lathe->Height2 = ymax; /* Get bounding cylinder. */ Lathe->Spline->BCyl = Create_BCyl(Lathe->Number, tmp_r1, tmp_r2, tmp_h1, tmp_h2); /* Get rid of temp. memory. */ POV_FREE(tmp_h2); POV_FREE(tmp_h1); POV_FREE(tmp_r2); POV_FREE(tmp_r1); } /***************************************************************************** * * FUNCTION * * test_hit * * INPUT * * Lathe - Pointer to lathe structure * Ray - Current ray * Depth_Stack - Current depth stack * d, w, n - Intersection depth, parameter and segment number * * OUTPUT * * Depth_Stack * * RETURNS * * AUTHOR * * Dieter Bayer * * DESCRIPTION * * Test if a hit is valid and push if on the intersection depth. * * CHANGES * * Oct 1996 : Creation. * ******************************************************************************/ static int test_hit(Lathe, Ray, Depth_Stack, d, w, n) LATHE *Lathe; RAY *Ray; ISTACK *Depth_Stack; DBL d, w; int n; { VECTOR IPoint; if ((d > DEPTH_TOLERANCE) && (d < Max_Distance)) { VEvaluateRay(IPoint, Ray->Initial, d, Ray->Direction); if (Point_In_Clip(IPoint, ((OBJECT *)Lathe)->Clip)) { push_entry_i1_d1(d, IPoint, (OBJECT *)Lathe, n, w, Depth_Stack); return(TRUE); } } return(FALSE); }