retour index

chapitre 4

Fractales naturelles

Arbres de Pythagore

Arbre en H

Tracé d'une île

Arbre 1

Arbuste

Arbre 2

Arbuste aléatoire

Ile brownienne

Montagnes

Exercices

 

Les fractales sont la géométrie préférée de la nature. Citons les arbres, les montagnes, les nuages, le bassin d'un fleuve et de ses affluents, les vaisseaux sanguins, les poumons...

Il ne s'agit pas de véritables fractales au sens mathématique du terme, mais de fractales statistiques dont la structure n'est pas rigide, mais s'adapte à l'environnement local, comme un arbre se penche dans le sens du vent dominant ou un relief dépend de la composition des roches.

Le nombre de niveaux d'organisation également est limité. Le tronc d'un arbre se sépare en branches maitresses qui se divisent à leur tour en branches plus fines, mais le nombre de séparations ne dépasse pas une dizaine. Il s'agit en fait d'une préfractale, analogue aux figures tracées à l'ordinateur où l'on s'arrête après un certain nombre d'itérations.

Pourquoi la nature préfère-t-elle la géométrie fractale ? C'est parce que dans la nature tout est organisé et structuré.

Une fractale résulte de l'application de la même règle à plusieurs reprises. Une règle du jeu est appliquée à un niveau qui s'organise en sous-niveaux, puis elle s'applique identiquement aux sous-niveaux et la situation se répète un certain nombre de fois.

Prenons une montagne qui s'érode. Du fait de l'érosion qui creuse, les vallées ont tendance à prendre un profil parabolique. Mais il en est de même des affluents, puis des ruisseaux et des ruissellets. Due à la même cause, on a la même structure sur différents niveaux du ruisseau au fleuve, mais la fractale obtenue est une fractale statistique qui ne se répète jamais deux fois de la même façon.

Quant à la stucture des plantes et des animaux dont nous faisons partie, elle est initiée et régulée par un programme génétique qui est à la chimie ce que le programme informatique est à l'ordinateur. L'ensemble des gènes est un programme chimique qui commande à une suite complexe de réactions chimiques. Si le même programme s'applique à des niveaux différents d'organisation, on obtiendra une structure fractale. A noter que le programme lui-même et son exécution sont soumis à une multitude d'aléas qui rendra la fractale statistique.

La structure fractale présente un certain nombre d'avantages. Par exemple celle de présenter pour le même volume une surface maximale d'échange comme dans le poumon ou les vaisseaux sanguins. Le système sanguin permet d'amener de l'énergie à toutes les cellules du corps, donc une subdivision quasiment infinie à partie de l'artère sortant du coeur.

Comme premier exemple de fractales pouvant servir de modèle aux structures naturelles, on va tracer des arbres de Pythagore.

début chapitre

Arbres de Pythagore

Carré de Pythagore

La version la plus simple de l'arbre de Pythagore consiste à partir d'un carré. Sur le côté supérieur de carré, on place un triangle rectangle, sur les côtés duquel on place deux nouveaux carrés, et on continue de cette façon.

Regardons la première itération :


chap4__1.pngfigure 4.1 : construction du carré de Pythagore

A partir du carré p $,$ on en fait une copie réduite du facteur $\cos \alpha $ (avec ici $\alpha =\pi /4$) sur les 2 axes à l'aide de la commande scale ;on arrive ainsi à p1 ;puis on passe à p2 par une rotation d'angle $\alpha $ et enfin à p3 par une translation de 1 suivant Oy. Le second carré se fait de la même façon, avec une rotation de $-(\pi /2-\alpha ),$ une translation de 1/2 suivant Ox et 1+1/2 suivant Oy lorsque $\alpha =\pi /4.$

> restart:with(plottools):with(plots):

> f:=proc(p) local p1,p2,p3,p4,p5:

p1:=scale(p,cos(alpha),cos(alpha)):p2:=rotate(p1,alpha)

p3:=translate(p2,0,1):

p4:=scale(p,cos(Pi/2-alpha),cos(Pi/2-alpha)):

p5:=translate(rotate(p3,-(Pi/2-alpha)),a*cos(alpha)^2,

1+a*sin(alpha)*cos(alpha)):p3,p5: end:

> a:=1:alpha:=Pi/4:

> q:=rectangle([a,0],[0,1],color=red):

> liste:=q:for i from 1 to 4 do:

