Bienvenue visiteur !
|
Désactiver la neige
Statistiques
Liste des membres
Contact
Mentions légales
356 connectés actuellement
30765767 visiteurs depuis l'ouverture
2505 visiteurs aujourd'hui
Partenaires
Tous nos partenaires
Devenir partenaire
|
◂
| Cosinus et Sinus, avec (+ - * /)
Approximer les fonctions trigonométriques cosinus et sinus en utilisant les opérations de base, idéal pour faire tourner des pictures autour de points. | Ecrit par Anton_ le 23/06/2013 |
▸
|
❤ 2Tassle AnthonyP PARTIE I : Présentation du problème
Prenons un exemple simple qui nous suivra tout au long de ce tutoriel : j'ai nommé, l'horloge.
L'horloge, comme chacun le sait, possède des compteurs qui tournent autour du cadran, mais voilà, qui voudrait mémoriser 60 positions différentes X et Y, avec autant de conditions chiantes et répétitives ? personne ! (à part les imbéciles)
oui, mais certains iront plutôt mettre des pictures d'aiguilles dans diverses positions, ce qui est plus adapté si on veut des aiguilles dans une horloge (c'est compréhensible)
Ici, on va se contenter d'une petite boule qui tourne autour d'un centre
on va définir l'angle de rotation de l'horloge en fonction d'une variable "secondes" qui incrémente quand le temps passe.
Et le Cos et le Sin seront définis par le modulo 360 de cet angle (on est en degrés, pas en radians...)
Les variables cos/sin finales seront comprises entre -1000 et 1000 au lieu de -1 et 1 (c'est mieux pour des valeurs entières)
1 seconde correspond à 1/60e de tour, soit 6°.
Sur le cercle trigonométrique, la position 0 de l'horloge correspond à +90° et elle tourne dans le sens -
angle_horloge = 90 - 6 * "secondes"
soit X = modulo 360 de cet angle.
Maintenant, observons les courbes des fonctions Cos et Sin, ça promet d'être passionnant
[mode Matheux ON]
PARTIE II : Des fonctions complexes...
la première fois qu'on voit les courbes de Cos et Sin, on se dit : "tiens, mais ça ressemble à des paraboles qu'on colle les uns après les autres"
C'est évidemment une fausse illusion, mais c'est également une bonne piste pour faire des approximations.
1) Un trinôme ?
on va décomposer les courbes en morceaux de paraboles entre 0 et 360 :
COS : [ (0-90) , maximum en 0 ] , [ (90-270) , minimum en 180 ] , [ (270-360) , maximum en 360 ]
SIN : [ (0-180) , maximum en 90 ] , [ (180-360) , minimum en 270 ]
Faites roulez les conditions !
exemple : on fait l'approximation de sin entre 0 et 180 :
Y = (A) *(X-90)² + 1000
avec A = -10/81
Notez plusieurs choses :
La parabole a son maximum en 90, si c'est un minimum, il faut multiplier le tout par -1
On soustrait aussi X de la position du sommet. (super important)
le coefficient A est le même pour tous les bouts de trinôme, il faut juste penser à son orientation !
(visualisez vos courbes sur excel si vous n'êtes pas sûrs)
Enfin bon, ça, c'est la méthode facile, légère en calcul, et rapide, mais elle a une grande marge d'erreur...
on obtient une erreur maximale de 6%, que qui fait un pixel à coté tous les 16.4 pixels de distance.
"oouuh remboursez, c'est pas ce qu'il y avait d'écrit sur la description !"
Tout juste, voici un polynôme plus précis.
2) Polynôme de Degré 4
Si on soustrait notre "mauvaise" fonction avec la vraie courbe de Cosinus ou Sinus, on voit une sorte de polynôme de Degré 4.
On modifie alors la fonction principale :
Y = A*(X-sommet) ^ 4 + B*(X-sommet) ^ 2 + 1000
j'ai tâtonné pendant des heures pour trouver les meilleurs coefficients, les voici !
A = (1/540)²
B = (7/18)²
N'oubliez pas l'orientation du polynôme !! (Si le sommet est en bas, multipliez tout par -1)
Et voilà, notre fonction est-elle prête à l'emploi ?
NON !
Le terme en X^4 est à manipuler avec précaution !
comme vous le voyez, (X-sommet) est toujours compris entre -90 et 90
Seulement voilà, 90^4 = 65 610 000
nombre trop grand pour être intégré à une variable RMesque, dont la limite est de 9 999 999
Il faut donc appliquer DANS L'ORDRE :
Terme_en_X4 = (X-sommet)^3
/36
*(X-sommet)
/8100
et voilà, plus de problèmes.
On observe la marge d'erreur par rapport aux vraies courbes ... 0.2% !! Soit 1 pixel de raté tous les 500 pixels !
Sur une résolution de 640x480, qui pourra faire la différence ?
3) résultats
Nous avons donc en entrée la variable "angle"
réservez 5 ou 6 variables pour le calcul intermédiaire
Et 2 variables sont en Sortie, COS et SIN.
4) Le code svp !
Voici le code ligne par ligne (simplifié pour une meilleure lecture)
INPUT : Angle, n'importe quel nombre entier, sera tranformé en un nombre entre 0 et 360 selon le modulo 360 du nombre initial.
L'angle suit le cercle trigonométrique : donc 0 c'est à l'Est, 90 au Nord, 180 à l'Ouest, et 270 au sud.
OUTPUT : outputCos, et outputSin, entre -1000 et +1000. représentent au mieux le cos et le sin de l'angle d'input donné en entrée.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
Angle %= 360
If : Angle < 0
Angle += 360
End If
// set sommet/signe of parabole for COS
If : Angle < 90
sommet = 0
signe = 1
Else
If : Angle < 270
sommet = 180
signe = -1
Else
sommet = 360
signe = 1
End If
End If
// GET Y of Parabole
// get x
x = Angle
x -= sommet
// get x^4 with the positive coeff (warning, 90^4 overflows)
x4 = x
x4 *= x
x4 *= x
x4 /= 36
x4 *= x
x4 /= 8100
// get x² with the negative coeff
x2 = x
x2 *= x
x2 *= 49
x2 /= 324
// add up everything
x = x4
x -= x2
x += 1000
// apply sign
x *= signe
// tadam !
outputCos = x
// set sommet/signe of parabole for SIN
If : Angle < 180
sommet = 90
signe = 1
Else
sommet = 270
signe = -1
End If
// GET Y of Parabole (same stuff)
// get x
x = Angle
x -= sommet
// get x^4 with the positive coeff (warning, 90^4 overflows)
x4 = x
x4 *= x
x4 *= x
x4 /= 36
x4 *= x
x4 /= 8100
// get x² with the negative coeff
x2 = x
x2 *= x
x2 *= 49
x2 /= 324
// add up everything
x = x4
x -= x2
x += 1000
// apply sign
x *= signe
// tadam !
outputSin = x |
PARTIE III : Applications
Nous avons donc COS et SIN , deux variables comprises entre -1000 et 1000
"C'est bien beau tout ça, mais comment on s'en sert ?"
C'est simple ... Il faut encore des variables !
Reprenons notre horloge :
Elle tourne dans un coin de l'écran. On définit son centre de rotation en un point dont on choisit les coordonnées : Cx et Cy
Il faut aussi la distance par rapport au centre : le rayon, R.
la position de la petite boule qui tourne autour est donc
X_final = Cx + (COS * R)/1000
Y_final = Cy + (SIN * R)/1000
Pourquoi je divise par 1000 ? C'est dans le but de définir COS et SIN entre -1 et 1
(appliquez la multiplication avant la division par 1000 !)
Et voilà, amusez vous bien !
BONUS : vous pouvez faire varier les entrées !!
Cx , Cy , R , angle , vitesse d'avance de l'angle
Mis à jour le 30 septembre 2020.
Autres articles similaires :
- Tassle, "Cosinus et Sinus, avec */+", Oniromancie, le 30 septembre 2020, https://www.rpg-maker.fr/index.php?page=tutos&id=499
|
verehn -
posté le 23/06/2013 à 19:07:04 (9058 messages postés)
- | Vhehrhehn | J'ai mis quelques passages en couleur, Anton. Si tu n'aimes pas je les enlèverai
|
Eldrao ~ PakuPaku ~ Winged Light ~ Ruin ~ Ma galerie ~ LTDAD ~ Don de graphismes plateforme 2D |
Anton_ -
posté le 23/06/2013 à 19:23:06 (1535 messages postés)
| | c'est impeccable, on fait super bien la différence avec ce qui est calcul et ce qui n'en est pas
edit importante :
Dans RM 2003 (et les autres, peut être), le modulo d'un nombre négatif donne un résultat négatif. (pourquoi ? je ne sais pas)
Alors qu'ici dans la fonction utilisée après, il nous faut un nombre entre 0 et 360.
Il faut rajouter ces deux lignes suivantes après X = Angle modulo 360
Si X < 0
{
X ajouter 360
}
|
Raetribution | Megamike || tutos : 1 2 || Une bonne dose de maths pour la route |
Joke -
posté le 23/06/2013 à 19:34:10 (5090 messages postés)
| Bilouteux fou | Tutoriel très intéressant, ça veut dire qu'on peut faire de faux cosinus et faux sinus sous RM2003, et donc faire parcourir des coordonnées sur des cercles ou ellipses... Cool : )
|
biloumaster.fr, mon joli site ouèb tout bô tout frai ! |
Grade -
posté le 23/06/2013 à 20:36:26 (905 messages postés)
| | Sympa !
Je m'en souvienderai définitivement la prochaine fois que je fais un projet RPG Maker.
Ça me donne envie d'écrire des tutos sur l'algorithmique ça.
|
MMORPG 2D Amateur | http://www.shinsekaionline.com |
Maelstorm -
posté le 23/06/2013 à 22:31:29 (3984 messages postés)
| Une chance sur un million | Citation: la première fois qu'on voit les courbes de Cos et Sin, on se dit : "tiens, mais ça ressemble à des paraboles qu'on colle les uns après les autres" |
euh ... ouais ?
peut etre un peut abrupt pour les néophytes ton tuto ...
|
Ixsuixwzone -
posté le 24/06/2013 à 10:26:45 (2453 messages postés)
| | Hey ! Mais c'est carrément utile ça 0.o
Merci Anton, c'est bien pensé. Ça risque de me servir plus tard.
|
| Âmes Bannies - Demo 0.2 | |
Anton_ -
posté le 27/09/2013 à 11:51:39 (1535 messages postés)
| | Je signale un détail sur l'angle et son modulo (oui oui, trois mois après !! )
Dans RM 2003 (et les autres, peut être), le modulo d'un nombre négatif donne un résultat négatif. (pourquoi ? je ne sais pas)
Alors qu'ici dans la fonction utilisée après, il nous faut un nombre entre 0 et 360.
Il faut rajouter ces deux lignes suivantes après X = Angle modulo 360
Si X < 0
{
X ajouter 360
}
|
Raetribution | Megamike || tutos : 1 2 || Une bonne dose de maths pour la route |
Anton_ -
posté le 14/07/2017 à 02:40:53 (1535 messages postés)
| | Je suis revenu ici pour réutiliser dans un projet le cos et le sin. Et quelle fut ma surprise de voir que ce tuto est TRES MAL EXPLIQUE SCROGNEUGNEU !!
Donc pour me faire pardonner, voici le code ligne par ligne (simplifié pour une meilleure lecture)
INPUT : Angle, n'importe quel nombre entier, sera tranformé en un nombre entre 0 et 360 selon le modulo 360 du nombre initial.
L'angle suit le cercle trigonométrique : donc 0 c'est à l'Est, 90 au Nord, 180 à l'Ouest, et 270 au sud.
OUTPUT : outputCos, et outputSin, entre -1000 et +1000. représentent au mieux le cos et le sin de l'angle d'input donné en entrée.
Bon copinage.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
Angle %= 360
If : Angle < 0
Angle += 360
End If
// set sommet/signe of parabole for COS
If : Angle < 90
sommet = 0
signe = 1
Else
If : Angle < 270
sommet = 180
signe = -1
Else
sommet = 360
signe = 1
End If
End If
// GET Y of Parabole
// get x
x = Angle
x -= sommet
// get x^4 with the positive coeff (warning, 90^4 overflows)
x4 = x
x4 *= x
x4 *= x
x4 /= 36
x4 *= x
x4 /= 8100
// get x² with the negative coeff
x2 = x
x2 *= x
x2 *= 49
x2 /= 324
// add up everything
x = x4
x -= x2
x += 1000
// apply sign
x *= signe
// tadam !
outputCos = x
// set sommet/signe of parabole for SIN
If : Angle < 180
sommet = 90
signe = 1
Else
sommet = 270
signe = -1
End If
// GET Y of Parabole (same stuff)
// get x
x = Angle
x -= sommet
// get x^4 with the positive coeff (warning, 90^4 overflows)
x4 = x
x4 *= x
x4 *= x
x4 /= 36
x4 *= x
x4 /= 8100
// get x² with the negative coeff
x2 = x
x2 *= x
x2 *= 49
x2 /= 324
// add up everything
x = x4
x -= x2
x += 1000
// apply sign
x *= signe
// tadam !
outputSin = x
|
|
Raetribution | Megamike || tutos : 1 2 || Une bonne dose de maths pour la route |
Tassle -
posté le 01/12/2021 à 17:18:07 (5274 messages postés)
❤ 2Nemau Roi of the Suisse | Disciple de Pythagolf | J'ai expérimenté un peu et j'ai trouvé une meilleure méthode:
Spoiler (cliquez pour afficher)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
a = Angle
IF : a < 0
a *= -1
END IF
a %= 360
a -= 180
IF : a < 0
a *= -1
END IF
sign = -1
IF : a > 90
sign = 1
a *= -1
a += 180
END IF
a *= a
b = 32151
b += a
b //= 4
outputCos = 8097
outputCos -= a
outputCos *= 994
outputCos //= b
outputCos *= sign
a = 90
a -= Angle
IF : a < 0
a *= -1
END IF
a %= 360
a -= 180
IF : a < 0
a *= -1
END IF
sign = -1
IF : a > 90
sign = 1
a *= -1
a += 180
END IF
a *= a
b = 32151
b += a
b //= 4
outputSin = 8097
outputSin -= a
outputSin *= 994
outputSin //= b
outputSin *= sign
|
La vitesse est exactement la même que pour la méthode d'Anton (si on supprime ses commentaires, parce que oui chaque commentaire coûte quasi autant de temps que tout autre instruction) mais l'erreur max est de 1.35 (au lieu de 1.91 avec la méthode d'Anton).
Si a1 et a2 sont des variables d'id consécutives, de même que b1 et b2, sign1 et sign2, outputCos et outputSin, on peut améliorer très légerement la vitesse d'execution en utilisant le fait que RM2k3 permet de modifier plusieurs variables en même temps (ce qui est aussi rapide que de modifier une seule variable):
Spoiler (cliquez pour afficher)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
a1 = Angle
a2 = 90
a2 -= Angle
IF : a1 < 0
a1 *= -1
END IF
IF : a2 < 0
a2 *= -1
END IF
a1, a2 %= 360
a1, a2 -= 180
IF : a1 < 0
a1 *= -1
END IF
IF : a2 < 0
a2 *= -1
END IF
sign1, sign2 = -1
IF : a1 > 90
sign1 = 1
a1 *= -1
a1 += 180
END IF
IF : a2 > 90
sign2 = 1
a2 *= -1
a2 += 180
END IF
a1 *= a1
a2 *= a2
b1, b2 = 32151
b1 += a1
b2 += a2
b1, b2 //= 4
outputCos, outputSin = 8097
outputCos -= a1
outputSin -= a2
outputCos, outputSin *= 994
outputCos //= b1
outputSin //= b2
outputCos *= sign1
outputSin *= sign2
|
(ce code est environ 11% plus rapide que le précédent, mais on utilise plus de variables différentes)
Edit: Pour ceux que ça intéresse, j'utilise une approximation par une fonction rationnelle plutôt que polynomiale. En gros cos(x) ~ 994*(8097-x^2)/((32151+x^2)/4) pour x entre -90 et 90 (avec des divisions entières). On pourrait enlever le /4 et remplacer 994 par 4*994 (= 3976) mais après les valeurs des variables pourraient dépasser le max de RM2k3.
|
~~ |
|
|
|