/// Uses 2D Newton's method using stereographic parametrization and fancy initial guess /// Pass: /// abc - coefficients of the ellipse equation; aka the half-extents /// p - point in ellipse coordinates public static Vector3 ClosestPointEllipsoid( Vector3 abc_, Vector3 p_, int numIters = 30, double threshold = 0) { // Doesn't like negative scales & result is the same by symmetry! vec3 abc = vec3.abs(new vec3(abc_)); // WLOG move to the all-positive octant; move back to original octant when done. vec3 orig_p = new vec3(p_); vec3 p = vec3.abs(orig_p); Stereo uv = Stereo.FromCartesian(InitialGuessClosestPointToEllipsoid(p, abc), abc); for (int i = 0; i < numIters; ++i) { Stereo prevUv = uv; uv = Iterate_Stereographic(uv, p, abc); if (Math.Abs(prevUv.x - uv.x) < threshold || Math.Abs(prevUv.y - uv.y) < threshold) { break; } } // Move back to correct octant vec3 wrongOctant = uv.ToCartesian(abc); vec3 rightOctant = wrongOctant * orig_p.sign(); return((Vector3)rightOctant); }