#! /usr/bin/env python3
# -*- coding: utf-8; mode: python -*-
""" Cadeau de Noël.
Petit script Python pour tracer un sapin de Noël, rédigé par Arnaud Basson, pour le cours d'informatique pour tous en prépa MP au Lycée Lakanal.
- *Date :* Noël 2015 ! (24 décembre 2015),
- *Auteur :* Arnaud Basson, pour le cours d'informatique pour tous en prépa MP (http://perso.crans.org/besson/infoMP/),
- *Licence :* MIT Licence (http://lbesson.mit-license.org).
"""
from __future__ import print_function, division # Python 2 compatibility
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.collections as coll
import matplotlib.animation as anim
[docs]def simil(u, v):
r""" Similitude complexe, donné par ses paramètres u et v.
- Renvoie une *fonction* :math:`f: z \mapsto a \times z + b.`
"""
# Si f(z) = a z + b
# Par définition u = f(0) = b, v = f(i) = a*i + b
# Alors b = u, a = (v-u)/i = i(u-v)
b = u
a = 1j*(u-v)
def f(z):
""" f(z) = a z + b """
return a * z + b
return f
#: 5 similitudes pour le système itéré
#: Première similitude du système itéré,
#: :math:`u = 0.2i, v = 0.2i + 0.5 \mathrm{e}^{(i \pi / 7)}`
f1 = simil(0.2j, 0.2j + 0.5*np.exp(1j*np.pi/7))
#: Seconde similitude du système itéré,
#: :math:`u = 0.22i, v = 0.22i + 0.45 \mathrm{e}^{(60 i \pi / 180)}`
f2 = simil(0.22j, 0.22j + 0.45j*np.exp(1j*60*np.pi/180))
#: Troisième similitude du système itéré,
#: :math:`u = 0.55i, v = 0.55i + 0.35 \mathrm{e}^{(30 i \pi / 180)}`
f3 = simil(0.55j, 0.55j + 0.35*np.exp(1j*30*np.pi/180))
#: Quatrième similitude du système itéré,
#: :math:`u = 0.57i, v = 0.57i + 0.3 i \mathrm{e}^{(i \pi / 3)}`
f4 = simil(0.57j, 0.57j + 0.3j*np.exp(1j*np.pi/3))
#: Cinquième similitude du système itéré,
#: :math:`u = 0.7i, v = .0\mathrm{1} - 1.2i`
f5 = simil(0.7j, 1.2j-0.01)
[docs]def iterer(n):
""" Calculer n itérations du système complexes des 5 similitudes :py:func:`f1`, :py:func:`f2`, :py:func:`f3`, :py:func:`f4`, :py:func:`f5`.
- Renvoie une liste d'affixes *complexes*.
- Complexité temporelle et mémoire en :math:`O(5^n)` (attention à garder n petit !).
"""
L = [0, 0.7j]
L1 = L[:] # Copie
for _ in range(n):
L2 = []
for f in [f1, f2, f3, f4, f5]:
L2.extend([f(z) for z in L1])
L.extend(L2)
L1 = L2
return L
[docs]def tracer(n):
""" Tracer la courbe fractale obtenue par n itérations du F-système.
.. warning:: Cette fonction est un peu complexe...
Ce qui est utilisé dans cette fonction **dépasse complètement le cadre du programme officiel** !
Ne perdez pas trop de temps à comprendre son fonctionnement, et ne retenez aucune des astuces ou idées vues ici.
"""
global sca # Pour que clignoter marche facilement.
# Affixes complexes
L = iterer(n)
pts = [(z.real, z.imag) for z in L]
fig = plt.figure()
# Afficher ces points comme des lignes vertes foncées (le sapin)
segments = coll.LineCollection(zip(pts[::2], pts[1::2]), color='darkgreen')
ax = plt.gca()
ax.add_collection(segments)
# Ajouter des boules clignotantes
nb = 30
l = len(L)
p = l//nb if l >= nb else 1
x = [z.real for z in L[1::p]]
y = [z.imag for z in L[1::p]]
# Alterner sur ces trois couleurs
couleurs = ['red', 'blue', 'yellow']
c = [couleurs[k % len(couleurs)] for k in range(len(x))]
# Afficher ces boules
sca = plt.scatter(x, y, s=60, c=c, zorder=2)
plt.axis('equal')
plt.ylim(0, 1.45)
plt.xticks([])
plt.yticks([])
# Lancer l'animation
a = anim.FuncAnimation(fig,
clignoter,
interval=20, # nb itérations
repeat=False,
blit=True # True to only draw what have changed
)
plt.show()
# FIXME not working on Windows!
# Conclude by saving the animation
a.save('sapinNoel.mp4',
fps=1,
writer='ffmpeg')
# And saving as a GIF file also works now :)
a.save('sapinNoel.gif',
fps=1,
writer='imagemagick')
# Fin tracer
[docs]def clignoter(i):
""" Fonction pour faire changer les boules de couleurs à chaque itération de l'animation !"""
coul = sca.get_facecolor() # array N*4 (RGBA)
coul2 = np.zeros_like(coul)
coul2[:-1] = coul[1:]
coul2[-1] = coul[0]
sca.set_facecolor(coul2)
# On conclut par lancer l'animation !
if __name__ == '__main__':
tracer(6)
# Fin sapinNoel.py