/****************************************************************************
* quadrics.c
*
* This module implements the code for the quadric shape primitive.
*
* 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.
*
*****************************************************************************/
#include "frame.h"
#include "povray.h"
#include "vector.h"
#include "povproto.h"
#include "bbox.h"
#include "objects.h"
#include "matrices.h"
#include "planes.h"
#include "quadrics.h"
/*****************************************************************************
* Local preprocessor defines
******************************************************************************/
/* The following defines make typing much easier! [DB 7/94] */
#define Xd Ray->Direction[X]
#define Yd Ray->Direction[Y]
#define Zd Ray->Direction[Z]
#define Xo Ray->Initial[X]
#define Yo Ray->Initial[Y]
#define Zo Ray->Initial[Z]
#define QA Quadric->Square_Terms[X]
#define QE Quadric->Square_Terms[Y]
#define QH Quadric->Square_Terms[Z]
#define QB Quadric->Mixed_Terms[X]
#define QC Quadric->Mixed_Terms[Y]
#define QF Quadric->Mixed_Terms[Z]
#define QD Quadric->Terms[X]
#define QG Quadric->Terms[Y]
#define QI Quadric->Terms[Z]
#define QJ Quadric->Constant
/*****************************************************************************
* Static functions
******************************************************************************/
static int Intersect_Quadric PARAMS((RAY *Ray, QUADRIC *Quadric, DBL *Depth1, DBL *Depth2));
static void Quadric_To_Matrix PARAMS((QUADRIC *Quadric, MATRIX Matrix));
static void Matrix_To_Quadric PARAMS((MATRIX Matrix, QUADRIC *Quadric));
static int All_Quadric_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack));
static int Inside_Quadric PARAMS((VECTOR IPoint, OBJECT *Object));
static void Quadric_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter));
static void *Copy_Quadric PARAMS((OBJECT *Object));
static void Translate_Quadric PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
static void Rotate_Quadric PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
static void Scale_Quadric PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
static void Transform_Quadric PARAMS((OBJECT *Object, TRANSFORM *Trans));
static void Invert_Quadric PARAMS((OBJECT *Object));
static void Destroy_Quadric PARAMS((OBJECT *Object));
/*****************************************************************************
* Local variables
******************************************************************************/
METHODS Quadric_Methods =
{
All_Quadric_Intersections,
Inside_Quadric, Quadric_Normal,
Copy_Quadric,
Translate_Quadric, Rotate_Quadric,
Scale_Quadric, Transform_Quadric, Invert_Quadric,
Destroy_Quadric
};
/*****************************************************************************
*
* FUNCTION
*
* All_Quadric_Intersections
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static int All_Quadric_Intersections(Object, Ray, Depth_Stack)
OBJECT *Object;
RAY *Ray;
ISTACK *Depth_Stack;
{
DBL Depth1, Depth2;
VECTOR IPoint;
register int Intersection_Found;
Intersection_Found = FALSE;
if (Intersect_Quadric(Ray, (QUADRIC *)Object, &Depth1, &Depth2))
{
if ((Depth1 > Small_Tolerance) && (Depth1 < Max_Distance))
{
VEvaluateRay(IPoint, Ray->Initial, Depth1, Ray->Direction);
if (Point_In_Clip(IPoint, Object->Clip))
{
push_entry(Depth1, IPoint, Object, Depth_Stack);
Intersection_Found = TRUE;
}
}
if ((Depth2 > Small_Tolerance) && (Depth2 < Max_Distance))
{
VEvaluateRay(IPoint, Ray->Initial, Depth2, Ray->Direction);
if (Point_In_Clip(IPoint, Object->Clip))
{
push_entry(Depth2, IPoint, Object, Depth_Stack);
Intersection_Found = TRUE;
}
}
}
return(Intersection_Found);
}
/*****************************************************************************
*
* FUNCTION
*
* Intersect_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static int Intersect_Quadric(Ray, Quadric, Depth1, Depth2)
RAY *Ray;
QUADRIC *Quadric;
DBL *Depth1, *Depth2;
{
register DBL a, b, c, d;
Increase_Counter(stats[Ray_Quadric_Tests]);
a = Xd * (QA * Xd + QB * Yd + QC * Zd) +
Yd * (QE * Yd + QF * Zd) +
QH * Zd * Zd;
b = Xd * (QA * Xo + 0.5 * (QB * Yo + QC * Zo + QD)) +
Yd * (QE * Yo + 0.5 * (QB * Xo + QF * Zo + QG)) +
Zd * (QH * Zo + 0.5 * (QC * Xo + QF * Yo + QI));
c = Xo * (QA * Xo + QB * Yo + QC * Zo + QD) +
Yo * (QE * Yo + QF * Zo + QG) +
Zo * (QH * Zo + QI) +
QJ;
if (a != 0.0)
{
/* The equation is quadratic - find its roots */
d = Sqr(b) - a * c;
if (d <= 0.0)
{
return(FALSE);
}
d = sqrt (d);
*Depth1 = (-b + d) / (a);
*Depth2 = (-b - d) / (a);
}
else
{
/* There are no quadratic terms. Solve the linear equation instead. */
if (b == 0.0)
{
return(FALSE);
}
*Depth1 = - 0.5 * c / b;
*Depth2 = Max_Distance;
}
Increase_Counter(stats[Ray_Quadric_Tests_Succeeded]);
return(TRUE);
}
/*****************************************************************************
*
* FUNCTION
*
* Inside_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static int Inside_Quadric(IPoint, Object)
VECTOR IPoint;
OBJECT *Object;
{
QUADRIC *Quadric = (QUADRIC *)Object;
/* This is faster and shorter. [DB 7/94] */
return((IPoint[X] * (QA * IPoint[X] + QB * IPoint[Y] + QD) +
IPoint[Y] * (QE * IPoint[Y] + QF * IPoint[Z] + QG) +
IPoint[Z] * (QH * IPoint[Z] + QC * IPoint[X] + QI) + QJ) <= 0.0);
}
/*****************************************************************************
*
* FUNCTION
*
* Quadric_Normal
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Quadric_Normal(Result, Object, Inter)
OBJECT *Object;
VECTOR Result;
INTERSECTION *Inter;
{
QUADRIC *Quadric = (QUADRIC *) Object;
DBL Len;
/* This is faster and shorter. [DB 7/94] */
Result[X] = 2.0 * QA * Inter->IPoint[X] +
QB * Inter->IPoint[Y] +
QC * Inter->IPoint[Z] +
QD;
Result[Y] = QB * Inter->IPoint[X] +
2.0 * QE * Inter->IPoint[Y] +
QF * Inter->IPoint[Z] +
QG;
Result[Z] = QC * Inter->IPoint[X] +
QF * Inter->IPoint[Y] +
2.0 * QH * Inter->IPoint[Z] +
QI;
VLength(Len, Result);
if (Len == 0.0)
{
/* The normal is not defined at this point of the surface. */
/* Set it to any arbitrary direction. */
Make_Vector(Result, 1.0, 0.0, 0.0);
}
else
{
VInverseScaleEq(Result, Len);
}
}
/*****************************************************************************
*
* FUNCTION
*
* Transform_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Transform_Quadric(Object, Trans)
OBJECT *Object;
TRANSFORM *Trans;
{
QUADRIC *Quadric=(QUADRIC *)Object;
MATRIX Quadric_Matrix, Transform_Transposed;
Quadric_To_Matrix (Quadric, Quadric_Matrix);
MTimes (Quadric_Matrix, Trans->inverse, Quadric_Matrix);
MTranspose (Transform_Transposed, Trans->inverse);
MTimes (Quadric_Matrix, Quadric_Matrix, Transform_Transposed);
Matrix_To_Quadric (Quadric_Matrix, Quadric);
Recompute_BBox(&Object->BBox, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Quadric_To_Matrix
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Quadric_To_Matrix(Quadric, Matrix)
QUADRIC *Quadric;
MATRIX Matrix;
{
MZero (Matrix);
Matrix[0][0] = Quadric->Square_Terms[X];
Matrix[1][1] = Quadric->Square_Terms[Y];
Matrix[2][2] = Quadric->Square_Terms[Z];
Matrix[0][1] = Quadric->Mixed_Terms[X];
Matrix[0][2] = Quadric->Mixed_Terms[Y];
Matrix[0][3] = Quadric->Terms[X];
Matrix[1][2] = Quadric->Mixed_Terms[Z];
Matrix[1][3] = Quadric->Terms[Y];
Matrix[2][3] = Quadric->Terms[Z];
Matrix[3][3] = Quadric->Constant;
}
/*****************************************************************************
*
* FUNCTION
*
* Matrix_To_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Matrix_To_Quadric(Matrix, Quadric)
MATRIX Matrix;
QUADRIC *Quadric;
{
Quadric->Square_Terms[X] = Matrix[0][0];
Quadric->Square_Terms[Y] = Matrix[1][1];
Quadric->Square_Terms[Z] = Matrix[2][2];
Quadric->Mixed_Terms[X] = Matrix[0][1] + Matrix[1][0];
Quadric->Mixed_Terms[Y] = Matrix[0][2] + Matrix[2][0];
Quadric->Mixed_Terms[Z] = Matrix[1][2] + Matrix[2][1];
Quadric->Terms[X] = Matrix[0][3] + Matrix[3][0];
Quadric->Terms[Y] = Matrix[1][3] + Matrix[3][1];
Quadric->Terms[Z] = Matrix[2][3] + Matrix[3][2];
Quadric->Constant = Matrix[3][3];
}
/*****************************************************************************
*
* FUNCTION
*
* Translate_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Translate_Quadric(Object, Vector, Trans)
OBJECT *Object;
VECTOR Vector;
TRANSFORM *Trans;
{
Transform_Quadric (Object, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Rotate_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Rotate_Quadric(Object, Vector, Trans)
OBJECT *Object;
VECTOR Vector;
TRANSFORM *Trans;
{
Transform_Quadric (Object, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Scale_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Scale_Quadric(Object, Vector, Trans)
OBJECT *Object;
VECTOR Vector;
TRANSFORM *Trans;
{
Transform_Quadric (Object, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Invert_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Invert_Quadric(Object)
OBJECT *Object;
{
QUADRIC *Quadric = (QUADRIC *) Object;
VScaleEq(Quadric->Square_Terms, -1.0);
VScaleEq(Quadric->Mixed_Terms, -1.0);
VScaleEq(Quadric->Terms, -1.0);
Quadric->Constant *= -1.0;
Invert_Flag(Object, INVERTED_FLAG);
}
/*****************************************************************************
*
* FUNCTION
*
* Create_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
QUADRIC *Create_Quadric()
{
QUADRIC *New;
New = (QUADRIC *)POV_MALLOC(sizeof (QUADRIC), "quadric");
INIT_OBJECT_FIELDS(New, QUADRIC_OBJECT, &Quadric_Methods)
Make_Vector (New->Square_Terms, 1.0, 1.0, 1.0);
Make_Vector (New->Mixed_Terms, 0.0, 0.0, 0.0);
Make_Vector (New->Terms, 0.0, 0.0, 0.0);
New->Constant = 1.0;
return(New);
}
/*****************************************************************************
*
* FUNCTION
*
* Copy_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void *Copy_Quadric(Object)
OBJECT *Object;
{
QUADRIC *New;
New = Create_Quadric();
*New = *((QUADRIC *)Object);
return(New);
}
/*****************************************************************************
*
* FUNCTION
*
* Destroy_Quadric
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Destroy_Quadric(Object)
OBJECT *Object;
{
POV_FREE (Object);
}
/*****************************************************************************
*
* FUNCTION
*
* Compute_Quadric_BBox
*
* INPUT
*
* Quadric - Qaudric object
*
* OUTPUT
*
* Quadric
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Compute a bounding box around a quadric.
*
* This function calculates the bounding box of a quadric given in
* its normal form, i.e. f(x,y,z) = A*x^2 + E*y^2 + H*z^2 + J = 0.
*
* NOTE: Translated quadrics can also be bounded by this function.
*
* Supported: cones, cylinders, ellipsoids, hyperboloids.
*
* CHANGES
*
* May 1994 : Creation.
*
* Sep 1994 : Added support of hyperpoloids. Improved bounding of
* quadrics used in CSG intersections. [DB]
*
******************************************************************************/
void Compute_Quadric_BBox(Quadric, ClipMin, ClipMax)
QUADRIC *Quadric;
VECTOR ClipMin, ClipMax;
{
DBL A, B, C, D, E, F, G, H, I, J;
DBL a, b, c, d;
DBL rx, ry, rz, rx1, rx2, ry1, ry2, rz1, rz2, x, y, z;
DBL New_Volume, Old_Volume;
VECTOR Min, Max, TmpMin, TmpMax, NewMin, NewMax, T1;
BBOX Old;
OBJECT *Sib;
/*
* Check for 'normal' form. If the quadric isn't in it's normal form
* we can't do anything (we could, but that would be to tedious!
* Diagonalising the quadric's 4x4 matrix, i.e. finding its eigenvalues
* and eigenvectors -> solving a 4th order polynom).
*/
/* Get quadrics coefficients. */
A = Quadric->Square_Terms[X];
E = Quadric->Square_Terms[Y];
H = Quadric->Square_Terms[Z];
B = Quadric->Mixed_Terms[X] / 2.0;
C = Quadric->Mixed_Terms[Y] / 2.0;
F = Quadric->Mixed_Terms[Z] / 2.0;
D = Quadric->Terms[X] / 2.0;
G = Quadric->Terms[Y] / 2.0;
I = Quadric->Terms[Z] / 2.0;
J = Quadric->Constant;
/* Set small values to 0. */
if (fabs(A) < EPSILON) A = 0.0;
if (fabs(B) < EPSILON) B = 0.0;
if (fabs(C) < EPSILON) C = 0.0;
if (fabs(D) < EPSILON) D = 0.0;
if (fabs(E) < EPSILON) E = 0.0;
if (fabs(F) < EPSILON) F = 0.0;
if (fabs(G) < EPSILON) G = 0.0;
if (fabs(H) < EPSILON) H = 0.0;
if (fabs(I) < EPSILON) I = 0.0;
if (fabs(J) < EPSILON) J = 0.0;
/* Non-zero mixed terms --> return */
if ((B != 0.0) || (C != 0.0) || (F != 0.0))
{
return;
}
/* Non-zero linear terms --> get translation vector */
if ((D != 0.0) || (G != 0.0) || (I != 0.0))
{
if (A != 0.0)
{
T1[X] = -D / A;
}
else
{
if (D != 0.0)
{
T1[X] = J / (2.0 * D);
}
else
{
T1[X] = 0.0;
}
}
if (E != 0.0)
{
T1[Y] = -G / E;
}
else
{
if (G != 0.0)
{
T1[Y] = J / (2.0 * G);
}
else
{
T1[Y] = 0.0;
}
}
if (H != 0.0)
{
T1[Z] = -I / H;
}
else
{
if (I != 0.0)
{
T1[Z] = J / (2.0 * I);
}
else
{
T1[Z] = 0.0;
}
}
/* Recalculate coefficients. */
D += A * T1[X];
G += E * T1[Y];
I += H * T1[Z];
J -= T1[X]*(A*T1[X] + 2.0*D) + T1[Y]*(E*T1[Y] + 2.0*G) + T1[Z]*(H*T1[Z] + 2.0*I);
}
else
{
Make_Vector(T1, 0.0, 0.0, 0.0);
}
/* Get old bounding box. */
Old = Quadric->BBox;
/* Init new bounding box. */
NewMin[X] = NewMin[Y] = NewMin[Z] = -BOUND_HUGE/2;
NewMax[X] = NewMax[Y] = NewMax[Z] = BOUND_HUGE/2;
/* Get the bounding box of the clipping object. */
if (Quadric->Clip != NULL)
{
Min[X] = Min[Y] = Min[Z] = -BOUND_HUGE;
Max[X] = Max[Y] = Max[Z] = BOUND_HUGE;
/* Intersect the members bounding boxes. */
for (Sib = Quadric->Clip; Sib != NULL; Sib = Sib->Sibling)
{
if (!Test_Flag(Sib, INVERTED_FLAG))
{
if (Sib->Methods == &Plane_Methods)
{
Compute_Plane_Min_Max((PLANE *)Sib, TmpMin, TmpMax);
}
else
{
Make_min_max_from_BBox(TmpMin, TmpMax, Sib->BBox);
}
Min[X] = max(Min[X], TmpMin[X]);
Min[Y] = max(Min[Y], TmpMin[Y]);
Min[Z] = max(Min[Z], TmpMin[Z]);
Max[X] = min(Max[X], TmpMax[X]);
Max[Y] = min(Max[Y], TmpMax[Y]);
Max[Z] = min(Max[Z], TmpMax[Z]);
}
}
Assign_Vector(ClipMin, Min);
Assign_Vector(ClipMax, Max);
}
/* Translate clipping box. */
VSubEq(ClipMin, T1);
VSubEq(ClipMax, T1);
/* We want A to be non-negative. */
if (A < 0.0)
{
A = -A;
D = -D;
E = -E;
G = -G;
H = -H;
I = -I;
J = -J;
}
/*
*
* Check for ellipsoid.
*
* x*x y*y z*z
* ----- + ----- + ----- - 1 = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E > 0.0) && (H > 0.0) && (J < 0.0))
{
a = sqrt(-J/A);
b = sqrt(-J/E);
c = sqrt(-J/H);
NewMin[X] = -a;
NewMin[Y] = -b;
NewMin[Z] = -c;
NewMax[X] = a;
NewMax[Y] = b;
NewMax[Z] = c;
}
/*
*
* Check for cylinder (x-axis).
*
* y*y z*z
* ----- + ----- - 1 = 0
* b*b c*c
*
*/
if ((A == 0.0) && (E > 0.0) && (H > 0.0) && (J < 0.0))
{
b = sqrt(-J/E);
c = sqrt(-J/H);
NewMin[Y] = -b;
NewMin[Z] = -c;
NewMax[Y] = b;
NewMax[Z] = c;
}
/*
*
* Check for cylinder (y-axis).
*
* x*x z*z
* ----- + ----- - 1 = 0
* a*a c*c
*
*/
if ((A > 0.0) && (E == 0.0) && (H > 0.0) && (J < 0.0))
{
a = sqrt(-J/A);
c = sqrt(-J/H);
NewMin[X] = -a;
NewMin[Z] = -c;
NewMax[X] = a;
NewMax[Z] = c;
}
/*
*
* Check for cylinder (z-axis).
*
* x*x y*y
* ----- + ----- - 1 = 0
* a*a b*b
*
*/
if ((A > 0.0) && (E > 0.0) && (H == 0.0) && (J < 0.0))
{
a = sqrt(-J/A);
b = sqrt(-J/E);
NewMin[X] = -a;
NewMin[Y] = -b;
NewMax[X] = a;
NewMax[Y] = b;
}
/*
*
* Check for cone (x-axis).
*
* x*x y*y z*z
* ----- - ----- - ----- = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E < 0.0) && (H < 0.0) && (J == 0.0))
{
a = sqrt(1.0/A);
b = sqrt(-1.0/E);
c = sqrt(-1.0/H);
/* Get radii for lower x value. */
x = ClipMin[X];
ry1 = fabs(x * b / a);
rz1 = fabs(x * c / a);
/* Get radii for upper x value. */
x = ClipMax[X];
ry2 = fabs(x * b / a);
rz2 = fabs(x * c / a);
ry = max(ry1, ry2);
rz = max(rz1, rz2);
NewMin[Y] = -ry;
NewMin[Z] = -rz;
NewMax[Y] = ry;
NewMax[Z] = rz;
}
/*
*
* Check for cone (y-axis).
*
* x*x y*y z*z
* ----- - ----- + ----- = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E < 0.0) && (H > 0.0) && (J == 0.0))
{
a = sqrt(1.0/A);
b = sqrt(-1.0/E);
c = sqrt(1.0/H);
/* Get radii for lower y value. */
y = ClipMin[Y];
rx1 = fabs(y * a / b);
rz1 = fabs(y * c / b);
/* Get radii for upper y value. */
y = ClipMax[Y];
rx2 = fabs(y * a / b);
rz2 = fabs(y * c / b);
rx = max(rx1, rx2);
rz = max(rz1, rz2);
NewMin[X] = -rx;
NewMin[Z] = -rz;
NewMax[X] = rx;
NewMax[Z] = rz;
}
/*
*
* Check for cone (z-axis).
*
* x*x y*y z*z
* ----- + ----- - ----- = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E > 0.0) && (H < 0.0) && (J == 0.0))
{
a = sqrt(1.0/A);
b = sqrt(1.0/E);
c = sqrt(-1.0/H);
/* Get radii for lower z value. */
z = ClipMin[Z];
rx1 = fabs(z * a / c);
ry1 = fabs(z * b / c);
/* Get radii for upper z value. */
z = ClipMax[Z];
rx2 = fabs(z * a / c);
ry2 = fabs(z * b / c);
rx = max(rx1, rx2);
ry = max(ry1, ry2);
NewMin[X] = -rx;
NewMin[Y] = -ry;
NewMax[X] = rx;
NewMax[Y] = ry;
}
/*
*
* Check for hyperboloid (x-axis).
*
* x*x y*y z*z
* ----- - ----- - ----- + 1 = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E < 0.0) && (H < 0.0) && (J > 0.0))
{
/* Get radii for lower x value. */
x = ClipMin[X];
d = 1.0 + A * Sqr(x);
ry1 = sqrt(-d / E);
rz1 = sqrt(-d / H);
/* Get radii for upper x value. */
x = ClipMax[X];
d = 1.0 + A * Sqr(x);
ry2 = sqrt(-d / E);
rz2 = sqrt(-d / H);
ry = max(ry1, ry2);
rz = max(rz1, rz2);
NewMin[Y] = -ry;
NewMin[Z] = -rz;
NewMax[Y] = ry;
NewMax[Z] = rz;
}
/*
*
* Check for hyperboloid (y-axis).
*
* x*x y*y z*z
* ----- - ----- + ----- - 1 = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E < 0.0) && (H > 0.0) && (J < 0.0))
{
/* Get radii for lower y value. */
y = ClipMin[Y];
d = 1.0 - E * Sqr(y);
rx1 = sqrt(d / A);
rz1 = sqrt(d / H);
/* Get radii for upper y value. */
y = ClipMax[Y];
d = 1.0 - E * Sqr(y);
rx2 = sqrt(d / A);
rz2 = sqrt(d / H);
rx = max(rx1, rx2);
rz = max(rz1, rz2);
NewMin[X] = -rx;
NewMin[Z] = -rz;
NewMax[X] = rx;
NewMax[Z] = rz;
}
/*
*
* Check for hyperboloid (z-axis).
*
* x*x y*y z*z
* ----- + ----- - ----- - 1 = 0
* a*a b*b c*c
*
*/
if ((A > 0.0) && (E > 0.0) && (H < 0.0) && (J < 0.0))
{
/* Get radii for lower z value. */
z = ClipMin[Z];
d = 1.0 - H * Sqr(z);
rx1 = sqrt(d / A);
ry1 = sqrt(d / E);
/* Get radii for upper z value. */
z = ClipMax[Z];
d = 1.0 - H * Sqr(z);
rx2 = sqrt(d / A);
ry2 = sqrt(d / E);
rx = max(rx1, rx2);
ry = max(ry1, ry2);
NewMin[X] = -rx;
NewMin[Y] = -ry;
NewMax[X] = rx;
NewMax[Y] = ry;
}
/*
*
* Check for paraboloid (x-axis).
*
* y*y z*z
* x - ----- - ----- = 0
* b*b c*c
*
*/
if ((A == 0.0) && (D != 0.0) && (E != 0.0) && (H != 0.0) && (J == 0.0))
{
/* Get radii for lower x value. */
x = ClipMin[X];
ry1 = sqrt(fabs(2.0 * D * x / E));
rz1 = sqrt(fabs(2.0 * D * x / H));
/* Get radii for upper x value. */
x = ClipMax[X];
ry2 = sqrt(fabs(2.0 * D * x / E));
rz2 = sqrt(fabs(2.0 * D * x / H));
ry = max(ry1, ry2);
rz = max(rz1, rz2);
NewMin[Y] = -ry;
NewMin[Z] = -rz;
NewMax[Y] = ry;
NewMax[Z] = rz;
}
/*
*
* Check for paraboloid (y-axis).
*
* x*x z*z
* y - ----- - ----- = 0
* a*a c*c
*
*/
if ((E == 0.0) && (G != 0.0) && (A != 0.0) && (H != 0.0) && (J == 0.0))
{
/* Get radii for lower y-value. */
y = ClipMin[Y];
rx1 = sqrt(fabs(2.0 * G * y / A));
rz1 = sqrt(fabs(2.0 * G * y / H));
/* Get radii for upper y value. */
y = ClipMax[Y];
rx2 = sqrt(fabs(2.0 * G * y / A));
rz2 = sqrt(fabs(2.0 * G * y / H));
rx = max(rx1, rx2);
rz = max(rz1, rz2);
NewMin[X] = -rx;
NewMin[Z] = -rz;
NewMax[X] = rx;
NewMax[Z] = rz;
}
/*
*
* Check for paraboloid (z-axis).
*
* x*x y*y
* z - ----- - ----- = 0
* a*a b*b
*
*/
if ((H == 0.0) && (I != 0.0) && (A != 0.0) && (E != 0.0) && (J == 0.0))
{
/* Get radii for lower z-value. */
z = ClipMin[Z];
rx1 = sqrt(fabs(2.0 * I * z / A));
ry1 = sqrt(fabs(2.0 * I * z / E));
/* Get radii for upper z value. */
z = ClipMax[Z];
rx2 = sqrt(fabs(2.0 * I * z / A));
ry2 = sqrt(fabs(2.0 * I * z / E));
rx = max(rx1, rx2);
ry = max(ry1, ry2);
NewMin[X] = -rx;
NewMin[Y] = -ry;
NewMax[X] = rx;
NewMax[Y] = ry;
}
/* Intersect clipping object's and quadric's bounding boxes */
NewMin[X] = max(NewMin[X], ClipMin[X]);
NewMin[Y] = max(NewMin[Y], ClipMin[Y]);
NewMin[Z] = max(NewMin[Z], ClipMin[Z]);
NewMax[X] = min(NewMax[X], ClipMax[X]);
NewMax[Y] = min(NewMax[Y], ClipMax[Y]);
NewMax[Z] = min(NewMax[Z], ClipMax[Z]);
/* Use old or new bounding box? */
New_Volume = (NewMax[X] - NewMin[X]) * (NewMax[Y] - NewMin[Y]) * (NewMax[Z] - NewMin[Z]);
BOUNDS_VOLUME(Old_Volume, Old);
if (New_Volume < Old_Volume)
{
/* Add translation. */
VAddEq(NewMin, T1);
VAddEq(NewMax, T1);
Make_BBox_from_min_max(Quadric->BBox, NewMin, NewMax);
/* Beware of bounding boxes to large. */
if ((Quadric->BBox.Lengths[X] > CRITICAL_LENGTH) ||
(Quadric->BBox.Lengths[Y] > CRITICAL_LENGTH) ||
(Quadric->BBox.Lengths[Z] > CRITICAL_LENGTH))
{
Make_BBox(Quadric->BBox, -BOUND_HUGE/2, -BOUND_HUGE/2, -BOUND_HUGE/2,
BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
}
}
}
/*****************************************************************************
*
* FUNCTION
*
* Compute_Plane_Min_Max
*
* INPUT
*
* Plane - Plane
* Min, Max - Vectors containing plane's dimensions
*
* OUTPUT
*
* Min, Max
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Compute min/max vectors for planes perpendicular to an axis.
*
* CHANGES
*
* May 1994 : Creation.
*
******************************************************************************/
void Compute_Plane_Min_Max(Plane, Min, Max)
PLANE *Plane;
VECTOR Min, Max;
{
DBL d;
VECTOR N;
Assign_Vector(N, Plane->Normal_Vector);
d = -Plane->Distance;
Min[X] = Min[Y] = Min[Z] = -BOUND_HUGE/2;
Max[X] = Max[Y] = Max[Z] = BOUND_HUGE/2;
/* y-z-plane */
if (fabs(1.0 - fabs(N[X])) < EPSILON)
{
if (N[X] > 0.0)
{
Max[X] = d;
}
else
{
Min[X] = -d;
}
}
/* x-z-plane */
if (fabs(1.0 - fabs(N[Y])) < EPSILON)
{
if (N[Y] > 0.0)
{
Max[Y] = d;
}
else
{
Min[Y] = -d;
}
}
/* x-y-plane */
if (fabs(1.0 - fabs(N[Z])) < EPSILON)
{
if (N[Z] > 0.0)
{
Max[Z] = d;
}
else
{
Min[Z] = -d;
}
}
}