Mathématice, intégration des Tice dans l'enseignement des mathématiques  
Sommaire > N°26 - Septembre 2011 > La panoplie du petit footballeur

La panoplie du petit footballeur
Les patrons dynamique de l’icosaèdre tronqué
Moteur de recherche
Mis en ligne le 21 août 2011, par Pierre-Marc Mazat

Sur le forum de CarMetal, à l’époque de la coupe du monde de football 2010, Jérôme Caré [1] propose des CaRScripts permettant de construire interactivement des patrons pour le cube et le dodécaèdre.
Yves Martin lance alors le défi d’écrire un tel script, mais adapté au ballon de foot, plus communément appelé icosaèdre tronqué (ou le contraire, c’est selon...).

Le défi a été relevé et voici la narration de son implémentation.

Commençons par un exemple auquel on peut accéder par :

L’algorithme que l’on propose de tester est le premier de la liste : "Manual construction".

Il s’agit, comme son nom l’indique, de construire manuellement le patron de ce polyèdre. Il suffit pour cela de lancer le script en cliquant dessus et de suivre ensuite les instructions dans la barre d’état, à savoir "Cliquer sur un segment bleu ou une arête verte", ce qui a pour effet de construire soit un pentagone, soit un hexagone. Ces arêtes, qui appartiennent au polyèdre, et ces segments, qui appartiennent au patron en cours de construction, indiquent les faces à partir desquelles il est possible de construire une nouvelle face. Voici un exemple de ce que l’on peut obtenir :

PNG - 60.6 ko
Un patron "peau d’orange"

Cet article propose de décortiquer l’algorithme de construction. Il se décompose en trois parties : la première est purement géométrique et on s’intéressera à la manière de construire les pentagones et hexagones. La deuxième, un peu plus technique, tente de détailler l’algorithme qui permet de construire successivement et dynamiquement les polygones du patron. Enfin, la troisième, propose un petit prolongement et quelques adaptations de l’algorithme principal.

Géométrie de l’hexagone et du pentagone

1. Présentation de la situation

L’icosaèdre tronqué est un solide d’Archimède comportant 32 faces, dont 12 pentagones et 20 hexagones. Difficulté supplémentaire par rapport au cube et au dodécaèdre donc, puisqu’il va falloir gérer deux types de faces. Les angles dièdres sont de 138° 11’ 22" entre deux hexagones et de 142° 37’ 21" entre un hexagone et un pentagone.

Dans la figure de base d’Yves Martin, la face posée sur le sol est un pentagone. Déjà construite, nous ne nous occuperons pas d’elle ; commençons donc par les cinq hexagones adjacents à celle-ci, mais avant d’implémenter un quelconque algorithme, occupons-nous d’abord de construire manuellement un seul de ces hexagones. En voici un tout fait, que l’on peut voir dans l’onglet n°3 du classeur en ligne.

Cette face est en rotation autour de l’axe $(p_0p_1)$. Il s’agit donc d’implémenter une telle rotation.

Comme on remarque immédiatement que les 6 sommets de l’hexagone sont coplanaires et qu’on sait qu’un plan est défini par trois points, il suffit de choisir trois « bons » points permettant de définir tous les autres. Deux s’imposent immédiatement : les extrémités de l’arête sur laquelle on va construire notre nouvelle face, c’est-à-dire $p_0$ et $p_1$. Il en faut encore un et pourquoi ne pas choisir le centre du polygone, (mais c’est juste histoire de ne pas faire de jaloux parmi les autres sommets ;) )

Une fois tous les autres points définis à l’aide de ces trois-là, il suffira, pour permettre une rotation de la face autour de $(p_0p_1)$, de seulement implémenter une rotation du centre autour de cet axe.

C’est maintenant que les ennuis commencent (ou les calculs, c’est chacun qui voit).

2. Construction d’un hexagone

Partons d’un hexagone déjà construit et analysons quelques données (onglet 2 du classeur en ligne) :

Dans le triangle équilatéral $P_0P_1P_6$, notons $P_m$ le pied de la hauteur issue de $P_6$. Un peu de trigonométrie nous dit que :

$P_mP_6 = \frac{P_1P_6}{\sin 60} = \frac{P_0P_1}{\sin 60}$

Cette distance est ce que l’on appelle l’apothème, et nous la noterons h, comme hexagone.


Ainsi, nous pouvons construire le centre à l’aide de la relation suivante, où o est un point de la perpendiculaire à $(p_0p_1)$ passant par $p_m$, donc autant choisir le centre du polygone précédent :

$\overrightarrow{p_mp_6}=h\frac{\overrightarrow{op_m}}{op_m}$