liste:=liste,seq(f(op(j,[liste])),j=1..nops([liste])): od:

> display(liste);


chap4__8.pngfigure 4.2 : carré de Pythagore

On obtient des arbres différents en faisant varier la largeur du tronc a et l'angle $\alpha $ (par exemple, a = 0,2 et $\alpha =\pi /3$).

Broncolis et pavages

On peut également mettre sur le côté supérieur du rectangle un triangle isocèle d'angle à la base $\alpha .$ Suivant la valeur de $\alpha ,$ on obtient des ''broncolis'' ou des pavages.

Soit $\alpha =\pi /8$ et a = 1,5. Cela donne :

> restart:with(plottools):with(plots):

> f:=proc(p) local p1,p2,p3,p4,p5,p6:

p1:=scale(p,1/(2*cos(alpha)),1/(2*cos(alpha))):

p2:=rotate(p1,alpha):p3:=translate(p2,0,1):

p4:=scale(p,1/(2*cos(alpha)),1/(2*cos(alpha))):

p5:=rotate(p4,-alpha):

p6:=translate(p5,a/2,1+a/2*tan(alpha)):p3,p6: end:

> a:=1.5:alpha:=Pi/8:

> q:=rectangle([a,0],[0,1],color=red):

> liste:=q:for i from 1 to 6 do:

liste:=liste,seq(f(op(j,[liste])),j=1..nops([liste])): od:

> display(liste,scaling=constrained);


chap4__14.pngfigure 4.3 : broncoli de Pythagore

Prenons $\alpha =\pi /3$ et a = 0,6 :


chap4__16.pngfigure 4.4 : pavage de Pythagore

On obtient un pavage de Pythagore dont on peut faire varier le motif en changeant les paramètres $\alpha $ et a.

Arbre de Pythagore

On peut obtenir un arbre plus réaliste en ne traçant que les deux côtés verticaux du rectangle de départ avec la commande line :

> restart:with(plottools):with(plots):

> f:=proc(p) local p1,p2,p3,p4:

p1:=scale(p,cos(alpha),cos(alpha)):

p2:=translate(rotate(p1,alpha),0,1):

p3:=scale(p,sin(alpha),sin(alpha)):

p4:=translate(rotate(p3,-(Pi/2-alpha)),a*cos(alpha)^2,

1+a*sin(alpha)*cos(alpha)):p2,p4: end:

> a:=0.2:alpha:=Pi/3.5:

> q:=display(line([0,0],[0,1],color=red),line([a,0],[a,1],color=red)):

> liste:=q:for i from 1 to 7 do:

liste:=liste,seq(f(op(j,[liste])),j=1..nops([liste])): od:

> display(liste);


chap4__18.pngfigure 4.5 : arbre de Pythagore

Faire varier de même a et $\alpha .$

début chapitre

Arbre en H

Il simule l'organisation du poumon. Dans celui-ci, l'air arrive par un conduit central qui se divise en 2 pour alimenter la gauche et la droite, puis chacun des deux conduits se sépare encore en 2 et ainsi de suite de façon à amener l'air dans chacune des alvéoles.

On part de la stucture suivante, composée d'un segment horizontal de longueur 2 et de 2 segments verticaux de longueur 1 centrés aux extrémités du segment horizontal :


chap4__20.pngfigure 4.6 : stucture en H

On ajoute ensuite la même structure dont les dimensions ont été réduites de moitié aux 4 extrémités de la première structure :


chap4__22.pngfigure 4.7 : 2$^{i\grave{e}me}$ itération de la structure en H

