1 /****************************************************************************
4 * This module implements the cone primitive.
5 * This file was written by Alexander Enzmann. He wrote the code for
6 * cones and generously provided us these enhancements.
8 * from Persistence of Vision(tm) Ray Tracer
9 * Copyright 1996,1999 Persistence of Vision Team
10 *---------------------------------------------------------------------------
11 * NOTICE: This source code file is provided so that users may experiment
12 * with enhancements to POV-Ray and to port the software to platforms other
13 * than those supported by the POV-Ray Team. There are strict rules under
14 * which you are permitted to use this file. The rules are in the file
15 * named POVLEGAL.DOC which should be distributed with this file.
16 * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
17 * Team Coordinator by email to team-coord@povray.org or visit us on the web at
18 * http://www.povray.org. The latest version of POV-Ray may be found at this site.
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24 *****************************************************************************/
37 /*****************************************************************************
38 * Local preprocessor defines
39 ******************************************************************************/
41 #define Cone_Tolerance 1.0e-6
43 #define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
45 /* Part of the cone/cylinder hit. [DB 9/94] */
53 /*****************************************************************************
55 ******************************************************************************/
57 typedef struct Cone_Intersection_Structure CONE_INT
;
59 struct Cone_Intersection_Structure
61 DBL d
; /* Distance of intersection point */
62 int t
; /* Type of intersection: base/cap plane or side */
67 /*****************************************************************************
69 ******************************************************************************/
71 static int intersect_cone (RAY
*Ray
, CONE
*Cone
, CONE_INT
*Depths
);
72 static void Destroy_Cone (OBJECT
*Object
);
73 static int All_Cone_Intersections (OBJECT
*Object
, RAY
*Ray
, ISTACK
*Depth_Stack
);
74 static int Inside_Cone (VECTOR point
, OBJECT
*Object
);
75 static void Cone_Normal (VECTOR Result
, OBJECT
*Object
, INTERSECTION
*Inter
);
76 static CONE
*Copy_Cone (OBJECT
*Object
);
77 static void Translate_Cone (OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
);
78 static void Rotate_Cone (OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
);
79 static void Scale_Cone (OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
);
80 static void Transform_Cone (OBJECT
*Object
, TRANSFORM
*Trans
);
81 static void Invert_Cone (OBJECT
*Object
);
84 /*****************************************************************************
86 ******************************************************************************/
88 static METHODS Cone_Methods
=
90 All_Cone_Intersections
,
91 Inside_Cone
, Cone_Normal
,
92 (COPY_METHOD
)Copy_Cone
, Translate_Cone
, Rotate_Cone
, Scale_Cone
, Transform_Cone
,
93 Invert_Cone
, Destroy_Cone
98 /*****************************************************************************
102 * All_Cone_Intersections
122 ******************************************************************************/
124 static int All_Cone_Intersections(OBJECT
*Object
, RAY
*Ray
, ISTACK
*Depth_Stack
)
126 int Intersection_Found
, cnt
, i
;
130 Intersection_Found
= FALSE
;
132 if ((cnt
= intersect_cone(Ray
, (CONE
*)Object
, I
)) != 0)
134 for (i
= 0; i
< cnt
; i
++)
136 VEvaluateRay(IPoint
, Ray
->Initial
, I
[i
].d
, Ray
->Direction
);
138 if (Point_In_Clip(IPoint
, Object
->Clip
))
140 push_entry_i1(I
[i
].d
,IPoint
,Object
,I
[i
].t
,Depth_Stack
);
142 Intersection_Found
= TRUE
;
147 return (Intersection_Found
);
152 /*****************************************************************************
176 ******************************************************************************/
178 static int intersect_cone(RAY
*Ray
, CONE
*Cone
, CONE_INT
*Intersection
)
181 DBL a
, b
, c
, z
, t1
, t2
, len
;
185 Increase_Counter(stats
[Ray_Cone_Tests
]);
187 /* Transform the ray into the cones space */
189 MInvTransPoint(P
, Ray
->Initial
, Cone
->Trans
);
190 MInvTransDirection(D
, Ray
->Direction
, Cone
->Trans
);
193 VInverseScaleEq(D
, len
);
195 if (Test_Flag(Cone
, CYLINDER_FLAG
))
197 /* Solve intersections with a cylinder */
199 a
= D
[X
] * D
[X
] + D
[Y
] * D
[Y
];
203 b
= P
[X
] * D
[X
] + P
[Y
] * D
[Y
];
205 c
= P
[X
] * P
[X
] + P
[Y
] * P
[Y
] - 1.0;
216 z
= P
[Z
] + t1
* D
[Z
];
218 if ((t1
> Cone_Tolerance
) && (t1
< Max_Distance
) && (z
>= 0.0) && (z
<= 1.0))
220 Intersection
[i
].d
= t1
/ len
;
221 Intersection
[i
++].t
= SIDE_HIT
;
224 z
= P
[Z
] + t2
* D
[Z
];
226 if ((t2
> Cone_Tolerance
) && (t1
< Max_Distance
) && (z
>= 0.0) && (z
<= 1.0))
228 Intersection
[i
].d
= t2
/ len
;
229 Intersection
[i
++].t
= SIDE_HIT
;
236 /* Solve intersections with a cone */
238 a
= D
[X
] * D
[X
] + D
[Y
] * D
[Y
] - D
[Z
] * D
[Z
];
240 b
= D
[X
] * P
[X
] + D
[Y
] * P
[Y
] - D
[Z
] * P
[Z
];
242 c
= P
[X
] * P
[X
] + P
[Y
] * P
[Y
] - P
[Z
] * P
[Z
];
244 if (fabs(a
) < EPSILON
)
246 if (fabs(b
) > EPSILON
)
248 /* One intersection */
252 z
= P
[Z
] + t1
* D
[Z
];
254 if ((t1
> Cone_Tolerance
) && (t1
< Max_Distance
) && (z
>= Cone
->dist
) && (z
<= 1.0))
256 Intersection
[i
].d
= t1
/ len
;
257 Intersection
[i
++].t
= SIDE_HIT
;
263 /* Check hits against the side of the cone */
274 z
= P
[Z
] + t1
* D
[Z
];
276 if ((t1
> Cone_Tolerance
) && (t1
< Max_Distance
) && (z
>= Cone
->dist
) && (z
<= 1.0))
278 Intersection
[i
].d
= t1
/ len
;
279 Intersection
[i
++].t
= SIDE_HIT
;
282 z
= P
[Z
] + t2
* D
[Z
];
284 if ((t2
> Cone_Tolerance
) && (t1
< Max_Distance
) && (z
>= Cone
->dist
) && (z
<= 1.0))
286 Intersection
[i
].d
= t2
/ len
;
287 Intersection
[i
++].t
= SIDE_HIT
;
293 if (Test_Flag(Cone
, CLOSED_FLAG
) && (fabs(D
[Z
]) > EPSILON
))
295 d
= (1.0 - P
[Z
]) / D
[Z
];
297 a
= (P
[X
] + d
* D
[X
]);
299 b
= (P
[Y
] + d
* D
[Y
]);
301 if (((Sqr(a
) + Sqr(b
)) <= 1.0) && (d
> Cone_Tolerance
) && (d
< Max_Distance
))
303 Intersection
[i
].d
= d
/ len
;
304 Intersection
[i
++].t
= CAP_HIT
;
307 d
= (Cone
->dist
- P
[Z
]) / D
[Z
];
309 a
= (P
[X
] + d
* D
[X
]);
311 b
= (P
[Y
] + d
* D
[Y
]);
313 if ((Sqr(a
) + Sqr(b
)) <= (Test_Flag(Cone
, CYLINDER_FLAG
) ? 1.0 : Sqr(Cone
->dist
))
314 && (d
> Cone_Tolerance
) && (d
< Max_Distance
))
316 Intersection
[i
].d
= d
/ len
;
317 Intersection
[i
++].t
= BASE_HIT
;
323 Increase_Counter(stats
[Ray_Cone_Tests_Succeeded
]);
331 /*****************************************************************************
355 ******************************************************************************/
357 static int Inside_Cone(VECTOR IPoint
, OBJECT
*Object
)
359 CONE
*Cone
= (CONE
*)Object
;
360 DBL w2
, z2
, offset
= (Test_Flag(Cone
, CLOSED_FLAG
) ? -EPSILON
: EPSILON
);
363 /* Transform the point into the cones space */
365 MInvTransPoint(New_Point
, IPoint
, Cone
->Trans
);
367 /* Test to see if we are inside the cone */
369 w2
= New_Point
[X
] * New_Point
[X
] + New_Point
[Y
] * New_Point
[Y
];
371 if (Test_Flag(Cone
, CYLINDER_FLAG
))
373 /* Check to see if we are inside a cylinder */
375 if ((w2
> 1.0 + offset
) ||
376 (New_Point
[Z
] < 0.0 - offset
) ||
377 (New_Point
[Z
] > 1.0 + offset
))
379 return (Test_Flag(Cone
, INVERTED_FLAG
));
383 return (!Test_Flag(Cone
, INVERTED_FLAG
));
388 /* Check to see if we are inside a cone */
390 z2
= New_Point
[Z
] * New_Point
[Z
];
392 if ((w2
> z2
+ offset
) ||
393 (New_Point
[Z
] < Cone
->dist
- offset
) ||
394 (New_Point
[Z
] > 1.0+offset
))
396 return (Test_Flag(Cone
, INVERTED_FLAG
));
400 return (!Test_Flag(Cone
, INVERTED_FLAG
));
407 /*****************************************************************************
431 ******************************************************************************/
433 static void Cone_Normal(VECTOR Result
, OBJECT
*Object
, INTERSECTION
*Inter
)
435 CONE
*Cone
= (CONE
*)Object
;
437 /* Transform the point into the cones space */
439 MInvTransPoint(Result
, Inter
->IPoint
, Cone
->Trans
);
441 /* Calculating the normal is real simple in canonical cone space */
447 if (Test_Flag(Cone
, CYLINDER_FLAG
))
453 Result
[Z
] = -Result
[Z
];
460 Make_Vector(Result
, 0.0, 0.0, -1.0)
466 Make_Vector(Result
, 0.0, 0.0, 1.0)
471 /* Transform the point out of the cones space */
473 MTransNormal(Result
, Result
, Cone
->Trans
);
475 VNormalize(Result
, Result
);
480 /*****************************************************************************
504 ******************************************************************************/
506 static void Translate_Cone(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
508 Transform_Cone(Object
, Trans
);
513 /*****************************************************************************
537 ******************************************************************************/
539 static void Rotate_Cone(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
541 Transform_Cone(Object
, Trans
);
546 /*****************************************************************************
570 ******************************************************************************/
572 static void Scale_Cone(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
574 Transform_Cone(Object
, Trans
);
579 /*****************************************************************************
603 ******************************************************************************/
605 static void Transform_Cone(OBJECT
*Object
, TRANSFORM
*Trans
)
607 CONE
*Cone
= (CONE
*)Object
;
609 Compose_Transforms(Cone
->Trans
, Trans
);
611 Compute_Cone_BBox(Cone
);
616 /*****************************************************************************
640 ******************************************************************************/
642 static void Invert_Cone(OBJECT
*Object
)
644 Invert_Flag(Object
, INVERTED_FLAG
);
649 /*****************************************************************************
673 ******************************************************************************/
679 New
= (CONE
*)POV_MALLOC(sizeof(CONE
), "cone");
681 INIT_OBJECT_FIELDS(New
, CONE_OBJECT
, &Cone_Methods
)
683 Make_Vector(New
->apex
, 0.0, 0.0, 1.0);
684 Make_Vector(New
->base
, 0.0, 0.0, 0.0);
686 New
->apex_radius
= 1.0;
687 New
->base_radius
= 0.0;
691 New
->Trans
= Create_Transform();
693 /* Cone/Cylinder has capped ends by default. */
695 Set_Flag(New
, CLOSED_FLAG
);
699 Make_BBox(New
->BBox
, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
706 /*****************************************************************************
730 ******************************************************************************/
732 static CONE
*Copy_Cone(OBJECT
*Object
)
738 /* Get rid of the transformation created in Create_Cone(). */
740 Destroy_Transform(New
->Trans
);
744 *New
= *((CONE
*)Object
);
746 New
->Trans
= Copy_Transform(((CONE
*)Object
)->Trans
);
753 /*****************************************************************************
777 ******************************************************************************/
779 CONE
*Create_Cylinder()
783 New
= (CONE
*)POV_MALLOC(sizeof(CONE
), "cone");
785 INIT_OBJECT_FIELDS(New
, CONE_OBJECT
, &Cone_Methods
)
787 Make_Vector(New
->apex
, 0.0, 0.0, 1.0);
788 Make_Vector(New
->base
, 0.0, 0.0, 0.0);
790 New
->apex_radius
= 1.0;
791 New
->base_radius
= 1.0;
794 New
->Trans
= Create_Transform();
796 Set_Flag(New
, CYLINDER_FLAG
); /* This is a cylinder. */
797 Set_Flag(New
, CLOSED_FLAG
); /* Has capped ends. */
801 Make_BBox(New
->BBox
, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
808 /*****************************************************************************
830 * Feb 1996: check for equal sized ends (cylinder) first [AED]
832 ******************************************************************************/
834 void Compute_Cone_Data(OBJECT
*Object
)
837 VECTOR tmpv
, axis
, origin
;
838 CONE
*Cone
= (CONE
*)Object
;
840 /* Process the primitive specific information */
842 if (fabs(Cone
->apex_radius
- Cone
->base_radius
) < EPSILON
)
844 /* What we are dealing with here is really a cylinder */
846 Set_Flag(Cone
, CYLINDER_FLAG
);
848 Compute_Cylinder_Data(Object
);
853 if (Cone
->apex_radius
< Cone
->base_radius
)
855 /* Want the bigger end at the top */
857 Assign_Vector(tmpv
,Cone
->base
);
858 Assign_Vector(Cone
->base
,Cone
->apex
);
859 Assign_Vector(Cone
->apex
,tmpv
);
861 tmpf
= Cone
->base_radius
;
862 Cone
->base_radius
= Cone
->apex_radius
;
863 Cone
->apex_radius
= tmpf
;
866 /* Find the axis and axis length */
868 VSub(axis
, Cone
->apex
, Cone
->base
);
874 Error("Degenerate cone/cylinder.\n");
878 VInverseScaleEq(axis
, len
)
881 /* Determine alignment */
883 tmpf
= Cone
->base_radius
* len
/ (Cone
->apex_radius
- Cone
->base_radius
);
885 VScale(origin
, axis
, tmpf
);
887 VSub(origin
, Cone
->base
, origin
);
891 Cone
->dist
= tmpf
/ tlen
;
893 Compute_Coordinate_Transform(Cone
->Trans
, origin
, axis
, Cone
->apex_radius
, tlen
);
895 /* Recalculate the bounds */
897 Compute_Cone_BBox(Cone
);
902 /*****************************************************************************
906 * Compute_Cylinder_Data
926 ******************************************************************************/
928 void Compute_Cylinder_Data(OBJECT
*Object
)
932 CONE
*Cone
= (CONE
*)Object
;
934 VSub(axis
, Cone
->apex
, Cone
->base
);
940 Error("Degenerate cylinder, base point = apex point.\n");
944 VInverseScaleEq(axis
, tmpf
)
946 Compute_Coordinate_Transform(Cone
->Trans
, Cone
->base
, axis
, Cone
->apex_radius
, tmpf
);
951 /* Recalculate the bounds */
953 Compute_Cone_BBox(Cone
);
959 /*****************************************************************************
983 ******************************************************************************/
985 static void Destroy_Cone(OBJECT
*Object
)
987 Destroy_Transform(((CONE
*)Object
)->Trans
);
994 /*****************************************************************************
1002 * Cone - Cone/Cylinder
1016 * Calculate the bounding box of a cone or cylinder.
1020 * Aug 1994 : Creation.
1022 ******************************************************************************/
1024 void Compute_Cone_BBox(CONE
*Cone
)
1026 Make_BBox(Cone
->BBox
, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
1028 Recompute_BBox(&Cone
->BBox
, Cone
->Trans
);