Von Koch et ses amis

A propos du code

Le code dans cet article a été écrit avec Code::Blocks et la SDL 2.
Vous pouvez trouver ici un guide pour installer ces logiciels.
Bien qu'il soit basé sur la SDL, je n'utilise pas ses fonctions directement. J'ai écrit une petite bibliothèque
avec quelques fonctions basiques pour faciliter la compréhension et la portabilité dans un autre langage.
Vous pouvez en apprendre plus sur cette bibliothèque ici.

Dans cet article j'utilise la classe Vec2f dont j'ai commencé à parler ici.

La courbe de von Koch

La courbe de von Koch est une des fractales les plus simples et elle est souvent utilisée comme exemple pour
enseigner ce qu'est une fractale.
Voici la définition de sa première étape. D'abord on commence avec une ligne que l'on suppose d'une longueur de 1
pour simplifier.


On la divise ene 3 parts égales:


On retire celle du milieu.


Et on dessine 2 autres segments à un angle de 60° de façon à ce que la partie centrale ressemble à un triangle
équilatéral sans le bas.


Puis, on répète ce processus pour chacun de ces 4 segments. On le répète pour chaque nouveau segment qu'on a créé.
Et ainsi de suite.

Alors pour coder ça on va écrire une fonction vonKoch qui va prendre les points de départ et de fin de la ligne,
ainsi qu'une variable level qu'on expliquera plus tard.
		void vonKoch(Vec2f p1, Vec2f p2, int level)
		{
				
On va calculer les positions des points N0, N1 et N2 comme décrit ci-dessus.
			Vec2f   n[3];

			Vec2f   v12 = p2 - p1;
			n[0] = p1 + v12 * 1 / 3;
			n[2] = p1 + v12 * 2 / 3;

			Vec2f   v02 = n[2] - n[0];
			v02.rotate(DEG_TO_RAD(-60));
			n[1] = n[0] + v02;
				
Puis on va rappeler la fonction pour chaque segment qu'on a
			vonKoch(  p1, n[0], level + 1);
			vonKoch(n[0], n[1], level + 1);
			vonKoch(n[1], n[2], level + 1);
			vonKoch(n[2],   p2, level + 1);
		}
				
Mais si on exécute ce programme tel quel il ne sortira jamais de cette fonction.
On a besoin d'un moyen d'en sortir après un nombre donné d'itérations.
Alors au début de la fonction, on va tester la variable level qui est en fait un simple compteur.
		int maxLevel = 5;

		void vonKoch(Vec2f p1, Vec2f p2, int level)
		{
			if (level >= maxLevel)
			{
				
Et comme on est ici au niveau maximum, on va dessiner la ligne a l'écran et sortir de la fonction.
				gfx.line(p1.x, p1.y, p2.x, p2.y, Color(255, 255, 255));
				return;
			}
				
Ensuite dans la fonction principale, on va simplement appeler la fonction vonKoch avec les coordonnées de notre
ligne de départ.
		Vec2f   left (             0, SCREEN_HEIGHT/2);
		Vec2f   right(SCREEN_WIDTH-1, SCREEN_HEIGHT/2);

		vonKoch(left, right, 0);

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voici le résultat de ce programme:


Animation

La façon la plus simple d'animer ce programme est de faire un rendu à l'écran et d'attendre un peu juste après
qu'on ait tracé la ligne.
Comme les appels à vonKoch() sont ordonnés, on va voir la courbe se dessiner de la gauche vers la droite.
		if (level >= maxLevel)
		{
			gfx.line(p1.x, p1.y, p2.x, p2.y, Color(255, 255, 255));
			gfx.render();
			sys.wait(20);
			return;
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Mais il y a une meilleure façon de l'animer en affichant les étapes successives de la fractale.
Pour faire ça on doit appeler la fonction d'affichage à l'intérieur de la boucle principale.
		int cnt = 0;

		// wait until we quit
		while (sys.isQuitRequested() == false)
		{
			if (cnt == 0)
			{
				gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));
				vonKoch(left, right, 0);
			}
				
La variable cnt est un compteur qui va être incrémenté. Et à chaque fois qu'il atteindra 50, on va incrémenter la
variable maxLevel jusqu'à ce qu'elle atteigne une valeur maximale.
			cnt++;

			if (maxLevel < 6 && cnt == 50)
			{
				cnt = 0;
				maxLevel++;
			}
				
Comme on attend pendant 20 ms à chaque tour de boucle, maxLevel sera incrémenté tous les 50 * 20 ms, donc toutes
les secondes.
			gfx.render();
			sys.wait(20);
			sys.processEvents();
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				

Le flocon de von Koch

Le flocon de von Koch utilise la même règle que la courbe de von Koch.
Mais maintenant on démarre avec un triangle au lieu d'une seule ligne.


		Vec2f   left (SCREEN_WIDTH/2 - SCREEN_WIDTH/4, (SCREEN_HEIGHT*5)/18);
		Vec2f   right(SCREEN_WIDTH/2 + SCREEN_WIDTH/4, (SCREEN_HEIGHT*5)/18);

		Vec2f   v = right - left;
		v.rotate(DEG_TO_RAD(60));
		Vec2f   bottom = left + v;
				
Ensuite, on va appeler la fonction de dessin 3 fois. Une fois pour chaque ligne.
		if (cnt == 0)
		{
			gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));
			vonKoch(left,   right,  0);
			vonKoch(right,  bottom, 0);
			vonKoch(bottom, left,   0);
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voici le résultat après 5 étapes:


La fractale Cesàro

