Fractales, éponge 3d de sierpinski-menger

Description

En 1974 (environ), Benoît Mandelbrot a inventé (découvert ?) les objets fractals (ou fractales).
Ce sont ces objets qui présentent une 'même' structure à n'importe quelle échelle.

A la même période, l'informatique commençait à permettre de calculer et de représenter graphiquement certains de ces
objets.

De plus, les fonctions (de programmation) commençaient à pouvoir s'appeler elle-même (ou récursivement).

Dernièrement, j'ai redécouvert quelques sources de programmes que j'avais développé pendant ces années héroïques de l'informatique.

Depuis quelques années, HTML5 a introduit l'élément "canvas" qui convient pour la représentation graphique.
Mais il faut donc utiliser un navigateur "à jour" pour tester ce programme.

Dans cet exemple de l'éponge de Sierpinski-Menger, la fonction de subdivision Cube(...) divise chaque cube en 20 petits cubes (voir sous Wikipédia).

Après avoir atteint le niveau (profondeur) de division voulue, on arrête la subdivision et on dessine les faces visibles du cube.

Les points 3D des cubes sont projetés avec une 'vraie' perspective, mais sans faire appel à un 'moteur 3D'.

Pour ne pas voir les facettes qui se trouvent "derrière" d'autres, on utilise "l'algorithme du peintre", c'est-à-dire qu'on commence par dessiner les éléments les plus éloignés, qui seront simplement recouverts par ceux qui sont plus proches.

"Malheureusement", les ordinateurs d'aujourd'hui sont trop rapides pour pouvoir suivre l'évolution du cube qui se construit. Comme Javascript ne comporte pas de vraie routine de pause (ou sleep, delay), j'ai fait une deuxième version qui 'enregistre' les faces et qui les dessine ensuite plus lentement à l'aide de setInterval(?)

Source / Exemple :