En procédant de la sorte, on arrive à l'arbre en H. On trace chacune des itérations successives avec un trait d'épaisseur décroissante (thickness augmente l'épaisseur du trait de 0 à 3 au maximum). Le conduit central est tracé séparément en traçant un rectangle de faible largeur :

> restart:with(plots):with(plottools):

> arbre:=proc(n) global liste : local k,h,l,m,x,y : liste:=op([]):

for k to n do h:=2^(1-k): for l to 2^(k-1) do:

for m to 2^(k-1) do:

x:=-2+(4*l-2)*h:y:=-2+(4*m-2)*h:

liste:=liste,line([x-h,y],[x+h,y],color=red),line([x-h,y-h],

[x-h,y+h],color=red),line([x+h,y-h],[x+h,y+h],color=red)

od od od end:

> display(seq(display(arbre(n),thickness=5-n),n=1..5),

rectangle([0.03,0],[-0.03,-2],color=red));


chap4__23.pngfigure 4.8 : arbre en H

Le même modèle peut s'appliquer également à la circulation sanguine.

début chapitre

Tracé d'une île

On a déjà tracé l'île de Koch au chapitre 2. Ce tracé n'est pas très réaliste, car trop régulier. Pour obtenir un tracé réaliste, il faut faire intervenir une certaine dose de hasard.

La commande rand est un générateur aléatoire ;rand(0..1)() donne soit 0, soit 1. En transformant le 0 en -1, on va introduire cette commande dans la construction de l'île de Koch de façon à tourner la courbe de Koch de manière aléatoire vers l'extérieur ou vers l'intérieur à chaque étape ;on fait trois tracés différents dont 2 sont déplacés et tournés pour tracer les 3 côtés de l'île :

> restart:with(plots):with(plottools):

> segment:=proc(a) local k: global courbe: k:=nops([courbe]):

courbe:=courbe,courbe[k-1]+cos(a),courbe[k]+sin(a) end:

> l:=1:a:=0:Koch:=proc(n) global a:local b,k:

if n=0 then segment(a) else b:=rand(0..1)():

if b=0 then k:=-1 else k:=1 fi: (k=+1 ou -1 au hasard)

Koch(n-1):a:=a+k*Pi/3: Koch(n-1):a:=a-2*k*Pi/3:

Koch(n-1):a:=a+k*Pi/3: Koch(n-1): fi end:

> courbe:=0,0:p1:=pointplot([Koch(4)],scaling=constrained,

style=line,color=red,axes=none):

> courbe:=0,0:p2:=pointplot([Koch(4)],scaling=constrained,

style=line,color=red,axes=none):

> courbe:=0,0:p3:=pointplot([Koch(4)],scaling=constrained,

style=line,color=red,axes=none):

> p4:=rotate(p2,Pi/3):p5:=rotate(p3,-Pi/3,[3^4,0]):

> display(p1,p4,p5);


chap4__24.pngfigure 4.9 : 2 exemples d'îles de Koch aléatoires

On peut faire également une île en partant de la courbe 3/2, étudiée à l'exercice 1 du chapitre 2, ou, mais le tracé n'est pas très réaliste bien qu'intéressant, à partir de l'île des fjords étudiée au chapitre 2. Ces tracés sont étudiés en exercice.

début chapitre

Arbre 1

Première méthode

A partir d'un segment vertical de longueur 1 représentant le tronc, on veut obtenir à la première itération 2 branches de longueur 0,7, la première inclinée de $\pi /4$ et la seconde de $-\pi /6,$ puis on recommence la construction sur chacune des branches.


chap4__27.pngfigure 4.10 : 3 premières itérations de arbre 1

La première méthode consiste à utiliser les nombres complexes :z1 (= 0) et z2 (= I) étant les extrémités du premier segment, les extrémités de la première branche sont z2 et MATH et celles de la seconde branche z2 et MATH On définit donc une procédure qui, à partir d'une branche, donne les coordonnées de cette branche et des deux branches qui s'y raccordent. Cette procédure est renouvelée plusieurs fois, puis on trace séparément à l'aide de complexplot chaque ensemble de trois branches et on rassemble les tracés avec display :

> restart:with(plots):

> b:=Pi/4:c:=-Pi/6:f:=proc(z1,z2) local a:a:=(z2-z1)*0.7:

z1,z2,z2,z2+a*exp(I*b),z2,z2+a*exp(I*c):end:

> liste:=0,I: for i to 6 do:

liste:=seq(op([f(liste[2*j-1],liste[2*j])]),j=1..nops([liste])/2): od:

> liste1:=seq(complexplot([f(liste[2*j-1],liste[2*j])]),

j=1..nops([liste])/2):

> display(liste1,axes=none,scaling=constrained);

On obtient le même dessin qu'avec le programme suivant qui est un peu plus rapide.

Deuxième méthode

C'est le même programme, mais écrit en nombres réels en séparant l'abcisse et l'ordonnée. La matrice rotation d'un angle $\theta $ est
MATH

On remplace $\theta $ par $\pi /4$ pour la première branche et par $-\pi /6$ pour la seconde. On donne les valeurs numériques pour diminuer le temps de calcul :

> restart:with(plots):

>f:=proc(x1,y1,x2,y2) local a,b:

a:=(x2-x1)*0.7:b:=(y2-y1)*0.7:

x1,y1,x2,y2,x2,y2,x2+a*0.707-b*0.707,y2+a*0.707+b*0.707,

x2,y2,x2+a*0.866+b*0.5,y2-a*0.5+b*0.866 end:

> liste:=0,0,0,1:

> for i to 7 do: liste:=seq(op([f(liste[4*j-3],liste[4*j-2],

liste[4*j-1],liste[4*j])]),j=1..nops([liste])/4): od:

> liste1:=seq(pointplot([f(liste[4*j-3],liste[4*j-2],liste[4*j-1],

liste[4*j])],style=line),j=1..nops([liste])/4):

> display(liste1,axes=none,scaling=constrained,color=red);


chap4__35.pngfigure 4.11 : arbre 1

On peut simuler la croissance de l'arbre en dessinant sur le même graphe les itérations 2 (p1), 4 (p2) et 6 (p3) au moyen du programme précédent en changeant le numéro de l'itération :

> p1:=display(liste1,axes=none,scaling=constrained,color=red):

> p2:=display(liste1,axes=none,scaling=constrained,color=red):

> p3:=display(liste1,axes=none,scaling=constrained,color=red):

> with(plottools): p4:=translate(p2,4,0): p5:=translate(p3,8,0):

> display(p1,p4,p5);


chap4__36.pngfigure 4.12 : croissance de arbre 1


début chapitre

Arbuste

On va dessiner un arbuste, dont les 2 premières itérations se présentent sous la forme :


chap4__37.pngfigure 4.13 : les 2 premières itérations de arbuste

Pour cela, on va faire un programme légèrement différent du programme précédent, car les deux rameaux, inclinés de $\pi /4$ et $-\pi /6,$ s'embranchent à des endroits différents. La procédure f va dépendre du point initial et des accroissements, notés dx et dy. Elle donne les extrémités des 5 segments composant la première itération. (un segment par ligne de programme). A partir de la seconde itération, on prend pour accroissement le tiers des composantes de la branche, ce qui permet d'embrancher au 1/3 et au 2/3 de la longueur de la branche(c'est le rôle de la division par 3 dans les deux séquences).

> restart:with(plots):

> f:=proc(x1,y1,dx,dy) local a,b :

a:=dx*1.1:b:=dy*1.1:(les branches sont un peu plus longues)

x1,y1,x1+dx,y1+dy, (premier segment vertical)

x1+dx,y1+dy,x1+dx+a*0.707-b*0.707,y1+dy+a*0.707+b*0.707, (deuxième segment à gauche)

x1+dx,y1+dy,x1+2*dx,y1+2*dy, (troisième segment vertical)

x1+2*dx,y1+2*dy,x1+2*dx+a*0.866+b*0.5,y1+2*dy-a*0.5+b*0.866, (quatrième segment à droite)

x1+2*dx,y1+2*dy,x1+3*dx,y1+3*dy end: (dernier segment vertical)

> liste:=f(0,0,0,1):

> for i to 2 do:liste:=seq(f(liste[4*i-3],liste[4*i-2],

(liste[4*i-1]-liste[4*i-3])/3,(liste[4*i]-liste[4*i-2])/3),

i=1..nops([liste])/4) od:

> liste1:=seq(pointplot([f(liste[4*i-3],liste[4*i-2],

(liste[4*i-1]-liste[4*i-3])/3,(liste[4*i]-liste[4*i-2])/3)],

style=line),i=1..nops([liste])/4): (séquence de pointplot)

> display(liste1,axes=none,scaling=constrained,color=red);


chap4__40.pngfigure 4.14 : arbuste

En changeant les paramètres $a$ et $b$ ainsi que les angles que font les branches avec le tronc, on peut obtenir des arbustes variés, tels que les trois exemples de la figure :


chap4__43.pngfigure 4.15 : arbuste avec différentes valeurs de a et b


début chapitre

Arbre 2

Partant d'un segment vertical de longueur 1, le motif sera l'ensemble des 8 segments ci-dessous :


chap4__44.pngfigure 4.16 : motif de arbre 2

L'écriture successive des extrémités des segments du motif étant fastidieuse, on opère au moyen de procédures. On définit d'abord f, f1 et f2 tels que f@f1 (f1 composée avec f) est une rotation de MATH et f@f2 une rotation de MATH On fait ensuite la liste des coordonnées des extrémités des 8 segments en progressant le long des segments. Le reste du programme est analogue aux programmes précédents.

> restart:with(plots):

> f:=proc(x,y,dx,dy):x+dx,y+dy,dx,dy end:

> f1:=proc(x,y,dx,dy): x,y,0.906*dx-0.422*dy,0.422*dx+0.906*dy end:

> f2:=proc(x,y,dx,dy):x,y,0.906*dx+0.422*dy,-0.422*dx+0.906*dy end:

> g:=proc(x,y,dx,dy) local a,b,liste: (tracé du motif)

liste:=x,y:a:=f(x,y,dx,dy):liste:=liste,[%][1],[%][2],[% ][1],[%][2]:

a:=f(a):liste:=liste,[%][1],[%][2],[%][1],[%][2]:b:=a:

a:=(f@f1@f1)(a):liste:=liste,[%][1],[%][2],[%][1],[%][2]:

a:=(f@f2)(a):liste:=liste,[%][1],[%][2],[%][1],[%][2]:

a:=(f@f2)(a):liste:=liste,[%][1],[%][2],[b][1],[b][2]:

a:=(f@f2)(b):liste:=liste,[%][1],[%][2],[%][1],[%][2]:

a:=(f@f1)(a):liste:=liste,[%][1],[%][2],[%][1],[%][2]:

a:=(f@f1)(a):liste:=liste,[%][1],[%][2] end:

>x:=0:y:=0:dx:=0:dy:=1:liste:=g(x,y,dx,dy): (itérations)

n:=2:for i to n do:liste:=seq(g(liste[4*i-3],liste[4*i-2],

(liste[4*i-1]-liste[4*i-3])/2,(liste[4*i]-liste[4*i-2])/2),

i=1..nops([liste])/4)od:

> liste1:=seq(pointplot([g(liste[4*i-3],liste[4*i-2],

(liste[4*i-1]-liste[4*i-3])/2,(liste[4*i]-liste[4*i-2])/2)],

style=line),i=1..nops([liste])/4): (tracé des branches)

> display(liste1,color=red,axes=framed,scaling=constrained);


chap4__47.pngfigure 4.17 : arbre 2

Les feuilles viennent du fait que la commande pointplot joint l'extrémité du segment 4 à l'origine du segment 5.En effectuant les 3 premiers tracés, on peut suivre la croissance de arbre 2 :


chap4__48.pngfigure 4.18 : croissance de arbre 2


début chapitre

Arbuste aléatoire

On va faire intervenir le hasard dans la construction d'un arbuste.

On prend 3 motifs différents, donnés par les procédures g1, g2 et g3 et représentés de gauche à droite sur la figure ci-dessous :


chap4__49.pngfigure 4.19 : motifs de arbuste aléatoire

Par un générateur de hasard, on choisit arbitrairement une des 3 transformations à chaque étape du calcul.

On fait ainsi 12 dessins d'arbustes que l'on réunit en appliquant 2 fois la commande display :

> restart:with(plots):

> f:=proc(x,y,dx,dy):x+dx,y+dy,dx,dy end:

> f1:=proc(x,y,dx,dy): x,y,0.7*(0.866*dx-0.5*dy),

0.7*(0.5*dx+0.866*dy) end:

> f2:=proc(x,y,dx,dy):x,y,0.7*(0.866*dx+0.5*dy),

0.7*(-0.5*dx+0.866*dy) end:

> g1:=proc(x,y,dx,dy) local liste,a,b,c: (premier motif)

liste:=x,y:a:=f(x,y,dx,dy):liste:=liste,[a][1],[a][2],[a][1],[a][2]:

(f@f1)(a):liste:=liste,[%][1],[%][2],[a][1],[a][2]:

b:=f(a):liste:=liste,[%][1],[%][2],[%][1],[%][2]:

(f@f2)(b):liste:=liste,[%][1],[%][2],[b][1],[b][2]:

c:=f(b):liste:=liste,[%][1],[%][2]: liste:end:

> g2:=proc(x,y,dx,dy) local liste,a,b,c: (deuxième motif)

liste:=x,y:a:=f(x,y,dx,dy):liste:=liste,[a][1],[a][2],[a][1],[a][2]:

(f@f1)(a):liste:=liste,[%][1],[%][2],[a][1],[a][2]:

b:=f(a):liste:=liste,[%][1],[%][2]:liste:end:

> g3:=proc(x,y,dx,dy) local liste,a,b,c: (troisième motif)

liste:=x,y:a:=f(x,y,dx,dy):liste:=liste,[a][1],[a][2],[a][1],[a][2]:

(f@f2)(a):liste:=liste,[%][1],[%][2],[a][1],[a][2]:

b:=f(a):liste:=liste,[%][1],[%][2];liste:end:

> h:=proc(x,y,dx,dy) local a,b: a:=rand(0..2):b:=a():

if b=0 then g1(x,y,dx,dy) elif b=1 then g2(x,y,dx,dy)

else g3(x,y,dx,dy) fi end: (choix au hasard d'un motif)

> liste1:=op([]):for j to 12 do (12 arbustes)

x:=0:y:=0:dx:=0:dy:=1:liste:=h(x,y,dx,dy):

n:=3:for i from 1 to n do:

if i<=n-1 then liste:=seq(h(liste[4*i-3],liste[4*i-2],

(liste[4*i-1]-liste[4*i-3])/2,(liste[4*i]-liste[4*i-2])/2),

i=1..nops([liste])/4)

else liste:=seq(pointplot([h(liste[4*i-3],liste[4*i-2],

(liste[4*i-1]-liste[4*i-3])/2,(liste[4*i]-liste[4*i-2])/2)],

style=line,color=red,axes=none,scaling=constrained),

i=1..nops([liste])/4):liste1:=liste1, display(liste): fi od od:

> display(liste1,insequence=true):

> display(%); (tracé des 12 arbustes)


chap4__50.pngfigure 4.20 : arbustes aléatoires


début chapitre

Ile brownienne

On va tracer l'île brownienne en se servant de la construction du mouvement brownien à une dimension décrite dans le chapitre des fractales physiques sous le nom de méthode du déplacement aléatoire du milieu.

Partons d'un quadrilatère de forme quelconque. On déplace le milieu de chacun des côtés d'une grandeur aléatoire gaussienne sur la perpendiculaire au côté en multipliant par le facteur $\dfrac{1}{2^{H}},$H est l'exposant de Hurst du mouvement brownien fractionnaire (H = 1/2 pour le mouvement brownien à 1 dimension. Cet exposant de Hurst va contrôler la ''méandricité'' de la côte, les fortes valeurs correspondant à une forme douce.

On recommence ensuite sur les milieux des nouveaux segments obtenus, en multipliant à chaque niveau par le facteur $\dfrac{1}{2^{H}}.$

On trace une séquence de 10 dessins, correspondant aux valeurs de H entre 0,1 et 1.

> restart:with(plots):

> a:=proc() rand() end:b:=proc() rand() end:c:=proc() rand() end:

> f:=proc(x1,y1,x2,y2,i) local u,v,u1,v1,d:global H:

d:=2*(a()+b()+c())/1e12-3: (nombre gaussien aléatoire)

u:=x2-x1:v:=y2-y1:u1:=-v/sqrt(u^2+v^2):

v1:=u/sqrt(u^2+v^2): (vecteur unitaire normal)

x1,y1,0.5*(x1+x2)+d*u1*2^(-H*i),

0.5*(y1+y2)+d*v1*2^(-H*i), 0.5*(x1+x2)+d*u1*2^(-H*i),

0.5*(y1+y2)+d*v1*2^(-H*i),x2,y2 end:

> liste1:=op([]):for H from 0.1 to 1 by 0.1 do:

liste:=0,0,4,0.4,4,0.4,4.2,4.4,4.2,4.4,0.2,4.8,0.2,4.8,0,0:

for i to 6 do:liste:=seq(f(op(4*j-3..4*j,[liste]),i),

j=1..nops([liste])/4) od:

liste1:=liste1,pointplot([liste],style=line,color=red,

scaling=constrained,axes=none) od:

> display(liste1,insequence=true):

> display(%);


chap4__53.pngfigure 4.21 : île brownienne ; H varie de 0,1 à 1

On voit qu'un dessin d'île réaliste nécessite un exposant de Hurst H, compris entre 0,5 pour une côte tourmentée et 0,8 pour une côte au relief doux.

début chapitre

Montagnes

Pour tracer une montagne, on va généraliser à 2 dimensions la méthode du déplacement aléatoire du milieu utilisée pour le mouvement brownien à une dimension et pour tracer les îles browniennes. On part d'un tableau carré de dimension 3 dont les coefficients sont fixés à 0 sauf le centre dont la valeur est un nombre gaussien aléatoire. Par exemple :
MATH

On intercale ensuite une ligne entre 2 lignes consécutives et de même pour les colonnes. On passe donc à un tableau de dimension 5 dont les coefficients des première et dernière lignes et colonnes sont fixés à 0. On reporte dans les lignes et les colonnes impaires en position impaire les coefficients de a[1]. Restent les coefficients à 2 indices pairs, centres de carrés dont on fixe la valeur en faisant la moyenne des 4 sommets et en ajoutant un nombre gaussien divisé par le facteur sqrt(2^(H*n)) (la racine carrée vient du fait que l'on procède en 2 temps), et les coefficients à un indice pair et l'autre impair auxquels on peut appliquer la même règle puisque les précédents ont été calculés ;par exemple :
MATH

On continue de cette façon, puis on trace les segments joignant les points du tableau considérés comme des altitudes, d'abord ligne par ligne, puis colonne par colonne et on trace le tout :

> restart:with(plots):with(stats):

> H:=0.5:

> a[1]:=array(1..3,1..3):

> for i to 3 do:a[1][i,1]:=0:a[1][1,i]:=0:a[1][3,i]:=0:a[1][i,3]:=0 od:

> b:=stats[random,normald](1): a[1][2,2]:=b:

( $a_{1}(2,2)$ est un nombre gaussien aléatoire)

> s:=4:for m from 1 to s do

n:=2^m:a[n]:=array(1..2*n+1,1..2*n+1):

(on ajoute une ligne et une colonne sur deux)

for i to 2*n+1 do:

a[n][i,1]:=0:a[n][1,i]:=0:a[n][2*n+1,i]:=0:a[n][i,2*n+1]:=0 od:

for p to 2*2^(m-1)+1 do:

for q to 2*2^(m-1)+1 do:

a[n][2*p-1,2*q-1]:=a[2^(m-1)][p,q] od:od:

(on remet les anciennes valeurs en position impaire dans les lignes et colonnes impaires)

for i to 2*n+1 do:

for j to 2*n+1 do:

b:=stats[random,normald](1):if irem(i,2)=0 and irem(j,2)=0 then

a[n][i,j]:=1/4*(a[n][i-1,j-1]+a[n][i+1,j-1]+a[n][i-1,j+1]+

a[n][i+1,j+1])+b/2^(H*n/2) fi od od:

(on calcule les centres des carrés aux deux indices pairs)

for i to 2*n+1 do:

for j to 2*n+1 do:

b:=stats[random,normald](1):if irem(i,2)=0 and irem(j,2)<>0 and j<>1 and j<>2*n+1

or irem(j,2)=0 and irem(i,2)<>0 and i<>1 and i<>2*n+1

then a[n][i,j]:=1/4*(a[n][i,j-1]+a[n][i,j-1]+a[n][i,j+1]+a[n][i,j+1])

+b/2^(H*n/2) fi od od od:

(on complète les éléments à un indice pair et l'autre impair)

> r:=2^s:for i to 2*r+1 do: for j to 2*r+1 do:

if a[r][i,j]<0 then a[r][i,j]:=0 fi od od:

(on supprime les valeurs négatives)

> liste:=op([]):for i to 2*r+1 do: for j to 2*r+1 do:

liste:=liste,[i,j,a[r][i,j]] od:od;

(on dresse la liste des points, ligne par ligne)

> p1:=seq(pointplot3d([op((2*r+1)*i-2*r..(2*r+1)*i,[liste])],

style=line),i=1..2*r+1):

> liste:=op([]):for j to 2*r+1 do: for i to 2*r+1 do:

liste:=liste,[i,j,a[r][i,j]] od:od;

(on dresse la liste des points, colonne par colonne)

> p2:=seq(pointplot3d([op((2*r+1)*i-2*r..(2*r+1)*i,[liste])],

style=line),i=1..2*r+1):

> display(p1,p2,color=red);

Avec H = 0,1, on obtient :


chap4__57.pngfigure 4.22 : montagne avec H=0,1

Avec H = 0,5 :


chap4__58.pngfigure 4.23 : montagne avec H = 0,5

Avec H = 0,9 :


chap4__59.pngfigure 4.24 : montagne avec H = 0,9

Le relief est de plus en plus touffu au fur et à mesure que l'on baisse la valeur de $H.$

début chapitre

Exercices

Exercice 1

L'île aléatoire 3/2

A partir de la courbe 3/2 étudiée à l'exercice 1 du chapitre 2, tracer une île 3/2 aléatoire.

On partira du carré 3/2, et l'on introduit dans la procédure un générateur aléatoire délivrant 0 ou 1, transformés en -1 ou 1 et permettant de changer le sens de la construction, comme on l'a fait pour l'île de Koch aléatoire dans ce chapitre. Les 4 côtés de l'île sont tracés séparément, puis mis en place par des rotations et des translations et finalement tracés ensemble.

Exercice 2

L'île aléatoire des fjords

De la même façon que dans l'exercice 1, tracer l'île aléatoire des fjords, en prenant pour modèle l'île des fjords tracée dans ce chapitre.

Réponses aux exercices

exercice 1

> restart:with(plots):with(plottools):

> segment:=proc(a) local k: global courbe: k:=nops([courbe]):

courbe:=courbe,courbe[k-1]+cos(a),courbe[k]+sin(a) end:

> a:=0:pro:=proc(n) global a:local b,k:

if n=0 then segment(a) else b:=rand(0..1)():

if b=0 then k:=-1 else k:=1 fi:

pro(n-1):a:=a+k*Pi/2: pro(n-1):a:=a-k*Pi/2: pro(n-1):

a:=a-k*Pi/2: pro(n-1):pro(n-1):a:=a+k*Pi/2:pro(n-1):

a:=a+k*Pi/2:pro(n-1): a:=a-k*Pi/2:pro(n-1): fi end:

> courbe:=0,0:p1:=pointplot([pro(3)],scaling=constrained,

style=line,color=red,axes=none):

> courbe:=0,0:p2:=pointplot([pro(3)],scaling=constrained,

style=line,color=red,axes=none):

> courbe:=0,0:p3:=pointplot([pro(3)],scaling=constrained,

style=line,color=red,axes=none):

> courbe:=0,0:p4:=pointplot([pro(3)],scaling=constrained,

style=line,color=red,axes=none):

> p5:=rotate(p2,Pi/2):p6:=translate(p3,0,4^3):

p7:=translate(rotate(p4,Pi/2),4^3,0):

> display(p1,p5,p6,p7);


chap4__61.pngfigure 4.25 : île 3/2 aléatoire

Cette île a pour dimension fractale 3/2.

exercice 2

restart:with(plots):with(plottools):

segment:=proc(l,a) local k: global courbe: k:=nops([courbe]):

courbe:=courbe,courbe[k-1]+l*cos(a),courbe[k]+l*sin(a) end:

> l:=1:a:=0:pro:=proc(n,l) global a:local b,k:

if n=0 then segment(l,a) else b:=rand(0..1)():

if b=0 then k:=-1 else k:=1 fi:

a:=a+k*Pi/4: pro(n-1,sqrt(0.3^2+0.3^2)*l):

a:=a-k*(Pi/4+arctan(0.3/0.2)): pro(n-1,sqrt(0.3^2+0.2^2)*2*l):

a:=a+k*(Pi/4+arctan(0.3/0.2)): pro(n-1,sqrt(0.3^2+0.3^2)*l):

a:=a-k*Pi/4 fi end:

> courbe:=0,0:pro(4,1):p1:=pointplot([courbe],

scaling=constrained,style=line,color=red,axes=none):

> courbe:=0,0:pro(4,1):p2:=pointplot([courbe],

scaling=constrained,style=line,color=red,axes=none):

> courbe:=0,0:pro(4,1):p3:=pointplot([courbe],

scaling=constrained,style=line,color=red,axes=none):

> courbe:=0,0:pro(4,1):

p4:=pointplot([courbe],scaling=constrained,

style=line,color=red,axes=none):

> p5:=rotate(p2,Pi/2):p6:=translate(p3,0,1):

> p7:=translate(rotate(p4,Pi/2),1,0):

> display(p1,p5,p6,p7);


chap4__62.pngfigure 4.26 : île des fjords aléatoire

En fait d'île, cela ressemble plutôt à un mouvement brownien !

début chapitre

retour index