int ON_Intersect( const ON_Sphere& sphere0, const ON_Sphere& sphere1, ON_Circle& circle ) { double r0 = sphere0.Radius(); double r1 = sphere1.Radius(); ON_3dPoint C0 = sphere0.Center(); ON_3dPoint C1 = sphere1.Center(); ON_3dVector D = C1-C0; double d = D.Length(); if (!D.Unitize()){ if (fabs(r1-r0) > ON_ZERO_TOLERANCE) return 0;//Same center, different radii return 3;//Same sphere. } //Spheres are appart. if (d > r0 + r1) return 0; //Spheres tangent and appart if (d == r0+r1){ ON_3dPoint P = C0 + r0*D; circle.Create(P, 0.0); return 1; } //Spheres tangent, one inside the other if (d == fabs(r0-r1)){ ON_3dPoint P = (r0 > r1) ? C0 + r0*D : C0 - r0*D; circle.Create(P, 0.0); return 1; } //Spheres don't intersect, one inside the other. if (d < fabs(r0-r1)) return 0; //Intersection is a circle double x = 0.5*(d*d + r0*r0 - r1*r1)/d; if (x >= r0){//Shouldn't happen ON_3dPoint P = C0 + r0*D; circle.Create(P, 0.0); return 1; } if (x <= -r0){//Shouldn't happen ON_3dPoint P = C0 - r0*D; circle.Create(P, 0.0); return 1; } double y = r0*r0 - x*x; if (y < 0.0)//Shouldn't happen return 0; y = sqrt(y); ON_3dPoint P = C0 + x*D; ON_Plane plane(P, D); circle.Create(plane, y); return 2; }
// Copied from opennurbs_intersect.cpp but with a bug fix. // We can remove it once the bug is fixed in OpenNurbs and once // Grasshopper has dropped Rhino4 support. int PS_Intersect( const ON_Plane& plane, const ON_Sphere& sphere, ON_Circle& circle ) { // 16 April 2011 Dale Lear // Prior to this date, this function did not return the correct answer. int rc = 0; const double sphere_radius = fabs(sphere.radius); double tol = sphere_radius*ON_SQRT_EPSILON; if ( !(tol >= ON_ZERO_TOLERANCE) ) tol = ON_ZERO_TOLERANCE; const ON_3dPoint sphere_center = sphere.Center(); ON_3dPoint circle_center = plane.ClosestPointTo(sphere_center); double d = circle_center.DistanceTo(sphere_center); circle.radius = 0.0; if ( ON_IsValid(sphere_radius) && ON_IsValid(d) && d <= sphere_radius + tol ) { if ( sphere_radius > 0.0 ) { d /= sphere_radius; d = 1.0 - d*d; // The d > 4.0*ON_EPSILON was picked by testing spheres with // radius = 1 and center = (0,0,0). Do not make 4.0*ON_EPSILON // any smaller and please discuss changes with Dale Lear. circle.radius = (d > 4.0*ON_EPSILON) ? sphere_radius*sqrt(d) : 0.0; } else circle.radius = 0.0; if ( circle.radius <= ON_ZERO_TOLERANCE ) { // return a single point rc = 1; circle.radius = 0.0; // When tolerance is in play, put the point on the sphere. // If the caller prefers the plane, then they can adjust the // returned answer to get the plane. ON_3dVector R = circle_center - sphere_center; double r0 = R.Length(); if ( r0 > 0.0 ) { R.Unitize(); ON_3dPoint C1 = sphere_center + sphere_radius*R; double r1 = C1.DistanceTo(sphere_center); if ( fabs(sphere.radius-r1) < fabs(sphere.radius-r0) ) circle_center = C1; } } else { // return a circle rc = 2; } } // Update circle's plane here in case the input plane // is the circle's plane member. circle.plane = plane; circle.plane.origin = circle_center; circle.plane.UpdateEquation(); return rc; }