| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030 |
- /****************************************************************************
- * cones.c
- *
- * This module implements the cone primitive.
- * This file was written by Alexander Enzmann. He wrote the code for
- * cones 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 "cones.h"
- #include "matrices.h"
- #include "objects.h"
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
- #define Cone_Tolerance 1.0e-6
- #define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
- /* Part of the cone/cylinder hit. [DB 9/94] */
- #define BASE_HIT 1
- #define CAP_HIT 2
- #define SIDE_HIT 3
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
- typedef struct Cone_Intersection_Structure CONE_INT;
- struct Cone_Intersection_Structure
- {
- DBL d; /* Distance of intersection point */
- int t; /* Type of intersection: base/cap plane or side */
- };
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
- static int intersect_cone (RAY *Ray, CONE *Cone, CONE_INT *Depths);
- static void Destroy_Cone (OBJECT *Object);
- static int All_Cone_Intersections (OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack);
- static int Inside_Cone (VECTOR point, OBJECT *Object);
- static void Cone_Normal (VECTOR Result, OBJECT *Object, INTERSECTION *Inter);
- static CONE *Copy_Cone (OBJECT *Object);
- static void Translate_Cone (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
- static void Rotate_Cone (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
- static void Scale_Cone (OBJECT *Object, VECTOR Vector, TRANSFORM *Trans);
- static void Transform_Cone (OBJECT *Object, TRANSFORM *Trans);
- static void Invert_Cone (OBJECT *Object);
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
- static METHODS Cone_Methods =
- {
- All_Cone_Intersections,
- Inside_Cone, Cone_Normal,
- (COPY_METHOD)Copy_Cone, Translate_Cone, Rotate_Cone, Scale_Cone, Transform_Cone,
- Invert_Cone, Destroy_Cone
- };
- /*****************************************************************************
- *
- * FUNCTION
- *
- * All_Cone_Intersections
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static int All_Cone_Intersections(OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)
- {
- int Intersection_Found, cnt, i;
- VECTOR IPoint;
- CONE_INT I[4];
- Intersection_Found = FALSE;
- if ((cnt = intersect_cone(Ray, (CONE *)Object, I)) != 0)
- {
- for (i = 0; i < cnt; i++)
- {
- VEvaluateRay(IPoint, Ray->Initial, I[i].d, Ray->Direction);
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- push_entry_i1(I[i].d,IPoint,Object,I[i].t,Depth_Stack);
- Intersection_Found = TRUE;
- }
- }
- }
- return (Intersection_Found);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * intersect_cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static int intersect_cone(RAY *Ray, CONE *Cone, CONE_INT *Intersection)
- {
- int i = 0;
- DBL a, b, c, z, t1, t2, len;
- DBL d;
- VECTOR P, D;
- Increase_Counter(stats[Ray_Cone_Tests]);
- /* Transform the ray into the cones space */
- MInvTransPoint(P, Ray->Initial, Cone->Trans);
- MInvTransDirection(D, Ray->Direction, Cone->Trans);
- VLength(len, D);
- VInverseScaleEq(D, len);
- if (Test_Flag(Cone, CYLINDER_FLAG))
- {
- /* Solve intersections with a cylinder */
- a = D[X] * D[X] + D[Y] * D[Y];
- if (a > EPSILON)
- {
- b = P[X] * D[X] + P[Y] * D[Y];
- c = P[X] * P[X] + P[Y] * P[Y] - 1.0;
- d = b * b - a * c;
- if (d >= 0.0)
- {
- d = sqrt(d);
- t1 = (-b + d) / a;
- t2 = (-b - d) / a;
- z = P[Z] + t1 * D[Z];
- if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= 0.0) && (z <= 1.0))
- {
- Intersection[i].d = t1 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- z = P[Z] + t2 * D[Z];
- if ((t2 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= 0.0) && (z <= 1.0))
- {
- Intersection[i].d = t2 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- }
- }
- }
- else
- {
- /* Solve intersections with a cone */
- a = D[X] * D[X] + D[Y] * D[Y] - D[Z] * D[Z];
- b = D[X] * P[X] + D[Y] * P[Y] - D[Z] * P[Z];
- c = P[X] * P[X] + P[Y] * P[Y] - P[Z] * P[Z];
- if (fabs(a) < EPSILON)
- {
- if (fabs(b) > EPSILON)
- {
- /* One intersection */
- t1 = -0.5 * c / b;
- z = P[Z] + t1 * D[Z];
- if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
- {
- Intersection[i].d = t1 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- }
- }
- else
- {
- /* Check hits against the side of the cone */
- d = b * b - a * c;
- if (d >= 0.0)
- {
- d = sqrt(d);
- t1 = (-b - d) / a;
- t2 = (-b + d) / a;
- z = P[Z] + t1 * D[Z];
- if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
- {
- Intersection[i].d = t1 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- z = P[Z] + t2 * D[Z];
- if ((t2 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
- {
- Intersection[i].d = t2 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- }
- }
- }
- if (Test_Flag(Cone, CLOSED_FLAG) && (fabs(D[Z]) > EPSILON))
- {
- d = (1.0 - P[Z]) / D[Z];
- a = (P[X] + d * D[X]);
- b = (P[Y] + d * D[Y]);
- if (((Sqr(a) + Sqr(b)) <= 1.0) && (d > Cone_Tolerance) && (d < Max_Distance))
- {
- Intersection[i].d = d / len;
- Intersection[i++].t = CAP_HIT;
- }
- d = (Cone->dist - P[Z]) / D[Z];
- a = (P[X] + d * D[X]);
- b = (P[Y] + d * D[Y]);
- if ((Sqr(a) + Sqr(b)) <= (Test_Flag(Cone, CYLINDER_FLAG) ? 1.0 : Sqr(Cone->dist))
- && (d > Cone_Tolerance) && (d < Max_Distance))
- {
- Intersection[i].d = d / len;
- Intersection[i++].t = BASE_HIT;
- }
- }
- if (i)
- {
- Increase_Counter(stats[Ray_Cone_Tests_Succeeded]);
- }
- return (i);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Inside_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static int Inside_Cone(VECTOR IPoint, OBJECT *Object)
- {
- CONE *Cone = (CONE *)Object;
- DBL w2, z2, offset = (Test_Flag(Cone, CLOSED_FLAG) ? -EPSILON : EPSILON);
- VECTOR New_Point;
- /* Transform the point into the cones space */
- MInvTransPoint(New_Point, IPoint, Cone->Trans);
- /* Test to see if we are inside the cone */
- w2 = New_Point[X] * New_Point[X] + New_Point[Y] * New_Point[Y];
- if (Test_Flag(Cone, CYLINDER_FLAG))
- {
- /* Check to see if we are inside a cylinder */
- if ((w2 > 1.0 + offset) ||
- (New_Point[Z] < 0.0 - offset) ||
- (New_Point[Z] > 1.0 + offset))
- {
- return (Test_Flag(Cone, INVERTED_FLAG));
- }
- else
- {
- return (!Test_Flag(Cone, INVERTED_FLAG));
- }
- }
- else
- {
- /* Check to see if we are inside a cone */
- z2 = New_Point[Z] * New_Point[Z];
- if ((w2 > z2 + offset) ||
- (New_Point[Z] < Cone->dist - offset) ||
- (New_Point[Z] > 1.0+offset))
- {
- return (Test_Flag(Cone, INVERTED_FLAG));
- }
- else
- {
- return (!Test_Flag(Cone, INVERTED_FLAG));
- }
- }
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Cone_Normal
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Cone_Normal(VECTOR Result, OBJECT *Object, INTERSECTION *Inter)
- {
- CONE *Cone = (CONE *)Object;
- /* Transform the point into the cones space */
- MInvTransPoint(Result, Inter->IPoint, Cone->Trans);
- /* Calculating the normal is real simple in canonical cone space */
- switch (Inter->i1)
- {
- case SIDE_HIT:
- if (Test_Flag(Cone, CYLINDER_FLAG))
- {
- Result[Z] = 0.0;
- }
- else
- {
- Result[Z] = -Result[Z];
- }
- break;
- case BASE_HIT:
- Make_Vector(Result, 0.0, 0.0, -1.0)
- break;
- case CAP_HIT:
- Make_Vector(Result, 0.0, 0.0, 1.0)
- break;
- }
- /* Transform the point out of the cones space */
- MTransNormal(Result, Result, Cone->Trans);
- VNormalize(Result, Result);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Translate_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Translate_Cone(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
- {
- Transform_Cone(Object, Trans);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Rotate_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Rotate_Cone(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
- {
- Transform_Cone(Object, Trans);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Scale_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Scale_Cone(OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)
- {
- Transform_Cone(Object, Trans);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Transform_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Transform_Cone(OBJECT *Object, TRANSFORM *Trans)
- {
- CONE *Cone = (CONE *)Object;
- Compose_Transforms(Cone->Trans, Trans);
- Compute_Cone_BBox(Cone);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Invert_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Invert_Cone(OBJECT *Object)
- {
- Invert_Flag(Object, INVERTED_FLAG);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- CONE *Create_Cone()
- {
- CONE *New;
- New = (CONE *)POV_MALLOC(sizeof(CONE), "cone");
- INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
- Make_Vector(New->apex, 0.0, 0.0, 1.0);
- Make_Vector(New->base, 0.0, 0.0, 0.0);
- New->apex_radius = 1.0;
- New->base_radius = 0.0;
- New->dist = 0.0;
- New->Trans = Create_Transform();
- /* Cone/Cylinder has capped ends by default. */
- Set_Flag(New, CLOSED_FLAG);
- /* Default bounds */
- Make_BBox(New->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
- return (New);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static CONE *Copy_Cone(OBJECT *Object)
- {
- CONE *New;
- New = Create_Cone();
- /* Get rid of the transformation created in Create_Cone(). */
- Destroy_Transform(New->Trans);
- /* Copy cone. */
- *New = *((CONE *)Object);
- New->Trans = Copy_Transform(((CONE *)Object)->Trans);
- return (New);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Cylinder
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- CONE *Create_Cylinder()
- {
- CONE *New;
- New = (CONE *)POV_MALLOC(sizeof(CONE), "cone");
- INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
- Make_Vector(New->apex, 0.0, 0.0, 1.0);
- Make_Vector(New->base, 0.0, 0.0, 0.0);
- New->apex_radius = 1.0;
- New->base_radius = 1.0;
- New->dist = 0.0;
- New->Trans = Create_Transform();
- Set_Flag(New, CYLINDER_FLAG); /* This is a cylinder. */
- Set_Flag(New, CLOSED_FLAG); /* Has capped ends. */
- /* Default bounds */
- Make_BBox(New->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
- return (New);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Cone_Data
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Feb 1996: check for equal sized ends (cylinder) first [AED]
- *
- ******************************************************************************/
- void Compute_Cone_Data(OBJECT *Object)
- {
- DBL tlen, len, tmpf;
- VECTOR tmpv, axis, origin;
- CONE *Cone = (CONE *)Object;
- /* Process the primitive specific information */
- if (fabs(Cone->apex_radius - Cone->base_radius) < EPSILON)
- {
- /* What we are dealing with here is really a cylinder */
- Set_Flag(Cone, CYLINDER_FLAG);
- Compute_Cylinder_Data(Object);
- return;
- }
- if (Cone->apex_radius < Cone->base_radius)
- {
- /* Want the bigger end at the top */
- Assign_Vector(tmpv,Cone->base);
- Assign_Vector(Cone->base,Cone->apex);
- Assign_Vector(Cone->apex,tmpv);
- tmpf = Cone->base_radius;
- Cone->base_radius = Cone->apex_radius;
- Cone->apex_radius = tmpf;
- }
- /* Find the axis and axis length */
- VSub(axis, Cone->apex, Cone->base);
- VLength(len, axis);
- if (len < EPSILON)
- {
- Error("Degenerate cone/cylinder.\n");
- }
- else
- {
- VInverseScaleEq(axis, len)
- }
- /* Determine alignment */
- tmpf = Cone->base_radius * len / (Cone->apex_radius - Cone->base_radius);
- VScale(origin, axis, tmpf);
- VSub(origin, Cone->base, origin);
- tlen = tmpf + len;
- Cone->dist = tmpf / tlen;
- Compute_Coordinate_Transform(Cone->Trans, origin, axis, Cone->apex_radius, tlen);
- /* Recalculate the bounds */
- Compute_Cone_BBox(Cone);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Cylinder_Data
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- void Compute_Cylinder_Data(OBJECT *Object)
- {
- DBL tmpf;
- VECTOR axis;
- CONE *Cone = (CONE *)Object;
- VSub(axis, Cone->apex, Cone->base);
- VLength(tmpf, axis);
- if (tmpf < EPSILON)
- {
- Error("Degenerate cylinder, base point = apex point.\n");
- }
- else
- {
- VInverseScaleEq(axis, tmpf)
- Compute_Coordinate_Transform(Cone->Trans, Cone->base, axis, Cone->apex_radius, tmpf);
- }
- Cone->dist = 0.0;
- /* Recalculate the bounds */
- Compute_Cone_BBox(Cone);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- static void Destroy_Cone(OBJECT *Object)
- {
- Destroy_Transform(((CONE *)Object)->Trans);
- POV_FREE (Object);
- }
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Cone_BBox
- *
- * INPUT
- *
- * Cone - Cone/Cylinder
- *
- * OUTPUT
- *
- * Cone
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate the bounding box of a cone or cylinder.
- *
- * CHANGES
- *
- * Aug 1994 : Creation.
- *
- ******************************************************************************/
- void Compute_Cone_BBox(CONE *Cone)
- {
- Make_BBox(Cone->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
- Recompute_BBox(&Cone->BBox, Cone->Trans);
- }
|