Ensuite, rien de bien compliqué :

  • $\overrightarrow{p_6p_2}=\overrightarrow{p_0p_1}$
  • $p_5$ est le symétrique de $p_2$ par rapport à $p_6$
  • $p_3$ est le symétrique de $p_0$ par rapport à $p_6$
  • $p_4$ est le symétrique de $p_1$ par rapport à $p_6$

Il reste tout de même un problème : quelle est la valeur de la distance $p_0p_1$ ? Pour cela, il suffit de revenir au pentagone de base, puisque les côtés des pentagones et hexagones ont la même longueur, et utiliser encore un peu de trigonométrie. Dans la figure suivante, on connait l’angle $\widehat{p_mp_0o}$ (propriétés du pentagone) ainsi que l’apothème $p=op_m$ (coefficient d’alignement entre o, X et $p_m$). On a alors :

$\tan 54=\frac{p}{p_mp_0} \Rightarrow p_0p_1=2\frac{p}{\tan 54}$

Passons maintenant en 3D.

Comme dit dans l’onglet n°1, il suffit d’implémenter une rotation du centre $p_6$ de l’hexagone autour de l’axe $(p_0p_1)$. Ce point se déplace dans le plan $(op_mz)$ et décrit un arc de cercle de centre $p_m$ et de rayon h (apothème de l’hexagone).
Considérons alors le repère orthonormé suivant :

$\left( p_m ;\frac{\overrightarrow{op_m}}{op_m} ; \overrightarrow{oz} \right)$

On a donc très classiquement :

$\overrightarrow{p_mp_6}=h\cos\alpha\frac{\overrightarrow{op_m}}{op_m}+h\sin\alpha\overrightarrow{oz}$

Concernant l’angle $\alpha$, l’angle dièdre entre un pentagone et un hexagone étant de 142° 37’ 21", $\alpha$ est compris entre 0 et 180° - 142°37’21" = 37,3775°.

Il reste encore un point à construire car nous en aurons besoin pour construire la face suivante, il s’agit du point $p_7$ tel que le vecteur $\overrightarrow{p_6p_7}$ soit orthonormal à la face que nous construisons. En effet, pour implémenter la rotation de notre hexagone, nous avons eu recours au point $z$, tel que $\overrightarrow{oz}$ soit orthonormal au pentagone de base. Il s’agit donc de se placer dans les mêmes conditions.

Ce vecteur $\overrightarrow{p_6p_7}$ étant orthonormal à la face, il l’est donc en particulier au vecteur $\overrightarrow{p_mp_6}$, ainsi : $\overrightarrow{p_6p_7}\cdot\overrightarrow{p_mp_6}=0$.
Toujours dans le repère donné ci-dessus, notons $r(x ; y)$ le point tel que $\overrightarrow{p_6p_7} = \overrightarrow{p_mr}$. Alors $\overrightarrow{p_mr}\cdot\overrightarrow{p_mp_6}=0$, c’est à dire :

$xh\cos\alpha+yh\sin\alpha=0 \Leftrightarrow x\cos\alpha+y\sin\alpha=0$

Comme on souhaite de plus que le vecteur $\overrightarrow{p_mr}$ soit unitaire, les solutions sont :

