1 //******************************************************************************
2 ///
3 /// @file core/shape/superellipsoid.cpp
4 ///
5 /// Implementation of the superellipsoid geometric primitive.
6 ///
7 /// @author Alexander Enzmann (original code)
8 /// @author Dieter Bayer (adaption to POV-Ray)
9 ///
10 /// @copyright
11 /// @parblock
12 ///
13 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
14 /// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd.
15 ///
16 /// POV-Ray is free software: you can redistribute it and/or modify
17 /// it under the terms of the GNU Affero General Public License as
18 /// published by the Free Software Foundation, either version 3 of the
19 /// License, or (at your option) any later version.
20 ///
21 /// POV-Ray is distributed in the hope that it will be useful,
22 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
23 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 /// GNU Affero General Public License for more details.
25 ///
26 /// You should have received a copy of the GNU Affero General Public License
27 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
28 ///
29 /// ----------------------------------------------------------------------------
30 ///
31 /// POV-Ray is based on the popular DKB raytracer version 2.12.
32 /// DKBTrace was originally written by David K. Buck.
33 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
34 ///
35 /// @endparblock
36 ///
37 //******************************************************************************
38 
39 /****************************************************************************
40 *
41 *  Explanation:
42 *
43 *    Superellipsoids are defined by the implicit equation
44 *
45 *      f(x,y,z) = (|x|^(2/e) + |y|^(2/e))^(e/n) + |z|^(2/n) - 1
46 *
47 *    Where e is the east/west exponent and n is the north/south exponent.
48 *
49 *    NOTE: The exponents are precomputed and stored in the Power element.
50 *
51 *    NOTE: Values of e and n that are close to degenerate (e.g.,
52 *          below around 0.1) appear to give the root solver fits.
53 *          Not sure quite where the problem lays just yet.
54 *
55 *  Syntax:
56 *
57 *    superellipsoid { <e, n> }
58 *
59 *
60 *  ---
61 *
62 *  Oct 1994 : Creation.
63 *
64 *****************************************************************************/
65 
66 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
67 #include "core/shape/superellipsoid.h"
68 
69 #include "core/bounding/boundingbox.h"
70 #include "core/math/matrix.h"
71 #include "core/render/ray.h"
72 #include "core/scene/tracethreaddata.h"
73 
74 // this must be the last file included
75 #include "base/povdebug.h"
76 
77 namespace pov
78 {
79 
80 /*****************************************************************************
81 * Local preprocessor defines
82 ******************************************************************************/
83 
84 /* Minimal intersection depth for a valid intersection. */
85 
86 const DBL DEPTH_TOLERANCE = 1.0e-4;
87 
88 /* If |x| < ZERO_TOLERANCE it is regarded to be 0. */
89 
90 const DBL ZERO_TOLERANCE = 1.0e-10;
91 
92 /* This is not the signum function because SGNX(0) is 1. */
93 
94 #define SGNX(x) (((x) >= 0.0) ? 1.0 : -1.0)
95 
96 const DBL MIN_VALUE = -1.01;
97 const DBL MAX_VALUE  = 1.01;
98 
99 const int MAX_ITERATIONS = 20;
100 
101 const int PLANECOUNT = 9;
102 
103 
104 
105 /*****************************************************************************
106 * Local variables
107 ******************************************************************************/
108 
109 const DBL planes[PLANECOUNT][4] =
110     {{1, 1, 0, 0}, {1,-1, 0, 0},
111      {1, 0, 1, 0}, {1, 0,-1, 0},
112      {0, 1, 1, 0}, {0, 1,-1, 0},
113      {1, 0, 0, 0},
114      {0, 1, 0, 0},
115      {0, 0, 1, 0}};
116 
117 
118 
119 /*****************************************************************************
120 *
121 * FUNCTION
122 *
123 *   All_Superellipsoid_Intersections
124 *
125 * INPUT
126 *
127 *   Object      - Object
128 *   Ray         - Ray
129 *   Depth_Stack - Intersection stack
130 *
131 * OUTPUT
132 *
133 *   Depth_Stack
134 *
135 * RETURNS
136 *
137 *   int - true, if a intersection was found
138 *
139 * AUTHOR
140 *
141 *   Dieter Bayer
142 *
143 * DESCRIPTION
144 *
145 *   Determine ray/superellipsoid intersection and clip intersection found.
146 *
147 * CHANGES
148 *
149 *   Oct 1994 : Creation.
150 *
151 ******************************************************************************/
152 
All_Intersections(const Ray & ray,IStack & Depth_Stack,TraceThreadData * Thread)153 bool Superellipsoid::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
154 {
155     Thread->Stats()[Ray_Superellipsoid_Tests]++;
156 
157     if (Intersect(ray, Depth_Stack, Thread))
158     {
159         Thread->Stats()[Ray_Superellipsoid_Tests_Succeeded]++;
160 
161         return(true);
162     }
163     return(false);
164 }
165 
166 
167 
168 /*****************************************************************************
169 *
170 * FUNCTION
171 *
172 *   intersect_superellipsoid
173 *
174 * INPUT
175 *
176 *   Ray            - Ray
177 *   Superellipsoid - Superellipsoid
178 *   Depth_Stack    - Depth stack
179 *
180 * OUTPUT
181 *
182 *   Intersection
183 *
184 * RETURNS
185 *
186 *   int - true if intersections were found.
187 *
188 * AUTHOR
189 *
190 *   Alexander Enzmann, Dieter Bayer
191 *
192 * DESCRIPTION
193 *
194 *   Determine ray/superellipsoid intersection.
195 *
196 * CHANGES
197 *
198 *   Oct 1994 : Creation.
199 *
200 ******************************************************************************/
201 
Intersect(const BasicRay & ray,IStack & Depth_Stack,TraceThreadData * Thread)202 bool Superellipsoid::Intersect(const BasicRay& ray, IStack& Depth_Stack, TraceThreadData *Thread)
203 {
204     int i, cnt, Found = false;
205     DBL dists[PLANECOUNT+2];
206     DBL t, t1, t2, v0, v1, len;
207     Vector3d P, D, P0, P1, P2, P3;
208 
209     /* Transform the ray into the superellipsoid space. */
210 
211     MInvTransPoint(P, ray.Origin, Trans);
212 
213     MInvTransDirection(D, ray.Direction, Trans);
214 
215     len = D.length();
216 
217     D /= len;
218 
219     /* Intersect superellipsoid's bounding box. */
220 
221     if (!intersect_box(P, D, &t1, &t2))
222     {
223         return(false);
224     }
225 
226     /* Test if superellipsoid lies 'behind' the ray origin. */
227 
228     if (t2 < DEPTH_TOLERANCE)
229     {
230         return(false);
231     }
232 
233     cnt = 0;
234 
235     if (t1 < DEPTH_TOLERANCE)
236     {
237         t1 = DEPTH_TOLERANCE;
238     }
239 
240     dists[cnt++] = t1;
241     dists[cnt++] = t2;
242 
243     /* Intersect ray with planes cutting superellipsoids in pieces. */
244 
245     cnt = find_ray_plane_points(P, D, cnt, dists, t1, t2);
246 
247     if (cnt <= 1)
248     {
249         return(false);
250     }
251 
252     P0 = P + dists[0] * D;
253 
254     v0 = evaluate_superellipsoid(P0);
255 
256     if (fabs(v0) < ZERO_TOLERANCE)
257     {
258         if (insert_hit(ray, dists[0] / len, Depth_Stack, Thread))
259         {
260             if (Type & IS_CHILD_OBJECT)
261             {
262                 Found = true;
263             }
264             else
265             {
266                 return(true);
267             }
268         }
269     }
270 
271     for (i = 1; i < cnt; i++)
272     {
273         P1 = P + dists[i] * D;
274 
275         v1 = evaluate_superellipsoid(P1);
276 
277         if (fabs(v1) < ZERO_TOLERANCE)
278         {
279             if (insert_hit(ray, dists[i] / len, Depth_Stack, Thread))
280             {
281                 if (Type & IS_CHILD_OBJECT)
282                 {
283                     Found = true;
284                 }
285                 else
286                 {
287                     return(true);
288                 }
289             }
290         }
291         else
292         {
293             if (v0 * v1 < 0.0)
294             {
295                 /* Opposite signs, there must be a root between */
296 
297                 solve_hit1(v0, P0, v1, P1, P2);
298 
299                 P3 = P2 - P;
300 
301                 t = P3.length();
302 
303                 if (insert_hit(ray, t / len, Depth_Stack, Thread))
304                 {
305                     if (Type & IS_CHILD_OBJECT)
306                     {
307                         Found = true;
308                     }
309                     else
310                     {
311                         return(true);
312                     }
313                 }
314             }
315             else
316             {
317                 /*
318                  * Although there was no sign change, we may actually be approaching
319                  * the surface. In this case, we are being fooled by the shape of the
320                  * surface into thinking there isn't a root between sample points.
321                  */
322 
323                 if (check_hit2(P, D, dists[i-1], P0, v0, dists[i], &t, P2))
324                 {
325                     if (insert_hit(ray, t / len, Depth_Stack, Thread))
326                     {
327                         if (Type & IS_CHILD_OBJECT)
328                         {
329                             Found = true;
330                         }
331                         else
332                         {
333                             return(true);
334                         }
335                     }
336                     else
337                     {
338                         break;
339                     }
340                 }
341             }
342         }
343 
344         v0 = v1;
345 
346         P0 = P1;
347     }
348 
349     return(Found);
350 }
351 
352 
353 
354 /*****************************************************************************
355 *
356 * FUNCTION
357 *
358 *   Inside_Superellipsoid
359 *
360 * INPUT
361 *
362 *   IPoint - Intersection point
363 *   Object - Object
364 *
365 * OUTPUT
366 *
367 * RETURNS
368 *
369 *   int - true if inside
370 *
371 * AUTHOR
372 *
373 *   Dieter Bayer
374 *
375 * DESCRIPTION
376 *
377 *   Test if a point lies inside the superellipsoid.
378 *
379 * CHANGES
380 *
381 *   Oct 1994 : Creation.
382 *
383 ******************************************************************************/
384 
Inside(const Vector3d & IPoint,TraceThreadData * Thread) const385 bool Superellipsoid::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
386 {
387     DBL val;
388     Vector3d P;
389 
390     /* Transform the point into the superellipsoid space. */
391 
392     MInvTransPoint(P, IPoint, Trans);
393 
394     val = evaluate_superellipsoid(P);
395 
396     if (val < EPSILON)
397     {
398         return(!Test_Flag(this, INVERTED_FLAG));
399     }
400     else
401     {
402         return(Test_Flag(this, INVERTED_FLAG));
403     }
404 }
405 
406 
407 
408 /*****************************************************************************
409 *
410 * FUNCTION
411 *
412 *   Superellipsoid_Normal
413 *
414 * INPUT
415 *
416 *   Result - Normal vector
417 *   Object - Object
418 *   Inter  - Intersection found
419 *
420 * OUTPUT
421 *
422 *   Result
423 *
424 * RETURNS
425 *
426 * AUTHOR
427 *
428 *   Dieter Bayer
429 *
430 * DESCRIPTION
431 *
432 *   Calculate the normal of the superellipsoid in a given point.
433 *
434 * CHANGES
435 *
436 *   Oct 1994 : Creation.
437 *
438 ******************************************************************************/
439 
Normal(Vector3d & Result,Intersection * Inter,TraceThreadData * Thread) const440 void Superellipsoid::Normal(Vector3d& Result, Intersection *Inter, TraceThreadData *Thread) const
441 {
442     Vector3d const& E = Power;
443     Vector3d P;
444 
445     /* Transform the point into the superellipsoid space. */
446     MInvTransPoint(P, Inter->IPoint, Trans);
447 
448     DBL r, z2n = 0;
449     if (P[Z] != 0)
450     {
451         z2n = power(fabs(P[Z]), E[Z]);
452         P[Z] = z2n / P[Z];
453     }
454 
455     if (fabs(P[X]) > fabs(P[Y]))
456     {
457         r = power(fabs(P[Y] / P[X]), E[X]);
458 
459         P[X] = (1-z2n)  /  P[X];
460         P[Y] = P[Y] ? (1-z2n) * r / P[Y] : 0;
461     }
462     else if (P[Y] != 0)
463     {
464         r = power(fabs(P[X] / P[Y]), E[X]);
465 
466         P[X] = P[X] ? (1-z2n) * r / P[X] : 0;
467         P[Y] = (1-z2n) / P[Y];
468     }
469     if(P[Z])
470         P[Z] *= (1 + r);
471 
472     /* Transform the normalt out of the superellipsoid space. */
473     MTransNormal(Result, P, Trans);
474 
475     Result.normalize();
476 }
477 
478 
479 
480 /*****************************************************************************
481 *
482 * FUNCTION
483 *
484 *   Translate_Superellipsoid
485 *
486 * INPUT
487 *
488 *   Object - Object
489 *   Vector - Translation vector
490 *
491 * OUTPUT
492 *
493 *   Object
494 *
495 * RETURNS
496 *
497 * AUTHOR
498 *
499 *   Dieter Bayer
500 *
501 * DESCRIPTION
502 *
503 *   Translate a superellipsoid.
504 *
505 * CHANGES
506 *
507 *   Oct 1994 : Creation.
508 *
509 ******************************************************************************/
510 
Translate(const Vector3d &,const TRANSFORM * tr)511 void Superellipsoid::Translate(const Vector3d&, const TRANSFORM *tr)
512 {
513     Transform(tr);
514 }
515 
516 
517 
518 /*****************************************************************************
519 *
520 * FUNCTION
521 *
522 *   Rotate_Superellipsoid
523 *
524 * INPUT
525 *
526 *   Object - Object
527 *   Vector - Rotation vector
528 *
529 * OUTPUT
530 *
531 *   Object
532 *
533 * RETURNS
534 *
535 * AUTHOR
536 *
537 *   Dieter Bayer
538 *
539 * DESCRIPTION
540 *
541 *   Rotate a superellipsoid.
542 *
543 * CHANGES
544 *
545 *   Oct 1994 : Creation.
546 *
547 ******************************************************************************/
548 
Rotate(const Vector3d &,const TRANSFORM * tr)549 void Superellipsoid::Rotate(const Vector3d&, const TRANSFORM *tr)
550 {
551     Transform(tr);
552 }
553 
554 
555 
556 /*****************************************************************************
557 *
558 * FUNCTION
559 *
560 *   Scale_Superellipsoid
561 *
562 * INPUT
563 *
564 *   Object - Object
565 *   Vector - Scaling vector
566 *
567 * OUTPUT
568 *
569 *   Object
570 *
571 * RETURNS
572 *
573 * AUTHOR
574 *
575 *   Dieter Bayer
576 *
577 * DESCRIPTION
578 *
579 *   Scale a superellipsoid.
580 *
581 * CHANGES
582 *
583 *   Oct 1994 : Creation.
584 *
585 ******************************************************************************/
586 
Scale(const Vector3d &,const TRANSFORM * tr)587 void Superellipsoid::Scale(const Vector3d&, const TRANSFORM *tr)
588 {
589     Transform(tr);
590 }
591 
592 
593 
594 /*****************************************************************************
595 *
596 * FUNCTION
597 *
598 *   Transform_Superellipsoid
599 *
600 * INPUT
601 *
602 *   Object - Object
603 *   Trans  - Transformation to apply
604 *
605 * OUTPUT
606 *
607 *   Object
608 *
609 * RETURNS
610 *
611 * AUTHOR
612 *
613 *   Dieter Bayer
614 *
615 * DESCRIPTION
616 *
617 *   Transform a superellipsoid and recalculate its bounding box.
618 *
619 * CHANGES
620 *
621 *   Oct 1994 : Creation.
622 *
623 ******************************************************************************/
624 
Transform(const TRANSFORM * tr)625 void Superellipsoid::Transform(const TRANSFORM *tr)
626 {
627     Compose_Transforms(Trans, tr);
628 
629     Compute_BBox();
630 }
631 
632 
633 
634 /*****************************************************************************
635 *
636 * FUNCTION
637 *
638 *   Create_Superellipsoid
639 *
640 * INPUT
641 *
642 * OUTPUT
643 *
644 * RETURNS
645 *
646 *   SUPERELLIPSOID * - new superellipsoid
647 *
648 * AUTHOR
649 *
650 *   Dieter Bayer
651 *
652 * DESCRIPTION
653 *
654 *   Create a new superellipsoid.
655 *
656 * CHANGES
657 *
658 *   Oct 1994 : Creation.
659 *
660 ******************************************************************************/
661 
Superellipsoid()662 Superellipsoid::Superellipsoid() : ObjectBase(SUPERELLIPSOID_OBJECT)
663 {
664     Trans = Create_Transform();
665 
666     Power = Vector3d(2.0, 2.0, 2.0);
667 }
668 
669 
670 
671 /*****************************************************************************
672 *
673 * FUNCTION
674 *
675 *   Copy_Superellipsoid
676 *
677 * INPUT
678 *
679 *   Object - Object
680 *
681 * OUTPUT
682 *
683 * RETURNS
684 *
685 *   void * - New superellipsoid
686 *
687 * AUTHOR
688 *
689 *   Dieter Bayer
690 *
691 * DESCRIPTION
692 *
693 *   Copy a superellipsoid structure.
694 *
695 * CHANGES
696 *
697 *   Oct 1994 : Creation.
698 *
699 ******************************************************************************/
700 
Copy()701 ObjectPtr Superellipsoid::Copy()
702 {
703     Superellipsoid *New = new Superellipsoid();
704 
705     Destroy_Transform(New->Trans);
706     *New = *this;
707     New->Trans = Copy_Transform(Trans);
708 
709     return(New);
710 }
711 
712 
713 
714 /*****************************************************************************
715 *
716 * FUNCTION
717 *
718 *   Destroy_Superellipsoid
719 *
720 * INPUT
721 *
722 *   Object - Object
723 *
724 * OUTPUT
725 *
726 *   Object
727 *
728 * RETURNS
729 *
730 * AUTHOR
731 *
732 *   Dieter Bayer
733 *
734 * DESCRIPTION
735 *
736 *   Destroy a superellipsoid.
737 *
738 * CHANGES
739 *
740 *   Oct 1994 : Creation.
741 *
742 ******************************************************************************/
743 
~Superellipsoid()744 Superellipsoid::~Superellipsoid()
745 {}
746 
747 
748 
749 /*****************************************************************************
750 *
751 * FUNCTION
752 *
753 *   Compute_Superellipsoid_BBox
754 *
755 * INPUT
756 *
757 *   Superellipsoid - Superellipsoid
758 *
759 * OUTPUT
760 *
761 *   Superellipsoid
762 *
763 * RETURNS
764 *
765 * AUTHOR
766 *
767 *   Dieter Bayer
768 *
769 * DESCRIPTION
770 *
771 *   Calculate the bounding box of a superellipsoid.
772 *
773 * CHANGES
774 *
775 *   Oct 1994 : Creation.
776 *
777 ******************************************************************************/
778 
Compute_BBox()779 void Superellipsoid::Compute_BBox()
780 {
781     Make_BBox(BBox, -1.0001, -1.0001, -1.0001, 2.0002, 2.0002, 2.0002);
782 
783     Recompute_BBox(&BBox, Trans);
784 }
785 
786 
787 
788 /*****************************************************************************
789 *
790 * FUNCTION
791 *
792 *   intersect_box
793 *
794 * INPUT
795 *
796 *   P, D       - Ray origin and direction
797 *   dmin, dmax - Intersection depths
798 *
799 * OUTPUT
800 *
801 *   dmin, dmax
802 *
803 * RETURNS
804 *
805 *   int - true, if hit
806 *
807 * AUTHOR
808 *
809 *   Dieter Bayer
810 *
811 * DESCRIPTION
812 *
813 *   Intersect a ray with an axis aligned unit box.
814 *
815 * CHANGES
816 *
817 *   Oct 1994 : Creation.
818 *
819 ******************************************************************************/
820 
intersect_box(const Vector3d & P,const Vector3d & D,DBL * dmin,DBL * dmax)821 bool Superellipsoid::intersect_box(const Vector3d& P, const Vector3d& D, DBL *dmin, DBL *dmax)
822 {
823     DBL tmin = 0.0, tmax = 0.0;
824 
825     /* Left/right. */
826 
827     if (fabs(D[X]) > EPSILON)
828     {
829         if (D[X] > EPSILON)
830         {
831             *dmin = (MIN_VALUE - P[X]) / D[X];
832 
833             *dmax = (MAX_VALUE - P[X]) / D[X];
834 
835             if (*dmax < EPSILON) return(false);
836         }
837         else
838         {
839             *dmax = (MIN_VALUE - P[X]) / D[X];
840 
841             if (*dmax < EPSILON) return(false);
842 
843             *dmin = (MAX_VALUE - P[X]) / D[X];
844         }
845 
846         if (*dmin > *dmax) return(false);
847     }
848     else
849     {
850         if ((P[X] < MIN_VALUE) || (P[X] > MAX_VALUE))
851         {
852             return(false);
853         }
854 
855         *dmin = -BOUND_HUGE;
856         *dmax =  BOUND_HUGE;
857     }
858 
859     /* Top/bottom. */
860 
861     if (fabs(D[Y]) > EPSILON)
862     {
863         if (D[Y] > EPSILON)
864         {
865             tmin = (MIN_VALUE - P[Y]) / D[Y];
866 
867             tmax = (MAX_VALUE - P[Y]) / D[Y];
868         }
869         else
870         {
871             tmax = (MIN_VALUE - P[Y]) / D[Y];
872 
873             tmin = (MAX_VALUE - P[Y]) / D[Y];
874         }
875 
876         if (tmax < *dmax)
877         {
878             if (tmax < EPSILON) return(false);
879 
880             if (tmin > *dmin)
881             {
882                 if (tmin > tmax) return(false);
883 
884                 *dmin = tmin;
885             }
886             else
887             {
888                 if (*dmin > tmax) return(false);
889             }
890 
891             *dmax = tmax;
892         }
893         else
894         {
895             if (tmin > *dmin)
896             {
897                 if (tmin > *dmax) return(false);
898 
899                 *dmin = tmin;
900             }
901         }
902     }
903     else
904     {
905         if ((P[Y] < MIN_VALUE) || (P[Y] > MAX_VALUE))
906         {
907             return(false);
908         }
909     }
910 
911     /* Front/back. */
912 
913     if (fabs(D[Z]) > EPSILON)
914     {
915         if (D[Z] > EPSILON)
916         {
917             tmin = (MIN_VALUE - P[Z]) / D[Z];
918 
919             tmax = (MAX_VALUE - P[Z]) / D[Z];
920         }
921         else
922         {
923             tmax = (MIN_VALUE - P[Z]) / D[Z];
924 
925             tmin = (MAX_VALUE - P[Z]) / D[Z];
926         }
927 
928         if (tmax < *dmax)
929         {
930             if (tmax < EPSILON) return(false);
931 
932             if (tmin > *dmin)
933             {
934                 if (tmin > tmax) return(false);
935 
936                 *dmin = tmin;
937             }
938             else
939             {
940                 if (*dmin > tmax) return(false);
941             }
942 
943             *dmax = tmax;
944         }
945         else
946         {
947             if (tmin > *dmin)
948             {
949                 if (tmin > *dmax) return(false);
950 
951                 *dmin = tmin;
952             }
953         }
954     }
955     else
956     {
957         if ((P[Z] < MIN_VALUE) || (P[Z] > MAX_VALUE))
958         {
959             return(false);
960         }
961     }
962 
963     return(true);
964 }
965 
966 
967 
968 /*****************************************************************************
969 *
970 * FUNCTION
971 *
972 *   evaluate_g
973 *
974 * INPUT
975 *
976 * OUTPUT
977 *
978 * RETURNS
979 *
980 *   DBL
981 *
982 * AUTHOR
983 *
984 *   Massimo Valentini
985 *
986 * DESCRIPTION
987 *
988 * CHANGES
989 *
990 ******************************************************************************/
991 
evaluate_g(DBL x,DBL y,DBL e)992 DBL Superellipsoid::evaluate_g(DBL x, DBL y, DBL e)
993 {
994     DBL g = 0;
995 
996     if (x > y)
997     {
998         g = 1 + power(y/x, e);
999         if(g != 1)
1000             g = power(g, 1/e);
1001         g *= x;
1002     }
1003     else if (y != 0)
1004     {
1005         g = 1 + power(x/y, e);
1006         if(g != 1)
1007             g = power(g, 1/e);
1008         g *= y;
1009     }
1010 
1011     return g;
1012 }
1013 
1014 
1015 
1016 /*****************************************************************************
1017 *
1018 * FUNCTION
1019 *
1020 *   evaluate_superellipsoid
1021 *
1022 * INPUT
1023 *
1024 *   P          - Point to evaluate
1025 *   Superellipsoid - Pointer to superellipsoid
1026 *
1027 * OUTPUT
1028 *
1029 * RETURNS
1030 *
1031 *   DBL
1032 *
1033 * AUTHOR
1034 *
1035 *   Dieter Bayer
1036 *
1037 * DESCRIPTION
1038 *
1039 *   Get superellipsoid value in the given point.
1040 *
1041 * CHANGES
1042 *
1043 *   Oct 1994 : Creation.
1044 *   Dec 2002 : Rewritten by Massimo Valentini.
1045 *
1046 ******************************************************************************/
1047 
evaluate_superellipsoid(const Vector3d & P) const1048 DBL Superellipsoid::evaluate_superellipsoid(const Vector3d& P) const
1049 {
1050     return evaluate_g(evaluate_g(fabs(P[X]), fabs(P[Y]), Power[X]), fabs(P[Z]), Power[Z]) - 1;
1051 }
1052 
1053 
1054 
1055 /*****************************************************************************
1056 *
1057 * FUNCTION
1058 *
1059 *   power
1060 *
1061 * INPUT
1062 *
1063 *   x - Argument
1064 *   e - Power
1065 *
1066 * OUTPUT
1067 *
1068 * RETURNS
1069 *
1070 *   DBL
1071 *
1072 * AUTHOR
1073 *
1074 *   Dieter Bayer
1075 *
1076 * DESCRIPTION
1077 *
1078 *   Raise x to the power of e.
1079 *
1080 * CHANGES
1081 *
1082 *   Oct 1994 : Creation.
1083 *
1084 ******************************************************************************/
1085 
power(DBL x,DBL e)1086 DBL Superellipsoid::power(DBL x, DBL  e)
1087 {
1088     int i;
1089     DBL b;
1090 
1091     b = x;
1092 
1093     i = (int)e;
1094 
1095     /* Test if we have an integer power. */
1096 
1097     if (e == (DBL)i)
1098     {
1099         switch (i)
1100         {
1101             case 0: return(1.0);
1102 
1103             case 1: return(b);
1104 
1105             case 2: return(Sqr(b));
1106 
1107             case 3: return(Sqr(b) * b);
1108 
1109             case 4: b *= b; return(Sqr(b));
1110 
1111             case 5: b *= b; return(Sqr(b) * x);
1112 
1113             case 6: b *= b; return(Sqr(b) * b);
1114 
1115             default: return(pow(x, e));
1116         }
1117     }
1118     else
1119     {
1120         return(pow(x, e));
1121     }
1122 }
1123 
1124 
1125 
1126 /*****************************************************************************
1127 *
1128 * FUNCTION
1129 *
1130 *   insert_hit
1131 *
1132 * INPUT
1133 *
1134 *   Object      - Object
1135 *   Ray         - Ray
1136 *   Depth       - Intersection depth
1137 *   Depth_Stack - Intersection stack
1138 *
1139 * OUTPUT
1140 *
1141 *   Depth_Stack
1142 *
1143 * RETURNS
1144 *
1145 *   int - true, if intersection is valid
1146 *
1147 * AUTHOR
1148 *
1149 *   Dieter Bayer
1150 *
1151 * DESCRIPTION
1152 *
1153 *   Push an intersection onto the depth stack if it is valid.
1154 *
1155 * CHANGES
1156 *
1157 *   Nov 1994 : Creation.
1158 *
1159 ******************************************************************************/
1160 
insert_hit(const BasicRay & ray,DBL Depth,IStack & Depth_Stack,TraceThreadData * Thread)1161 bool Superellipsoid::insert_hit(const BasicRay &ray, DBL Depth, IStack& Depth_Stack, TraceThreadData *Thread)
1162 {
1163     Vector3d IPoint;
1164 
1165     if ((Depth > DEPTH_TOLERANCE) && (Depth < MAX_DISTANCE))
1166     {
1167         IPoint = ray.Evaluate(Depth);
1168 
1169         if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
1170         {
1171             Depth_Stack->push(Intersection(Depth, IPoint, this));
1172 
1173             return(true);
1174         }
1175     }
1176 
1177     return(false);
1178 }
1179 
1180 
1181 
1182 /*****************************************************************************
1183 *
1184 * FUNCTION
1185 *
1186 *   compdists
1187 *
1188 * INPUT
1189 *
1190 * OUTPUT
1191 *
1192 * RETURNS
1193 *
1194 * AUTHOR
1195 *
1196 *   Alexander Enzmann
1197 *
1198 * DESCRIPTION
1199 *
1200 *   Compare two slabs.
1201 *
1202 * CHANGES
1203 *
1204 *   Nov 1994 : Creation.
1205 *
1206 ******************************************************************************/
1207 
compdists(const void * in_a,const void * in_b)1208 int Superellipsoid::compdists(const void *in_a, const void *in_b)
1209 {
1210     DBL a, b;
1211 
1212     a = *reinterpret_cast<const DBL *>(in_a);
1213     b = *reinterpret_cast<const DBL *>(in_b);
1214 
1215     if (a < b)
1216     {
1217         return(-1);
1218     }
1219 
1220     if (a == b)
1221     {
1222         return(0);
1223     }
1224     else
1225     {
1226         return(1);
1227     }
1228 }
1229 
1230 
1231 
1232 /*****************************************************************************
1233 *
1234 * FUNCTION
1235 *
1236 *   find_ray_plane_points
1237 *
1238 * INPUT
1239 *
1240 * OUTPUT
1241 *
1242 * RETURNS
1243 *
1244 * AUTHOR
1245 *
1246 *   Alexander Enzmann
1247 *
1248 * DESCRIPTION
1249 *
1250 *   Find all the places where the ray intersects the set of
1251 *   subdividing planes through the superquadric.  Return the
1252 *   number of valid hits (within the bounding box).
1253 *
1254 * CHANGES
1255 *
1256 *   Nov 1994 : Creation.
1257 *
1258 ******************************************************************************/
1259 
find_ray_plane_points(const Vector3d & P,const Vector3d & D,int cnt,DBL * dists,DBL mindist,DBL maxdist) const1260 int Superellipsoid::find_ray_plane_points(const Vector3d& P, const Vector3d& D, int cnt, DBL *dists, DBL mindist, DBL maxdist) const
1261 {
1262     int i;
1263     DBL t, d;
1264 
1265     /* Since min and max dist are the distance to two of the bounding planes
1266        we are considering, there is a high probablity of missing them due to
1267        round off error. Therefore we adjust min and max. */
1268 
1269     t = EPSILON * (maxdist - mindist);
1270 
1271     mindist -= t;
1272     maxdist += t;
1273 
1274     /* Check the sets of planes that cut apart the superquadric. */
1275 
1276     for (i = 0; i < PLANECOUNT; i++)
1277     {
1278         d = (D[0] * planes[i][0] + D[1] * planes[i][1] + D[2] * planes[i][2]);
1279 
1280         if (fabs(d) < EPSILON)
1281         {
1282             /* Can't possibly get a hit for this combination of ray and plane. */
1283 
1284             continue;
1285         }
1286 
1287         t = (planes[i][3] - (P[0] * planes[i][0] + P[1] * planes[i][1] + P[2] * planes[i][2])) / d;
1288 
1289         if ((t >= mindist) && (t <= maxdist))
1290         {
1291             dists[cnt++] = t;
1292         }
1293     }
1294 
1295     /* Sort the results for further processing. */
1296 
1297     QSORT(reinterpret_cast<void *>(dists), cnt, sizeof(DBL), compdists);
1298 
1299     return(cnt);
1300 }
1301 
1302 
1303 
1304 /*****************************************************************************
1305 *
1306 * FUNCTION
1307 *
1308 *   solve_hit1
1309 *
1310 * INPUT
1311 *
1312 * OUTPUT
1313 *
1314 * RETURNS
1315 *
1316 * AUTHOR
1317 *
1318 *   Alexander Enzmann
1319 *
1320 * DESCRIPTION
1321 *
1322 *   Home in on the root of a superquadric using a combination of
1323 *   secant and bisection methods.  This routine requires that
1324 *   the sign of the function be different at P0 and P1, it will
1325 *   fail drastically if this isn't the case.
1326 *
1327 * CHANGES
1328 *
1329 *   Nov 1994 : Creation.
1330 *
1331 ******************************************************************************/
1332 
solve_hit1(DBL v0,const Vector3d & tP0,DBL v1,const Vector3d & tP1,Vector3d & P) const1333 void Superellipsoid::solve_hit1(DBL v0, const Vector3d& tP0, DBL v1, const Vector3d& tP1, Vector3d& P) const
1334 {
1335     int i;
1336     DBL x, v2, v3;
1337     Vector3d P0, P1, P2, P3;
1338 
1339     P0 = tP0;
1340     P1 = tP1;
1341 
1342     /* The sign of v0 and v1 changes between P0 and P1, this
1343        means there is an intersection point in there somewhere. */
1344 
1345     for (i = 0; i < MAX_ITERATIONS; i++)
1346     {
1347         if (fabs(v0) < ZERO_TOLERANCE)
1348         {
1349             /* Near point is close enough to an intersection - just use it. */
1350 
1351             P = P0;
1352 
1353             break;
1354         }
1355 
1356         if (fabs(v1) < ZERO_TOLERANCE)
1357         {
1358             /* Far point is close enough to an intersection. */
1359 
1360             P = P1;
1361 
1362             break;
1363         }
1364 
1365         /* Look at the chord connecting P0 and P1. */
1366 
1367         /* Assume a line between the points. */
1368 
1369         x = fabs(v0) / fabs(v1 - v0);
1370 
1371         P2 = P1 - P0;
1372 
1373         P2 = P0 + x * P2;
1374 
1375         v2 = evaluate_superellipsoid(P2);
1376 
1377         /* Look at the midpoint between P0 and P1. */
1378 
1379         P3 = P1 - P0;
1380 
1381         P3 = P0 + 0.5 * P3;
1382 
1383         v3 = evaluate_superellipsoid(P3);
1384 
1385         if( v2 * v3 < 0.0 )
1386         {
1387             /* We can move both ends. */
1388 
1389             v0 = v2;
1390             P0 = P2;
1391 
1392             v1 = v3;
1393             P1 = P3;
1394         }
1395         else
1396         {
1397             if( fabs(v2) < fabs(v3) )
1398             {
1399                 /* secant method is doing better */
1400                 if( v0 * v2 < 0)
1401                 {
1402                     v1 = v2;
1403                     P1 = P2;
1404                 }
1405                 else
1406                 {
1407                     v0 = v2;
1408                     P0 = P2;
1409                 }
1410             }
1411             else
1412             {
1413                 /* bisection method is doing better */
1414                 if( v0 * v3 < 0)
1415                 {
1416                     v1 = v3;
1417                     P1 = P3;
1418                 }
1419                 else
1420                 {
1421                     v0 = v3;
1422                     P0 = P3;
1423                 }
1424             }
1425         }
1426     }
1427 
1428     if (i == MAX_ITERATIONS)
1429     {
1430         // The loop never quite closed in on the result - just use the point
1431         // closest to zero.  This really shouldn't happen since the max number
1432         // of iterations is enough to converge with straight bisection.
1433 
1434         if (fabs(v0) < fabs(v1))
1435         {
1436             P = P0;
1437         }
1438         else
1439         {
1440             P = P1;
1441         }
1442     }
1443 }
1444 
1445 
1446 
1447 
1448 /*****************************************************************************
1449 *
1450 * FUNCTION
1451 *
1452 *   check_hit2
1453 *
1454 * INPUT
1455 *
1456 * OUTPUT
1457 *
1458 * RETURNS
1459 *
1460 * AUTHOR
1461 *
1462 *   Alexander Enzmann
1463 *
1464 * DESCRIPTION
1465 *
1466 *   Try to find the root of a superquadric using Newtons method.
1467 *
1468 * CHANGES
1469 *
1470 *   Nov 1994 : Creation.
1471 *
1472 ******************************************************************************/
1473 
check_hit2(const Vector3d & P,const Vector3d & D,DBL t0,Vector3d & P0,DBL v0,DBL t1,DBL * t,Vector3d & Q) const1474 bool Superellipsoid::check_hit2(const Vector3d& P, const Vector3d& D, DBL t0, Vector3d& P0, DBL v0, DBL t1, DBL *t, Vector3d& Q) const
1475 {
1476     int i;
1477     DBL dt0, dt1, v1, deltat, maxdelta;
1478     Vector3d P1;
1479 
1480     dt0 = t0;
1481     dt1 = t0 + 0.0001 * (t1 - t0);
1482 
1483     maxdelta = t1 - t0;
1484 
1485     for (i = 0; (dt0 < t1) && (i < MAX_ITERATIONS); i++)
1486     {
1487         P1 = P + dt1 * D;
1488 
1489         v1 = evaluate_superellipsoid(P1);
1490 
1491         if (v0 * v1 < 0)
1492         {
1493             /* Found a crossing point, go back and use normal root solving. */
1494 
1495             solve_hit1(v0, P0, v1, P1, Q);
1496 
1497             P0 = Q - P;
1498 
1499             *t = P0.length();
1500 
1501             return(true);
1502         }
1503         else
1504         {
1505             if (fabs(v1) < ZERO_TOLERANCE)
1506             {
1507                 Q = P + dt1 * D;
1508 
1509                 *t = dt1;
1510 
1511                 return(true);
1512             }
1513             else
1514             {
1515                 if (((v0 > 0.0) && (v1 > v0)) || ((v0 < 0.0) && (v1 < v0)))
1516                 {
1517                     /* We definitely failed */
1518 
1519                     break;
1520                 }
1521                 else
1522                 {
1523                     if (v1 == v0)
1524                     {
1525                         break;
1526                     }
1527                     else
1528                     {
1529                         deltat = v1 * (dt1 - dt0) / (v1 - v0);
1530                     }
1531                 }
1532             }
1533         }
1534 
1535         if (fabs(deltat) > maxdelta)
1536         {
1537             break;
1538         }
1539 
1540         v0 = v1;
1541 
1542         dt0 = dt1;
1543 
1544         dt1 -= deltat;
1545     }
1546 
1547     return(false);
1548 }
1549 
1550 }
1551