A Bézier curve a non seulement un point de début et de fin, mais aussi points de contrôle qui guident la forme de la courbe. Dans la démonstration DynApi que vous avez liée, les points de fin sont marqués en jaune et les points de contrôle sont marqués en rouge.
Votre chemin sera une suite de courbes de Bézier, connectées bout à bout.
Prenons donc votre pseudo-code, mais nous traiterons tous les points qui ont une propriété .time comme points de contrôle et non.
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;
}
Alors c'est la partie mathématique qui est faite. C'est à vous de l'accrocher à la toile et de la faire disparaître.
Voilà comment vous appelez cette méthode:
// 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);
Wow, merci pour la réponse très descriptive. Je me sens maintenant stupide d'ajouter que le chemin (collection de points) que je possède ne contient aucun point de contrôle. Je devrais vraiment avoir mentionné que je veux juste adoucir ce chemin. Donc, au lieu d'un jagged rejoindre l'animation des points, je veux produire une animation lisse qui traverse ces points. J'ai joué avec le concept de «deviner» ces points de contrôle étant donné le point précédent et le point suivant (d'un segment de chemin à 2 points), mais cela ne m'amène pas trop loin. Tnx à nouveau pour une réponse grandement décrite. – gatapia
Oh! Je me sens bête maintenant de ne pas comprendre ce que tu voulais. Cela semble être une approche raisonnable, mais il pourrait être difficile de deviner ces points de contrôle. Vous devez comprendre quelles sont les contraintes. Par exemple, un point donné et les points de contrôle juste avant et juste après doivent s'aligner. Sinon, vous aurez un changement soudain de direction au point. –
Quelque chose que j'ai fait une fois dans cette situation est de (a) choisir la vélocité que je veux à chaque point, en fonction des points environnants; (b) en donnant deux points, et la vitesse désirée à chaque point, calculer la fonction cubique unique qui correspond à la facture. Dans votre cas, vous avez une contrainte supplémentaire, cependant: une durée fixe. –