$\left\{ \begin{array}{l} x=\pm\sin\alpha \\ y=\mp\cos\alpha \end{array} \right.$

Des deux orientations, il faut choisir celle pour laquelle le vecteur $\overrightarrow{p_mr}$ est dirigé vers le centre du polyèdre lorsque $0\leq\alpha\leq37,3775°$. Il faut donc que le point $r$ soit dans le même demi-plan que le point $z$ lorsque $\alpha=0$, c’est-à-dire $y>0$ lorsque $\alpha=0$. On garde donc la seconde solution et on a finalement :

$\overrightarrow{p_6p_7}=-\sin\alpha\frac{\overrightarrow{op_m}}{op_m}+\cos\alpha\overrightarrow{oz}$

Le résultat de toutes ces formules peut être admiré dynamiquement dans l’onglet n°3 du classeur en ligne.

Petit "Mais..."

Mais... (car il y a toujours un "mais"), les hexagones ne sont pas toujours adjacents à des pentagones ! Dans ce cas-là, quelques données changent, comme la définition du point $p_6$, puisque la distance $op_m$ est alors égale à l’apothème h de l’hexagone. On a donc :

$\overrightarrow{p_mp_6}=\cos\alpha\overrightarrow{op_m}+h\sin\alpha\overrightarrow{oz}$

L’angle dièdre entre deux hexagones étant de 142° 37’ 21", l’angle $\alpha$ sera compris entre 0 et 180° - 142° 37’ 21" = 41,81°.

Ce résultat peut lui aussi être admiré dynamiquement dans l’onglet n° 3bis du classeur en ligne.

3. Construction d’un pentagone

Les étapes de calculs sont sensiblement les mêmes que pour un hexagone. Partons d’un pentagone déjà construit et analysons la situation (onglet 4 du classeur en ligne) :

On a déjà établi dans l’onglet précédent une forme donnant la longueur de l’apothème en fonction de la longueur du côté : $p=P_mP_5=P_0P_1\frac{\tan 54}{2}$. Ainsi, on aura la formule suivante, très analogue à celle déjà établie pour un hexagone. Elle se simplifie quelque peu puisqu’il n’est possible de construire un pentagone qu’à partir d’un hexagone. La longueur $op_m$ étant ainsi l’apothème d’un hexagone, elle est tout le temps égale à $h$ :

$\overrightarrow{p_mp_5}=p\frac{\overrightarrow{op_m}}{op_m}=\frac{p}{h}\overrightarrow{op_m}$

Concernant le point $p_3$, il appartient à la droite $(p_mp_5)$ et la distance $p_5p_3$ est le rayon du pentagone. Le calcul de cette distance se fait à l’aide de la trigonométrie : $P_1P_5=\frac{P_mP_5}{\sin54}$. On aura donc :

$\overrightarrow{p_5p_3}=\frac{\overrightarrow{p_mp_5}}{\sin 54}$

Les points $p_2$ et $p_4$

Considérons le repère

$\left(P_1 ;\frac{\overrightarrow{P_0P_1}}{P_0P_1}=\overrightarrow{u} ; \frac{\overrightarrow{P_mP_5}}{p}=\overrightarrow{v} \right)$

Dans ce repère, et en notant c la longueur du côté d’un pentagone, on a donc $\overrightarrow{P_1P_2}=\left( \begin{array}{l} c\cos72 \\ c\sin72 \end{array} \right)$

On aura donc :

$\overrightarrow{p_1p_2}=c\cos72\frac{\overrightarrow{p_0p_1}}{p_0p_1} + c\sin72\frac{\overrightarrow{p_mp_5}}{p} = \cos72\overrightarrow{p_0p_1} + \frac{2\sin72}{\tan54}\overrightarrow{p_mp_5}$

On obtient une formule similaire pour le point $p_4$, seule la première coordonnée a un signe opposé.

Passons maintenant en 3D.

Comme pour l’hexagone, le centre $p_5$ doit décrire un arc de cercle de centre $p_m$ et de rayon $p$, on a donc :

$\overrightarrow{p_mp_5}=p\cos\alpha\frac{\overrightarrow{op_m}}{h}+p\sin\alpha\overrightarrow{oz}$

On ne peut construire un pentagone qu’à partir d’un hexagone, il n’y a donc qu’un seul angle dièdre à considérer et l’angle $\alpha$ est donc compris entre 0° et 37,775°.

Il ne reste que l’extrémité du vecteur normal et par un raisonnement analogue à celui mené dans l’onglet précédent, on obtient :

$\overrightarrow{p_5p_6}=-\sin\alpha\frac{\overrightarrow{op_m}}{h}+\cos\alpha\overrightarrow{oz}$

Le résultat peut être admiré dans l’onglet n°5 du classeur en ligne.

4. Récapitulatif des formules

  • L’apothème p du pentagone est calculée comme un coefficient d’alignement à partir de la figure 3D de base :
  • On peut alors calculer la longueur c des côtés, commune aux pentagones et hexagones :
    $c = \frac{2p}{\tan 54}$
  • Finalement, on calcule l’apothème h de l’hexagone :
    $h = c\sin 60=\frac{2p\sin60}{\tan54} \Leftrightarrow \frac{h}{p}=\frac{2\sin60}{\tan 54}$
  • Le centre $p_6$ d’un hexagone est défini par les formules suivantes, selon que l’on vient respectivement d’un pentagone ou d’un hexagone :
    $\overrightarrow{p_mp_6}=h\cos\alpha\frac{\overrightarrow{op_m}}{p}+h\sin\alpha\overrightarrow{oz}, 0\leq \alpha\leq 37,3775°$
    $\overrightarrow{p_mp_6}=\cos\alpha\overrightarrow{op_m}+h\sin\alpha\overrightarrow{oz}, 0\leq\alpha\leq 41,81°$
  • Le centre $p_5$ d’un pentagone est défini par la formule suivante :
    $\overrightarrow{p_mp_5}=ph\cos\alpha\frac{\overrightarrow{op_m}}{h}+p\sin\alpha\overrightarrow{oz}, 0\leq\alpha\leq 37,3775°$
  • L’extrémité $p_7$ du vecteur normal à un hexagone est défini par la formule suivante, où d = p si l’on vient d’un pentagone et h si l’on vient d’un pentagone :
    $\overrightarrow{p_6p_7}=-\sin\alpha\frac{\overrightarrow{op_m}}{d}+\cos\alpha\overrightarrow{oz}$
  • L’extrémité $p_6$ du vecteur normal à un pentagone est défini par la formule suivante :
    $\overrightarrow{p_5p_6}=-\sin\alpha\frac{\overrightarrow{op_m}}{p}+\cos\alpha\overrightarrow{oz}$

Description de l’algorithme

1. Principe

Construire la face au sol ;

Tant qu’il reste des faces à construire, faire :
        Tant que l’on n’a pas cliqué sur un segment ou une arête proposée, faire :
                Demander de cliquer sur un segment ou une arête ;

                Identifier  la face déjà construite et la face à construire auxquelles appartiennent
                ce segment ou cette arête ;
                (c’est ici qu’on se rend compte si l’utilisateur a cliqué sur une arête appartenant
                à deux faces déjà traitées ou deux faces non traitées, auquel cas :)

                Affichage d’un petit texte d’erreur au cas où l’on aurait mal cliqué ;

                Construire un nouvel hexagone ou pentagone ;

                Gérer les segments bleus et les arêtes
                (suppression et créations pour les premiers, couleurs pour les seconds) ;

                Affichage du nombre de faces qu’il reste à traiter ;
        FinTanQue
FinTantQue

Pour mettre en œuvre cet algorithme, nous aurons besoin de définir deux objets : un pour l’hexagone et un pour le pentagone qui nous permettrons de définir de manière unique chaque polygone du patron. Passons à l’onglet suivant.

2. Deux classes d’objets

Comment définir un hexagone ?

  • On peut tout de suite penser aux six sommets (ceux du patron, pas ceux du polyèdre !!)
  • D’après ce qui a été décrit dans la première partie de cet article, il est aussi nécessaire de disposer du centre du polygone ainsi que de l’extrémité du vecteur orthogonal.
  • Les 6 arêtes, pour faire la correspondance entre la face du polyèdre et celle du patron.
  • Dans notre cas, il nous faut aussi disposer de la liste des six segments qui seront cliquables par l’utilisateur.
  • Finalement, une dernière variable nous sera utile (bien qu’il soit possible de faire autrement), celle désignant l’état de la face : non traitée (à construire) ou bien traitée (construite), c’est-à-dire numériquement 0 ou bien 1.

Ces informations permettent de définir en JavaScript le constructeur Hexagone :

Attardons-nous un instant sur le mot clef this qui permet de référer à l’objet actuel. Par exemple, this.arete fait référence au tableau de dimension 1x6 du futur objet de type Hexagone.

On définit évidemment de manière totalement similaire un constructeur Pentagone.

On peut s’apercevoir que ces deux constructeurs sont des fonctions de six (ou cinq) variables que sont les arêtes du polyèdre. Il convient donc de connaître celles-ci afin d’instancier correctement les 32 faces du patron.

Les arêtes sont numérotées sur 13 étages, de l’étage 00 à l’étage 12. Sur chaque étage, les arêtes sont numérotées de 0 à 9 maximum. Chaque arête portera le nom axy, où a est la première lettre qui m’est venue à l’esprit, x représente l’étage (à deux chiffres) et y la position dans l’étage (de 0 à 9).

La face sur le sol

Elle figure à l’étage 00. Elle contient les arêtes a00y, pour y variant de 0 à 4. Le sens de numérotation est le sens direct si l’on regarde le polyèdre « depuis le haut ».

Les cinq faces hexagonales suivantes

Une petite image avant de se lancer dans les explications :

Chacune comporte six arêtes, s’étendant des étages 00 à 03. On les numérote en suivant le même sens qu’à l’étage 00.
Les arêtes du bas (en rose) et du haut (en rouge) sont de même position dans leur étage respectif. Il est donc facile de nommer celles de l’étage 03 : a03y, pour y variant de 0 à 4. Ainsi, chaque face comporte les arêtes suivantes, pour y variant entre 0 et 4 :

a00y ; ... ; ... ; a03y ; ... ; ...

Continuons avec les arêtes de l’étage 01, en vert. Pour chaque hexagone, donnons à l’arête de gauche la même position que celle du bas ou du haut, et à celle de droite un de plus. Le problème est que lorsqu’on arrive au cinquième hexagone, pour y = 4, la position de droite donne 5, alors qu’elle a déjà été numérotée 0. Mais en remarquant que 5$\equiv$0[5], on a alors pour chaque face les arêtes :

a00y ; a01y ; ... ; a03y ; ... ; a01(y+1)[5]

Finissons avec les arêtes de l’étage 02, en bleu. Elles sont deux fois plus nombreuses et on les groupera par deux par rapport à l’arête du bas, d’où la numérotation pour chaque face, y variant toujours de 0 à 4 :

a00y ; a01y ; a02(2y) ; a03y ; a02(2y+1) ; a01(y+1)[5]

Les cinq faces pentagonales "pointe en bas"

PNG - 36.9 ko
Toutes les arêtes ne sont pas numérotées pour ne pas surcharger la figure.

Chaque face comporte cinq arêtes : deux à l’étage 02, deux à l’étage 04 et une à l’étage 05. Cela donne, en commençant par celle de l’étage 02 la plus à gauche et en tournant dans le sens direct :

a02... ; a02... ; a04... ; a05... ; a04...

Prenons ici comme référence pour y la position des arêtes de l’étage 05, au nombre de 5. Cela donne, pour y variant de 0 à 4 :

a02... ; a02... ; a04... ; a05y ; a04...

Il y a 10 arêtes à l’étage 02 et on les groupera par deux par rapport à celles de l’étage 05. De par la numérotation déjà imposée, si y est la position d’une arête de l’étage 05, 2y est la position de l’arête de droite à l’étage 02 ; celle de gauche étant logiquement numérotée (2y - 1) d’après la numérotation déjà existante. Un problème survient lorsque y = 0, qui donne 0 au lieu de 9. Mais en remarquant que -1$\equiv$9[10], on a alors (2y-1)[10]$\equiv$(2y+9)[10]. La numérotation devient alors :

a02(2y) ; a02(2y+9)[10] ; a04... ; a05y ; a04...

Même numérotation pour l’étage 04, dont les arêtes sont de même position qu’à l’étage 02 :

a02(2y) ; a02(2y+9)[10] ; a04(2y+9) ; a05y ; a04(2y)

On ne détaillera pas plus la numérotation des autres arêtes (Non non, ne me remerciez pas...), mais elle suit le même principe. Et maintenant que toutes ces arêtes sont correctement numérotées, passons à l’instanciation des 32 faces.

3. Initialisation

Commençons donc par l’initialisation des 32 faces du polyèdre, c’est-à-dire les instanciations des 32 polygones en fonction des informations dont nous disposons pour le moment.

  • Pour la face au sol, il n’y a rien de bien compliqué puisque tous les objets la définissant existent déjà. Il suffit d’instancier un nouveau Pentagone (grâce au mot clef new) avec les arêtes correctes (l. 126). Les six points (sommets) sont déjà connus (l. 127) ainsi que le centre et le sommet du vecteur orthogonal (l. 128).
  • Pour toutes les autres faces, on ne connait que les arêtes, il suffit de les instancier correctement, en respectant la nomenclature décrite dans l’onglet précédent.
    À noter qu’on aurait très bien pu ne pas baptiser ces arêtes et instancier manuellement les 32 faces en relevant les noms préexistants de tous ces segments, mais un peu d’ordre fait toujours du bien ;)