<!DOCTYPE html>
<html>
<head>
   <title>HTML5  Fractales: Éponge de Sierpinski-Menger en évolution</title>
   <script type="text/javascript">
   //<![CDATA[
      var cnv,ctx,niv=0,lim=5,width=700,height=630; // nombre de niveaux et dimension du canvas
      var UX=-646.2198,UY=861.6264,VX=-320,VY=-240,VZ=1000 // perspective
         ,WX=-0.7427814,WY=-0.5570860,WZ=-0.37139068,Z=1077.033;
      var u,v,u0=u0=350,v0=280; // centrage
      var tmr,iD,nD,D=new Array(14*8000);
      
      function Psp(x,y,z) { // (x,y,z) --> (u,v)
         var w=WX*x+WY*y+WZ*z+Z;
         if ((-1.0e-12<w)&&(w<1.0e-12)) w=1.0e-12;
         u=(UX*x+UY*y)/w; v=(VX*x+VY*y+VZ*z)/w;
      }
      function Cube(x,y,z,d,n) {
         if (--n>0) { // subdivision
            d/=3;
            var xa=x+d,ya=y+d,za=z+d,xb=x+d+d,yb=y+d+d,zb=z+d+d;
            Cube(x,y ,z ,d,n); Cube(xa,y ,z ,d,n); Cube(x ,ya,z ,d,n); Cube(xb,y ,z ,d,n);
            Cube(x,yb,z ,d,n); Cube(xb,ya,z ,d,n); Cube(xa,yb,z ,d,n); Cube(xb,yb,z ,d,n);
            Cube(x,y ,za,d,n); Cube(xb,y ,za,d,n); Cube(x ,yb,za,d,n); Cube(xb,yb,za,d,n);
            Cube(x,y ,zb,d,n); Cube(xa,y ,zb,d,n); Cube(x ,ya,zb,d,n); Cube(xb,y ,zb,d,n);
            Cube(x,yb,zb,d,n); Cube(xb,ya,zb,d,n); Cube(xa,yb,zb,d,n); Cube(xb,yb,zb,d,n);
         } else { // enregistrement
            Psp(x+d,y  ,z  ); D[nD++]=u; D[nD++]=v;
            Psp(x  ,y+d,z  ); D[nD++]=u; D[nD++]=v;
            Psp(x  ,y  ,z+d); D[nD++]=u; D[nD++]=v;
            Psp(x+d,y+d,z  ); D[nD++]=u; D[nD++]=v;
            Psp(x  ,y+d,z+d); D[nD++]=u; D[nD++]=v;
            Psp(x+d,y  ,z+d); D[nD++]=u; D[nD++]=v;
            Psp(x+d,y+d,z+d); D[nD++]=u; D[nD++]=v;       
         }
      }
      function Eponge() {
         if (++niv>lim) niv=1;
         ctx.setTransform(1,0,0,1,0,0); ctx.clearRect(0,0,width,height);
         ctx.translate(u0,v0); ctx.scale(1.2,-1.2);
         nD=0; Cube(-160,-160,-160,320,niv);
         iD=0; tmr=setInterval('Evo()',512>>(2*niv));
         if (iD>=nD) clearInterval(tmr);
      }
      function Evo() {
         var ux=D[iD++],vx=D[iD++],uy=D[iD++],vy=D[iD++],uz=D[iD++],vz=D[iD++],uxy=D[iD++]
            ,vxy=D[iD++],uyz=D[iD++],vyz=D[iD++],uzx=D[iD++],vzx=D[iD++],uxyz=D[iD++],vxyz=D[iD++];
         ctx.beginPath(); ctx.fillStyle='#00BB55'; // face X
         ctx.moveTo(ux,vx); ctx.lineTo(uxy,vxy); ctx.lineTo(uxyz,vxyz); ctx.lineTo(uzx,vzx);
         ctx.fill(); ctx.closePath();          
         ctx.beginPath(); ctx.fillStyle='#0055BB'; // face Y
         ctx.moveTo(uy,vy); ctx.lineTo(uyz,vyz); ctx.lineTo(uxyz,vxyz); ctx.lineTo(uxy,vxy);
         ctx.fill(); ctx.closePath();          
         ctx.beginPath(); ctx.fillStyle='#FFFF77'; // face Z
         ctx.moveTo(uz,vz); ctx.lineTo(uzx,vzx); ctx.lineTo(uxyz,vxyz); ctx.lineTo(uyz,vyz);
         ctx.fill(); ctx.closePath();          
         if (iD>=nD) clearInterval(tmr);
      }
      function Ini() {
         cnv=document.getElementById('cv'); cnv.width=width; cnv.height=height;
         ctx=cnv.getContext("2d"); Eponge();
      }
   //]]>
   </script>
</head>
<body style='background-color:#BBBBBB;' onload='Ini()'>
   <canvas id='cv' onclick='clearInterval(tmr); Eponge()' style='background-color:#DDDDDD; cursor:pointer;'
      title="Cliquez pour passer à l'objet suivant">Your browser does not support HTML5 canvas
   </canvas>
   <div>
      <br/><br/>Wikipédia: &nbsp;
      <a href='http://fr.wikipedia.org/wiki/%C3%89ponge_de_Menger'>Éponge de Sierpinski-Menger</a>
      <br/><br/><a href='http://www.william-voirol.ch/Prog/Fractales/Eponge.zip'>Zip des codes<br/></a>
   </div>
</body>
</html>

Conclusion :


Faites directement un test: (observez la remarque ci-dessous)
http://www.william-voirol.ch/Prog/Fractales/Eponge
http://www.william-voirol.ch/Prog/Fractales/Eponge/evol.html

Remarque: de temps en temps, des espaces (caractères blancs) s'immiscent
dans certains textes. (CodeS-SourceS est au courant du problème).
Si c'était le cas ici, enlevez les espaces avant d'utiliser les adresses Web ci-dessus.

Les deux exemples se trouvent sur le fichier zip.

Dites-moi si la manière de définir d'autres projections 3D->2D (axonométries ou perspectives) vous intéressent ?

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.