2

我正在尝试定义点路径。每个点都有一个 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
}

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

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

谢谢

圭多

4

2 回答 2

6

贝塞尔曲线不仅有起点和终点,而且还有控制曲线形状的控制点。在您链接的 DynApi 演示中,端点标记为黄色,控制点标记为红色。

您的路径将是一系列贝塞尔曲线,首尾相连。

因此,让我们使用您的伪代码,但我们会将所有没有.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;
}

这样数学部分就完成了。将它连接到画布并让它运行取决于您。

以下是您如何调用该方法:

// 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);
于 2009-11-20T05:40:57.960 回答
0

The control points of a bezier curve are in fact exactly what you get by adding the desired velocity vector at each end point to the end point. For example, if you want velocity vx0,vy0 at point x0,y0 and then to proceed to point x1,y1 arriving there with velocity vx1,vy1, then use the following four points to define your bezier curve: (x0,y0); (x0+vx0,y0+vy0); (x1-vx1,y1-vy1); (x1,y1). (the middle two are your control points.)

于 2012-05-05T22:32:41.630 回答