@@ -101,6 +101,7 @@ namespace pov
101101
102102const DBL DEPTH_TOLERANCE = 1.0e-6 ;
103103const DBL ZERO_TOLERANCE = 1.0e-4 ;
104+ const DBL RADIUS_TOLERANCE = 1.0e-6 ;
104105
105106// TODO - Technically this should be `(Num_Spheres + Num_Segments * order) * 2` [CLi]
106107#define SPHSWEEP_MAX_ISECT ((Num_Spheres + Num_Segments) * 2 + 64 )
@@ -408,7 +409,6 @@ int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segm
408409 DBL fp0, fp1;
409410 DBL t;
410411 SPHSWEEP_SPH Temp_Sphere;
411- Vector3d Center;
412412
413413 Isect_Count = 0 ;
414414
@@ -617,51 +617,31 @@ int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segm
617617 m++;
618618 }
619619
620- switch (Segment-> Num_Coefs )
620+ for (m = 0 ; m < Num_Poly_Roots; m++ )
621621 {
622- case 2 :
623- for (m = 0 ; m < Num_Poly_Roots; m++)
624- {
625- fp0 = 2.0 * d * Root[m]
626- + e;
627- fp1 = b;
628-
629- if (fabs (fp1) > ZERO_TOLERANCE)
630- {
631- t = -fp0 / fp1;
632-
633- if ((t > -MAX_DISTANCE) && (t < MAX_DISTANCE))
634- {
635- // Add intersection
636- Isect[Isect_Count].t = t;
622+ // Calculate center and radius of sphere at root
637623
638- // Calculate point
639- Isect[Isect_Count].Point = ray.Evaluate (t);
624+ DBL rootPwr = 1 ;
625+ Temp_Sphere.Center = Segment->Center_Coef [0 ];
626+ Temp_Sphere.Radius = Segment->Radius_Coef [0 ];
627+ for (n = 1 ; n < Segment->Num_Coefs ; ++n)
628+ {
629+ rootPwr *= Root[m];
630+ Temp_Sphere.Center += Segment->Center_Coef [n] * rootPwr;
631+ Temp_Sphere.Radius += Segment->Radius_Coef [n] * rootPwr;
632+ }
640633
641- // Calculate normal
642- Center = Segment-> Center_Coef [ 0 ] + Root[m] * Segment-> Center_Coef [ 1 ];
643- Isect[Isect_Count]. Normal = (Isect[Isect_Count]. Point - Center). normalized ();
634+ switch (Segment-> Num_Coefs )
635+ {
636+ case 2 :
644637
645- Isect_Count++;
646- }
647- }
648- else
649- {
650- // Calculate center of single sphere
651- Temp_Sphere.Center = Segment->Center_Coef [1 ] * Root[m] + Segment->Center_Coef [0 ];
638+ fp0 = 2.0 * d * Root[m]
639+ + e;
640+ fp1 = b;
641+ break ;
652642
653- // Calculate radius of single sphere
654- Temp_Sphere.Radius = Segment->Radius_Coef [1 ] * Root[m] + Segment->Radius_Coef [0 ];
643+ case 4 :
655644
656- // Calculate intersections
657- if (Intersect_Sphere (ray, &Temp_Sphere, Isect + Isect_Count))
658- Isect_Count += 2 ;
659- }
660- }
661- break ;
662- case 4 :
663- for (m = 0 ; m < Num_Poly_Roots; m++)
664- {
665645 fp0 = 6.0 * f * Root[m] * Root[m] * Root[m] * Root[m] * Root[m]
666646 + 5.0 * g * Root[m] * Root[m] * Root[m] * Root[m]
667647 + 4.0 * h * Root[m] * Root[m] * Root[m]
@@ -671,49 +651,49 @@ int SphereSweep::Intersect_Segment(const BasicRay &ray, const SPHSWEEP_SEG *Segm
671651 fp1 = 3.0 * b * Root[m] * Root[m]
672652 + 2.0 * c * Root[m]
673653 + d;
654+ break ;
674655
675- if (fabs (fp1) > ZERO_TOLERANCE)
676- {
677- t = -fp0 / fp1;
656+ default :
657+ POV_SHAPE_ASSERT (false );
658+ break ;
659+ }
678660
679- if ((t > -MAX_DISTANCE) && (t < MAX_DISTANCE))
680- {
681- // Add intersection
682- Isect[Isect_Count]. t = t;
661+ bool doubleIsect = ( fabs (fp1) < ZERO_TOLERANCE);
662+ if (!doubleIsect)
663+ {
664+ // Looks like a single-intersection root at first glance
683665
684- // Calculate point
685- Isect[Isect_Count].Point = ray.Evaluate (t);
666+ t = -fp0 / fp1;
686667
687- // Calculate normal
688- Center = Segment->Center_Coef [3 ] * (Root[m] * Root[m] * Root[m])
689- + Segment->Center_Coef [2 ] * (Root[m] * Root[m])
690- + Segment->Center_Coef [1 ] * Root[m]
691- + Segment->Center_Coef [0 ];
692- Isect[Isect_Count].Normal = (Isect[Isect_Count].Point - Center).normalized ();
668+ if ((t > -MAX_DISTANCE) && (t < MAX_DISTANCE))
669+ {
670+ // Calculate intersection point
671+ Isect[Isect_Count].Point = ray.Evaluate (t);
693672
694- Isect_Count++;
695- }
696- }
697- else
673+ // Calculate normal
674+ Isect[Isect_Count].Normal = (Isect[Isect_Count].Point - Temp_Sphere.Center ).normalized ();
675+
676+ // Sanity-check intersection point for proper radius
677+ DBL rIsect = (Isect[Isect_Count].Point - Temp_Sphere.Center ).length ();
678+ DBL rRoot = Temp_Sphere.Radius ;
679+
680+ // Check for numeric instability; this may (only?) happen if the root corresponds to two intersections
681+ doubleIsect = fabs (rIsect - rRoot) > RADIUS_TOLERANCE;
682+ if (!doubleIsect)
698683 {
699- // Calculate center of single sphere
700- Temp_Sphere.Center = Segment->Center_Coef [3 ] * (Root[m] * Root[m] * Root[m])
701- + Segment->Center_Coef [2 ] * (Root[m] * Root[m])
702- + Segment->Center_Coef [1 ] * Root[m]
703- + Segment->Center_Coef [0 ];
704-
705- // Calculate radius of single sphere
706- Temp_Sphere.Radius = Segment->Radius_Coef [3 ] * Root[m] * Root[m] * Root[m]
707- + Segment->Radius_Coef [2 ] * Root[m] * Root[m]
708- + Segment->Radius_Coef [1 ] * Root[m]
709- + Segment->Radius_Coef [0 ];
710-
711- // Calculate intersections
712- if (Intersect_Sphere (ray, &Temp_Sphere, Isect + Isect_Count))
713- Isect_Count += 2 ;
684+ // Add intersection
685+ Isect[Isect_Count].t = t;
686+ Isect_Count++;
714687 }
715688 }
716- break ;
689+ }
690+
691+ if (doubleIsect)
692+ {
693+ // Calculate intersections
694+ if (Intersect_Sphere (ray, &Temp_Sphere, Isect + Isect_Count))
695+ Isect_Count += 2 ;
696+ }
717697 }
718698
719699 return Isect_Count;
@@ -1353,10 +1333,8 @@ void SphereSweep::Compute_BBox()
13531333 {
13541334 for (i = 0 ; i < Num_Modeling_Spheres; i++)
13551335 {
1356- {
1357- mins = min (mins, Modeling_Sphere[i].Center - Vector3d (fabs (Modeling_Sphere[i].Radius )));
1358- maxs = max (maxs, Modeling_Sphere[i].Center + Vector3d (fabs (Modeling_Sphere[i].Radius )));
1359- }
1336+ mins = min (mins, Modeling_Sphere[i].Center - Vector3d (fabs (Modeling_Sphere[i].Radius )));
1337+ maxs = max (maxs, Modeling_Sphere[i].Center + Vector3d (fabs (Modeling_Sphere[i].Radius )));
13601338 }
13611339 }
13621340
0 commit comments