Encore quelques petites lignes de code avant d’attaquer le gros de l’algorithme :

  • l’instanciation de la liste des faces créées, vide pour l’instant, donc… (l. 148)
  • l’instanciation puis l’initialisation de la liste des faces à faire, qui contient donc pour l’instant les numéros de toutes les faces (l. 149 à 152)
  • enfin… la construction d’une première face ! Certes, peu impressionnante, mais nécessaire pour démarrer, il s’agit de la face au sol (l. 155 à 161). On notera bien l’astuce habituelle (qui nous poursuivra tout au long de l’article et déjà rencontrée) à la fin de la l. 157. Le « %5 » qui permet, lors du dernier passage dans la boucle, c’est-à-dire lorsque i=4, de revenir cycliquement au point 0 de la liste.
  • on ajoute la face 0 à la liste des faces créées, son indice est aussi 0 puisqu’elle est la première à faire son entrée dans cette liste (l. 160)
  • on supprime cette même face de la liste des faces à faire, grâce à la commande splice() (l. 163)
  • on affiche dans CaRMetal le nombre de faces qu’il reste à construire (l. 164)

On pourra soulever une question relative aux l. 157 & 158. Pourquoi créer des segments si c’est pour les cacher immédiatement ? Tout simplement car dans la suite de l’algorithme, et comme cela a déjà été dit dans l’onglet n°1, il s’agira de gérer les segments proposés, donc en particulier leur suppression... et on ne peut supprimer quelque chose qui n’existe pas ! Il s’agit donc seulement de cohérence interne à l’algorithme.

