1 /****************************************************************************
4 * This module implements the box primitive.
5 * This file was written by Alexander Enzmann. He wrote the code for
6 * boxes 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 /* Minimal intersection depth. */
43 #define DEPTH_TOLERANCE 1.0e-6
45 /* Two values are equal if their difference is small than CLOSE_TOLERANCE. */
47 #define CLOSE_TOLERANCE 1.0e-6
60 /*****************************************************************************
62 ******************************************************************************/
63 static int All_Box_Intersections (OBJECT
*Object
, RAY
*Ray
, ISTACK
*Depth_Stack
);
64 static int Inside_Box (VECTOR point
, OBJECT
*Object
);
65 static void Box_Normal (VECTOR Result
, OBJECT
*Object
, INTERSECTION
*Inter
);
66 static void Translate_Box (OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
);
67 static void Rotate_Box (OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
);
68 static void Scale_Box (OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
);
69 static void Transform_Box (OBJECT
*Object
, TRANSFORM
*Trans
);
70 static void Invert_Box (OBJECT
*Object
);
74 /*****************************************************************************
76 ******************************************************************************/
80 All_Box_Intersections
,
81 Inside_Box
, Box_Normal
,
82 (COPY_METHOD
)Copy_Box
, Translate_Box
, Rotate_Box
, Scale_Box
, Transform_Box
,
83 Invert_Box
, Destroy_Box
88 /*****************************************************************************
92 * All_Box_Intersections
112 ******************************************************************************/
114 static int All_Box_Intersections(OBJECT
*Object
, RAY
*Ray
, ISTACK
*Depth_Stack
)
116 int Intersection_Found
;
121 Increase_Counter(stats
[Ray_Box_Tests
]);
123 Intersection_Found
= FALSE
;
125 if (Intersect_Box(Ray
, (BOX
*)Object
, &Depth1
, &Depth2
, &Side1
, &Side2
))
127 if (Depth1
> DEPTH_TOLERANCE
)
129 VEvaluateRay(IPoint
, Ray
->Initial
, Depth1
, Ray
->Direction
);
131 if (Point_In_Clip(IPoint
, Object
->Clip
))
133 push_entry_i1(Depth1
,IPoint
,Object
,Side1
,Depth_Stack
);
135 Intersection_Found
= TRUE
;
139 VEvaluateRay(IPoint
, Ray
->Initial
, Depth2
, Ray
->Direction
);
141 if (Point_In_Clip(IPoint
, Object
->Clip
))
143 push_entry_i1(Depth2
,IPoint
,Object
,Side2
,Depth_Stack
);
145 Intersection_Found
= TRUE
;
149 if (Intersection_Found
)
151 Increase_Counter(stats
[Ray_Box_Tests_Succeeded
]);
154 return (Intersection_Found
);
159 /*****************************************************************************
181 * Sep 1994 : Added code to decide which side was hit in the case
182 * intersection points are close to each other. This removes
183 * some ugly artefacts one could observe at the corners of
184 * boxes due to the usage of the wrong normal vector. [DB]
186 ******************************************************************************/
188 int Intersect_Box(RAY
*Ray
, BOX
*box
, DBL
*Depth1
, DBL
*Depth2
, int *Side1
, int *Side2
)
190 int smin
= 0, smax
= 0; /* Side hit for min/max intersection. */
194 /* Transform the point into the boxes space */
196 if (box
->Trans
!= NULL
)
198 MInvTransPoint(P
, Ray
->Initial
, box
->Trans
);
199 MInvTransDirection(D
, Ray
->Direction
, box
->Trans
);
203 Assign_Vector(P
, Ray
->Initial
);
204 Assign_Vector(D
, Ray
->Direction
);
216 t
= (box
->bounds
[0][X
] - P
[X
]) / D
[X
];
218 if (t
< tmin
) return(FALSE
);
226 t
= (box
->bounds
[1][X
] - P
[X
]) / D
[X
];
230 if (t
> tmax
) return(FALSE
);
240 t
= (box
->bounds
[1][X
] - P
[X
]) / D
[X
];
242 if (t
< tmin
) return(FALSE
);
250 t
= (box
->bounds
[0][X
] - P
[X
]) / D
[X
];
254 if (t
> tmax
) return(FALSE
);
262 if ((P
[X
] < box
->bounds
[0][X
]) || (P
[X
] > box
->bounds
[1][X
]))
275 t
= (box
->bounds
[0][Y
] - P
[Y
]) / D
[Y
];
277 if (t
< tmin
) return(FALSE
);
279 if (t
<= tmax
- CLOSE_TOLERANCE
)
287 * If intersection points are close to each other find out
288 * which side to use, i.e. is most probably hit. [DB 9/94]
291 if (t
<= tmax
+ CLOSE_TOLERANCE
)
293 if (-D
[Y
] > fabs(D
[X
])) smax
= SIDE_Y_0
;
297 t
= (box
->bounds
[1][Y
] - P
[Y
]) / D
[Y
];
299 if (t
>= tmin
+ CLOSE_TOLERANCE
)
301 if (t
> tmax
) return(FALSE
);
309 * If intersection points are close to each other find out
310 * which side to use, i.e. is most probably hit. [DB 9/94]
313 if (t
>= tmin
- CLOSE_TOLERANCE
)
315 if (-D
[Y
] > fabs(D
[X
])) smin
= SIDE_Y_1
;
323 t
= (box
->bounds
[1][Y
] - P
[Y
]) / D
[Y
];
325 if (t
< tmin
) return(FALSE
);
327 if (t
<= tmax
- CLOSE_TOLERANCE
)
335 * If intersection points are close to each other find out
336 * which side to use, i.e. is most probably hit. [DB 9/94]
339 if (t
<= tmax
+ CLOSE_TOLERANCE
)
341 if (D
[Y
] > fabs(D
[X
])) smax
= SIDE_Y_1
;
345 t
= (box
->bounds
[0][Y
] - P
[Y
]) / D
[Y
];
347 if (t
>= tmin
+ CLOSE_TOLERANCE
)
349 if (t
> tmax
) return(FALSE
);
357 * If intersection points are close to each other find out
358 * which side to use, i.e. is most probably hit. [DB 9/94]
361 if (t
>= tmin
- CLOSE_TOLERANCE
)
363 if (D
[Y
] > fabs(D
[X
])) smin
= SIDE_Y_0
;
369 if ((P
[Y
] < box
->bounds
[0][Y
]) || (P
[Y
] > box
->bounds
[1][Y
]))
380 t
= (box
->bounds
[0][Z
] - P
[Z
]) / D
[Z
];
382 if (t
< tmin
) return(FALSE
);
384 if (t
<= tmax
- CLOSE_TOLERANCE
)
392 * If intersection points are close to each other find out
393 * which side to use, i.e. is most probably hit. [DB 9/94]
396 if (t
<= tmax
+ CLOSE_TOLERANCE
)
401 case SIDE_X_1
: if (-D
[Z
] > fabs(D
[X
])) smax
= SIDE_Z_0
; break;
404 case SIDE_Y_1
: if (-D
[Z
] > fabs(D
[Y
])) smax
= SIDE_Z_0
; break;
409 t
= (box
->bounds
[1][Z
] - P
[Z
]) / D
[Z
];
411 if (t
>= tmin
+ CLOSE_TOLERANCE
)
413 if (t
> tmax
) return(FALSE
);
421 * If intersection points are close to each other find out
422 * which side to use, i.e. is most probably hit. [DB 9/94]
425 if (t
>= tmin
- CLOSE_TOLERANCE
)
430 case SIDE_X_1
: if (-D
[Z
] > fabs(D
[X
])) smin
= SIDE_Z_1
; break;
433 case SIDE_Y_1
: if (-D
[Z
] > fabs(D
[Y
])) smin
= SIDE_Z_1
; break;
442 t
= (box
->bounds
[1][Z
] - P
[Z
]) / D
[Z
];
444 if (t
< tmin
) return(FALSE
);
446 if (t
<= tmax
- CLOSE_TOLERANCE
)
454 * If intersection points are close to each other find out
455 * which side to use, i.e. is most probably hit. [DB 9/94]
458 if (t
<= tmax
+ CLOSE_TOLERANCE
)
463 case SIDE_X_1
: if (D
[Z
] > fabs(D
[X
])) smax
= SIDE_Z_1
; break;
466 case SIDE_Y_1
: if (D
[Z
] > fabs(D
[Y
])) smax
= SIDE_Z_1
; break;
471 t
= (box
->bounds
[0][Z
] - P
[Z
]) / D
[Z
];
473 if (t
>= tmin
+ CLOSE_TOLERANCE
)
475 if (t
> tmax
) return(FALSE
);
483 * If intersection points are close to each other find out
484 * which side to use, i.e. is most probably hit. [DB 9/94]
487 if (t
>= tmin
- CLOSE_TOLERANCE
)
492 case SIDE_X_1
: if (D
[Z
] > fabs(D
[X
])) smin
= SIDE_Z_0
; break;
495 case SIDE_Y_1
: if (D
[Z
] > fabs(D
[Y
])) smin
= SIDE_Z_0
; break;
502 if ((P
[Z
] < box
->bounds
[0][Z
]) || (P
[Z
] > box
->bounds
[1][Z
]))
509 if (tmax
< DEPTH_TOLERANCE
)
525 /*****************************************************************************
549 ******************************************************************************/
551 static int Inside_Box(VECTOR IPoint
, OBJECT
*Object
)
554 BOX
*box
= (BOX
*) Object
;
556 /* Transform the point into box space. */
558 if (box
->Trans
!= NULL
)
560 MInvTransPoint(New_Point
, IPoint
, box
->Trans
);
564 Assign_Vector(New_Point
,IPoint
);
567 /* Test to see if we are outside the box. */
569 if ((New_Point
[X
] < box
->bounds
[0][X
]) || (New_Point
[X
] > box
->bounds
[1][X
]))
571 return (Test_Flag(box
, INVERTED_FLAG
));
574 if ((New_Point
[Y
] < box
->bounds
[0][Y
]) || (New_Point
[Y
] > box
->bounds
[1][Y
]))
576 return (Test_Flag(box
, INVERTED_FLAG
));
579 if ((New_Point
[Z
] < box
->bounds
[0][Z
]) || (New_Point
[Z
] > box
->bounds
[1][Z
]))
581 return (Test_Flag(box
, INVERTED_FLAG
));
584 /* Inside the box. */
586 return (!Test_Flag(box
, INVERTED_FLAG
));
591 /*****************************************************************************
615 ******************************************************************************/
617 static void Box_Normal(VECTOR Result
, OBJECT
*Object
, INTERSECTION
*Inter
)
621 case SIDE_X_0
: Make_Vector(Result
, -1.0, 0.0, 0.0); break;
622 case SIDE_X_1
: Make_Vector(Result
, 1.0, 0.0, 0.0); break;
623 case SIDE_Y_0
: Make_Vector(Result
, 0.0, -1.0, 0.0); break;
624 case SIDE_Y_1
: Make_Vector(Result
, 0.0, 1.0, 0.0); break;
625 case SIDE_Z_0
: Make_Vector(Result
, 0.0, 0.0, -1.0); break;
626 case SIDE_Z_1
: Make_Vector(Result
, 0.0, 0.0, 1.0); break;
628 default: Error("Unknown box side in Box_Normal().\n");
631 /* Transform the point into the boxes space. */
633 if (((BOX
*)Object
)->Trans
!= NULL
)
635 MTransNormal(Result
, Result
, ((BOX
*)Object
)->Trans
);
637 VNormalize(Result
, Result
);
643 /*****************************************************************************
667 ******************************************************************************/
669 static void Translate_Box(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
671 if (((BOX
*)Object
)->Trans
== NULL
)
673 VAddEq(((BOX
*)Object
)->bounds
[0], Vector
);
675 VAddEq(((BOX
*)Object
)->bounds
[1], Vector
);
677 Compute_Box_BBox((BOX
*)Object
);
681 Transform_Box(Object
, Trans
);
687 /*****************************************************************************
711 ******************************************************************************/
713 static void Rotate_Box(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
715 Transform_Box(Object
, Trans
);
720 /*****************************************************************************
744 ******************************************************************************/
746 static void Scale_Box(OBJECT
*Object
, VECTOR Vector
, TRANSFORM
*Trans
)
749 BOX
*Box
= (BOX
*)Object
;
751 if (((BOX
*)Object
)->Trans
== NULL
)
753 VEvaluateEq(Box
->bounds
[0], Vector
);
754 VEvaluateEq(Box
->bounds
[1], Vector
);
756 if (Box
->bounds
[0][X
] > Box
->bounds
[1][X
])
758 temp
= Box
->bounds
[0][X
];
760 Box
->bounds
[0][X
] = Box
->bounds
[1][X
];
761 Box
->bounds
[1][X
] = temp
;
764 if (Box
->bounds
[0][Y
] > Box
->bounds
[1][Y
])
766 temp
= Box
->bounds
[0][Y
];
768 Box
->bounds
[0][Y
] = Box
->bounds
[1][Y
];
769 Box
->bounds
[1][Y
] = temp
;
772 if (Box
->bounds
[0][Z
] > Box
->bounds
[1][Z
])
774 temp
= Box
->bounds
[0][Z
];
776 Box
->bounds
[0][Z
] = Box
->bounds
[1][Z
];
777 Box
->bounds
[1][Z
] = temp
;
780 Compute_Box_BBox((BOX
*)Object
);
784 Transform_Box(Object
, Trans
);
790 /*****************************************************************************
814 ******************************************************************************/
816 static void Invert_Box(OBJECT
*Object
)
818 Invert_Flag(Object
, INVERTED_FLAG
);
823 /*****************************************************************************
847 ******************************************************************************/
849 static void Transform_Box(OBJECT
*Object
, TRANSFORM
*Trans
)
851 BOX
*box
= (BOX
*)Object
;
853 if (box
->Trans
== NULL
)
855 box
->Trans
= Create_Transform();
858 Compose_Transforms(box
->Trans
, Trans
);
860 Compute_Box_BBox(box
);
865 /*****************************************************************************
889 ******************************************************************************/
895 New
= (BOX
*)POV_MALLOC(sizeof(BOX
), "box");
897 INIT_OBJECT_FIELDS(New
, BOX_OBJECT
, &Box_Methods
)
899 Make_Vector(New
->bounds
[0], -1.0, -1.0, -1.0);
900 Make_Vector(New
->bounds
[1], 1.0, 1.0, 1.0);
902 Make_BBox(New
->BBox
, -1.0, -1.0, -1.0, 2.0, 2.0, 2.0);
911 /*****************************************************************************
935 ******************************************************************************/
937 BOX
*Copy_Box(OBJECT
*Object
)
945 *New
= *((BOX
*)Object
);
947 New
->Trans
= Copy_Transform(((BOX
*)Object
)->Trans
);
954 /*****************************************************************************
978 ******************************************************************************/
980 void Destroy_Box(OBJECT
*Object
)
982 Destroy_Transform(((BOX
*)Object
)->Trans
);
989 /*****************************************************************************
1011 * Calculate the bounding box of a box.
1015 * Aug 1994 : Creation.
1017 ******************************************************************************/
1019 void Compute_Box_BBox(BOX
*Box
)
1021 Assign_BBox_Vect(Box
->BBox
.Lower_Left
, Box
->bounds
[0]);
1023 VSub(Box
->BBox
.Lengths
, Box
->bounds
[1], Box
->bounds
[0]);
1025 if (Box
->Trans
!= NULL
)
1027 Recompute_BBox(&Box
->BBox
, Box
->Trans
);