/**************************************************************************** * 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 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 "discs.h" #include "matrices.h" #include "objects.h" /***************************************************************************** * Local preprocessor defines ******************************************************************************/ /***************************************************************************** * Static functions ******************************************************************************/ static int Intersect_Disc PARAMS((RAY *Ray, DISC *Disc, DBL *Depth)); static int All_Disc_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)); static int Inside_Disc PARAMS((VECTOR point, OBJECT *Object)); static void Disc_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter)); static void *Copy_Disc PARAMS((OBJECT *Object)); static void Translate_Disc PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Rotate_Disc PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Scale_Disc PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Transform_Disc PARAMS((OBJECT *Object, TRANSFORM *Trans)); static void Invert_Disc PARAMS((OBJECT *Object)); static void Destroy_Disc PARAMS((OBJECT *Object)); static void Compute_Disc_BBox PARAMS((DISC *Disc)); /***************************************************************************** * Local variables ******************************************************************************/ static METHODS Disc_Methods = { All_Disc_Intersections, Inside_Disc, Disc_Normal, 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, Ray, Depth_Stack) 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, disc, Depth) RAY *Ray; DISC *disc; DBL *Depth; { 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); } /***************************************************************************** * * FUNCTION * * Inside_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static int Inside_Disc (IPoint, Object) VECTOR IPoint; OBJECT *Object; { 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)); } } /***************************************************************************** * * FUNCTION * * Disc_Normal * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Disc_Normal (Result, Object, Inter) OBJECT *Object; VECTOR Result; INTERSECTION *Inter; { Assign_Vector(Result, ((DISC *)Object)->normal); } /***************************************************************************** * * FUNCTION * * Translate_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Translate_Disc (Object, Vector, Trans) 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, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { MTransNormal(((DISC *)Object)->normal, ((DISC *)Object)->normal, Trans); Transform_Disc(Object, Trans); } /***************************************************************************** * * FUNCTION * * Scale_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Scale_Disc(Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { MTransNormal(((DISC *)Object)->normal, ((DISC *)Object)->normal, Trans); VNormalize(((DISC *)Object)->normal, ((DISC *)Object)->normal); Transform_Disc(Object, Trans); } /***************************************************************************** * * FUNCTION * * Invert_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Invert_Disc (Object) OBJECT *Object; { Invert_Flag(Object, INVERTED_FLAG); } /***************************************************************************** * * FUNCTION * * Transform_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Transform_Disc (Object, Trans) OBJECT *Object; TRANSFORM *Trans; { DISC *Disc = (DISC *)Object; Compose_Transforms(Disc->Trans, Trans); /* Recalculate the bounds */ Compute_Disc_BBox(Disc); } /***************************************************************************** * * FUNCTION * * Create_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ DISC *Create_Disc () { 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); } /***************************************************************************** * * FUNCTION * * Copy_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * Sep 1994 : Fixed memory leakage [DB] * ******************************************************************************/ static void *Copy_Disc (Object) OBJECT *Object; { 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); } /***************************************************************************** * * FUNCTION * * Destroy_Disc * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Alexander Enzmann * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Destroy_Disc (Object) OBJECT *Object; { Destroy_Transform(((DISC *)Object)->Trans); 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. * ******************************************************************************/ void Compute_Disc(Disc) DISC *Disc; { Compute_Coordinate_Transform(Disc->Trans, Disc->center, Disc->normal, 1.0, 1.0); Compute_Disc_BBox(Disc); } /***************************************************************************** * * 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 *Disc; { 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); }