Passons maintenant au cœur de l’algorithme.

4. Cœur de l’algorithme

Les descriptions suivantes ne sont autres que celles données dans l’onglet n°1.

  • une boucle principale, qui englobe tout le reste de l’algorithme, qui s’exécute tant que toutes les faces n’ont pas été traitées (l. 167) ;
  • une seconde boucle (l. 169) qui s’exécute tant que l’on n’a pas cliqué sur une « bonne » arête ou un segment.

    On verra où sont incrémentées les variables nftt et nfntt, mais le principe est le suivant :
    • ces variables sont remises à 0 avant chaque nouvelle tentative de construction (l. 168) ;
    • si l’on a cliqué sur une arête appartenant à deux faces déjà traitées, seule la variable nftt sera incrémentée (deux fois), et donc le produit nftt*nfntt aura la valeur 0 ;
    • si l’on a cliqué sur une arête appartenant à deux faces non traitées, seule la variable nfntt sera incrémentée (deux fois), et donc le même produit aura encore la même valeur ;
    • si l’on a « bien » cliqué, chacune des deux valeurs sera incrémentée une seule fois, et le produit sera égal à 1, (qui, on le rappelle, est différent de 0).
    • il s’agit donc de redemander de cliquer sur un segment tant que le produit est égal à 0 (on aurait aussi très bien pu coder « différent de 1 »)
  • les l. 170 à 176 sont une petite astuce pour une version « jeune » de CaRMetal.

    Il suffirait maintenant de la seule l. 172, mais décrivons tout de même ces quelques lignes de code. La l. 170 peut paraitre surprenante car à première vue, quelle condition va bien pouvoir permettre à cette boucle de s’arrêter ? Eh bien, aucune, puisque true est toujours vraie (ça fait un peu bizarre de l’écrire) ! C’est donc une boucle sans fin... enfin presque... puisque l’instruction de la l. 173 finira bien par la stopper. Mais pour que cette instruction puisse s’exécuter, il aura fallu que celle de la ligne précédente puisse s’exécuter sans créer de bug, ce qui était malheureusement le cas dans les premières versions de CaRMetal 3 où un clic sur autre chose (même rien) que l’objet annoncé, ici Segment, provoquait un bug. Et pour que ce bug ne provoque pas l’interruption de l’algorithme, l’InterativeInput est incorporé dans un bloc try catch .
  • après avoir cliqué avec succès sur un segment bleu ou une arête, il s’agit donc d’identifier à quelles faces appartient cet objet. Dans les deux captures suivantes, on traite le cas du clic sur un segment (l. 178).
    • On parcourt donc la liste des faces déjà créées (l. 182) et la boucle s’arrête lorsque occ!=0 ou i>=nb_faces_creees. On cherche alors ce segment dans la face nf (l. 185).
    • On notera la façon particulière de cette recherche, effectuée à l’aide d’une boucle for. Ce type de boucle a bien trop souvent tendance à être réduite à une utilisation du type :
      pour i allant de 1 à 10 par pas de 1, faire {
              //instruction à exécuter
      }

      En fait, une boucle for n’est autre qu’une boucle while synthétisée et doit se lire ainsi :

      initialisation de i à 1;
      tant que i<=10, faire {
              //instruction à exécuter
              incrémenter i de 1;
      }

      Dans ce type de recherche, on doit prendre la précaution supplémentaire j<l car il se peut (ce qui arrive d’ailleurs le plus souvent) que le segment s n’apparaisse pas dans la liste des segments. L’index j dépasserait alors la taille du tableau, ce qui provoquerait une erreur.

    • On portera une attention particulière à l’ordre des conditions de cette l. 185. L’opérateur logique && évalue les conditions de gauche à droite et continue cette évaluation tant qu’il ne rencontre pas de condition fausse. S’il en rencontre une, il renvoie alors la valeur booléenne false et les conditions suivantes ne sont alors pas évaluées car c’est inutile d’après la définition du ET logique. Il est donc primordial de tester si l’indice j ne dépasse pas la taille du tableau avant de demander un élément du tableau à cet emplacement !
    • À la sortie de cette boucle, on teste (l. 186) si on s’est bien arrêté à cause de la découverte de l’occurrence du segment s, mais on aurait très bien pu écrire if(j!=l). S’ensuivent alors quelques affectations permettant de sauvegarder les paramètres nécessaires à la suite de la construction.
  • pour identifier la face à construire, on procède de manière analogue, à la différence près qu’on ne cherche pas le segment sur lequel on a cliqué, puisqu’il n’existe pas dans cette face non construite, mais l’arrête correspondante (sauvegardée à la l. 190).
  • la capture suivante montre le code permettant d’identifier les faces lorsqu’on a cliqué sur une arête. Pas de commentaires inutiles, le principe étant largement le même que lors de la sélection d’un segment bleu. On peut juste signaler les tests sur les variables nftt et nfntt qui permettent d’afficher un texte pour prévenir l’utilisateur que son choix n’est pas judicieux !
  • enfin, l’appel aux fonctions permettant de construire les polygones et de gérer les segments bleus (ainsi que la couleur des arêtes). Ces fonctions seront détaillées dans l’onglet suivant.
    • on notera la commande push, l. 246
    • la recherche de la position de la face nvlf dans la liste_faces_afaire, faite selon la même méthode décrite précédemment. Mais ici, on n’a pas pris de précaution sur l’indice i, du type i<liste_faces_afaire.length, car on est sûr que cet indice ne dépassera pas la taille du tableau... tout simplement car on est sûr que cette face fait bien partie de la liste.

