贝塞尔定时动画路径

gat*_*pia 2 javascript animation bezier canvas

我正在尝试定义一个点的路径.每个点都有x,y和时间.然后,我想查询此路径并获取该时间点的当前位置.让我分享一些伪代码.

point {x, y, time}


function initialisePath(point[] path) {
    ... // Create Bezier Path
}

function getXYAtTime(time) {
    return ... // Get interpolated point along the bezier path at the specified time
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用canvas标签在javascript中实现它.但是,任何语言的样本都可以.有没有人知道任何创建这种可查询路径的开源库(用任何语言)?

注意:我一直试图从DynApi项目中了解这个示例和代码,但是从这个样本转移到时间感知路径对于我糟糕的动画技能来说是一个延伸.

谢谢

圭多

Jas*_*rff 6

贝塞尔曲线不仅具有开始和结束点,而且控制点指导的曲线的形状.在您链接的DynApi演示中,端点标记为黄色,控制点标记为红色.

您的路径将是一系列Bézier曲线,端到端连接.

因此,让我们采用您的伪代码,但我们会将所有没有 .time属性的点视为控制点.

function Path(points) {
    this.points = points;

    // Sanity check.
    if (points[0].time == undefined || points[points.length - 1].time == undefined)
        throw new Error("all control points must be between two real points");
}

Path.prototype.getXYAtTime = function (t) {
    var points = this.points;

    // First, see if t is out of range.
    if (t < points[0].time)
        return points[0];
    if (t > points[points.length - 1].time)
        return points[points.length - 1];

    // OK, t is in range. Find out which Bezier curve we're in.
    //
    // Specifically we want 'start' and 'stop' to be the indexes of two points
    // that each have a .time property, bracketing the current time t; and
    // all the points in between 'start' and 'stop' should be control points.
    //
    var start = 0, stop = points.length - 1;
    for (var i = 1; i < points.length; i++) {
        var p = points[i];
        if (t < p.time) {
            stop = i;
            break;
        }
        if (p.time != undefined)
            start = i;
    }
    var n = stop - start;

    // Adjust t to be in the range [0, 1).
    var t0 = points[start].time, t1 = points[stop].time;
    t = (t - t0) / (t1 - t0);
    var tInv = 1 - t;

    // Now calculate the current position in the curve.
    // Wikipedia says this is:
    //   sum for i = 0 to n of (n C i * (1 - t) ^ (n - i) * t ^ i * P[i])
    // 
    var x = 0, y = 0;
    for (var i = 0; i <= n; i++) {
        var p = points[start + i];
        var c = nCr(n, i) * Math.pow(1 - t, n - i) * Math.pow(t, i);
        x += c * p.x;
        y += c * p.y;
    }
    return {x: x, y: y};
}

// The number of k-combinations of a set of size n.
function nCr(n, k) {
    var z = 1;
    for (var i = 1; i <= k; i++)
        z *= (n + 1 - i) / i;
    return z;
}
Run Code Online (Sandbox Code Playgroud)

这就是数学部分完成的.你可以把它连接到画布并让它去.

以下是您调用该方法的方法:

// Here's a Path consisting of a single Bezier curve.
var path = new Path([
    {x: 200, y: 150, time: 0},  // start point
    {x: 200, y: 500},           // 2 control points
    {x: 250, y: 100},
    {x: 500, y: 300, time: 50}  // end point
  ]);

var p = path.getXYAtTime(2.718);
alert(p.x + ", " + p.y);
Run Code Online (Sandbox Code Playgroud)