кривая Безье имеет не только начальную и конечную точки, но и управление точки, определяющие форму кривой. В демонстрационной версии 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);
person
Jason Orendorff
schedule
20.11.2009