Tracer une chaînette
Pour dessiner les fils entre les ballons de Balloon Platform Defense, j’ai dû trouver comment tracer une corde suspendue entre deux points, la forme plus généralement appelée chaînette. Tous les exemples que j’ai trouvés en ligne imposaient des contraintes au problème, comme des points à la même hauteur, ou supposaient connues certaines informations, comme l’angle de départ de la corde, qui n’étaient pas disponibles ici : on ne connaît que les points de départ et d’arrivée de la corde, et sa longueur. Wikipédia donne beaucoup d’informations sur les équations de la chaînette, et c’est de là que je suis parti. L’équation de la chaînette est :y=a\cosh \left (\frac{x}{a} \right )=\frac{a\left ( e^{\frac{x}{a}}+e^{-\frac{x}{a}} \right )}{2}
Elle suppose que le point le plus bas de la corde est là où elle coupe l’axe des y. En pratique, des constantes s’ajoutent aux variables x et y, toutes deux encore à déterminer, puisqu’on ne sait pas où sera le point le plus bas – l’une des raisons pour lesquelles ce problème est plus compliqué que tous les exemples des manuels. (Avez-vous remarqué que les problèmes de maths de la vie réelle sont toujours bien plus compliqués que les exemples des manuels ? J’attends encore le problème réel comportant une intégrale qui se calcule analytiquement.) Mais cela attendra, car il faut d’abord déterminer la valeur de a, la constante de l’équation qui décide essentiellement de l’étroitesse ou de la largeur de la courbe. Attention : si les points sont au même endroit sur l’axe des x, a est infini, donc ce cas doit être traité avant d’en arriver là – de même que le cas où ils sont très proches et où a devient incalculablement grand. (« Incalculablement grand » désigne ici tout nombre qui, passé en argument à la fonction exponentielle, lui ferait renvoyer NaN ou l’infini pour la précision en virgule flottante que vous utilisez.) Et bien sûr, évitez que votre code arrive jusqu’ici si les deux points sont plus éloignés que la longueur de la corde : le résultat serait mauvais.
Calculer le facteur d’échelle
Pour calculer a, Wikipédia donne l’équation suivante (fondée sur une propriété de la chaînette : alors que cosh donne la position de la courbe, sinh en donne la longueur) :\sqrt{s^{2}-v^{2}}=2a\sinh \left ( \frac{h}{2a} \right )
où s est la longueur de la corde, et h et v les distances horizontale et verticale (en valeur absolue) entre les points de départ et d’arrivée. Ce sont toutes des valeurs connues ; il ne reste qu’une inconnue, mais elle doit être déterminée numériquement. J’ai d’abord essayé sans trop me soucier de la valeur de départ, et la convergence était aléatoire. Heureusement, il s’avère facile de trouver une bonne valeur de départ. La série de Taylor du sinus hyperbolique est :
\sinh x=x+\frac{x^{3}}{3!}+\frac{x^{5}}{5!}+\cdots
Si l’on pose u = \frac{1}{4a^{2}} et c = \sqrt{s^{2}-v^{2}}, l’équation à résoudre devient :
c=\frac{1}{\sqrt{u}}\sinh \left ( h\sqrt{u} \right )
ce qui, en prenant les trois premiers termes de la série de Taylor de sinh et en simplifiant, donne :
c=\frac{1}{\sqrt{u}}\left (h\sqrt{u}+\frac{\left ( h\sqrt{u} \right )^{3}}{3!} +\frac{\left ( h\sqrt{u} \right )^{5}}{5!} \right )
c=\frac{1}{\sqrt{u}}\left (h\sqrt{u}+\frac{h^{3}u\sqrt{u}}{3!} +\frac{h^{5}u^{2}\sqrt{u}}{5!} \right )
c=h+\frac{h^{3}u}{3!} +\frac{h^{5}u^{2}}{5!}
soit, réarrangé :
\frac{h^{5}}{120}u^{2}+\frac{h^{3}}{6}u+\left ( h-c \right )=0
C’est une simple équation du second degré en u, et en remplaçant ses coefficients dans la formule bien connue du lycée x = \frac{-b\pm \sqrt{b^{2}-4ac}}{2a}
on obtient une bonne valeur de départ pour u, et donc pour a.
u = \frac{-\frac{1}{6}h^{3}+ \sqrt{\frac{1}{36}h^{6}-\frac{1}{30}h^{5}\left ( h-c \right )}}{\frac{1}{60}h^{5}}, où a=\frac{1}{2\sqrt{u}}
Cette valeur de départ est assez proche pour trouver une solution par la méthode de Newton. En écrivant le problème sous la forme f\left ( a \right )=0
on a f\left ( a \right )=2a \sinh \left ( \frac{h}{2a} \right )-c
et {f}'\left ( a \right )=2 \sinh \left ( \frac{h}{2a} \right )-\frac{h}{a}\cosh \left ( \frac{h}{2a} \right )
Puisque a_{n+1}=a_{n}-\frac{f\left ( a_{n} \right )}{{f}'\left ( a_{n} \right )}
,
a_{n+1}=a_{n}-\frac{2a \sinh \left ( \frac{h}{2a} \right )-c}{2 \sinh \left ( \frac{h}{2a} \right )-\frac{h}{a}\cosh \left ( \frac{h}{2a} \right )}=a_{n}-\frac{a \sinh \left ( \frac{h}{2a} \right )-0.5c}{ \sinh \left ( \frac{h}{2a} \right )-\frac{h}{2a}\cosh \left ( \frac{h}{2a} \right )}
Pour l’instant, je considère que la suite a convergé quand elle est à moins de 0,001 de sa valeur précédente, ce qui arrive en général en 2 à 4 itérations, mais il en faut parfois plus de dix quand les abscisses sont plus proches. Des méthodes de Householder d’ordre supérieur seraient sans doute possibles sans beaucoup plus de calculs, puisque l’essentiel du travail consiste à évaluer les fonctions hyperboliques et que les dérivées suivantes de la fonction ne devraient en donner que d’autres multiples. Maintenant que l’échelle est connue, on peut calculer la translation.
Calculer la translation
L’équation standardy=a\cosh \left (\frac{x}{a} \right )
suppose que la chaînette est symétrique par rapport à l’axe des y et que son point le plus bas est en (0,a), alors que celle que nous dessinons peut se trouver n’importe où à l’écran. Il faut donc trouver une translation (p,q) qui la place au bon endroit, ce qui donne l’équation :
y-q=a\cosh \left (\frac{x-p}{a} \right )
(Pour rappel, a est connu à ce stade, x et y sont des variables, il ne reste donc que p et q d’inconnus.) Ma première idée a été de remplacer dans l’équation x et y par leurs valeurs connues, c’est-à-dire les deux extrémités de la corde. Cela fonctionne en théorie, mais malgré tous mes efforts pour simplifier les équations obtenues, les calculs intermédiaires produisaient souvent des valeurs que les nombres à virgule flottante en double précision ne supportaient pas. J’ai fini par trouver une autre approche, qui s’est d’ailleurs révélée plus efficace.
Rappelons qu’en remplaçant cosh par sinh dans l’équation de la chaînette, on obtient la longueur de la courbe. En y remplaçant les abscisses des extrémités gauche et droite, avec la longueur souhaitée de la corde à dessiner (s), on obtient l’équation :
a\sinh \left (\frac{x_{right}-p}{a} \right )-a\sinh \left (\frac{x_{left}-p}{a} \right )=s
L’une des identités des fonctions hyperboliques dit que :
\sinh x - \sinh y=2\cosh\left ( \frac{x+y}{2} \right ) \sinh \left ( \frac{x-y}{2} \right )
Donc :
\sinh \left (\frac{x_{right}-p}{a} \right )-\sinh \left (\frac{x_{left}-p}{a} \right )=2\cosh\left ( \frac{x_{right}+x_{left}-2p}{2a} \right ) \sinh \left ( \frac{x_{right}-x_{left}}{2a} \right )
Dans l’argument de cosh, les abscisses droite et gauche sont additionnées puis divisées par 2, ce qui donne l’abscisse du milieu ; autant la remplacer directement. La soustraction dans l’argument de sinh donne la valeur que nous avons appelée h plus haut, donc ce sinh se calcule lui aussi comme une quantité connue, et l’équation de départ se réarrange en :
\cosh\left ( \frac{x_{middle}-p}{a} \right ) = \frac{s}{2a\sinh \left ( \frac{h}{2a}\right )}
On peut maintenant trouver p en prenant l’argument cosinus hyperbolique (arcosh), mais avec prudence. Comme cosh est une fonction paire, on obtient toujours une réponse positive, mais il existe aussi une réponse négative, ce qui donne deux valeurs possibles pour p.
p =x_{middle}\pm a\cosh^{-1}\left ( \frac{s}{2a\sinh \left ( \frac{h}{2a}\right )} \right )
Pour savoir laquelle choisir, on regarde les ordonnées des extrémités. Une expérience avec un bout de ficelle vous montrera qu’à longueur de corde et abscisses égales, le bas de la courbe (s’il se trouve entre les deux abscisses) est à droite du milieu – et correspond donc à l’arcosh positif – si l’ordonnée de droite est plus basse que celle de gauche, et inversement.
Un autre problème peut survenir : quand les ordonnées sont égales, le bas de la courbe doit être exactement au milieu, l’argument de cosh doit donc être nul, et la valeur dont on prend l’arcosh doit valoir un. À cause des imprécisions en virgule flottante, elle vaut souvent un peu moins de un, ce qui provoque une erreur au moment de prendre l’arcosh. Il est sage de vérifier si les ordonnées sont égales (ou presque) avant ce calcul, ce qui économise des calculs et évite cette erreur, et dans ce cas de supposer simplement que p est exactement à mi-chemin entre les extrémités.
Maintenant que a et p sont connus, on calcule q en remplaçant x et y par les coordonnées de l’une des extrémités dans l’équation
y-q=a\cosh \left (\frac{x-p}{a} \right )
et en la réarrangeant ainsi :
q=y-a\cosh \left (\frac{x-p}{a} \right )
Calculez q avec cette formule, et vous avez l’équation finale qui permet de tracer la courbe.
y=a\cosh \left (\frac{x-p}{a} \right )+q
Tracer la courbe est désormais simple. J’ai calculé les fonctions hyperboliques aussi précisément que possible pendant la plupart des étapes du calcul des paramètres, car il était difficile de savoir comment une imprécision se propagerait. Mais dans cette dernière étape, qui représente la majorité des calculs, vous savez quelle est la grandeur de l’argument utilisé et quelle imprécision vous pouvez tolérer, et vous pouvez prévoir si une série de Taylor jusqu’à une certaine puissance sera assez précise – et, d’après mon expérience, elle en vaut la peine la plupart du temps.