home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Graphics
/
Graphics.zip
/
povsrc31.zip
/
discs.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-09-12
|
20KB
|
975 lines
/****************************************************************************
* discs.c
*
* This module implements the disc primitive.
* This file was written by Alexander Enzmann. He wrote the code for
* discs and generously provided us these enhancements.
*
* from Persistence of Vision(tm) Ray Tracer
* Copyright 1996,1999 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 email to team-coord@povray.org or visit us on the web at
* http://www.povray.org. The latest version of POV-Ray may be found at this site.
*
* 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 "discs.h"
#include "matrices.h"
#include "objects.h"
/*****************************************************************************
* Local preprocessor defines
******************************************************************************/
#ifdef FastDiscPatch
/* DISC.C is temporar place for next few defines*/
#define UV_Dot(a,b,c) { a=(b)[X]*(c)[X]+(b)[Y]*(c)[Y];}
#define Make_UV_Vector(v,a,b ) { (v)[X]=(a); (v)[Y]=(b); }
#define UV_ScaleEq(a,k) { (a)[X]*=(k); (a)[Y]*=(k); }
#define UV_LinComb2(V,k1,V1,k2,V2) \
{ \
(V)[X] = (k1) * (V1)[X] + (k2) * (V2)[X]; \
(V)[Y] = (k1) * (V1)[Y] + (k2) * (V2)[Y]; \
}
#define max3_coordinate(x,y,z) \
(((x) > (y)) ? (((x) > (z)) ? X : Z) : (((y) > (z)) ? Y : Z))
#endif
/*****************************************************************************
* Static functions
******************************************************************************/
#ifdef FastDiscPatch
static void ellipse_main_axis( UV_VECT x_axis, UV_VECT y_axis, UV_VECT ex, UV_VECT ey );
#endif
static int Intersect_Disc (RAY *Ray, DISC *Disc, DBL *Depth);
static int All_Disc_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
static int Inside_Disc (VECTOR point, OBJECT *Object);
static void Disc_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
static DISC *Copy_Disc (OBJECT *Object);
static void Translate_Disc (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
static void Rotate_Disc (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
static void Scale_Disc (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
static void Transform_Disc (OBJECT *Object, TRANSFORM *Trans);
static void Invert_Disc (OBJECT *Object);
static void Destroy_Disc (OBJECT *Object);
static void Compute_Disc_BBox (DISC *Disc);
/*****************************************************************************
* Local variables
******************************************************************************/
static METHODS Disc_Methods =
{
All_Disc_Intersections,
Inside_Disc, Disc_Normal, Default_UVCoord,
(COPY_METHOD)Copy_Disc, Translate_Disc, Rotate_Disc, Scale_Disc, Transform_Disc,
Invert_Disc, Destroy_Disc
};
/*****************************************************************************
*
* FUNCTION
*
* All_Disc_Intersections
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static int All_Disc_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
{
int Intersection_Found;
DBL Depth;
VECTOR IPoint;
Intersection_Found = FALSE;
if (Intersect_Disc (Ray, (DISC *)Object, &Depth))
{
VEvaluateRay(IPoint, Ray->Initial, Depth, Ray->Direction);
if (Point_In_Clip (IPoint, Object->Clip))
{
push_entry(Depth,IPoint,Object,Depth_Stack);
Intersection_Found = TRUE;
}
}
return (Intersection_Found);
}
/*****************************************************************************
*
* FUNCTION
*
* Intersect_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static int Intersect_Disc (RAY *Ray, DISC *disc, DBL *Depth)
{
#ifndef FastDiscPatch
DBL t, u, v, r2, len;
VECTOR P, D;
Increase_Counter(stats[Ray_Disc_Tests]);
/* Transform the point into the discs space */
MInvTransPoint(P, Ray->Initial, disc->Trans);
MInvTransDirection(D, Ray->Direction, disc->Trans);
VLength(len, D);
VInverseScaleEq(D, len);
if (fabs(D[Z]) > EPSILON)
{
t = -P[Z] / D[Z];
if (t >= 0.0)
{
u = P[X] + t * D[X];
v = P[Y] + t * D[Y];
r2 = Sqr(u) + Sqr(v);
if ((r2 >= disc->iradius2) && (r2 <= disc->oradius2))
{
*Depth = t / len;
if ((*Depth > Small_Tolerance) && (*Depth < Max_Distance))
{
Increase_Counter(stats[Ray_Disc_Tests_Succeeded]);
return (TRUE);
}
}
}
}
return (FALSE);
#else
DBL u, v, r2;
DBL NormalDotP, NormalDotDirection;
VECTOR P, IPoint;
Increase_Counter(stats[Ray_Disc_Tests]);
VDot( NormalDotDirection, disc->normal, Ray->Direction );
if( fabs( NormalDotDirection ) < EPSILON ) return (FALSE);
VSub( P, Ray->Initial, disc->center );
VDot( NormalDotP, disc->normal, P );
*Depth = - NormalDotP / NormalDotDirection;
if ( *Depth <= Small_Tolerance ) return (FALSE);
switch( disc->Dominant_Axis )
{
case( X ):
IPoint[ Y ] = P[ Y ] + *Depth * Ray->Direction[ Y ];
IPoint[ Z ] = P[ Z ] + *Depth * Ray->Direction[ Z ];
u = IPoint[ Y ] * disc->u_axis[ X ] + IPoint[ Z ] * disc->u_axis[ Y ];
v = IPoint[ Y ] * disc->v_axis[ X ] + IPoint[ Z ] * disc->v_axis[ Y ];
break;
case( Y ):
IPoint[ X ] = P[ X ] + *Depth * Ray->Direction[ X ];
IPoint[ Z ] = P[ Z ] + *Depth * Ray->Direction[ Z ];
u = IPoint[ Z ] * disc->u_axis[ X ] + IPoint[ X ] * disc->u_axis[ Y ];
v = IPoint[ Z ] * disc->v_axis[ X ] + IPoint[ X ] * disc->v_axis[ Y ];
break;
case( Z ):
IPoint[ X ] = P[ X ] + *Depth * Ray->Direction[ X ];
IPoint[ Y ] = P[ Y ] + *Depth * Ray->Direction[ Y ];
u = IPoint[ X ] * disc->u_axis[ X ] + IPoint[ Y ] * disc->u_axis[ Y ];
v = IPoint[ X ] * disc->v_axis[ X ] + IPoint[ Y ] * disc->v_axis[ Y ];
break;
}
r2 = Sqr(u) + Sqr(v);
if ( ( disc->iradius2 <= r2 ) && ( r2 <= 1.0 ) )
{
if ( (*Depth < Max_Distance) )
{
Increase_Counter(stats[Ray_Disc_Tests_Succeeded]);
return (TRUE);
}
}
return (FALSE);
#endif
}
/*****************************************************************************
*
* FUNCTION
*
* Inside_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static int Inside_Disc (VECTOR IPoint, OBJECT *Object)
{
#ifndef FastDiscPatch
VECTOR New_Point;
DISC *disc = (DISC *) Object;
/* Transform the point into the discs space */
MInvTransPoint(New_Point, IPoint, disc->Trans);
if (New_Point[Z] >= 0.0)
{
/* We are outside. */
return (Test_Flag(disc, INVERTED_FLAG));
}
else
{
/* We are inside. */
return (!Test_Flag(disc, INVERTED_FLAG));
}
#else
DBL Temp;
DISC *Disc = (DISC *) Object;
VDot (Temp, IPoint, Disc->normal);
return ( (Temp + Disc->d) < EPSILON );
#endif
}
/*****************************************************************************
*
* FUNCTION
*
* Disc_Normal
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Disc_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
{
Assign_Vector(Result, ((DISC *)Object)->normal);
}
/*****************************************************************************
*
* FUNCTION
*
* Translate_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Translate_Disc (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
{
Transform_Disc(Object, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Rotate_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Rotate_Disc(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
{
Transform_Disc(Object, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Scale_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Scale_Disc(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
{
Transform_Disc(Object, Trans);
}
/*****************************************************************************
*
* FUNCTION
*
* Invert_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Invert_Disc (OBJECT *Object)
{
#ifndef FastDiscPatch
Invert_Flag(Object, INVERTED_FLAG);
#else
VScaleEq(((DISC *)Object)->normal, -1.0);
((DISC *)Object)->d *= -1.0;
#endif
}
#ifdef FastDiscPatch
/*****************************************************************************
*
* FUNCTION
*
* ellipse_main_axis
*
* INPUT
*
* OUTPUT
* ex, ey
* RETURNS
* x_axis, y_axis
* AUTHOR
*
* Dejan D. M. Milosavljevic
*
* DESCRIPTION
*
* Compute main axis of elipse given at form
* ex * cos( alpha ) + ey * sin( alpha );
* Where 0 <= alpha <= 2*M_PI.
*
* CHANGES
*
* April 2000: Creation [DDMM]
*
******************************************************************************/
static void ellipse_main_axis( UV_VECT x_axis, UV_VECT y_axis, UV_VECT ex, UV_VECT ey )
{
DBL b, c, alpha;
DBL t1, t2;
UV_Dot( t1, ex, ex );
UV_Dot( t2, ey, ey );
b = t2 - t1; if( fabs( b ) < EPSILON ) b = 0.0;
UV_Dot( c, ex, ey ); if( fabs( c ) < EPSILON ) c = 0.0;
switch( ( ( b != 0.0 ) << 1 ) + ( c != 0.0 ) )
{
case( 0 + 0 ):
Assign_UV_Vect( x_axis, ex );
Assign_UV_Vect( y_axis, ey );
break;
case( 0 + 1 ):
alpha = M_PI_2 / 2.0;
t1 = cos( alpha ); t2 = sin( alpha );
UV_LinComb2( x_axis, t1, ex, t2, ey );
t1 = cos( alpha + M_PI_2 ); t2 = sin( alpha + M_PI_2 );
UV_LinComb2( y_axis, t1, ex, t2, ey );
break;
case( 2 + 0 ):
Assign_UV_Vect( x_axis, ex );
Assign_UV_Vect( y_axis, ey );
break;
case( 2 + 1 ):
alpha = atan( -2.0 * c / b )/2.0;
t1 = cos( alpha ); t2 = sin( alpha );
UV_LinComb2( x_axis, t1, ex, t2, ey );
t1 = cos( alpha + M_PI_2 ); t2 = sin( alpha + M_PI_2 );
UV_LinComb2( y_axis, t1, ex, t2, ey );
break;
}
UV_Dot( t1, x_axis, x_axis ); t1=1.0/t1; UV_ScaleEq( x_axis, t1 );
UV_Dot( t1, y_axis, y_axis ); t1=1.0/t1; UV_ScaleEq( y_axis, t1 );
}
#endif
/*****************************************************************************
*
* FUNCTION
*
* Transform_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Transform_Disc (OBJECT *Object, TRANSFORM *Trans)
{
#ifndef FastDiscPatch
DISC *Disc = (DISC *)Object;
MTransNormal(((DISC *)Object)->normal, ((DISC *)Object)->normal, Trans);
VNormalize(((DISC *)Object)->normal, ((DISC *)Object)->normal);
Compose_Transforms(Disc->Trans, Trans);
/* Recalculate the bounds */
Compute_Disc_BBox(Disc);
#else
UV_VECT u, v;
DISC *Disc = (DISC *)Object;
/* Recalculate the normal */
MTransNormal( Disc->normal, Disc->normal, Trans);
VNormalizeEq( Disc->normal );
/* Recalculate the center */
MTransPoint( Disc->center, Disc->center, Trans );
/* Recalculate the d */
VDot( Disc->d, Disc->center, Disc->normal );
Disc->d = - Disc->d;
/* Recalculate the x and y axis */
MTransDirection( Disc->x_axis, Disc->x_axis, Trans );
MTransDirection( Disc->y_axis, Disc->y_axis, Trans );
/* Recalculate the u and v axis */
Disc->Dominant_Axis
= max3_coordinate
(
fabs( Disc->normal[ X ] ),
fabs( Disc->normal[ Y ] ),
fabs( Disc->normal[ Z ] )
);
switch( Disc->Dominant_Axis )
{
case( X ):
Make_UV_Vector( u, Disc->x_axis[ Y ], Disc->x_axis[ Z ] );
Make_UV_Vector( v, Disc->y_axis[ Y ], Disc->y_axis[ Z ] );
ellipse_main_axis( Disc->u_axis, Disc->v_axis, u, v );
break;
case( Y ):
Make_UV_Vector( u, Disc->x_axis[ Z ], Disc->x_axis[ X ] );
Make_UV_Vector( v, Disc->y_axis[ Z ], Disc->y_axis[ X ] );
ellipse_main_axis( Disc->u_axis, Disc->v_axis, u, v );
break;
case( Z ):
Make_UV_Vector( u, Disc->x_axis[ X ], Disc->x_axis[ Y ] );
Make_UV_Vector( v, Disc->y_axis[ X ], Disc->y_axis[ Y ] );
ellipse_main_axis( Disc->u_axis, Disc->v_axis, u, v );
break;
}
/* Recalculate the bounds */
Compute_Disc_BBox(Disc);
#endif
}
/*****************************************************************************
*
* FUNCTION
*
* Create_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
DISC *Create_Disc ()
{
#ifndef FastDiscPatch
DISC *New;
New = (DISC *)POV_MALLOC(sizeof (DISC), "disc");
INIT_OBJECT_FIELDS(New, DISC_OBJECT, &Disc_Methods)
Make_Vector (New->center, 0.0, 0.0, 0.0);
Make_Vector (New->normal, 0.0, 0.0, 1.0);
New->iradius2 = 0.0;
New->oradius2 = 1.0;
New->d = 0.0;
New->Trans = Create_Transform();
/* Default bounds */
Make_BBox(New->BBox, -1.0, -1.0, -Small_Tolerance, 2.0, 2.0, 2.0 * Small_Tolerance);
return (New);
#else
DISC *New;
New = (DISC *)POV_MALLOC(sizeof (DISC), "disc");
INIT_OBJECT_FIELDS(New, DISC_OBJECT, &Disc_Methods)
Make_Vector( New->x_axis, 1.0, 0.0, 0.0 );
Make_Vector( New->y_axis, 0.0, 1.0, 0.0 );
Make_Vector( New->normal, 0.0, 0.0, 1.0 );
Make_Vector( New->center, 0.0, 0.0, 0.0 );
New->Dominant_Axis = Z;
Make_UV_Vector( New->u_axis, 1.0, 0.0 );
Make_UV_Vector( New->v_axis, 0.0, 1.0 );
New->iradius2 = 0.0;
New->d = 0.0;
/* Default bounds */
Make_BBox( New->BBox, -1.0, -1.0, -Small_Tolerance,
2.0, 2.0, 2.0 * Small_Tolerance );
return (New);
#endif
}
/*****************************************************************************
*
* FUNCTION
*
* Copy_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* Sep 1994 : Fixed memory leakage [DB]
*
******************************************************************************/
static DISC *Copy_Disc (OBJECT *Object)
{
#ifndef FastDiscPatch
DISC *New;
New = Create_Disc();
/* Get rid of the transformation created in Create_Disc(). */
Destroy_Transform(New->Trans);
/* Copy disc. */
*New = *((DISC *) Object);
New->Trans = Copy_Transform(((DISC *)Object)->Trans);
return (New);
#else
DISC *New;
New = Create_Disc();
/* Copy disc. */
*New = *((DISC *) Object);
return (New);
#endif
}
/*****************************************************************************
*
* FUNCTION
*
* Destroy_Disc
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Alexander Enzmann
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static void Destroy_Disc (OBJECT *Object)
{
#ifndef FastDiscPatch
Destroy_Transform(((DISC *)Object)->Trans);
#endif
POV_FREE (Object);
}
/*****************************************************************************
*
* FUNCTION
*
* Compute_Disc
*
* INPUT
*
* Disc - Disc
*
* OUTPUT
*
* Disc
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Calculate the transformation that scales, rotates, and translates
* the disc to the desired location and orientation.
*
* CHANGES
*
* Aug 1994 : Creation.
*
******************************************************************************/
#ifndef FastDiscPatch
void Compute_Disc(DISC *Disc)
{
Compute_Coordinate_Transform(Disc->Trans, Disc->center, Disc->normal, 1.0, 1.0);
Compute_Disc_BBox(Disc);
#else
void Compute_Disc(DISC *Disc, VECTOR center, VECTOR normal, DBL inner_radius, DBL outer_radius )
{
DBL t;
VECTOR _normal;
TRANSFORM Trans;
if( outer_radius < inner_radius )
{
t = inner_radius; inner_radius = outer_radius; outer_radius = t;
}
Disc->iradius2 = inner_radius / outer_radius;
Disc->iradius2 *= Disc->iradius2;
VNormalize( _normal, normal );
Compute_Coordinate_Transform( &Trans, center, _normal, outer_radius, 1.0 );
Transform_Disc( (OBJECT *)Disc, &Trans );
Compute_Disc_BBox(Disc);
#endif
}
/*****************************************************************************
*
* FUNCTION
*
* Compute_Disc_BBox
*
* INPUT
*
* Disc - Disc
*
* OUTPUT
*
* Disc
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Calculate the bounding box of a disc.
*
* CHANGES
*
* Aug 1994 : Creation.
*
******************************************************************************/
static void Compute_Disc_BBox(DISC *Disc)
{
#ifndef FastDiscPatch
DBL rad;
rad = sqrt(Disc->oradius2);
Make_BBox(Disc->BBox, -rad, -rad, -Small_Tolerance, 2.0*rad, 2.0*rad, 2.0*Small_Tolerance);
Recompute_BBox(&Disc->BBox, Disc->Trans);
#else
int i,j, k;
VECTOR lo, hi, v;
VECTOR z_axis;
VScale( z_axis, Disc->normal, Small_Tolerance );
Assign_Vector( lo, Disc->center );
Assign_Vector( hi, Disc->center );
for( k = -1; k < 2; k += 2 )
for( j = -1; j < 2; j += 2 )
for( i = -1; i < 2; i += 2 )
{
VLinComb3( v, i, Disc->x_axis, j, Disc->y_axis, k, z_axis );
VAddEq( v, Disc->center );
lo[ X ] = min( lo[ X ], v[ X ] ); hi[ X ] = max( hi[ X ], v[ X ] );
lo[ Y ] = min( lo[ Y ], v[ Y ] ); hi[ Y ] = max( hi[ Y ], v[ Y ] );
lo[ Z ] = min( lo[ Z ], v[ Z ] ); hi[ Z ] = max( hi[ Z ], v[ Z ] );
}
Make_BBox_from_min_max( Disc->BBox, lo, hi );
#endif
}