Real DistancePointEllipse (const Real e[2], const Real y[2], Real x[2]) { // Determine reflections for y to the first quadrant. bool reflect[2]; int i, j; for (i = 0; i < 2; ++i) { reflect[i] = (y[i] < (Real)0); } // Determine the axis order for decreasing extents. int permute[2]; if (e[0] < e[1]) { permute[0] = 1; permute[1] = 0; } else { permute[0] = 0; permute[1] = 1; } int invpermute[2]; for (i = 0; i < 2; ++i) { invpermute[permute[i]] = i; } Real locE[2], locY[2]; for (i = 0; i < 2; ++i) { j = permute[i]; locE[i] = e[j]; locY[i] = y[j]; if (reflect[j]) { locY[i] = -locY[i]; } } Real locX[2]; Real distance = DistancePointEllipseSpecial(locE, locY, locX); // Restore the axis order and reflections. for (i = 0; i < 2; ++i) { j = invpermute[i]; if (reflect[i]) { locX[j] = -locX[j]; } x[i] = locX[j]; } return distance; }
/* from www.geometrictools.com (by David Eberly) */ double Ellipse_Point_Distance(double dU, double dV, /* test point (u,v) */ double dA, double dB, /* ellipse (x/a)^2 + (y/b)^2 = 1 */ double *rdX, double *rdY) { double dEpsilon = 1e-5; /* zero tolerance for Newton's method */ int iMax = 100; /* maximum iterations in Newton's method */ //int riIFinal; double tmp_rdX, tmp_rdY; if (rdX == NULL) { rdX = &tmp_rdX; } if (rdY == NULL) { rdY = &tmp_rdY; } // special case of circle if (fabs(dA-dB) < dEpsilon) { double dLength = sqrt(dU*dU+dV*dV); *rdX = dA / dLength * dU; *rdY = dA / dLength * dV; return fabs(dLength - dA); } // reflect U = -U if necessary, clamp to zero if necessary BOOL bXReflect; if (dU > dEpsilon) { bXReflect = FALSE; } else if (dU < -dEpsilon) { bXReflect = TRUE; dU = -dU; } else { bXReflect = FALSE; dU = 0.0; } // reflect V = -V if necessary, clamp to zero if necessary BOOL bYReflect; if (dV > dEpsilon) { bYReflect = FALSE; } else if (dV < -dEpsilon) { bYReflect = TRUE; dV = -dV; } else { bYReflect = FALSE; dV = 0.0; } // transpose if necessary double dSave; BOOL bTranspose; if (dA >= dB) { bTranspose = FALSE; } else { bTranspose = TRUE; dSave = dA; dA = dB; dB = dSave; dSave = dU; dU = dV; dV = dSave; } double dDistance; if (dU != 0.0) { if (dV != 0.0) { dDistance = DistancePointEllipseSpecial(dU,dV,dA,dB,dEpsilon,iMax, /*riIFinal,*/rdX,rdY); } else { double dBSqr = dB*dB; if (dU < dA - dBSqr/dA) { double dASqr = dA*dA; *rdX = dASqr*dU/(dASqr-dBSqr); double dXDivA = *rdX/dA; *rdY = dB*sqrt(fabs(1.0-dXDivA*dXDivA)); double dXDelta = *rdX - dU; dDistance = sqrt(dXDelta*dXDelta+(*rdY) * (*rdY)); //riIFinal = 0; } else { dDistance = fabs(dU - dA); *rdX = dA; *rdY = 0.0; //riIFinal = 0; } } } else { dDistance = fabs(dV - dB); *rdX = 0.0; *rdY = dB; //riIFinal = 0; } if (bTranspose) { dSave = *rdX; *rdX = *rdY; *rdY = dSave; } if (bYReflect) { *rdY = -(*rdY); } if (bXReflect) { *rdX = -(*rdX); } return dDistance; }