distance from given point to given ellipse

后端 未结 7 1951
抹茶落季
抹茶落季 2021-02-05 08:07

I have an ellipse, defined by Center Point, radiusX and radiusY, and I have a Point. I want to find the point on the ellipse that is closest to the given point. In the illustrat

相关标签:
7条回答
  • 2021-02-05 08:22

    There is a relatively simple numerical method with better convergence than Newtons Method. I have a blog post about why it works http://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/

    This implementation works without any trig functions:

    def solve(semi_major, semi_minor, p):  
        px = abs(p[0])
        py = abs(p[1])
    
        tx = 0.707
        ty = 0.707
    
        a = semi_major
        b = semi_minor
    
        for x in range(0, 3):
            x = a * tx
            y = b * ty
    
            ex = (a*a - b*b) * tx**3 / a
            ey = (b*b - a*a) * ty**3 / b
    
            rx = x - ex
            ry = y - ey
    
            qx = px - ex
            qy = py - ey
    
            r = math.hypot(ry, rx)
            q = math.hypot(qy, qx)
    
            tx = min(1, max(0, (qx * r / q + ex) / a))
            ty = min(1, max(0, (qy * r / q + ey) / b))
            t = math.hypot(ty, tx)
            tx /= t 
            ty /= t 
    
        return (math.copysign(a * tx, p[0]), math.copysign(b * ty, p[1]))
    

    Credit to Adrian Stephens for the Trig-Free Optimization.

    0 讨论(0)
  • 2021-02-05 08:23

    Here is the code translated to C# implemented from this paper to solve for the ellipse: http://www.geometrictools.com/Documentation/DistancePointEllipseEllipsoid.pdf

    Note that this code is untested - if you find any errors let me know.

        //Pseudocode for robustly computing the closest ellipse point and distance to a query point. It
        //is required that e0 >= e1 > 0, y0 >= 0, and y1 >= 0.
        //e0,e1 = ellipse dimension 0 and 1, where 0 is greater and both are positive.
        //y0,y1 = initial point on ellipse axis (center of ellipse is 0,0)
        //x0,x1 = intersection point
    
        double GetRoot ( double r0 , double z0 , double z1 , double g )
        {
            double n0 = r0*z0;
            double s0 = z1 - 1; 
            double s1 = ( g < 0 ? 0 : Math.Sqrt(n0*n0+z1*z1) - 1 ) ;
            double s = 0;
            for ( int i = 0; i < maxIter; ++i ){
                s = ( s0 + s1 ) / 2 ;
                if ( s == s0 || s == s1 ) {break; }
                double ratio0 = n0 /( s + r0 );
                double ratio1 = z1 /( s + 1 );
                g = ratio0*ratio0 + ratio1*ratio1 - 1 ;
                if (g > 0) {s0 = s;} else if (g < 0) {s1 = s ;} else {break ;}
            }
            return s;
        }
        double DistancePointEllipse( double e0 , double e1 , double y0 , double y1 , out double x0 , out double x1)
        {
            double distance;
            if ( y1 > 0){
                if ( y0 > 0){
                    double z0 = y0 / e0; 
                    double z1 = y1 / e1; 
                    double g = z0*z0+z1*z1 - 1;
                    if ( g != 0){
                        double r0 = (e0/e1)*(e0/e1);
                        double sbar = GetRoot(r0 , z0 , z1 , g);
                        x0 = r0 * y0 /( sbar + r0 );
                        x1 = y1 /( sbar + 1 );
                        distance = Math.Sqrt( (x0-y0)*(x0-y0) + (x1-y1)*(x1-y1) );
                        }else{
                            x0 = y0; 
                            x1 = y1;
                            distance = 0;
                        }
                    }
                    else // y0 == 0
                        x0 = 0 ; x1 = e1 ; distance = Math.Abs( y1 - e1 );
            }else{ // y1 == 0
                double numer0 = e0*y0 , denom0 = e0*e0 - e1*e1;
                if ( numer0 < denom0 ){
                        double xde0 = numer0/denom0;
                        x0 = e0*xde0 ; x1 = e1*Math.Sqrt(1 - xde0*xde0 );
                        distance = Math.Sqrt( (x0-y0)*(x0-y0) + x1*x1 );
                    }else{
                        x0 = e0; 
                        x1 = 0; 
                        distance = Math.Abs( y0 - e0 );
                }
            }
            return distance;
        }
    
    0 讨论(0)
  • 2021-02-05 08:28

    Consider a bounding circle around the given point (c, d), which passes through the nearest point on the ellipse. From the diagram it is clear that the closest point is such that a line drawn from it to the given point must be perpendicular to the shared tangent of the ellipse and circle. Any other points would be outside the circle and so must be further away from the given point.

    enter image description here

    So the point you are looking for is not the intersection between the line and the ellipse, but the point (x, y) in the diagram.

    Gradient of tangent:

    enter image description here

    Gradient of line:

    enter image description here

    Condition for perpedicular lines - product of gradients = -1:

    enter image description here

    enter image description here

    enter image description here

    When rearranged and substituted into the equation of your ellipse...

    enter image description here

    ...this will give two nasty quartic (4th-degree polynomial) equations in terms of either x or y. AFAIK there are no general analytical (exact algebraic) methods to solve them. You could try an iterative method - look up the Newton-Raphson iterative root-finding algorithm.

    Take a look at this very good paper on the subject: http://www.spaceroots.org/documents/distance/distance-to-ellipse.pdf

    Sorry for the incomplete answer - I totally blame the laws of mathematics and nature...

    EDIT: oops, i seem to have a and b the wrong way round in the diagram xD

    0 讨论(0)
  • 2021-02-05 08:29

    Given an ellipse E in parametric form and a point P

    eqn

    the square of the distance between P and E(t) is

    eqn

    The minimum must satisfy

    eqn

    Using the trigonometric identities

    eqn

    and substituting

    yields the following quartic equation:

    Here's an example C function that solves the quartic directly and computes sin(t) and cos(t) for the nearest point on the ellipse:

    void nearest(double a, double b, double x, double y, double *ecos_ret, double *esin_ret) {
        double ax = fabs(a*x);
        double by = fabs(b*y);
        double r  = b*b - a*a;
        double c, d;
        int switched = 0;
    
        if (ax <= by) {
            if (by == 0) {
                if (r >= 0) { *ecos_ret = 1; *esin_ret = 0; }
                else        { *ecos_ret = 0; *esin_ret = 1; }
                return;
            }
            c = (ax - r) / by;
            d = (ax + r) / by;
        } else {
            c = (by + r) / ax;
            d = (by - r) / ax;
            switched = 1;
        }
    
        double cc = c*c;
        double D0 = 12*(c*d + 1);      // *-4
        double D1 = 54*(d*d - cc);     // *4
        double D  = D1*D1 + D0*D0*D0;  // *16
    
        double St;
        if (D < 0) {
            double t = sqrt(-D0);             // *2
            double phi = acos(D1 / (t*t*t));
            St = 2*t*cos((1.0/3)*phi);        // *2
        } else {
            double Q = cbrt(D1 + sqrt(D));    // *2
            St = Q - D0 / Q;                  // *2
        }
    
        double p    = 3*cc;                          // *-2
        double SS   = (1.0/3)*(p + St);              // *4
        double S    = sqrt(SS);                      // *2
        double q    = 2*cc*c + 4*d;                  // *2
        double l    = sqrt(p - SS + q / S) - S - c;  // *2
        double ll   = l*l;                           // *4
        double ll4  = ll + 4;                        // *4
        double esin = (4*l)    / ll4;
        double ecos = (4 - ll) / ll4;
    
        if (switched) {
            double t = esin;
            esin = ecos;
            ecos = t;
        }
    
        *ecos_ret = copysign(ecos, a*x);
        *esin_ret = copysign(esin, b*y);
    }
    

    Try it online!

    0 讨论(0)
  • 2021-02-05 08:30

    I've solved the distance issue via focal points.

    For every point on the ellipse

    r1 + r2 = 2*a0

    where

    r1 - Euclidean distance from the given point to focal point 1

    r2 - Euclidean distance from the given point to focal point 2

    a0 - semimajor axis length

    I can also calculate the r1 and r2 for any given point which gives me another ellipse that this point lies on that is concentric to the given ellipse. So the distance is

    d = Abs((r1 + r2) / 2 - a0)

    0 讨论(0)
  • 2021-02-05 08:38

    You just need to calculate the intersection of the line [P1,P0] to your elipse which is S1.

    If the line equeation is:

    enter image description here

    and the elipse equesion is:

    elipse equesion

    than the values of S1 will be:

    enter image description here

    Now you just need to calculate the distance between S1 to P1 , the formula (for A,B points) is: distance

    0 讨论(0)
提交回复
热议问题