/**************************************************************************** * 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 Raytracer * Copyright 1993 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 "vector.h" #include "povproto.h" METHODS Disc_Methods = { All_Disc_Intersections, Inside_Disc, Disc_Normal, Copy_Disc, Translate_Disc, Rotate_Disc, Scale_Disc, Transform_Disc, Invert_Disc, Destroy_Disc }; extern long Ray_Disc_Tests, Ray_Disc_Tests_Succeeded; int All_Disc_Intersections (Object, Ray, Depth_Stack) OBJECT *Object; RAY *Ray; ISTACK *Depth_Stack; { DBL Depth; VECTOR IPoint; register int Intersection_Found; Intersection_Found = FALSE; if (Intersect_Disc (Ray, (DISC *)Object, &Depth)) { VScale (IPoint, Ray->Direction, Depth); VAddEq (IPoint, Ray->Initial); if (Point_In_Clip (&IPoint, Object->Clip)) { push_entry(Depth,IPoint,Object,Depth_Stack); Intersection_Found = TRUE; } } return (Intersection_Found); } int Intersect_Disc (Ray, disc, Depth) RAY *Ray; DISC *disc; DBL *Depth; { DBL t1, t2, len, tmpf; VECTOR P, D, tmpv; Ray_Disc_Tests++; /* Transform the point into the discs space */ MInvTransPoint(&P, &Ray->Initial, disc->Trans); MInvTransDirection(&D, &Ray->Direction, disc->Trans); *Depth = HUGE_VAL; VLength(len, D); VInverseScaleEq(D, len); /* Do the normal ray-plane intersection */ VDot(t1, disc->normal, D); if (fabs(t1) < 1.0e-10) return 0; VDot(t2, disc->normal, P); t2 = -(t2 + disc->d) / t1; if (t2 < 0) return 0; VScale(tmpv, D, t2); VAddEq(tmpv, P); VSub(tmpv, tmpv, disc->center); VDot(tmpf, tmpv, tmpv); if (tmpf < disc->iradius2 || tmpf > disc->oradius2) return 0; else *Depth = t2 / len; if (*Depth < Small_Tolerance || *Depth > Max_Distance) return FALSE; Ray_Disc_Tests_Succeeded++; return TRUE; } int Inside_Disc (IPoint, Object) VECTOR *IPoint; OBJECT *Object; { VECTOR New_Point; DISC *disc = (DISC *) Object; DBL tmpf, offset = (disc->Inverted ? -EPSILON : EPSILON); /* Transform the point into the discs space */ MInvTransPoint(&New_Point, IPoint, disc->Trans); VDot(tmpf, New_Point, disc->normal); tmpf += disc->d; if (tmpf+offset > 0) return disc->Inverted; else return 1 - disc->Inverted; } void Disc_Normal (Result, Object, IPoint) OBJECT *Object; VECTOR *Result, *IPoint; { DISC *disc = (DISC *) Object; MTransNormal(Result, &disc->normal, disc->Trans); VNormalize(*Result, *Result); } void *Copy_Disc (Object) OBJECT *Object; { DISC *New; New = Create_Disc(); *New = *((DISC *) Object); New->Trans = Copy_Transform(((DISC *)Object)->Trans); return (New); } void Translate_Disc (Object, Vector) OBJECT *Object; VECTOR *Vector; { TRANSFORM Trans; Compute_Translation_Transform(&Trans, Vector); Transform_Disc(Object, &Trans); } void Rotate_Disc (Object, Vector) OBJECT *Object; VECTOR *Vector; { TRANSFORM Trans; Compute_Rotation_Transform(&Trans, Vector); Transform_Disc(Object, &Trans); } void Scale_Disc (Object, Vector) OBJECT *Object; VECTOR *Vector; { TRANSFORM Trans; Compute_Scaling_Transform(&Trans, Vector); Transform_Disc(Object, &Trans); } void Invert_Disc (Object) OBJECT *Object; { ((DISC *)Object)->Inverted = 1 - ((DISC *)Object)->Inverted; } void Transform_Disc (Object, Trans) OBJECT *Object; TRANSFORM *Trans; { DISC *Disc = (DISC *)Object; VECTOR lengths; DBL len; Compose_Transforms(Disc->Trans, Trans); /* Recalculate the bounds */ len = sqrt(Disc->oradius2); Make_Vector(&lengths, len, len, len); VSub(Disc->Bounds.Lower_Left, Disc->center, lengths); VScale(Disc->Bounds.Lengths, lengths, 2.0); recompute_bbox(&Disc->Bounds, Disc->Trans); } DISC *Create_Disc () { DISC *New; if ((New = (DISC *) malloc (sizeof (DISC))) == NULL) MAError ("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, 1.0, 0.0); New->iradius2 = 0.0; New->oradius2 = 1.0; New->d = 0.0; New->Trans = Create_Transform(); New->Inverted = 0; /* Default bounds */ Make_Vector(&New->Bounds.Lower_Left, -1.0, -EPSILON, -1.0); Make_Vector(&New->Bounds.Lengths, 2.0, 2*EPSILON, 2.0); return New; } void Destroy_Disc (Object) OBJECT *Object; { Destroy_Transform(((DISC *)Object)->Trans); free (Object); }