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