La fractale Cesàro est une version plus pointue de la courbe de von Koch.
La construction est la même mais l'angle des segments centraux est plus grand que 60°.


Pour programmer ça j'ai choisi un angle de 80°:
		Vec2f   n[3];

		Vec2f   v12 = p2 - p1;
		n[0] = p1 + v12 * 0.427f;
		n[2] = p2 - v12 * 0.427f;

		Vec2f   v = n[0] - p1;
		v.rotate(DEG_TO_RAD(-80));
		n[1] = n[0] + v;

		vonKoch(  p1, n[0], level + 1);
		vonKoch(n[0], n[1], level + 1);
		vonKoch(n[1], n[2], level + 1);
		vonKoch(n[2],   p2, level + 1);

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voici à quoi ça ressemble:


La pyramide de carrés

Si on suit l'idée de la fractale Cesàro jusqu'à 90° on finit avec un modèle en forme de "T":


		Vec2f   n[3];

		Vec2f   v12 = p2 - p1;
		n[0] = p1 + v12 / 2;
		n[2] = n[0];

		Vec2f   v = n[0] - p1;
		v.rotate(DEG_TO_RAD(-90));
		n[1] = n[0] + v;

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voilà le résultat:


L'ensemble de Cantor

La règle de l'ensemble de Cantor commence comme celle de von Koch's mais on s'arrête après avoir retiré le segment
du milieu:


		Vec2f   n[2];

		Vec2f   v12 = p2 - p1;
		n[0] = p1 + v12 * 1 / 3;
		n[1] = p1 + v12 * 2 / 3;

		vonKoch(  p1, n[0], level + 1);
		vonKoch(n[1],   p2, level + 1);

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voici ce qu'on obtient après 5 itérations:


La von Koch quadratique

La règle de la von Koch quadratique est la suivante:


		Vec2f   n[7];

		Vec2f   v  = (p2 - p1) / 4;
		Vec2f   v2 = v;
		v2.rotate(DEG_TO_RAD(-90));

		n[0] = p1 + v;
		n[6] = p2 - v;

		n[1] = n[0] + v2;
		n[5] = n[6] - v2;

		n[2] = n[1] + v;
		n[4] = n[5] - v;

		n[3] = (n[2] + n[4]) / 2;

		vonKoch(  p1, n[0], level + 1);
		vonKoch(n[0], n[1], level + 1);
		vonKoch(n[1], n[2], level + 1);
		vonKoch(n[2], n[3], level + 1);
		vonKoch(n[3], n[4], level + 1);
		vonKoch(n[4], n[5], level + 1);
		vonKoch(n[5], n[6], level + 1);
		vonKoch(n[6],   p2, level + 1);

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Voilà ce qu'on a après 4 itérations:


L'île quadratique

Si on applique la règle quadratique sur un carré on obtient ce qu'on appelle une île quadratique ou un flocon
quadratique.
		Vec2f   p[4];
		p[0] = Vec2f(SCREEN_WIDTH/2 - SCREEN_HEIGHT/4,  SCREEN_HEIGHT   /4);
		p[1] = Vec2f(SCREEN_WIDTH/2 + SCREEN_HEIGHT/4,  SCREEN_HEIGHT   /4);
		p[3] = Vec2f(SCREEN_WIDTH/2 - SCREEN_HEIGHT/4, (SCREEN_HEIGHT*3)/4);
		p[2] = Vec2f(SCREEN_WIDTH/2 + SCREEN_HEIGHT/4, (SCREEN_HEIGHT*3)/4);

		[...]

		for (int i = 0; i < 4; i++)
		{
			int n = (i + 1) %4;
			vonKoch(p[i], p[n], 0);
		}

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voici de quoi elle a l'air:


La courbe "C"

Maintenant, essayons d'appliquer cette règle:


		Vec2f v12 = p2 - p1;
		v12 /= sqrt(2);
		v12.rotate(DEG_TO_RAD(-45));
		Vec2f n = p1 + v12;

		vonKoch(p1,  n, level + 1);
		vonKoch( n, p2, level + 1);

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voilà ce qu'on voit après 10 itérations:


La courbe Peano-like

La dernière règle est un peu plus complexe:


Elle s'inspire de la courbe de Peano.
		Vec2f   n[8];

		Vec2f   v12  = (p2 - p1) * 4.0f / 15.0f;
		Vec2f   v12b = v12;
		Vec2f   v12c = v12;

		v12b.rotate(DEG_TO_RAD(-80));
		v12c.rotate(DEG_TO_RAD(80));

		n[0] = p1 + v12;
		n[7] = p2 - v12;

		n[1] = n[0] + v12b;
		n[6] = n[7] - v12b;

		n[2] = n[1] + v12;
		n[5] = n[6] - v12;

		n[3] = n[2] + v12c;
		n[4] = n[5] - v12c;

		vonKoch(  p1, n[0], level + 1);
		vonKoch(n[0], n[1], level + 1);
		vonKoch(n[1], n[2], level + 1);
		vonKoch(n[2], n[3], level + 1);
		vonKoch(n[3], n[4], level + 1);
		vonKoch(n[4], n[5], level + 1);
		vonKoch(n[5], n[6], level + 1);
		vonKoch(n[6], n[7], level + 1);
		vonKoch(n[7],   p2, level + 1);

		Télécharger le code source
		Télécharger l'exécutable pour Windows
				
Et voilà le résultat après 4 itérations.


Liens

Vidéo des programmes de cet article

Vidéo: courbe de von Koch en Javascript

Science et Vie Micro n°6 page 92