finding a point on a path

前端 未结 2 1470
无人及你
无人及你 2020-12-17 01:05

I have an app that draws a bezier curve in a UIView and I need to find the X intersect when I set a value for Y. First, as I understand, there isn’t a way to fi

相关标签:
2条回答
  • 2020-12-17 01:33

    It took me a while but the code below is how I solved finding a point on a bezier curve. The math only finds one of the potential 3 values so I suspect if there is more than one it will fail, but in my circumstance my bezier should only ever have one solution since my curve should never cross the same X or Y plane more than once. I wanted to share what I have and I welcome any questions, comments, or suggestions.

    #import "Calculation.h"
    
    @implementation Calculation
    
    @synthesize a, b, c, d, xy;
    
    - (float) calc
    {
    
        float squareRootCalc =
        sqrt(
        6*pow(xy,2)*b*d
        +4*a*pow(c,3)
        -3*pow(b,2)*pow(c,2)
        +9*pow(xy,2)*pow(c,2)
        -6*a*c*b*d
        +6*a*xy*c*b
        -18*pow(xy,2)*b*c
        +6*a*pow(xy,2)*c
        -12*a*xy*pow(c,2)
        -2*pow(a,2)*xy*d
        +pow(a,2)*pow(d,2)
        +4*pow(b,3)*d
        +pow(xy,2)*pow(d,2)
        -4*pow(b,3)*xy
        -4*pow(c,3)*xy
        +pow(a,2)*pow(xy,2)
        +6*c*b*d*xy
        +6*a*c*d*xy
        +6*a*b*d*xy
        -12*pow(b,2)*d*xy
        +6*xy*c*pow(b,2)
        +6*xy*b*pow(c,2)
        -2*a*pow(xy,2)*d
        -2*a*xy*pow(d,2)
        -6*c*d*pow(xy,2)
        +9*pow(xy,2)*pow(b,2)
        -6*a*pow(xy,2)*b)
        ;
    
        float aCalc = 24*c*d*xy + 24*a*pow(c,2) - 36*xy*pow(c,2) + 4 * squareRootCalc * a;
    
        float bCalc = -12 * squareRootCalc * b;
    
        float cCalc = 12 * squareRootCalc * c;
    
        float dCalc = -4 * squareRootCalc * d;
    
    
        float xyCalc =
        24*xy*a*b
        -24*xy*b*d
        -12*b*a*d
        -12*c*a*d
        -12*c*b*d
        +8*xy*a*d
        +8*pow(b,3)
        +8*pow(c,3)
        +4*pow(a,2)*d
        +24*pow(b,2)*d
        -4*xy*pow(a,2)
        -4*xy*pow(d,2)
        +4*a*pow(d,2)
        -12*c*pow(b,2)
        -12*b*pow(c,2)
        -12*a*b*c
        -24*xy*a*c
        +72*xy*c*b
        -36*xy*pow(b,2)
        ;
    
        float cubeRootCalc = cbrt(aCalc + bCalc + cCalc + dCalc + xyCalc);
    
        float denomCalc = (a-3*b+3*c-d);
    
        float secOneCalc = 0.5 * cubeRootCalc / denomCalc;
    
        float secTwoCalc = -2 * ((a*c - a*d - pow(b,2) + c*b + b*d - pow(c,2)) / (denomCalc * cubeRootCalc));
    
        float secThreeCalc = (a - 2*b + c) / denomCalc;
    
        return secOneCalc + secTwoCalc + secThreeCalc;
    
    
    }
    
    - (Calculation *) initWithA:(float)p0 andB:(float)p1 andC:(float)p2 andD:(float)p3 andXy:(float)xyValue
    {
        self = [super init];
    
        if (self) {
            [self setA:p0];
            [self setB:p1];
            [self setC:p2];
            [self setD:p3];
            [self setXy:xyValue];
        }
        return self;
    }
    
    - (void) setA:(float)p0 andB:(float)p1 andC:(float)p2 andD:(float)p3 andXy:(float)xyValue
    {
        [self setA:p0];
        [self setB:p1];
        [self setC:p2];
        [self setD:p3];
        [self setXy:xyValue];
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-17 01:35

    A cubic Bézier curve is defined by 4 points

    P0 = (x0, y0) = start point,
    P1 = (x1, y1) = first control point,
    P2 = (x2, y2) = second control point,
    P3 = (x3, y3) = end point,
    

    and consists of all points

    x(t) = (1-t)^3 * x0 + 3*t*(1-t)^2 * x1 + 3*t^2*(1-t) * x2 + t^3 * x3
    y(t) = (1-t)^3 * y0 + 3*t*(1-t)^2 * y1 + 3*t^2*(1-t) * y2 + t^3 * y3
    

    where t runs from 0 to 1.

    Therefore, to calculate X for a given value of Y, you first have to calculate a parameter value T such that 0 <= T <= 1 and

     Y = (1-T)^3 * y0 + 3*T*(1-T)^2 * y1 + 3*T^2*(1-T) * y2 + T^3 * y3      (1)
    

    and then compute the X coordinate with

     X = (1-T)^3 * x0 + 3*T*(1-T)^2 * x1 + 3*T^2*(1-T) * x2 + T^3 * x3      (2)
    

    So you have to solve the cubic equation (1) for T and substitute the value into (2).

    Cubic equations can be solved explicitly (see e.g. http://en.wikipedia.org/wiki/Cubic_function) or iteratively (for example using the http://en.wikipedia.org/wiki/Bisection_method).

    In general, a cubic equation can have up to three different solutions. In your concrete case we have

    P0 = (0, 280), P1 = (adjust, 280), P3 = (adjust, 0), P4 = (280, 0)
    

    so that the equation (1) becomes

    Y = (1-T)^3 * 280 + 3*T*(1-T)^2 * 280
    

    which simplifies to

    Y/280 = 1 - 3*T^2 + 2*T^3    (3)
    

    The right hand side of (3) is a strictly decreasing function of T in the interval [0, 1], so it is not difficult to see that (3) has exactly one solution if 0 <= Y <= 280. Substituting this solution into (2) gives the desired X value.

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