Alex Rivera | Logout

y coordinate for a given x cubic bezier

Asked 2011-09-08T12:29:06.927
12

This question is very similar to: Quadratic bezier curve: Y coordinate for a given X?. But this one is cubic...

I'm using the getBezier function to calculate the Y coordinates of a bezier curve. The bezier curve starts always at (0,0) and ends always at (1,1).

I know the X value, so I tried to insert it as percent (I'm a moron). But that didn't work, obviously. Could you provide a solution? It's necessary it's an idiot proof function. Like:

function yFromX (c2x,c2y,c3x,c3y) { //c1 = (0,0) and c4 = (1,1), domainc2 and domainc3 = [0,1]
    //your magic
    return y;
}
Edit
Report

1 Answer

9

I used the algorithm from this page and wrote it down in JavaScript. It works for all the cases I have tested so far. (And doesn't use a while loop.)

Call the solveCubicBezier function. Pass in the x values of all the control points and the x value you want to get the y coordinate from. For example:

var results = solveCubicBezier(p0.x, p1.x, p2.x, p3.x, myX);

results is an array containing the 't' values originally passed into the Bezier function. The array can contain 0 to 3 elements, because not all x values have a corresponding y value, and some even have multiple.

function solveQuadraticEquation(a, b, c) {

    var discriminant = b * b - 4 * a * c;

    if (discriminant < 0) {
        return [];

    } else {
        return [
            (-b + Math.sqrt(discriminant)) / (2 * a),
            (-b - Math.sqrt(discriminant)) / (2 * a)
        ];
    }

}

function solveCubicEquation(a, b, c, d) {

    if (!a) return solveQuadraticEquation(b, c, d);

    b /= a;
    c /= a;
    d /= a;

    var p = (3 * c - b * b) / 3;
    var q = (2 * b * b * b - 9 * b * c + 27 * d) / 27;

    if (p === 0) {
        return [ Math.pow(-q, 1 / 3) ];

    } else if (q === 0) {
        return [Math.sqrt(-p), -Math.sqrt(-p)];

    } else {

        var discriminant = Math.pow(q / 2, 2) + Math.pow(p / 3, 3);

        if (discriminant === 0) {
            return [Math.pow(q / 2, 1 / 3) - b / 3];

        } else if (discriminant > 0) {
            return [Math.pow(-(q / 2) + Math.sqrt(discriminant), 1 / 3) - Math.pow((q / 2) + Math.sqrt(discriminant), 1 / 3) - b / 3];

        } else {

            var r = Math.sqrt( Math.pow(-(p/3), 3) );
            var phi = Math.acos(-(q / (2 * Math.sqrt(Math.pow(-(p / 3), 3)))));

            var s = 2 * Math.pow(r, 1/3);

            return [
answered 2013-07-09T10:54:34.977

Your Answer