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;
}
Example #2
0
/* 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; 
}