5. Fonctions auxiliaires

On ne détaillera que la fonction permettant de construire un nouveau pentagone, celle permettant de construire un nouvel hexagone étant très similaire. Les formules définissant les points ont déjà été données dans la première partie de cet article, on va donc seulement se concentrer sur l’utilisation des variables dira et dirn.

Admettons qu’un hexagone soit donné et que l’on ait cliqué sur l’arête repérée comme étant la n°2 (ou bien sur le segment correspondant à cette arête), c’est-à-dire celle figurant en troisième position lors de l’instanciation de cet hexagone (voir onglet n°3, Initialisation). Dans ce cas-là, la variable dira vaut 2.

Admettons aussi que cette même arête ait été repérée comme étant la n°4 sur le nouveau pentagone à construire, c’est-à-dire que la variable dirn vaut 4.

Concernant la numérotation des objets, on a d’abord identifié toutes les arêtes par rapport aux deux imposées, dans le sens trigonométrique. La numérotation des points suit, ou plutôt précède celle des arêtes.

Les deux points de l’hexagone qui serviront de base à la construction du pentagone sont $q_2$ et $q_3$. Ainsi, le premier point de construction est repéré par la valeur de la variable dira et le second est repéré par la valeur de la variable dira augmentée de 1 (3 = 2+1). On n’oubliera pas le modulo 6 qui permet d’avoir des valeurs toujours comprises entre 0 et 5.

