1 //******************************************************************************
2 ///
3 /// @file core/shape/box.cpp
4 ///
5 /// Implementation of the box geometric primitive.
6 ///
7 /// @author Alexander Enzmann
8 ///
9 /// @copyright
10 /// @parblock
11 ///
12 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
13 /// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
14 ///
15 /// POV-Ray is free software: you can redistribute it and/or modify
16 /// it under the terms of the GNU Affero General Public License as
17 /// published by the Free Software Foundation, either version 3 of the
18 /// License, or (at your option) any later version.
19 ///
20 /// POV-Ray is distributed in the hope that it will be useful,
21 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
22 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 /// GNU Affero General Public License for more details.
24 ///
25 /// You should have received a copy of the GNU Affero General Public License
26 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 ///
28 /// ----------------------------------------------------------------------------
29 ///
30 /// POV-Ray is based on the popular DKB raytracer version 2.12.
31 /// DKBTrace was originally written by David K. Buck.
32 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
33 ///
34 /// @endparblock
35 ///
36 //******************************************************************************
37 
38 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
39 #include "core/shape/box.h"
40 
41 #include "base/pov_err.h"
42 
43 #include "core/bounding/boundingbox.h"
44 #include "core/math/matrix.h"
45 #include "core/render/ray.h"
46 #include "core/scene/tracethreaddata.h"
47 
48 // this must be the last file included
49 #include "base/povdebug.h"
50 
51 namespace pov
52 {
53 
54 /*****************************************************************************
55 * Local preprocessor defines
56 ******************************************************************************/
57 
58 /* Minimal intersection depth. */
59 
60 const DBL DEPTH_TOLERANCE = 1.0e-6;
61 
62 /* Two values are equal if their difference is small than CLOSE_TOLERANCE. */
63 
64 const DBL CLOSE_TOLERANCE = 1.0e-6;
65 
66 
67 /*****************************************************************************
68 *
69 * FUNCTION
70 *
71 *   All_Box_Intersections
72 *
73 * INPUT
74 *
75 * OUTPUT
76 *
77 * RETURNS
78 *
79 * AUTHOR
80 *
81 *   Alexander Enzmann
82 *
83 * DESCRIPTION
84 *
85 *   -
86 *
87 * CHANGES
88 *
89 *   -
90 *
91 ******************************************************************************/
92 
All_Intersections(const Ray & ray,IStack & Depth_Stack,TraceThreadData * Thread)93 bool Box::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
94 {
95     int Intersection_Found;
96     int Side1, Side2;
97     DBL Depth1, Depth2;
98     Vector3d IPoint;
99 
100     Thread->Stats()[Ray_Box_Tests]++;
101 
102     Intersection_Found = false;
103 
104     if (Intersect(ray, Trans, bounds[0], bounds[1], &Depth1, &Depth2, &Side1, &Side2))
105     {
106         if (Depth1 > DEPTH_TOLERANCE)
107         {
108             IPoint = ray.Evaluate(Depth1);
109 
110             if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
111             {
112                 Depth_Stack->push(Intersection(Depth1,IPoint,this,Side1));
113 
114                 Intersection_Found = true;
115             }
116         }
117 
118         IPoint = ray.Evaluate(Depth2);
119 
120         if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
121         {
122             Depth_Stack->push(Intersection(Depth2,IPoint,this,Side2));
123 
124             Intersection_Found = true;
125         }
126     }
127 
128     if (Intersection_Found)
129         Thread->Stats()[Ray_Box_Tests_Succeeded]++;
130 
131     return (Intersection_Found);
132 }
133 
134 
135 
136 /*****************************************************************************
137 *
138 * FUNCTION
139 *
140 *   Intersect_Box
141 *
142 * INPUT
143 *
144 * OUTPUT
145 *
146 * RETURNS
147 *
148 * AUTHOR
149 *
150 *   Alexander Enzmann
151 *
152 * DESCRIPTION
153 *
154 *   -
155 *
156 * CHANGES
157 *
158 *   Sep 1994 : Added code to decide which side was hit in the case
159 *              intersection points are close to each other. This removes
160 *              some ugly artefacts one could observe at the corners of
161 *              boxes due to the usage of the wrong normal vector. [DB]
162 *
163 ******************************************************************************/
164 
Intersect(const BasicRay & ray,const TRANSFORM * Trans,const Vector3d & Corner1,const Vector3d & Corner2,DBL * Depth1,DBL * Depth2,int * Side1,int * Side2)165 bool Box::Intersect(const BasicRay& ray, const TRANSFORM *Trans, const Vector3d& Corner1, const Vector3d& Corner2, DBL *Depth1, DBL  *Depth2, int *Side1, int  *Side2)
166 {
167     int smin = 0, smax = 0;    /* Side hit for min/max intersection. */
168     DBL t, tmin, tmax;
169     Vector3d P, D;
170 
171     /* Transform the point into the boxes space */
172 
173     if (Trans != nullptr)
174     {
175         MInvTransPoint(P, ray.Origin, Trans);
176         MInvTransDirection(D, ray.Direction, Trans);
177     }
178     else
179     {
180         P = ray.Origin;
181         D = ray.Direction;
182     }
183 
184     tmin = 0.0;
185     tmax = BOUND_HUGE;
186 
187     /*
188      * Sides first.
189      */
190 
191     if (D[X] < -EPSILON)
192     {
193         t = (Corner1[X] - P[X]) / D[X];
194 
195         if (t < tmin) return(false);
196 
197         if (t <= tmax)
198         {
199             smax = kSideHit_X0;
200             tmax = t;
201         }
202 
203         t = (Corner2[X] - P[X]) / D[X];
204 
205         if (t >= tmin)
206         {
207             if (t > tmax) return(false);
208 
209             smin = kSideHit_X1;
210             tmin = t;
211         }
212     }
213     else
214     {
215         if (D[X] > EPSILON)
216         {
217             t = (Corner2[X] - P[X]) / D[X];
218 
219             if (t < tmin) return(false);
220 
221             if (t <= tmax)
222             {
223                 smax = kSideHit_X1;
224                 tmax = t;
225             }
226 
227             t = (Corner1[X] - P[X]) / D[X];
228 
229             if (t >= tmin)
230             {
231                 if (t > tmax) return(false);
232 
233                 smin = kSideHit_X0;
234                 tmin = t;
235             }
236         }
237         else
238         {
239             if ((P[X] < Corner1[X]) || (P[X] > Corner2[X]))
240             {
241                 return(false);
242             }
243         }
244     }
245 
246     /*
247      * Check Top/Bottom.
248      */
249 
250     if (D[Y] < -EPSILON)
251     {
252         t = (Corner1[Y] - P[Y]) / D[Y];
253 
254         if (t < tmin) return(false);
255 
256         if (t <= tmax - CLOSE_TOLERANCE)
257         {
258             smax = kSideHit_Y0;
259             tmax = t;
260         }
261         else
262         {
263             /*
264              * If intersection points are close to each other find out
265              * which side to use, i.e. is most probably hit. [DB 9/94]
266              */
267 
268             if (t <= tmax + CLOSE_TOLERANCE)
269             {
270                 if (-D[Y] > fabs(D[X])) smax = kSideHit_Y0;
271             }
272         }
273 
274         t = (Corner2[Y] - P[Y]) / D[Y];
275 
276         if (t >= tmin + CLOSE_TOLERANCE)
277         {
278             if (t > tmax) return(false);
279 
280             smin = kSideHit_Y1;
281             tmin = t;
282         }
283         else
284         {
285             /*
286              * If intersection points are close to each other find out
287              * which side to use, i.e. is most probably hit. [DB 9/94]
288              */
289 
290             if (t >= tmin - CLOSE_TOLERANCE)
291             {
292                 if (-D[Y] > fabs(D[X])) smin = kSideHit_Y1;
293             }
294         }
295     }
296     else
297     {
298         if (D[Y] > EPSILON)
299         {
300             t = (Corner2[Y] - P[Y]) / D[Y];
301 
302             if (t < tmin) return(false);
303 
304             if (t <= tmax - CLOSE_TOLERANCE)
305             {
306                 smax = kSideHit_Y1;
307                 tmax = t;
308             }
309             else
310             {
311                 /*
312                  * If intersection points are close to each other find out
313                  * which side to use, i.e. is most probably hit. [DB 9/94]
314                  */
315 
316                 if (t <= tmax + CLOSE_TOLERANCE)
317                 {
318                     if (D[Y] > fabs(D[X])) smax = kSideHit_Y1;
319                 }
320             }
321 
322             t = (Corner1[Y] - P[Y]) / D[Y];
323 
324             if (t >= tmin + CLOSE_TOLERANCE)
325             {
326                 if (t > tmax) return(false);
327 
328                 smin = kSideHit_Y0;
329                 tmin = t;
330             }
331             else
332             {
333                 /*
334                  * If intersection points are close to each other find out
335                  * which side to use, i.e. is most probably hit. [DB 9/94]
336                  */
337 
338                 if (t >= tmin - CLOSE_TOLERANCE)
339                 {
340                     if (D[Y] > fabs(D[X])) smin = kSideHit_Y0;
341                 }
342             }
343         }
344         else
345         {
346             if ((P[Y] < Corner1[Y]) || (P[Y] > Corner2[Y]))
347             {
348                 return(false);
349             }
350         }
351     }
352 
353     /* Now front/back */
354 
355     if (D[Z] < -EPSILON)
356     {
357         t = (Corner1[Z] - P[Z]) / D[Z];
358 
359         if (t < tmin) return(false);
360 
361         if (t <= tmax - CLOSE_TOLERANCE)
362         {
363             smax = kSideHit_Z0;
364             tmax = t;
365         }
366         else
367         {
368             /*
369              * If intersection points are close to each other find out
370              * which side to use, i.e. is most probably hit. [DB 9/94]
371              */
372 
373             if (t <= tmax + CLOSE_TOLERANCE)
374             {
375                 switch (smax)
376                 {
377                     case kSideHit_X0 :
378                     case kSideHit_X1 : if (-D[Z] > fabs(D[X])) smax = kSideHit_Z0; break;
379 
380                     case kSideHit_Y0 :
381                     case kSideHit_Y1 : if (-D[Z] > fabs(D[Y])) smax = kSideHit_Z0; break;
382                 }
383             }
384         }
385 
386         t = (Corner2[Z] - P[Z]) / D[Z];
387 
388         if (t >= tmin + CLOSE_TOLERANCE)
389         {
390             if (t > tmax) return(false);
391 
392             smin = kSideHit_Z1;
393             tmin = t;
394         }
395         else
396         {
397             /*
398              * If intersection points are close to each other find out
399              * which side to use, i.e. is most probably hit. [DB 9/94]
400              */
401 
402             if (t >= tmin - CLOSE_TOLERANCE)
403             {
404                 switch (smin)
405                 {
406                     case kSideHit_X0 :
407                     case kSideHit_X1 : if (-D[Z] > fabs(D[X])) smin = kSideHit_Z1; break;
408 
409                     case kSideHit_Y0 :
410                     case kSideHit_Y1 : if (-D[Z] > fabs(D[Y])) smin = kSideHit_Z1; break;
411                 }
412             }
413         }
414     }
415     else
416     {
417         if (D[Z] > EPSILON)
418         {
419             t = (Corner2[Z] - P[Z]) / D[Z];
420 
421             if (t < tmin) return(false);
422 
423             if (t <= tmax - CLOSE_TOLERANCE)
424             {
425                 smax = kSideHit_Z1;
426                 tmax = t;
427             }
428             else
429             {
430                 /*
431                  * If intersection points are close to each other find out
432                  * which side to use, i.e. is most probably hit. [DB 9/94]
433                  */
434 
435                 if (t <= tmax + CLOSE_TOLERANCE)
436                 {
437                     switch (smax)
438                     {
439                         case kSideHit_X0 :
440                         case kSideHit_X1 : if (D[Z] > fabs(D[X])) smax = kSideHit_Z1; break;
441 
442                         case kSideHit_Y0 :
443                         case kSideHit_Y1 : if (D[Z] > fabs(D[Y])) smax = kSideHit_Z1; break;
444                     }
445                 }
446             }
447 
448             t = (Corner1[Z] - P[Z]) / D[Z];
449 
450             if (t >= tmin + CLOSE_TOLERANCE)
451             {
452                 if (t > tmax) return(false);
453 
454                 smin = kSideHit_Z0;
455                 tmin = t;
456             }
457             else
458             {
459                 /*
460                  * If intersection points are close to each other find out
461                  * which side to use, i.e. is most probably hit. [DB 9/94]
462                  */
463 
464                 if (t >= tmin - CLOSE_TOLERANCE)
465                 {
466                     switch (smin)
467                     {
468                         case kSideHit_X0 :
469                         case kSideHit_X1 : if (D[Z] > fabs(D[X])) smin = kSideHit_Z0; break;
470 
471                         case kSideHit_Y0 :
472                         case kSideHit_Y1 : if (D[Z] > fabs(D[Y])) smin = kSideHit_Z0; break;
473                     }
474                 }
475             }
476         }
477         else
478         {
479             if ((P[Z] < Corner1[Z]) || (P[Z] > Corner2[Z]))
480             {
481                 return(false);
482             }
483         }
484     }
485 
486     if (tmax < DEPTH_TOLERANCE)
487     {
488         return (false);
489     }
490 
491     *Depth1 = tmin;
492     *Depth2 = tmax;
493 
494     *Side1 = smin;
495     *Side2 = smax;
496 
497     return(true);
498 }
499 
500 
501 
502 /*****************************************************************************
503 *
504 * FUNCTION
505 *
506 *   Inside_Box
507 *
508 * INPUT
509 *
510 * OUTPUT
511 *
512 * RETURNS
513 *
514 * AUTHOR
515 *
516 *   Alexander Enzmann
517 *
518 * DESCRIPTION
519 *
520 *   -
521 *
522 * CHANGES
523 *
524 *   -
525 *
526 ******************************************************************************/
527 
Inside(const Vector3d & IPoint,TraceThreadData * Thread) const528 bool Box::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
529 {
530     Vector3d New_Point;
531 
532     /* Transform the point into box space. */
533 
534     if (Trans != nullptr)
535     {
536         MInvTransPoint(New_Point, IPoint, Trans);
537     }
538     else
539     {
540         New_Point = IPoint;
541     }
542 
543     /* Test to see if we are outside the box. */
544 
545     if ((New_Point[X] < bounds[0][X]) || (New_Point[X] > bounds[1][X]))
546     {
547         return (Test_Flag(this, INVERTED_FLAG));
548     }
549 
550     if ((New_Point[Y] < bounds[0][Y]) || (New_Point[Y] > bounds[1][Y]))
551     {
552         return (Test_Flag(this, INVERTED_FLAG));
553     }
554 
555     if ((New_Point[Z] < bounds[0][Z]) || (New_Point[Z] > bounds[1][Z]))
556     {
557         return (Test_Flag(this, INVERTED_FLAG));
558     }
559 
560     /* Inside the box. */
561 
562     return (!Test_Flag(this, INVERTED_FLAG));
563 }
564 
565 
566 
567 /*****************************************************************************
568 *
569 * FUNCTION
570 *
571 *   Box_Normal
572 *
573 * INPUT
574 *
575 * OUTPUT
576 *
577 * RETURNS
578 *
579 * AUTHOR
580 *
581 *   Alexander Enzmann
582 *
583 * DESCRIPTION
584 *
585 *   -
586 *
587 * CHANGES
588 *
589 *   -
590 *
591 ******************************************************************************/
592 
Normal(Vector3d & Result,Intersection * Inter,TraceThreadData * Thread) const593 void Box::Normal(Vector3d& Result, Intersection *Inter, TraceThreadData *Thread) const
594 {
595     switch (Inter->i1)
596     {
597         case kSideHit_X0: Result = Vector3d(-1.0,  0.0,  0.0); break;
598         case kSideHit_X1: Result = Vector3d( 1.0,  0.0,  0.0); break;
599         case kSideHit_Y0: Result = Vector3d( 0.0, -1.0,  0.0); break;
600         case kSideHit_Y1: Result = Vector3d( 0.0,  1.0,  0.0); break;
601         case kSideHit_Z0: Result = Vector3d( 0.0,  0.0, -1.0); break;
602         case kSideHit_Z1: Result = Vector3d( 0.0,  0.0,  1.0); break;
603 
604         default: throw POV_EXCEPTION_STRING("Unknown box side in Box_Normal().");
605     }
606 
607     /* Transform the point into the boxes space. */
608 
609     if (Trans != nullptr)
610     {
611         MTransNormal(Result, Result, Trans);
612 
613         Result.normalize();
614     }
615 }
616 
617 
618 
619 /*****************************************************************************
620 *
621 * FUNCTION
622 *
623 *   Translate_Box
624 *
625 * INPUT
626 *
627 * OUTPUT
628 *
629 * RETURNS
630 *
631 * AUTHOR
632 *
633 *   Alexander Enzmann
634 *
635 * DESCRIPTION
636 *
637 *   -
638 *
639 * CHANGES
640 *
641 *   -
642 *
643 ******************************************************************************/
644 
Translate(const Vector3d & Vector,const TRANSFORM * tr)645 void Box::Translate(const Vector3d& Vector, const TRANSFORM *tr)
646 {
647     if (Trans == nullptr)
648     {
649         bounds[0] += Vector;
650 
651         bounds[1] += Vector;
652 
653         Compute_BBox();
654     }
655     else
656     {
657         Transform(tr);
658     }
659 }
660 
661 
662 
663 /*****************************************************************************
664 *
665 * FUNCTION
666 *
667 *   Rotate_Box
668 *
669 * INPUT
670 *
671 * OUTPUT
672 *
673 * RETURNS
674 *
675 * AUTHOR
676 *
677 *   Alexander Enzmann
678 *
679 * DESCRIPTION
680 *
681 *   -
682 *
683 * CHANGES
684 *
685 *   -
686 *
687 ******************************************************************************/
688 
Rotate(const Vector3d &,const TRANSFORM * tr)689 void Box::Rotate(const Vector3d&, const TRANSFORM *tr)
690 {
691     Transform(tr);
692 }
693 
694 
695 
696 /*****************************************************************************
697 *
698 * FUNCTION
699 *
700 *   Scale_Box
701 *
702 * INPUT
703 *
704 * OUTPUT
705 *
706 * RETURNS
707 *
708 * AUTHOR
709 *
710 *   Alexander Enzmann
711 *
712 * DESCRIPTION
713 *
714 *   -
715 *
716 * CHANGES
717 *
718 *   -
719 *
720 ******************************************************************************/
721 
Scale(const Vector3d & Vector,const TRANSFORM * tr)722 void Box::Scale(const Vector3d& Vector, const TRANSFORM *tr)
723 {
724     DBL temp;
725 
726     if (Trans == nullptr)
727     {
728         bounds[0] *= Vector;
729         bounds[1] *= Vector;
730 
731         if (bounds[0][X] > bounds[1][X])
732         {
733             temp = bounds[0][X];
734 
735             bounds[0][X] = bounds[1][X];
736             bounds[1][X] = temp;
737         }
738 
739         if (bounds[0][Y] > bounds[1][Y])
740         {
741             temp = bounds[0][Y];
742 
743             bounds[0][Y] = bounds[1][Y];
744             bounds[1][Y] = temp;
745         }
746 
747         if (bounds[0][Z] > bounds[1][Z])
748         {
749             temp = bounds[0][Z];
750 
751             bounds[0][Z] = bounds[1][Z];
752             bounds[1][Z] = temp;
753         }
754 
755         Compute_BBox();
756     }
757     else
758     {
759         Transform(tr);
760     }
761 }
762 
763 
764 
765 /*****************************************************************************
766 *
767 * FUNCTION
768 *
769 *   Transform_Box
770 *
771 * INPUT
772 *
773 * OUTPUT
774 *
775 * RETURNS
776 *
777 * AUTHOR
778 *
779 *   Alexander Enzmann
780 *
781 * DESCRIPTION
782 *
783 *   -
784 *
785 * CHANGES
786 *
787 *   -
788 *
789 ******************************************************************************/
790 
Transform(const TRANSFORM * tr)791 void Box::Transform(const TRANSFORM *tr)
792 {
793     if (Trans == nullptr)
794         Trans = Create_Transform();
795 
796     Compose_Transforms(Trans, tr);
797 
798     Compute_BBox();
799 }
800 
801 
802 
803 /*****************************************************************************
804 *
805 * FUNCTION
806 *
807 *   Create_Box
808 *
809 * INPUT
810 *
811 * OUTPUT
812 *
813 * RETURNS
814 *
815 * AUTHOR
816 *
817 *   Alexander Enzmann
818 *
819 * DESCRIPTION
820 *
821 *   -
822 *
823 * CHANGES
824 *
825 *   -
826 *
827 ******************************************************************************/
828 
Box()829 Box::Box() : ObjectBase(BOX_OBJECT)
830 {
831     bounds[0] = Vector3d(-1.0, -1.0, -1.0);
832     bounds[1] = Vector3d( 1.0,  1.0,  1.0);
833 
834     Make_BBox(BBox, -1.0, -1.0, -1.0, 2.0, 2.0, 2.0);
835 
836     Trans = nullptr;
837 }
838 
839 
840 
841 /*****************************************************************************
842 *
843 * FUNCTION
844 *
845 *   Copy_Box
846 *
847 * INPUT
848 *
849 * OUTPUT
850 *
851 * RETURNS
852 *
853 * AUTHOR
854 *
855 *   Alexander Enzmann
856 *
857 * DESCRIPTION
858 *
859 *   -
860 *
861 * CHANGES
862 *
863 *   -
864 *
865 ******************************************************************************/
866 
Copy()867 ObjectPtr Box::Copy()
868 {
869     Box *New = new Box();
870     Destroy_Transform(New->Trans);
871     *New = *this;
872     New->Trans = Copy_Transform(Trans);
873 
874     return (New);
875 }
876 
877 
878 
879 /*****************************************************************************
880 *
881 * FUNCTION
882 *
883 *   Destroy_Box
884 *
885 * INPUT
886 *
887 * OUTPUT
888 *
889 * RETURNS
890 *
891 * AUTHOR
892 *
893 *   Alexander Enzmann
894 *
895 * DESCRIPTION
896 *
897 *   -
898 *
899 * CHANGES
900 *
901 *   -
902 *
903 ******************************************************************************/
904 
~Box()905 Box::~Box()
906 {}
907 
908 
909 
910 /*****************************************************************************
911 *
912 * FUNCTION
913 *
914 *   Compute_Box_BBox
915 *
916 * INPUT
917 *
918 *   Box - Box
919 *
920 * OUTPUT
921 *
922 *   Box
923 *
924 * RETURNS
925 *
926 * AUTHOR
927 *
928 *   Dieter Bayer
929 *
930 * DESCRIPTION
931 *
932 *   Calculate the bounding box of a box.
933 *
934 * CHANGES
935 *
936 *   Aug 1994 : Creation.
937 *
938 ******************************************************************************/
939 
Compute_BBox()940 void Box::Compute_BBox()
941 {
942     BBox.lowerLeft = BBoxVector3d(bounds[0]);
943 
944     BBox.size = BBoxVector3d(bounds[1] - bounds[0]);
945 
946     if (Trans != nullptr)
947     {
948         Recompute_BBox(&BBox, Trans);
949     }
950 }
951 
952 /*****************************************************************************
953 *
954 * FUNCTION
955 *
956 *   Box_UVCoord
957 *
958 * INPUT
959 *
960 * OUTPUT
961 *
962 * RETURNS
963 *
964 * AUTHOR
965 *
966 *   Nathan Kopp, Lutz Kretzschmar
967 *
968 * DESCRIPTION
969 *
970 *        +-----+
971 *        ^  4  |
972 *        z     |
973 *  +-----+--x>-#--z>-+-<x--+
974 *  |     ^     |     |     |
975 *  |  1  y  5  |  2  |  6  |
976 *  |     |     |     |     |
977 *  +-----O--x>-+-----+-----+
978 *        |     |
979 *        |  3  |
980 *        +-----+
981 *
982 *  planes:
983 *  1: min x   2: max x
984 *  3: min y   4: max y
985 *  5: min z   6: max z
986 *
987 *  O : Origin
988 *  # : <1,1,0>
989 *
990 * CHANGES
991 *
992 *   The code was changed to use somthing similar to environmental cube mappping
993 *
994 *   1        +-----+           #
995 *            |     |
996 * V          z  4  |
997 *            |     |
998 *  .6  +--z>-+--x>-+-<z--+-<x--+
999 *      |     ^     |     |     |
1000 *      |  1  y  5  |  2  |  6  |
1001 *      |     |     |     |     |
1002 *  .3  +-----+--x>-+-----+-----+
1003 *            ^     |
1004 *            z  3  |
1005 *            |     |
1006 *  0   O     +-----+
1007 *
1008 *      0    .25    .5   .75    1
1009 *                            U
1010 *
1011 *  planes:
1012 *  1: min x   2: max x
1013 *  3: min y   4: max y
1014 *  5: max z   6: min z
1015 *
1016 *  O : Origin of U,V map
1017 *  # : <1,1,0>
1018 *
1019 ******************************************************************************/
1020 
UVCoord(Vector2d & Result,const Intersection * Inter,TraceThreadData * Thread) const1021 void Box::UVCoord(Vector2d& Result, const Intersection *Inter, TraceThreadData *Thread) const
1022 {
1023     Vector3d P, Box_Diff;
1024 
1025     /* Transform the point into the cube's space */
1026     if (Trans != nullptr)
1027         MInvTransPoint(P, Inter->IPoint, Trans);
1028     else
1029         P = Inter->IPoint;
1030 
1031     Box_Diff = bounds[1] - bounds[0];
1032 
1033     /* this line moves the bottom,left,front corner of the box to <0,0,0> */
1034     P -= bounds[0];
1035     /* this line normalizes the face offsets */
1036     P /= Box_Diff;
1037 
1038     /* The following code does a variation of cube environment mapping. All the
1039        textures are not mirrored when the cube is viewed from outside. */
1040 
1041     switch (Inter->i1)
1042     {
1043         case kSideHit_X0:
1044             Result[U] =               (P[Z] / 4.0);
1045             Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1046             break;
1047         case kSideHit_X1:
1048             Result[U] = (3.0 / 4.0) - (P[Z] / 4.0);
1049             Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1050             break;
1051         case kSideHit_Y0:
1052             Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
1053             Result[V] =               (P[Z] / 3.0);
1054             break;
1055         case kSideHit_Y1:
1056             Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
1057             Result[V] = (3.0 / 3.0) - (P[Z] / 3.0);
1058             break;
1059         case kSideHit_Z0:
1060             Result[U] =  1.0        - (P[X] / 4.0);
1061             Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1062             break;
1063         case kSideHit_Z1:
1064             Result[U] = (1.0 / 4.0) + (P[X] / 4.0);
1065             Result[V] = (1.0 / 3.0) + (P[Y] / 3.0);
1066             break;
1067 
1068         default: throw POV_EXCEPTION_STRING("Unknown box side in Box_Normal().");
1069     }
1070 }
1071 
Intersect_BBox(BBoxDirection,const BBoxVector3d &,const BBoxVector3d &,BBoxScalar) const1072 bool Box::Intersect_BBox(BBoxDirection, const BBoxVector3d&, const BBoxVector3d&, BBoxScalar) const
1073 {
1074     return true;
1075 }
1076 
1077 }
1078