Jeu du chaos en javascript
Autosimilarité fractale dans un polygone
Description & résultat / affichage
Le jeu du chaos est une méthode algorithmique qui permet de constuire relativement facilement l'attracteur d'un IFS (Système de Fonctions Itérées) qui a généralement des propriétés fractales.Ce jeu (ou plutôt cette méthode) a été introduit par Barnsley dans les années 80. Originellement il se situe dans un polygone et se construit de la fa¸on suivante. On note N le nombre de sommets du polygone et k un nombre compris entre 0 et 1: paramètre modifiable interactivement ci-dessous).
- On part d'un point M quelconque (ici le point de coordonnées (1,0))
- on tire un nombre entier i, au hasard entre 1 et N
- on calcule les coordonnées du nouveau point M situé à un rapport k entre le i-ème sommet et M précédent
- On réitère l'étape précédente
Formulaire html
Tout d'abord la partiehtml
avec form
et canvas
pour la représentation graphique:
<form id="globalform" onchange="Drawh();return false;" onsubmit="Drawh();return false;"> <label>Nombre de points:</label> <input type="number" id="Np" min="0" value="50000" max="500000" step="10"> <br> <label>Nombre de sommets:</label> <input type="number" id="Ns" min="3" value="6" max="30" step="1" onchange="Chbx();return false;"> <br> <label for="chbx">Rapports identiques pour tous les sommets</label> <input type="checkbox" id="chbx" checked onchange="Chbx();return false;"> <div id="RapportFields"></div> </form> <canvas id="cnv" width="400" height="400"></canvas>
L'
input
"checkbox" permet de séparer, ou non, chacun des sommets.
Lorsque sélectionné, un seul rapport est appliqué à tous les sommets, sinon, on sépare chacun des sommets
et on créé autant d'input
que de sommets.
La création dynamique d'
input
est traitée là.
Programme javascript
<script> // Références du canvas et ses dimensions cnvj = document.getElementById("cnv"); ctx = cnvj.getContext("2d"); Width=document.getElementById("cnv").width; Height=document.getElementById("cnv").height; // Nouveau système de coordonnées, // voir: là xmin=-1;xmax=1; ymin=-1;ymax=1; function cnv2x(X) {return X*(xmax-xmin)/Width+xmin;} function cnv2y(Y) {return (Height-Y)*(ymax-ymin)/Height+ymin;} function x2cnv(x) {return Width*(x-xmin)/(xmax-xmin);} function y2cnv(y) {return Height-Height*(y-ymin)/(ymax-ymin);} // fonction barycentre: // retourne les coordonnées du point situé au rapport k // entre les points A et B function f(A,B,k) { //retourne C tel que Vecteur(AC)=k*Vecteur(AB) xC=(1-k)*A[0]+k*B[0] yC=(1-k)*A[1]+k*B[1] return [xC,yC];} // Fonction "check Box" qui créé, si besoin // dynamiquement autant d'input que de sommets // voir cette page function Chbx() { Fields=document.getElementById("RapportFields"); if (!(Fields.hasChildNodes())) {k=0.6;} else { if (document.getElementById("k")) {k=document.getElementById("k").value;} else {k=document.getElementById("k0").value; } while (Fields.hasChildNodes()) {Fields.removeChild(Fields.lastChild);} } if (document.getElementById("chbx").checked) { Fields.appendChild(document.createTextNode(" Rapport k")); var input = document.createElement("input"); input.type = "number"; input.name = "member"; input.min=0;input.max=1;input.step=0.01; input.style="width:4em;" input.id = "k";input.value=k; Fields.appendChild(input); } else { Ns=document.getElementById("Ns").value; for (i=0;i<Ns;i++) { // Texte précédent le nouvel input Fields.appendChild(document.createTextNode("Sommet S"+(i+1)+" - Rapport k" + (i+1))); // Nouvelinput
crée: var input = document.createElement("input"); //... et ses attributs input.type = "number"; input.name = "member" + i; input.min=0;input.max=1;input.step=0.01; input.style = "width:4em;" input.id = "k" + i; Fields.appendChild(input); document.getElementById("k"+i).value=k; // On va enfin à la ligne: Fields.appendChild(document.createElement("br")); } } } // La fonction graphique, enfin... function Drawh() { Np=document.getElementById("Np").value; Ns=document.getElementById("Ns").value; var k=new Array;// pour simplifier la suite, même s'il n'y a qu'un seul rapport k, // on considère k comme un tableau à un seul élément for (i=0;i<Ns;i++) { if (!(document.getElementById("chbx").checked)) { k[i]=document.getElementById("k"+i).value;} else {k[i]=document.getElementById("k").value;} } ctx.clearRect(0,0,Width,Height);// On efface tout le canvas // On dessine le polygone régulier // d'angle au centre α=i2π/Ns // Les coordonnées des sommets sont donc (cos(αi),sin(αi)) // et on relie ces points:lineTo
alpha=2*Math.PI/Ns; var S=new Array; S[0]=[1,0]; ctx.fillStyle="blue"; ctx.beginPath(); X=x2cnv(1);Y=y2cnv(0); ctx.moveTo(X,Y); for (i=1;i<Ns;i++) { x=Math.cos(i*alpha);y=Math.sin(i*alpha); S[i]=[x,y]; ctx.lineTo(x2cnv(x),y2cnv(y)); } ctx.lineTo(x2cnv(1),y2cnv(0)); ctx.stroke(); // Jeu du chaos à proprement parler: M=[0,0];// Initialisation, point M de départ for (i=1;i<Np;i++) { p=Math.floor(Ns*Math.random());// Tirage d'un sommet au hasard M=f(M,S[p],k[p]); // Nouveau point M, entre M et Sp, avec rapport kp X=x2cnv(M[0]);Y=y2cnv(M[1]); // Retour aux coordonnées du canvas ctx.fillRect(X,Y,1,1); // On dessine le point } } // Initialisation: on exécute tout de suite // chaque fonction et on dessine le graphique Chbx(); Drawh(); </script>