Considérons maintenant ces deux points comme appartenant au pentagone. Le premier est repéré par la valeur de la variable dirn et le second par cette même valeur augmentée de 1. Comme précédemment, on n’oubliera pas le modulo 5 pour des valeurs exactement comprises entre 0 et 4.

Ces deux paragraphes expliquent complètement les deux affectations des l. 67 & 68. Les noms des variables utilisés, $p_0$ et $p_1$, ne sont que des noms de variables internes à la fonction. En fait, peu importe leur nom, mais ils ont cependant un petit lien avec la description de la construction faite dans la première partie, onglet n°2.

Enfin, les points $p_2$, $p_1$ et $p_3$ sont repérés par la valeur de la variable dirn augmentée de respectivement 3, 2 et 4, ce qui explique les l. 71, 72 & 73.

6. Gestion des segments

Pas de blabla inutiles, voici l’algorithme :

l. 107

EXTERMINATE était peut-être un peu trop extrême !

Un petit commentaire sur la l. 103. Cette ligne un peu compacte doit être comprise ainsi, grâce aux règles de priorité des opérateurs et du fait que la valeur booléenne true correspond à l’entier 1 et la valeur booléenne false correspond à l’entier 0 :

if(face[f].arete[k]==art){
     occ = 1; //ou occ++; ou occ +=1;
}

Prolongement : quelques variations de l’algorithme principal

1. Du manuel à l’automatique

Après quelques recherches sur la toile et en particulier sur Wolfram, on ne trouve nulle part le nombre de patrons distincts de l’icosaèdre tronqué. Si quelqu’un le connait, je suis tout à fait preneur... L’idée a alors surgit d’évaluer statistiquement ce nombre de la manière suivante :

  • admettons qu’on sache construire automatiquement et aléatoirement des patrons de l’icosaèdre tronqué ;
  • pour un patron donné, et pour un (grand) nombre N de patrons construits aléatoirement, si on obtient n fois ce patron, alors on peut en déduire que le nombre de patrons distincts est proche de N/n.

Pas de problème pour le premier point, qui sera détaillé ci-dessous ; par contre, le second point est toujours en attente, faute de savoir comparer deux patrons donnés. Si après lecture de cet article, vous vous sentez de relever le flambeau, il ne faut pas hésiter !

Description de l’algorithme "random construction"

