Dessiner la fractale de Mandelbrot

Pour commencer ma découverte de displayio, j'ai commencé avec un bitmap et une palette de couleur. La fractale de Mandelbrot est l'objet idéal pour commencer à jouer avec displayio.

Le bitmap reçoit les informations sur les pixels, chaque pixel étant codé par une couleur de 0 à 100. La couleur correspond au temps que met a suite itérée \(z_{n+1}=z_n+c\) à sortir du disque de rayon 2.

La palette associe à chaque numéro de couleur la couleur codée en RVB. La fonction ColorMap() permet de créer un dégradé.

Ensuite, on définit une grille contenant une tuile et on définit un groupe contenant cette grille. Un groupe est ce qui sera affiché à l'écran.

Il ne reste plus qu'à actualiser le bitmap avec les calculs de la fractale et d'afficher l'écran à chaque fois qu'une colonne est calculée.

MéthodeLe programme

Voici le programme complet. La partie Initialisation de l'écran est propre à l'écran que j'utilise. Si vous utilisez un autre écran, il faudra adapter. Cette partie peut être simplifiée si vous utilisez une carte pyPortal ou pyBadge car l'écran est accessible via board.DISPLAY.

1
import board
2
import displayio
3
import busio
4
5
#############################
6
# Initialisation de l'ecran #
7
#############################
8
9
_INIT_SEQUENCE = bytearray(
10
    b"\x01\x80\x96" # SWRESET and Delay 150ms
11
    b"\x11\x80\xff" # SLPOUT and Delay
12
    b"\xb1\x03\x01\x2C\x2D" # _FRMCTR1
13
    b"\xb2\x03\x01\x2C\x2D" # _FRMCTR2
14
    b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D" # _FRMCTR3
15
    b"\xb4\x01\x07" # _INVCTR line inversion
16
    b"\xc0\x03\xa2\x02\x84" # _PWCTR1 GVDD = 4.7V, 1.0uA
17
    b"\xc1\x01\xc5" # _PWCTR2 VGH=14.7V, VGL=-7.35V
18
    b"\xc2\x02\x0a\x00" # _PWCTR3 Opamp current small, Boost frequency
19
    b"\xc3\x02\x8a\x2a"
20
    b"\xc4\x02\x8a\xee"
21
    b"\xc5\x01\x0e" # _VMCTR1 VCOMH = 4V, VOML = -1.1V
22
    b"\x20\x00" # _INVOFF
23
    b"\x36\x01\xb8" # _MADCTL bottom to top refresh
24
    # 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie,
25
    # fix on VTL
26
    b"\x3a\x01\x05" # COLMOD - 16bit color
27
    b"\xe0\x10\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10" # _GMCTRP1 Gamma
28
    b"\xe1\x10\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10" # _GMCTRN1
29
    b"\x13\x80\x0a" # _NORON
30
    b"\x29\x80\x64" # _DISPON
31
)
32
33
displayio.release_displays()
34
_tft_spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI)
35
_tft_spi.try_lock()
36
_tft_spi.configure(baudrate=24000000)
37
_tft_spi.unlock()
38
_fourwire = displayio.FourWire(_tft_spi, command=board.A3,
39
                               chip_select=board.A2,reset=board.A4)
40
display = displayio.Display(_fourwire, _INIT_SEQUENCE, width=160, height=128,
41
                            rotation=0, backlight_pin=board.A5)
42
display.auto_brightness = True
43
44
#############################
45
# Dessin d'un bitmap        #
46
#############################
47
48
# Definition des constantes
49
N=100
50
WIDTH=160
51
HEIGHT=128
52
53
# Echelle
54
CENTER = (-.7435669, .1314023)
55
DIAMX = .0022878
56
#CENTER = (-0.5, 0)
57
#DIAMX = 3
58
DIAMY = DIAMX*HEIGHT/WIDTH
59
XMIN=CENTER[0]-DIAMX/2
60
XMAX=CENTER[0]+DIAMX/2
61
YMIN=CENTER[1]-DIAMY/2
62
YMAX=CENTER[1]+DIAMY/2
63
64
dx=(XMAX-XMIN)/WIDTH
65
dy=(YMAX-YMIN)/HEIGHT
66
67
# definition de l'objet bitmap
68
bitmap = displayio.Bitmap(WIDTH, HEIGHT, N)
69
70
# construction de la palette de N couleurs
71
def ColorMap(p):
72
    sr=0 ; sg=0 ; sb=0;
73
    if (p < 64):
74
        sr=0 ; sg=p*4 ; sb=255;
75
    elif (p < 128):
76
        sr=0 ; sg=255 ; sb=(255-(p-64)*4);
77
    elif (p < 192):
78
        sr=(p-128)*4 ; sg=255  ;sb = 0;
79
    elif (p < 256):
80
        sr=255 ; sg=(256-(p-191)*4) ; sb=0;
81
    return (sr,sg,sb);
82
83
palette = displayio.Palette(N)
84
for i in range(N):
85
    r=255*i//(N-1)
86
    s=ColorMap(r)
87
    palette[i]=s[0]*2**16+s[1]*2**8+s[2]
88
palette[0]=0
89
palette[1]=0xffffff
90
91
# On construit une grille contenant le bitmap
92
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette)
93
# On cree un groupe contenant la grille
94
group = displayio.Group()
95
group.append(tile_grid)
96
display.show(group)
97
98
#############################
99
# Dessin de Mandelbrot      #
100
#############################
101
102
def mandelbrot(x,y,iter):
103
    c=x+y*1j
104
    z=c
105
    i=0
106
    while abs(z)<2 and i<iter:
107
       i+=1
108
       z=z*z+c
109
    return -1 if i>=iter else i
110
    
111
x=XMIN
112
for xp in range(WIDTH):
113
    y=YMIN
114
    for yp in range(HEIGHT):
115
        bitmap[xp,yp]=mandelbrot(x,y,N-1)+1
116
        y += dy
117
    x += dx
118
    display.refresh_soon()
119
    
120
# Attente
121
while True:
122
    pass

ComplémentChanger de zone

Vous pouvez jouer sur les variables d'échelle pour changer la zone affichée. Pour avoir la fractale de Mandelbrot en entier, voici des paramètres qui conviennent.

1
# Echelle
2
CENTER = (-0.5, 0)
3
DIAMX = 3