118 lines
5.6 KiB
Python
118 lines
5.6 KiB
Python
|
# coding: utf-8
|
||
|
#
|
||
|
# Chapitre 6 - TP 2 - Dessiner des fractales (page 129)
|
||
|
#
|
||
|
|
||
|
from math import cos, sin, radians
|
||
|
from matplotlib.colors import rgb2hex
|
||
|
from dessin import Dessin, Trait, Arc, main_loop
|
||
|
|
||
|
|
||
|
# constantes
|
||
|
TAILLE = 800 # taille de la surface de dessin
|
||
|
# la surface de dessin, avec un fond blanc
|
||
|
dessin_arbre = Dessin("white", TAILLE, TAILLE)
|
||
|
|
||
|
|
||
|
def ytree(
|
||
|
n,
|
||
|
x,
|
||
|
y,
|
||
|
orientation_arbre,
|
||
|
longueur,
|
||
|
ecart_angulaire_fils=radians(22.5),
|
||
|
ratio_longueur=0.8,
|
||
|
n_max=None,
|
||
|
):
|
||
|
""" Dessine un arbre binaire ytree de hauteur n+1.
|
||
|
Entrée:
|
||
|
- n : hauteur de l'arbre courant -1
|
||
|
- x,y : coordonnées de la racine de l'arbre
|
||
|
- orientation_arbre : orientation de l'arête partant de la racine du y-tree courant, en radians: radians(0) si horizontale, radians(90) = pi/2 pour orienter verticalement vers le haut
|
||
|
- longueur : longueur de l'arête partant de la racine du y-tree courant
|
||
|
- ratio_longueur : le ratio servant à diminuer la longueur d'un niveau à l'autre.
|
||
|
- n_max : le nombre de niveaux de l'arbre global. Utilisé uniquement pour attribuer la bonne couleur en fonction du niveau du y-tree courant dans l'arbre global.
|
||
|
-------
|
||
|
Un y-tree de niveau 1 (n=1) est un simple trait.
|
||
|
Un y-tree de niveau n>=2 est formé d'un trait suivi de 2 y-trees de niveau n-1.
|
||
|
Dans un y-tree:
|
||
|
=> c'est l'arête rejoignant un noeud à son père qui est l'axe de symétrie entre ses 2 sous-arbres.
|
||
|
=> l'angle entre les fils est constant: 2*ecart_angulaire_fils, donc chaque arête s'écarte de l'arête parente d'un angle +/-'ecart_angulaire_fils'.
|
||
|
On a choisi de diminuer la longueur d'un facteur constant à chaque niveau.
|
||
|
Les branches sont colorées proportionnellement à leur niveau dans l'arbre :
|
||
|
=> le lien partant de la racine globale est noir
|
||
|
=> pour n >= 2, les liens aboutissant aux feuilles sont verts
|
||
|
-------
|
||
|
Complexité: linéaire dans la taille de l'arbre.
|
||
|
"""
|
||
|
if n >= 0:
|
||
|
if n_max == None:
|
||
|
n_max = n
|
||
|
x1 = x + cos(orientation_arbre) * longueur
|
||
|
y1 = y + sin(orientation_arbre) * longueur
|
||
|
couleur = rgb2hex((0.0, 1.0, 0.0))
|
||
|
if n_max >= 1:
|
||
|
couleur = rgb2hex((0.0, float(n_max - n) / (n_max), 0.0))
|
||
|
Trait(dessin_arbre, x, y, x1, y1, couleur)
|
||
|
ytree(n-1, x1, y1, orientation_arbre + ecart_angulaire_fils, longueur*ratio_longueur, ecart_angulaire_fils, ratio_longueur, n_max)
|
||
|
ytree(n-1, x1, y1, orientation_arbre - ecart_angulaire_fils, longueur*ratio_longueur, ecart_angulaire_fils, ratio_longueur, n_max)
|
||
|
# A compléter
|
||
|
# Pour effectuer les appels récursifs :
|
||
|
# - ecart_angulaire_fils, ratio_longueur, n_max ne changent pas
|
||
|
# - la nouvelle origine est x1, y1
|
||
|
# - la longueur diminue et devient longueur*ratio_longueur
|
||
|
# - l'orientation des sous-arbre est obtenue en fonction de orientation_arbre et ecart_angulaire_fils
|
||
|
|
||
|
|
||
|
def dessiner_arbre_binaire_arc(n, x, y, w):
|
||
|
""" Dessine un arbre binaire de hauteur n+1, en représentant les arêtes par des arcs de cercle.
|
||
|
Entrée:
|
||
|
- x,y : coordonnées de la racine de l'arbre
|
||
|
- w : écart horizontal entre les 2 fils de la racine.
|
||
|
- h : écart vertical entre 2 niveaux
|
||
|
- n : hauteur de l'arbre courant -1
|
||
|
-------
|
||
|
L'arbre est représenté verticalement de haut en bas.
|
||
|
Les 2 noeuds sont reliés par des arcs de cercles à leurs parents (1/4 de cercle pour chaque fils, de manière à former un demi-cercle d'un fils à l'autre).
|
||
|
=> C'est l'axe vertical qui est l'axe de symétrie entre les 2 sous-arbres.
|
||
|
=> En divisant w par 2 à chaque niveau, on a la garantie que les branches ne se croisent pas (et comme les noeuds sont de simples points qui n'ont pas de largeur, il n'y a pas de risque que les feuilles se recouvrent).
|
||
|
-------
|
||
|
Complexité: linéaire dans la taille de l'arbre.
|
||
|
"""
|
||
|
if n > 0:
|
||
|
Arc(dessin_arbre, x - w / 2, y, x + w / 2, y + w, 0, 180)
|
||
|
dessiner_arbre_binaire_arc(n-1, x-w/2, y+w/2, w/2)
|
||
|
dessiner_arbre_binaire_arc(n-1, x+w/2, y+w/2, w/2)
|
||
|
|
||
|
|
||
|
def dessiner_arbre_binaire_trait(n, x, y, w, h):
|
||
|
""" Dessine un arbre binaire classique de hauteur n+1.
|
||
|
Entrée:
|
||
|
- x,y : coordonnées de la racine de l'arbre
|
||
|
- w : écart horizontal entre les 2 fils de la racine.
|
||
|
- h : écart vertical entre 2 niveaux
|
||
|
- n : hauteur de l'arbre courant -1
|
||
|
-------
|
||
|
L'arbre est représenté verticalement de haut en bas.
|
||
|
=> C'est l'axe vertical qui est la bisectrice entre les 2 arêtes rejoignant un noeud à ses fils.
|
||
|
=> En divisant w par 2 à chaque niveau, on a la garantie que les branches ne se croisent pas (et comme les noeuds sont de simples points qui n'ont pas de largeur, il n'y a pas de risque que les feuilles se recouvrent).
|
||
|
A vous de modifier pour que cet arbre soit fractal en modifiant l'écart vertical.
|
||
|
Tel qu'il est écrit en l'absence de modification, cet arbre n'est pas réellement fractal car l'angle entre les fils varie à chaque niveau (donc en "zoomant" on n'a pas exactement la même figure que la figure globale).
|
||
|
-------
|
||
|
Complexité: linéaire dans la taille de l'arbre.
|
||
|
"""
|
||
|
# A modifier :
|
||
|
if n > 0:
|
||
|
Trait(dessin_arbre, x, y, x - w / 2, y + h)
|
||
|
Trait(dessin_arbre, x, y, x + w / 2, y + h)
|
||
|
dessiner_arbre_binaire_trait(n - 1, x - w / 2, y + h, w / 2, h)
|
||
|
dessiner_arbre_binaire_trait(n - 1, x + w / 2, y + h, w / 2, h)
|
||
|
|
||
|
|
||
|
# Test :
|
||
|
ytree(10, 100, 200, 0, 50, radians(22.5), .8)
|
||
|
dessiner_arbre_binaire_arc(5, 600, 20, 160)
|
||
|
dessiner_arbre_binaire_trait(5, 600, 400, 160, 40)
|
||
|
|
||
|
main_loop()
|