2009-11-20 75 views
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 
} 

我想在JavaScript中使用画布标记实现这一点。然而,任何语言的样本都可以。有谁知道任何创建这种查询路径的开源库(以任何语言)?

注意:我一直在试着从DynApi project这个样本和代码中找到我的头,但是从这个样本移动到一个时间感知的路径对于我可怜的动画技能来说是一个延伸。

由于

回答

6

Bézier curve不仅具有起点和终点还控制点该引导曲线的形状。在您链接的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); 
+0

哇,非常感谢描述性的答案。我现在感到愚蠢的是,我添加的路径(点集合)没有包含任何控制点。 我真的应该提到,我只是想平滑这条道路。因此,我想要生成一个流畅的动画,通过这些点,而不是一个锯齿状的加入点动画。 我一直在玩弄'猜测'这些控制点的概念,给出了前一点和下一点(2点路径段),但是这并没有让我感到太过分。 Tnx再次为一个很大程度上描述的响应。 – gatapia 2009-11-20 20:22:40

+0

哦!我不明白你想要什么,我现在感到很愚蠢。这听起来像是一个合理的方法,但可能很难猜测这些控制点。你需要弄清楚约束是什么。例如,在给定点和控制点之前和之后需要排队。否则,你会在这个点上突然改变方向。 – 2009-11-21 14:26:35

+0

我曾经在这种情况下做过的事情是(a)根据周围的点来选择我想要的每个点的速度; (b)给出两点,以及每个点所需的速度,计算适合账单的唯一三次函数。在你的情况下,你有一个额外的限制,但是:固定的时间量。 – 2009-11-21 14:33:25

0

贝塞尔曲线的控制点,其实你在每个端点到端点添加所需的速度矢量得到什么。例如,如果您想要速度vx0,vy0在点x0,y0处,然后进入点x1,y1以速度vx1,vy1到达那里,然后使用以下四点来定义您的贝塞尔曲线:(x0,y0); (x0+vx0,y0+vy0); (x1-vx1,y1-vy1); (x1,y1)。 (中间两个是你的控制点。)