4545*
4646* ovus
4747* {
48- * bottom_radius,top_radius
48+ * bottom_radius,top_radius [distance d] [radius r] [precision p] [sturm]
4949* }
5050*
5151* The so long awaited 'Egg' forms.
5252*
5353* Normally, the bottom_radius is bigger than the top_radius
54- * the center of the top sphere is at the zenith of the bottom sphere
54+ * the center of the top sphere is at the zenith of the bottom sphere, unless
55+ * a greater distance d is specified with "distance"
5556* and the bottom sphere is centered at 0.0
5657* The radius of the connecting surface is the double of the biggest radius
5758* (yes, the biggest diameter is used as the curvature of the connection)
59+ * unless overriden with "radius"
5860*
5961* The hard part was just to find where the connection starts and ends.
6062*
@@ -82,13 +84,6 @@ namespace pov
8284* Local preprocessor defines
8385******************************************************************************/
8486
85- // Minimal depth for a valid intersection.
86- // TODO FIXME - can we use EPSILON or a similar more generic constant instead?
87- const DBL DEPTH_TOLERANCE = 1.0e-4 ;
88-
89- // Tolerance used for order reduction during root finding.
90- // TODO FIXME - can we use EPSILON or a similar more generic constant instead?
91- const DBL ROOT_TOLERANCE = 1.0e-4 ;
9287
9388
9489
@@ -110,6 +105,7 @@ void Ovus::Intersect_Ovus_Spheres(const Vector3d& P, const Vector3d& D,
110105 *Depth1 = *Depth2 = *Depth3 = *Depth4 = *Depth5 = *Depth6 = -100 ; // TODO FIXME - magic value
111106 // no hit unless...
112107
108+ // compute intersection with bottom sphere
113109 Padj = -P;
114110 Rad1 = Sqr (BottomRadius);
115111 Rad2 = Sqr (TopRadius);
@@ -140,8 +136,10 @@ void Ovus::Intersect_Ovus_Spheres(const Vector3d& P, const Vector3d& D,
140136 }
141137 }
142138 }
139+ // shape can only have a maximum of 2 intersections, if we have them already, return
143140 if (lcount > 1 ) return ;
144- Second_Center = Vector3d (0 , BottomRadius, 0 );
141+ // compute intersection with top sphere
142+ Second_Center = Vector3d (0 , VerticalSpherePosition, 0 );
145143 Padj = Second_Center - P;
146144
147145 OCSquared = Padj.lengthSqr ();
@@ -172,7 +170,9 @@ void Ovus::Intersect_Ovus_Spheres(const Vector3d& P, const Vector3d& D,
172170
173171 }
174172 }
173+ // shape can only have a maximum of 2 intersections, if we have them already, return
175174 if (lcount > 1 ) return ;
175+ // need to evaluate the spindle of the torus, because intersions are not yet all found
176176 Second_Center = Vector3d (0 , VerticalPosition, 0 );
177177 Padj = P - Second_Center;
178178 R2 = Sqr (HorizontalPosition);
@@ -196,7 +196,7 @@ void Ovus::Intersect_Ovus_Spheres(const Vector3d& P, const Vector3d& D,
196196
197197 c[4 ] = k1 * k1 + 4.0 * R2 * (Py2 - r2);
198198
199- n = Solve_Polynomial (4 , c, r, Test_Flag (this , STURM_FLAG), ROOT_TOLERANCE , Thread->Stats ());
199+ n = Solve_Polynomial (4 , c, r, Test_Flag (this , STURM_FLAG), RootTolerance , Thread->Stats ());
200200 while (n--)
201201 {
202202 // here we only keep the 'lemon' inside the torus
@@ -213,7 +213,7 @@ void Ovus::Intersect_Ovus_Spheres(const Vector3d& P, const Vector3d& D,
213213 {
214214 horizontal = sqrt (Sqr (IPoint[X]) + Sqr (IPoint[Z]));
215215 OCSquared = Sqr ((horizontal + HorizontalPosition)) + Sqr ((vertical - VerticalPosition));
216- if (fabs (OCSquared - Sqr (ConnectingRadius)) < ROOT_TOLERANCE )
216+ if (fabs (OCSquared - Sqr (ConnectingRadius)) < RootTolerance )
217217 {
218218 if (*Depth5 < 0 )
219219 {
@@ -322,7 +322,7 @@ bool Ovus::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadDat
322322 if (Clip.empty ()||(Point_In_Clip (Real_Pt, Clip, Thread)))
323323 {
324324 INormal = IPoint;
325- INormal[Y] -= BottomRadius ;
325+ INormal[Y] -= VerticalSpherePosition ;
326326 INormal /= TopRadius;
327327 MTransNormal (Real_Normal, INormal, Trans);
328328 Real_Normal.normalize ();
@@ -341,7 +341,7 @@ bool Ovus::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadDat
341341 if (Clip.empty ()||(Point_In_Clip (Real_Pt, Clip, Thread)))
342342 {
343343 INormal = IPoint;
344- INormal[Y] -= BottomRadius ;
344+ INormal[Y] -= VerticalSpherePosition ;
345345 INormal /= TopRadius;
346346 MTransNormal (Real_Normal, INormal, Trans);
347347 Real_Normal.normalize ();
@@ -435,7 +435,7 @@ bool Ovus::Inside(const Vector3d& IPoint, TraceThreadData *Thread) const
435435 DBL horizontal, vertical;
436436 bool INSide = false ;
437437 Vector3d Origin, New_Point, Other;
438- Origin = Vector3d (0 , BottomRadius , 0 );
438+ Origin = Vector3d (0 , VerticalSpherePosition , 0 );
439439 MInvTransPoint (New_Point, IPoint, Trans);
440440 OCSquared = New_Point.lengthSqr ();
441441 if (OCSquared < Sqr (BottomRadius))
@@ -698,6 +698,8 @@ Ovus::Ovus() : ObjectBase(OVUS_OBJECT)
698698 BottomVertical = 0.0 ;
699699 TopVertical = 0.0 ;
700700 ConnectingRadius = 0.0 ;
701+ VerticalSpherePosition = 0.0 ;
702+ RootTolerance = 1.0e-4 ;
701703}
702704
703705
@@ -774,7 +776,8 @@ ObjectPtr Ovus::Copy()
774776******************************************************************************/
775777
776778Ovus::~Ovus ()
777- {}
779+ {
780+ }
778781
779782
780783
@@ -811,7 +814,11 @@ void Ovus::Compute_BBox()
811814{
812815 // Compute the biggest vertical cylinder radius
813816 DBL biggest;
817+ DBL bottom;
818+ DBL length;
814819 biggest = ConnectingRadius - HorizontalPosition;
820+ bottom = -BottomRadius;
821+ length = BottomRadius + VerticalSpherePosition + TopRadius;
815822 if (biggest < BottomRadius)
816823 {
817824 biggest = BottomRadius;
@@ -820,9 +827,17 @@ void Ovus::Compute_BBox()
820827 {
821828 biggest = TopRadius;
822829 }
830+ // handle degenerated ovus in sphere
831+ // negative value have been intercepted by Parser::Parse_Ovus
832+ // and the 0.0 is only possible for detected degenerated ovus in that function
833+ if (BottomRadius == 0.0 )
834+ {
835+ bottom = VerticalSpherePosition-TopRadius;
836+ length = 2 *TopRadius;
837+ }
823838
824- Make_BBox (BBox, -biggest, -BottomRadius , -biggest,
825- 2.0 * biggest, 2.0 * BottomRadius + TopRadius , 2.0 * biggest);
839+ Make_BBox (BBox, -biggest, bottom , -biggest,
840+ 2.0 * biggest, length , 2.0 * biggest);
826841
827842 Recompute_BBox (&BBox, Trans);
828843}
@@ -883,46 +898,64 @@ void Ovus::UVCoord(Vector2d& Result, const Intersection *Inter, TraceThreadData
883898*
884899* CHANGES
885900*
901+ * due to the addition of distance, the mapping is changed to something similar
902+ * to lemon, cone & cylinder
903+ *
886904******************************************************************************/
887905
888906void Ovus::CalcUV (const Vector3d& IPoint, Vector2d& Result) const
889907{
890- DBL len, x, y, z ;
908+ DBL len, x, z, t ;
891909 DBL phi, theta;
892910 Vector3d P;
893911
894- // Transform the ray into the ovus space.
912+ // Transform the point back into the ovus space.
895913 MInvTransPoint (P, IPoint, Trans);
896914
897- // the center of UV coordinate is the bottom center when top radius ->0
898- // and it is the top center when top radius -> 2.0* bottom radius
899- // when top radius == bottom radius, it is half-way between both center
900- //
901- // bottom center is <0,0,0>
902- // top center is <0,BottomRadius,0>
903- // TODO FIXME - comment doesn't seem to match the following code
915+ // the center of UV coordinate is the <0,0> point
904916 x = P[X];
905- // y = P[Y] - BottomRadius*(TopRadius/(2.0*BottomRadius));
906- y = P[Y] - (TopRadius/2.0 );
907917 z = P[Z];
908918
909- // now assume it's just a sphere, for UV mapping/projection
910- len = sqrt ( x * x + y * y + z * z) ;
919+ // Determine its angle from the point (0, 0, 0) in the x-z plane.
920+ len = x * x + z * z;
911921
912- if (len == 0.0 )
913- return ;
922+ if ( (P[Y] > EPSILON) && (P[Y] < (VerticalSpherePosition - EPSILON) ) )
923+ {
924+ // when on the spindle, the range 0.25 to 0.75 is used
925+ // Verbatim from C-Lipka:
926+ // Dividing at 1/4 and 3/4 has the advantage of the division being exactly at a pixel boundary
927+ // if the texture is an image 2^N by 2^M pixels in size, which is common for image textures
928+ // originally designed for mesh-based renderers. It also happens to work for 20N by 20M pixels,
929+ // which is common for image textures with "arbitrary" sizes.
930+ phi = 0.75 -0.5 *(P[Y])/(VerticalSpherePosition);
931+ }
932+ else if (P[Y]>EPSILON)
933+ {
934+ // aka P[Y] is above VerticalSpherePositon, use TopRadius, from 0% to 25%
935+ phi = 0.0 ;
936+ if (TopRadius != 0.0 )
937+ {
938+ t = ((P[Y]-VerticalSpherePosition)/(TopRadius));
939+ phi = (sin (sqrt (1 -t)*M_PI_2)/(4.0 ));
940+ }
941+ }
914942 else
915943 {
916- x /= len;
917- y /= len;
918- z /= len;
944+ // aka P[Y] is below origin (<0), use BottomRadius, from 75% to 100%
945+ phi = 1.0 ;
946+ if (BottomRadius != 0.0 )
947+ {
948+ t = ((BottomRadius+P[Y])/(BottomRadius));
949+ phi = 1.0 -sin (sqrt (t)*M_PI_2)/(4.0 );
950+ }
951+ else if (TopRadius != 0.0 ) // per Parser::Parse_Ovus, TopRadius & BottomRadius cannot be both 0.0 at the same time, but keep the test due to division
952+ {
953+ // degenerate ovus in sphere
954+ t = ((TopRadius-VerticalSpherePosition+P[Y])/(TopRadius));
955+ phi = 1.0 -sin (sqrt (t)*M_PI_2)/(4.0 );
956+ }
919957 }
920958
921- // Determine its angle from the x-z plane.
922- phi = 0.5 + asin (y) / M_PI; // This will be from 0 to 1
923-
924- // Determine its angle from the point (1, 0, 0) in the x-z plane.
925- len = x * x + z * z;
926959
927960 if (len > EPSILON)
928961 {
0 commit comments