Dessiner une étoile en Python
Résolu/Fermé
Miaourt
-
Modifié le 4 mars 2021 à 13:52
mamiemando Messages postés 33616 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 3 avril 2025 - 8 mars 2021 à 12:20
mamiemando Messages postés 33616 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 3 avril 2025 - 8 mars 2021 à 12:20
3 réponses
mamiemando
Messages postés
33616
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
3 avril 2025
7 837
4 mars 2021 à 15:38
4 mars 2021 à 15:38
Bonjour,
Là il faut faire un peu de trigonométrie.
Ton étoile peut être vue comme un hexagone (6 triangle équilatéraux) pour lequel on a greffé 6 triangles équilatéraux (de même taille) sur chacun de ses côté. Si on note L la longueur d'un côté d'un triangle équilatéral, ton étoile à donc ton étoile est de hauteur 4L et de largeur 3L.
Les angles d'un triangle équilatéral mesurent 60°. Cela signifie que tu ne peux pas monter/descendre de 1 caractère quand tu vas 1 caractère vers la droite le long d'un bord diagonal. Cela reviendrait à un angle de 45°. Tant que L est petit ce n'est pas très grave, car de toute façon comme on passe de R^2 (le plan) à N^2 (un espace discret en deux dimension dans lequel on écrit les caractère), les arrondis font que "ça marche". Mais bien évidemment, quand L devient plus grand, les arrondis ne suffisent plus à contrebalancer cet écart.
Or si on regarde ton code, le raisonnement est construit sur des triangles avec des angles de 60°. En effet, soit tel triangle équilatéral ABC et supposons que le bord AB soit de longueur L. Alors le projeté de C sur AB est de longueur L.cos(60°) = L / 2. C'est ce que tu as appelé
Il faudrait donc clarifier si ton étoile est construite selon des triangles isocèles (dont les angles associés au bord horizontal font 45°) ou si tu cherches vraiment à faire une étoile basée sur des triangles équilatéraux (auquel cas l'algorithme doit être repensé).
Personnellement, je commencerais par écrire une fonction qui permet de tracer un segment dont selon quatre entier (x1, y1, x2, y2)
On obtient ainsi une liste de couples (x, y) qui définissent les cases de N^2 à écrire avec le caractère utilisé pour faire le trait (* dans ton cas). De cette liste on peut tirer ymax et xmax. Pour faire l'étoile on défini donc 12 segments avec les coordonnées appropriées qui forment bords de l'étoile. Il ne reste plus qu'à itérer pour chaque valeur de x allant de 0 à xmax et pour chaque valeur de y à ymax et regardé si le point (x, y) est dans la liste de couple pour décider quel caractère utiliser.
Optimisation: On peut même avoir un xmax qui dépend du y courant (en cherchant, pour la valeur de y courante, la plus grande valeur de x présente dans les couples), ce qui peut valoir le coup d'utiliser un dictionnaire qui à chaque valeur de y associe les valeurs de x (triées) associées à ces couples.
Bonne chance
Là il faut faire un peu de trigonométrie.
Ton étoile peut être vue comme un hexagone (6 triangle équilatéraux) pour lequel on a greffé 6 triangles équilatéraux (de même taille) sur chacun de ses côté. Si on note L la longueur d'un côté d'un triangle équilatéral, ton étoile à donc ton étoile est de hauteur 4L et de largeur 3L.
Les angles d'un triangle équilatéral mesurent 60°. Cela signifie que tu ne peux pas monter/descendre de 1 caractère quand tu vas 1 caractère vers la droite le long d'un bord diagonal. Cela reviendrait à un angle de 45°. Tant que L est petit ce n'est pas très grave, car de toute façon comme on passe de R^2 (le plan) à N^2 (un espace discret en deux dimension dans lequel on écrit les caractère), les arrondis font que "ça marche". Mais bien évidemment, quand L devient plus grand, les arrondis ne suffisent plus à contrebalancer cet écart.
Or si on regarde ton code, le raisonnement est construit sur des triangles avec des angles de 60°. En effet, soit tel triangle équilatéral ABC et supposons que le bord AB soit de longueur L. Alors le projeté de C sur AB est de longueur L.cos(60°) = L / 2. C'est ce que tu as appelé
mid_row. Le raisonnement est le même si AB est vertical (c'est ce que tu as appelé
mid_col.
Il faudrait donc clarifier si ton étoile est construite selon des triangles isocèles (dont les angles associés au bord horizontal font 45°) ou si tu cherches vraiment à faire une étoile basée sur des triangles équilatéraux (auquel cas l'algorithme doit être repensé).
Personnellement, je commencerais par écrire une fonction qui permet de tracer un segment dont selon quatre entier (x1, y1, x2, y2)
- Si le segment est plutôt horizontal (|x1-x2| <= |y1-y2|), pour chaque valeur de x allant de x1 à x2, on calcule le y correspondant.
- Sinon, le segment est plutôt vertical (|x1-x2| > |y1-y2|), pour chaque valeur de y allant de y1 à y2, on calcule le x correspondant.
On obtient ainsi une liste de couples (x, y) qui définissent les cases de N^2 à écrire avec le caractère utilisé pour faire le trait (* dans ton cas). De cette liste on peut tirer ymax et xmax. Pour faire l'étoile on défini donc 12 segments avec les coordonnées appropriées qui forment bords de l'étoile. Il ne reste plus qu'à itérer pour chaque valeur de x allant de 0 à xmax et pour chaque valeur de y à ymax et regardé si le point (x, y) est dans la liste de couple pour décider quel caractère utiliser.
Optimisation: On peut même avoir un xmax qui dépend du y courant (en cherchant, pour la valeur de y courante, la plus grande valeur de x présente dans les couples), ce qui peut valoir le coup d'utiliser un dictionnaire qui à chaque valeur de y associe les valeurs de x (triées) associées à ces couples.
Bonne chance
mamiemando
Messages postés
33616
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
3 avril 2025
7 837
Modifié le 8 mars 2021 à 13:25
Modifié le 8 mars 2021 à 13:25
Il faut être inscrit sur le site pour pouvoir clôturer, je m'en occupe.
Ensuite l'explication du triangle équilatéral vs isocèle. Imagine ce triangle
Sa base fait 5 caractères de large et ses côtés diagonaux 5.racine(2)/2 car les angles au niveau de la base font 45° (plus généralement pour une base de taille n, si l'angle forme 45°, un bord diagonal mesurera n.racine(2)/2 ~ 1.414.n. Bref, il n'est donc pas équilatéral. C'est un peu inévitable car tu dessines ton triangle dans une grille donc tu n'auras jamais un triangle purement équilatéral. Si on cherchait le "meilleur arrondi" ça coïncide à peu près pour de petite valeurs de n. Par contre cet arrondi devient faux pour de grande valeur de n. Tu peux regarder dans un logiciel comme paint, tu verras que par moment tu te déplaces de deux pixels verticalement quand tu avances d'un pixel horizontalement le long d'un bord diagonal...
Bonne continuation :)
Ensuite l'explication du triangle équilatéral vs isocèle. Imagine ce triangle
@
@@@
@@@@@
Sa base fait 5 caractères de large et ses côtés diagonaux 5.racine(2)/2 car les angles au niveau de la base font 45° (plus généralement pour une base de taille n, si l'angle forme 45°, un bord diagonal mesurera n.racine(2)/2 ~ 1.414.n. Bref, il n'est donc pas équilatéral. C'est un peu inévitable car tu dessines ton triangle dans une grille donc tu n'auras jamais un triangle purement équilatéral. Si on cherchait le "meilleur arrondi" ça coïncide à peu près pour de petite valeurs de n. Par contre cet arrondi devient faux pour de grande valeur de n. Tu peux regarder dans un logiciel comme paint, tu verras que par moment tu te déplaces de deux pixels verticalement quand tu avances d'un pixel horizontalement le long d'un bord diagonal...
Bonne continuation :)
Bonjour,
Merci pour cette réponse.
J'ai effectivement revu le code de 0 et je l'ai décomposé en 6 parties, en gérant l'espace entre les étoiles pour les diagonales.
Je n'ai par contre pas compris la seconde partie de ton explication, surement parce que je ne suis pas au niveau en maths, mais l'essentiel est que ça marche !
Merci encore !
PS: Je ne vois pas où clôturer le sujet ?
Merci pour cette réponse.
J'ai effectivement revu le code de 0 et je l'ai décomposé en 6 parties, en gérant l'espace entre les étoiles pour les diagonales.
Je n'ai par contre pas compris la seconde partie de ton explication, surement parce que je ne suis pas au niveau en maths, mais l'essentiel est que ça marche !
Merci encore !
PS: Je ne vois pas où clôturer le sujet ?