comment dessiner la courbe lisse par N points à l'aide de javascript HTML5 canvas?
Pour une application de dessin, je suis d'enregistrer le mouvement de la souris en coordonnées dans un tableau puis les dessiner avec lineTo. La ligne n'est pas lisse. Comment puis-je produire une courbe unique entre tous les réunis points?
J'ai cherché sur google mais j'ai seulement trouvé 3 fonctions de dessin de lignes: 2 points d'exemple, il suffit d'utiliser lineTo. Pour 3 points d'échantillonnage quadraticCurveTo, pour 4 points d'échantillonnage, bezierCurveTo.
(J'ai essayé de dessiner un bezierCurveTo pour tous les 4 points de la matrice, mais cela conduit à des kinks toutes les 4 points d'exemple, au lieu d'en continu d'une courbe lisse.)
Comment puis-je écrire une fonction pour dessiner une courbe lisse avec 5 points d'échantillonnage et au-delà?
- Qu'entendez-vous par "lisse"? Infiniment dérivable? Deux fois dérivable? Splines cubiques ("courbes de Bézier") ont beaucoup de bonnes propriétés et sont deux fois dérivable, et assez facile à calculer.
- SB, par "lisse", je veux dire visuellement ne peut pas détecter tous les coins/cuspides etc.
- êtes-vous rendu les lignes en temps réel, ou de retarder le rendu jusqu'à ce que après avoir recueilli un tas de points?
- Je suis la collecte de points dans un tableau. Vous avez besoin d'au moins 4 points à utiliser cet algorithme. Après cela, vous pouvez effectuer le rendu en temps réel sur une toile de compensation de l'écran à chaque appel de mouseMove
- N'oubliez pas d'accepter une réponse. C'est bien si c'est votre propre.
Vous devez vous connecter pour publier un commentaire.
Le problème à l'adhésion ultérieure de l'échantillon de points avec disjoints "curveTo" type de fonctions, est celui où les courbes se rencontrent est pas lisse. C'est parce que les deux courbes de partager un point final, mais sont influencés par complètement disjoints points de contrôle. La seule solution est de "courbe" le milieu entre les 2 autres points d'échantillonnage. Rejoindre les courbes à l'aide de ces nouveaux points interpolés donne une transition en douceur à la fin des points (ce qui est un point de départ pour une itération devient un point de contrôle pour la prochaine itération.) En d'autres termes, les deux disjoints courbes ont beaucoup plus en commun maintenant.
Cette solution a été extraite du livre "de la Fondation d'ActionScript 3.0 Animation: Faire bouger les choses". p.95 - les techniques de rendu: création de plusieurs courbes.
Remarque: cette solution ne fait pas de tirage au travers de chacun des points, qui était le titre de ma question (ou plutôt, il se rapproche de la courbe passant par les points d'échantillonnage, mais ne va jamais au travers de l'échantillon de points), mais pour ma part (une application de dessin), c'est assez bon pour moi et visuellement, vous ne pouvez pas faire la différence. Il y est une solution de passer par tous les points d'échantillonnage, mais il est beaucoup plus compliqué (voir http://www.cartogrammar.com/blog/actionscript-curves-update/)
Voici le code de dessin pour la méthode d'approximation:
Un peu tard, mais pour l'enregistrement.
Vous pouvez obtenir des lignes lisses en utilisant le cardinal splines (aka canonique spline) pour dessiner des courbes harmonieuses qui passe par les points.
J'ai fait cette fonction pour la toile, il est divisé en trois pour fonction d'accroître la polyvalence. La principale fonction wrapper ressemble à ceci:
Pour dessiner une courbe avez un tableau avec x, y des points dans l'ordre:
x1,y1, x2,y2, ...xn,yn
.L'utiliser comme ceci:
La fonction ci-dessus appelle deux sous-fonctions, une pour calculer le lissage des points. Elle retourne un tableau avec les nouveaux points - c'est le noyau de la fonction qui calcule le lissage des points:
Et à réellement dessiner les points d'une courbe lissée (ou tout autre segmenté lignes aussi longtemps que vous avez une x,y array):
JS:
CSS:
HTML:
Il en résulte ceci:
Vous pouvez facilement étendre la toile de sorte que vous pouvez l'appeler comme ceci à la place:
Ajouter les éléments suivants à l'javascript:
Vous pouvez trouver une version optimisée de ce sur NPM (
npm i cardinal-spline-js
) ou sur GitLab.ptsa
devrait êtrepts
, ou bien il serait jeter erros.La première réponse ne passera pas par tous les points. Ce graphique exactement à passer à travers tous les points et sera un préfet de la courbe avec les points comme points [{x:,y:}] n de ces points.
Comme Daniel Howard souligne, Rob Spencer décrit ce que vous voulez à http://scaledinnovation.com/analytics/splines/aboutSplines.html.
Voici une démo interactive: http://jsbin.com/ApitIxo/2/
Ici, c'est comme un morceau de code dans le cas jsbin est en baisse.
HTML:
Donner KineticJS un essayez - vous pouvez définir une Spline avec un tableau de points. Voici un exemple:
Ancienne url: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/
Voir archive url: https://web.archive.org/web/20141204030628/http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-spline-tutorial/
J'ai décider d'ajouter, plutôt que de poster ma solution pour un autre post.
Ci-dessous sont la solution que je construis, peut-être pas parfait, mais jusqu'à présent, la sortie sont bon.
Important: il va passer en revue tous les points!
Si vous avez une idée, à faire mieux, s'il vous plaît partager à moi. Merci.
Voici la comparaison avant-après:
Enregistrez ce code HTML de le tester.
J'ai trouvé que c'était bien
À ajouter à K3N du cardinal méthode des splines et peut-être l'adresse de T. J. Crowder préoccupations concernant les courbes 'plongeant' trompeuse lieux, j'ai inséré le code suivant dans la
getCurvePoints()
fonction, juste avantres.push(x);
Cela crée effectivement un (invisible) de la boîte englobante entre chaque paire de points successifs et s'assure de la courbe reste à l'intérieur de cette boîte englobante - ie. si un point de la courbe est au-dessus/ci-dessous/à gauche/à droite des deux points, il modifie sa position à l'intérieur de la boîte. Ici, le milieu est utilisé, mais cela pourrait être améliorée, peut-être en utilisant l'interpolation linéaire.
Incroyablement en retard, mais inspiré par Homan est brillamment simple réponse, je me permets de poster un plus générale de la solution (en général dans le sens que Homan la solution se bloque sur des tableaux de points avec moins de 3 sommets):