Rotation d'une image autour d'un point (Basic)
Posté le 30/06/2016 12:32
Bonjour, bonsoir, mes salutations.
Je voulais proposer, pour ceux que ça intéresserait, Un programme vous permettant d'obtenir vos images/objets dont les coordonnées des points sont contenues dans une liste après rotation autour d'un point.
Pour cela, nous allons utiliser les complexes et les radians.
Admettons que votre dessin soit contenu dans les listes 2 (X) et 3 (Y).
On va d'abord définir une liste (list 1) qui contient les affixes des points correspondant aux listes 2 et 3.
List 2+[b]i[/b]List 3→List 1
Dim list 1→Tθmax "On va utiliser la fonction Graph(X,Y)"
Il s'agit maintenant de faire tourner chaque point autour de l'origine grâce aux fonctions Arg et Abs (Argument et Module d'un complexe).
Pour ceux qui ne connaissent pas bien les complexes, rappelons qu'un complexe peut s'écrire (sous forme algébrique) sous la forme z = a + b
i avec a et b des réels (et
i tel que
i²=-1)
La partie réelle d'un complexe définit l'abscisse du point et la partie imaginaire définit son ordonnée :
z = a + b [b]i[/b]
Rep z = a "Partie réelle de Z"
Imp z = b "Partie Imaginaire de Z"
L'argument d'un complexe traduit l'angle entre le vecteur unitaire des abscisses (u, par exemple) et la demi-droite [OZ) avec O l'origine du repère et Z le point d'affixe (=de coordonnées) z = a + b i. Le module de z traduit quant à lui la longueur OZ.
Bref, (re)passez la terminale S si vous ne comprenez rien.
C'est là que ça devient intéressant. Vous vous connaissez du cercle trigonométrique, cette merveille ?
Ce qui m'intéresse, c'est que dans ce cercle (de rayon 1), X = cos(t) et Y = sin(t) avec t l'angle sur l'image.
Avec les complexes, ça nous donne a = cos (arg z) et b = sin (arg z)
avec arg z l'argument de z... Mais pas tout à fait. Le cercle trigonométrique est de rayon 1. On multiplie ces valeurs par le module (distance OZ) pour obtenir ce que l'on veut :
donc on a :
a = (module de z : )|z|*cos (arg z)
et b = |z| * sin(arg z)
Seulement, on souhaite faire
tourner ce point d'affixe z. On va donc augmenter (ou diminuer) l'argument de z, c'est-à-dire l'angle entre l'axe des abscisses (le vecteur directeur u) et la demi-droite [OZ). Prenons une rotation de π radians, et z'=a' +
i b' le nouvel affixe du point Z après rotation.
Alors :
a' = |z|*cos(π + arg z)
et b' = |z|*sin(π + arg z)
C'est bien beau tout ça, mais on va où ? Akwasasert ?
Ne paniquez pas. Nous y sommes. Ce code consistera donc à modifier tous les affixes de tous les points en les faisant tourner de θ radians. Mais il manque un détail : Cela ne fonctionne que pour les rotations autour de l'origine du repère. Nous allons donc définir au préalable un point de coordonnées (I , J) qui fera office de centre de rotation (en général le centre de l'image). En faisant l'opération List 1 - ( I +
i J ), le centre de l'image coïncide avec l'origine. Voici donc comment tout cela se met en place :
Cliquez sur moi pour me dérouler
Cliquez sur moi pour m'enrouler
?→I
?→J
?→θ
List 2 - I + [b]i[/b](List 3 -J→List 1
Dim List 1→Tθmax
For 1→A To Tθmax
List 1[A→B
Abs (B)((cos (θ+Arg B) + [b]i[/b]sin (θ+Arg B→List 1[A
Next
List 1+I+[b]i[/b] J→List 1
Voici une idée de code. Bien sûr, les techniques peuvent varier et sont plus ou moins efficaces selon les situations.
Je vous renvoie sur ce
Tutoriel de neuronix qui donne également une très bonne piste dans cette optique.
Mais comment s'en servir ?
J'ai conçu ce code pour mon futur programme de jeu en basic casio. Si vous avez un personnage portant une arme et donnant un coup avec, par exemple, il est évident que vous n'allez pas vous amuser à réécrire les trois (ou cinq, voire dix... soyons fous.) listes différentes pour un même objet qui ne fait que tourner. Pour une image avec peu de points, vous pouvez également créer des animations, pourquoi pas. Les possibilités sont multiples et ce code me permet d'approfondir l'utilisation des graphismes en basic.
Je l'ai donné un peu brut, c'est fait exprès. Vous pouvez vous le réapproprier, vous en inspirer ou l'employer tel quel.
It's up to you, guys!
Nota bene : Vous pouvez rencontrer des soucis dès lors que votre point de coordonnées I, J coïncide avec l'un des points de votre dessin. La machine vous indiquera une erreur lors du calcul de l'argument d'un point d'affixe 0. Une astuce consisterait à employer une valeur de I ou de J très légèrement différente (de 0.1, par exemple) pour que le code fonctionne et que votre dessin semble bien tourner !
Fichier joint
Citer : Posté le 30/06/2016 12:55 | #
Si ta liste contient des complexes, la rotation d'angle x autour de 0 s'exprime par
La multiplication est automatiquement mappée sur la liste, donc si le centre est en 0 :
Sinon, on la ramène en 0 par translation. Supposons que le centre soit (A, B) :
Et voilà !
Citer : Posté le 30/06/2016 13:38 | #
Effectivement, j'ai employé la forme trigonométrique dans mon code. La forme exponentielle semble bien plus efficace (je rage de ne pas y avoir pensé... Grrrmmmbblrgrgb...) et surtout plus courte.
J'ai l'impression d'avoir fait ça pour rien, ça m'énerve.
Citer : Posté le 30/06/2016 13:41 | #
Non, ce n'était pas pour rien. La dernière fois que j'ai fait un calcul de rotation en C j'ai utilisé la même méthode et j'ai employé atan2(). Le résultat était désastreux, mais maintenant que j'ai fait le cours sur les espaces vectoriels réels et les isométries, je me ferai plus avoir.
Ça fait de l'expérience et au moins le plaisir d'avoir réussi à le faire, quelle que soit la forme. C'est pas rien déjà !
Citer : Posté le 01/07/2016 13:42 | #
En effet, la forme exponentielle simplifie grandement ce genre de tranformation.
Sinon une matrice de rotation fait aussi bien l'affaire, je ne sais pas lequel est le plus rapide
Citer : Posté le 01/07/2016 13:44 | #
En l'occurrence si la liste est en complexes il vaut mieux utiliser la forme exponentielle. Le produit matriciel n'est utilisable réellement en Basic, que si l'on dispose de matrices pour les coordonnées.
Citer : Posté le 01/07/2016 13:48 | #
C'est vrai, mais ici l'espace de départ est R, il passe des réels aux complexes pour revenir aux réels.
Non pas forcement besoin d'utiliser les matrices Mat, il faut utiliser directement la projection sur x et sur y on obtient 2 équations
Citer : Posté le 01/07/2016 14:15 | #
Bien sûr, mais au final c'est strictement pareil puisque la matrice de rotation est le complexe associé (du point de vue d'un isomorphisme classique entre Z et M_2(R)). Faire le produit revient au même, mais l'idée c'est toujours d'en faire faire le plus implicitement à l'interpréteur. Ici on évite de séparer les coordonnées, tandis que l'approche vectorielle nous oblige à récupérer indépendamment les parties, ce qui sera fatalement plus lent.
Citer : Posté le 01/07/2016 16:58 | #
ce qui sera fatalement plus lent
La matrice de rotation ((cos -sin)(sin cos)) va bien plus vite. Faire la rotation de 6 points va 25% plus vite et faire la rotation avec 16 points va 35% plus vite.
Citer : Posté le 01/07/2016 16:59 | #
Comment as-tu implémenté ça ?
Citer : Posté le 01/07/2016 17:04 | #
D'un coté
{...->List 2
List 1+iList 2->List 3
e^(9i)*List 3->List 3
Rep List 3->List 4
Imp List 3->List 5
et de l'autre
{...->List 2
cos 9*List 1-sin 9*List 2->List 3
sin 9*List 1+cos 9*List 2->List 4
Ajouté le 01/07/2016 à 17:05 :
Je fais tourner ce code X fois et je mesure le temps
Citer : Posté le 01/07/2016 17:09 | #
Je partais du principe que l'on disposait d'une seule liste avec des valeurs complexes et que l'on générait en sortie une autre liste à valeurs complexes, comme le font les programmes réels. Du coup, je soulignais que l'on devait passer par les parties réelles et imaginaires ([l'approche vectorielle nous oblige à récupérer indépendamment les parties]).
Que donnent les performances dans ce cas-là ? Car de ces deux codes, le premier me semble « de vue » plus efficace :
+i(sin 9*(ReP List1)+cos 9*(ImP List1))→List 2
Citer : Posté le 01/07/2016 17:25 | #
comme le font les programmes réel
Enfin il faut être maso pour calculer ça, là c'est clairment plus lent. 75% plus lent pour 16 points
Citer : Posté le 01/07/2016 17:26 | #
Est-ce que quelqu'un pourrait m'expliquer le principe de vos "matrices de rotation" ?! J'en entends sans arrêt parler quand je passe dans le coin !
Citer : Posté le 01/07/2016 17:27 | #
Bien sûr, Tu as vu les matrices en cours ?
Citer : Posté le 01/07/2016 17:28 | #
Oui, j'étais en spé maths cette années !
Citer : Posté le 01/07/2016 17:31 | #
C'est à dire ? Je n'ai j'amais vu l'utilisation des complexes dans ce genre d'application.
Wait, je suis le seul à faire du Super DrawStat en complexes ? --'
Enfin il faut être maso pour calculer ça, là c'est clairment plus lent. 75% plus lent pour 16 points
Ben ouais, c'est pour ça que je disais que ce serait « fatalement plus lent ».
Citer : Posté le 01/07/2016 17:33 | #
Et bien, pour faire simple tu as un point de coordonnées (x,y) On peut créer une matrice 2x1 avec ces coordonnées (verticale donc)
Si on fait le produit de cette matrice par une autre matrice particulière dite "de rotation" alors le résultat (qui est une matrice 2x1 toujours) correspond aux coordonnées de ton point après rotation.
regarde la tête de la matrice sur wiki
Ajouté le 01/07/2016 à 17:35 :
Wait, je suis le seul à faire du Super DrawStat en complexes ? --'
Citer : Posté le 01/07/2016 17:38 | #
Comment ça se présente ? C'est une matrice 1x2 fois une matrice 1x2 ou un matrice carrée d'ordre 2 fois une matrice 1x2 ?
Citer : Posté le 01/07/2016 17:41 | #
Comme ça lien
Avec x et y les coordonnées de ton point et x' et y' après la rotation. Refait le calcul matrciel à la main, il te donne deux équations (x' = cos(t) x - sin(t) y et y' = sin(t) x + cos(t) y)
Citer : Posté le 01/07/2016 17:41 | #
En gros t'as ça :
Avec Y la matrices des nouvelles coordonnées (2×1 si en 2D, 3×1 si 3D)
M la matrice de rotation (2×2 ou 3×3)
X la matrice des anciennes coordonnées (2×1 ou 3×1)