Ce que vous voulez est Cardinal spline car les splines cardinaux passent par les points réels que vous dessinez. Remarque: pour obtenir un résultat professionnel, vous devez également implémenter une moyenne mobile pour les seuils courts tout en utilisant des splines cardinales pour les seuils plus élevés et en utilisant les valeurs du genou pour casser les lignes au coin aigu afin de ne pas lisser toute la ligne. Je ne vais pas m'adresser à la moyenne mobile ou au genou ici (ni effiler) car ceux-ci sont en dehors de la portée, mais montrent une façon d'utiliser la spline cardinale.
Une note de côté aussi - l'effet que l'application semble modifier la ligne est in évitable que le lissage se produit post. Il existe des algorithmes qui lissent pendant que vous dessinez mais ils ne conservent pas les valeurs de genou et les lignes semblent "osciller" pendant que vous dessinez. C'est une question de préférence, je suppose.
Voici un violon à démontrer ce qui suit:
ONLINE DEMO
D'abord quelques conditions préalables (j'utilise ma bibliothèque easyCanvas pour configurer l'environnement dans la démo car il me permet de gagner beaucoup de travail, mais ce n'est pas une exigence pour que cette solution fonctionne):
- Je vous recommande de dessiner le nouveau trait sur un canevas séparé qui est au-dessus de celui principal.
- Lorsque le mouvement est terminé (souris vers le haut), passez-le dans le lisseur et stockez-le dans la pile de traits.
- Dessinez ensuite la ligne lissée à la ligne principale.
Lorsque vous avez des points dans un ordre de tableau par X/Y (c.-à-[x1, y1, x2, y2, ... xn, yn]
), vous pouvez utiliser cette fonction pour lisser:
La tension valeur(ts
, par défaut 0,5) est ce que lisse la courbe. Plus le nombre est élevé, plus la courbe devient ronde. Vous pouvez sortir de l'intervalle normal [0, 1] pour faire des boucles. Le segment (nos
, ou nombre de segments) est la résolution entre chaque point. Dans la plupart des cas, vous n'aurez probablement pas besoin de plus de 9-10. Mais sur les ordinateurs plus lents ou où vous dessinez rapidement des valeurs plus élevées est nécessaire.
La fonction (optimisé):
/// cardinal spline by Ken Fyrstenberg, CC-attribute
function smoothCurve(pts, ts, nos) {
// use input value if provided, or use a default value
ts = (typeof ts === 'undefined') ? 0.5 : ts;
nos = (typeof nos === 'undefined') ? 16 : nos;
var _pts = [], res = [], // clone array
x, y, // our x,y coords
t1x, t2x, t1y, t2y, // tension vectors
c1, c2, c3, c4, // cardinal points
st, st2, st3, st23, st32, // steps
t, i, r = 0,
len = pts.length,
pt1, pt2, pt3, pt4;
_pts.push(pts[0]); //copy 1. point and insert at beginning
_pts.push(pts[1]);
_pts = _pts.concat(pts);
_pts.push(pts[len - 2]); //copy last point and append
_pts.push(pts[len - 1]);
for (i = 2; i < len; i+=2) {
pt1 = _pts[i];
pt2 = _pts[i+1];
pt3 = _pts[i+2];
pt4 = _pts[i+3];
t1x = (pt3 - _pts[i-2]) * ts;
t2x = (_pts[i+4] - pt1) * ts;
t1y = (pt4 - _pts[i-1]) * ts;
t2y = (_pts[i+5] - pt2) * ts;
for (t = 0; t <= nos; t++) {
// pre-calc steps
st = t/nos;
st2 = st * st;
st3 = st2 * st;
st23 = st3 * 2;
st32 = st2 * 3;
// calc cardinals
c1 = st23 - st32 + 1;
c2 = st32 - st23;
c3 = st3 - 2 * st2 + st;
c4 = st3 - st2;
res.push(c1 * pt1 + c2 * pt3 + c3 * t1x + c4 * t2x);
res.push(c1 * pt2 + c2 * pt4 + c3 * t1y + c4 * t2y);
} //for t
} //for i
return res;
}
Ensuite, appelez simplement de l'événement mouseup
après des points a été stockés:
stroke = smoothCurve(stroke, 0.5, 16);
strokes.push(stroke);
commentaires courts sur les valeurs du genou:
A la valeur du genou dans ce contexte est l'angle entre les points (en tant que partie d'un segment de ligne) dans la ligne est supérieur à un certain seuil (typiquement entre 45 - 60 deg rees). Quand un genou se produit, les lignes sont divisées en une nouvelle ligne de sorte que seule la ligne composée de points avec un angle inférieur au seuil entre eux est utilisée (vous voyez les petites boucles dans la démo en raison de ne pas utiliser de genoux).
commentaire court sur la moyenne mobile:
Moving average est généralement utilisé à des fins statistiques, mais il est très utile pour dessiner des applications. Lorsque vous avez un groupe de plusieurs points avec une courte distance entre eux, les splines ne fonctionnent pas très bien. Donc, ici, vous pouvez utiliser MA pour lisser les points.
Il existe également des algorithmes de réduction de points pouvant être utilisés, tels que le Ramer/Douglas/Peucker, mais ils sont davantage utilisés à des fins de stockage pour réduire la quantité de données.
Pas tout à fait clair à ce que vous essayez. Tracez-vous une courbe avec la souris et attendez-vous à ce que la toile trace la courbe exacte que la souris a suivie? – jing3142
mmm, +1: très intéressant. Cependant, si vous envisagez de faire une application de dessin professionnel, à mon humble avis, vous feriez mieux d'opter pour une application native. Le seul avantage d'une application de navigateur est la compatibilité croisée, mais cela a un prix énorme. – Saturnix