L’algorithme est donc remanié. Exit les segments bleus cliquables et bienvenue à un tableau contenant les arêtes cliquables (celles qui étaient vertes).

  • on commence par insérer dans ce tableau les cinq arêtes du pentagone de base (l. 123 à 125)
  • au lieu de demander à l’utilisateur de cliquer sur une arête verte ou un segment bleu, l’algorithme se charge lui-même de choisir aléatoirement une arête dans cette liste (l. 131 à 134)
  • le reste de l’algorithme ne change pas : on recherche les faces auxquelles appartient cette arête, etc.

Il est par contre bien sûr nécessaire que cette liste soit mise à jour après chaque construction d’un nouveau polygone. La fonction GestionSegments est alors adaptée et change de nom pour GestionListeAretes. En voici le code :

2. Reproduire un beau patron

On pourrait avoir envie, lorsqu’on a trouvé un beau patron (par exemple la peau d’orange), de reproduire automatiquement ce patron. Pour cela, il faut que l’algorithme soit capable :

  • d’exporter un code (série de nombres) représentant le patron,
  • de lire (interpréter) ce code et produit le patron correspondant

Voici un exemple de code (je vous laisse le copier / coller dans après avoir lancé l’algorithme adéquat) :

Cette magnifique suite de nombres se lit de la manière suivante par tranche de deux :

  1. n° de la face sur laquelle on va construire la nouvelle face ;
  2. n° de la face à construire.

En somme, rien de bien compliqué, il suffit juste de connaitre quelle type de polygone correspond à quel nombre...

Remarque historique

J’ai bien dit historique et pas Historique : n’attendez rien de fabuleux !

En fait, ce code n’est pas celui qui avait été pensé à l’origine. Le premier code se lisait par tranche de trois nombres :

  1. n° de la face sur laquelle on va construire la nouvelle face ;
  2. direction de construction pour la nouvelle face relative à la direction de construction de la fa construite ;
  3. n° de la face à construire.

Il s’avère que cette deuxième indication ne sert pas pour la reconstruction d’un patron. Peut-être pourrait-elle servir pour la comparaison... la question est posée, mais non résolue !

Numéros des faces

  • les pentagones portent les numéros 0 ; 6 à 10 inclus ; 21 à 24 inclus ; 31
  • les hexagones portent bien sûr tous les numéros restant (entre 0 et 31)

En appliquant cette numérotation à l’exemple précédent, on en déduit que :

  1. sur la face de base (0), on construit un hexagone (3), mais pas n’importe lequel car il y en a 5 possibles... en fait il s’agit de connaitre l’arête commune...
  2. sur la face de base (0), on construit un hexagone (5) ;
  3. sur la face 3, on construit un hexagone (4) ;
  4. etc.

Modification de l’algorithme : outpout path (manual) & (random)

Il suffit pour cela d’ajouter 4 petites lignes de code :

  • la déclaration d’un tableau ;
  • le stockage des faces dans de tableau ;
  • l’impression (à l’écran) qui nous permet de récupérer ce fameux code.

Algorithme permettant de reproduire un patron à partir de ce code : input path

Rien de bien compliqué non plus :

  • on commence par demander à l’utilisateur de saisir un chemin. On prend quelques précautions en vérifiant au moins que ce chemin possède une taille correcte, c’est-à-dire 62 = 2x31 nombres. Si ce n’est pas le cas, l’algorithme refuse de faire quoi que ce soit !
  • on cherche ensuite l’arête commune à l’ancienne face à la nouvelle face. La technique est habituelle : pour chaque arête de ancf, on regarde si elle existe dans nvlf. Si c’est le cas, on sauvegarde les directions, et on utilisera la même portion de code que précédemment pour construire les polygones !

3. Vers d’autres polyèdres

Une fois qu’on a compris le principe, il est assez facile d’adapter l’algorithme à d’autres polyèdres tel que le cube tronqué aux sommets.

Le fichier est téléchargeable en fin d’article, à titre d’exemple.


notes

[1Historiquement, Jérôme Caré est le premier à avoir proposé un CaRScript objet. Voici son site où figurent quelques scripts orientés objets

[2utiliser de préférence les navigateurs IE ou Chrome, les versions récentes de Mozilla Firefox peuvent poser un problème. Répondre oui aux questions liées à la signature de l’applet

Documents associés à l'article
  Truncated Icosahedron   |   (CarMetal - 159.3 ko)
  Truncated Cube on Top   |   (CarMetal - 45.5 ko)
Réagir à cet article
Vous souhaitez compléter cet article pour un numéro futur, réagir à son contenu, demander des précisions à l'auteur ou au comité de rédaction...
À lire aussi ici
MathémaTICE est un projet
en collaboration avec
Suivre la vie du site Flux RSS 2.0  |  Espace de rédaction  |  Nous contacter  |  Site réalisé avec: SPIP  |  N° ISSN 2109-9197