Pasidaryk pats: fraktalai
Parašė: Armandas, 2008-07-30
Kategorijose: Kodas, Python, Smagumynai
Fraktalas yra geometrinė forma, kuriai yra būdingas panašumas į save, bei begalinis detalumas. Mandelbroto aibė yra vienas iš žinomiausių fraktalų pasaulyje, išgarsėjęs apie 1980 metus. Vėlus tokio įspūdingo objekto atsiradimas buvo nulemtas modernių kompiuterių nebuvimo.
Nors Mandelbroto aibė yra begalo (tikrąja šio žodžio prasme) komplikuota forma, ją sugeneruoti galima naudojant neįtikėtinai paprastą formulę: z = z2 + C. Čia z yra iteruojamas kompleksinis skaičius, o C – konstanta – koordinatė kompleksinėje plokštumoje.
Skaičius priklauso Mandelbroto aibei, jei z niekada “nepabėga” į begalybę, nesvarbu kiek iteracijų būtų atlikta. Kadangi mes neturime galimybių tuom įsitikinti, galima nustatyti “pakankamai aukštą” pakartojimų skaičių, ir jei jį peržengus z visdar neviršija dviejų, laikyti, kad skaičius C priklauso Mandelbroto aibei.
Prieš pradedant gaminti savadarbius fraktalus, mums reikia sužinoti aibės ribas ir tuo pačiu nusistatyti keletą konstantų. Koordinačių plokštumoje, fraktalo reliatyvus dydis yra nekintantis. X ašyje z “nepabėga” į begalybę intervale [-2, 0.25]. Y ašyje – [-1, 1]. Kad fraktalas neatrodytų suspaustas, programoje naudosime intervalą [-2.2, 1] X ašiai ir [-1.2, 1.2] Y ašiai. Tokios ribos mums duos proporciją lygią 1.333333, kas reiškia, kad nurodę plotį 1024, aukštį gausime 768. Patogu, ar ne? ;)
Atkreipkite dėmesį, kad X ašyje yra realieji skaičiai, o Y – menamieji.
Žiūrime ką turime:
#kiek iteracijų darysime prieš nuspresdami,
#kad skaičius priklauso aibei.
max_i = 200
#reliatyvūs dydžiai
r_width = 3.2
r_height = 2.4
#pagal proporciją parinksime aukštį
ratio = r_width / r_height
#plotis bus nurodomas vartotojo
width = int(sys.argv[1])
height = int(width / ratio)
#žingsnelis padės apskaičiuoti konkretaus pixelio koordinatę
x_step = r_width / width
y_step = r_height / height
#realiųjų skaičių ašis
x_axis = arange(-2.2, 1.0, x_step).tolist()
#menamųjų skaičių ašis
y_axis = arange(-1.2, 1.2, y_step).tolist()
Ašims generuoti naudojame arange() (ne arrange!) funkciją, nes range() nepriima float tipo argumentų. Funkciją galima importuoti iš Numeric modulio.
Dabar apsirašysime reikalingas funkcijas. Pradėkime nuo skaičiaus z modulio. Jo radimui pritaikysime pitagoro teoremą. Funkcijos rezultatas yra modulio kvadratas, tad tikrindami ar skaičius priklauso aibei, lyginsime ne su dvejetu, o 22 t.y. 4.
def r_sq(z):
"""
Grąžina skaičiaus z modulį.
"""
return z.real**2 + z.imag**2
Dabar pagrindinė funkcija: mandelbrot(). Vienintelis būtinas argumentas – C. Funkcija yra rekursinė, z pradedamas nuo 0+0j ir kaskart jam pritaikoma formulė z = z2 + C. Funkcijos rezultatas – iteratorius i. Pagal jo reikšmę nustatysime kokią spalvą naudoti pikseliui.
def mandelbrot(c, z=0+0j, i=0):
"""
Checks if the number escapes to infinity
"""
if r_sq(z) > 4:
return i
elif i == max_i:
return -1
else:
return mandelbrot(c, (z**2 + c), i+1)
Keisdami laipsnį, kuriuo keliamas z, galite išgauti ir kitokias figūras:

z^3

z^5.5

z^16
Jei darytumėm dvispalvį paveikslą, to mums pakaktų, tačiau spalvotam fraktalui reikia ir spalvinimo funkcijos. Nekursime nieko sudėtingo, panaudosime quick&dirty metodą – spalvų indeksą.
def get_color(iterations):
"""
Grąžina spalvos kodą, priklausomai nuo to, kada
(jei išvis) skaičius "pabėgo" į begalybę
"""
#atrodo, kad schema yra BGR, ne RGB :))
index = {
#iteracijos #spalva
(0, 1): 0xff0000,
(1, 2): 0xff1000,
(2, 3): 0xff2000,
(3, 4): 0xff3000,
(4, 5): 0xff4000,
(5, 6): 0xff5000,
(6, 7): 0xff6000,
(7, 8): 0xff7000,
(8, 10): 0xff9000,
(10, 15): 0xffa600,
(15, 21): 0xffb500,
(21, 50): 0xffdf00,
(50, max_i+1): 0xffffff,
}
for point in index:
if iterations in range(point[0], point[1]):
return index[point]
Visas pixelių spalvas laikysime sąraše, kuris poto labai lengvai bus “sumetamas” į paveiksliuką.
#sukuriame kintamąjį duomenims
out = []
for y in y_axis:
for x in x_axis:
result = mandelbrot(complex(x, y))
if result < 0:
#taškai, priklausantys aibei (juodi)
out.append(0x000000)
else:
#taškai, kurie nepriklauso (gaunam spalvą)
out.append(get_color(result))
Paveikslėlio generavimui naudojam PIL biblioteką. Naudojimas labai paprastas:
img = Image.new('RGB', (width, height))
img.putdata(out)
img.save('m.png')
Turintys python ir norintys išbandyti viską “dykai” gali atsisiųsti scenarijų. Nesitikėkite nieko ypatingo. Programa neturi nei anti-aliasing savybės, nei tolygaus spalvų perėjimo. Įrašas skirtas daugiau supažindinimui, ir džiaugsmo “va pasidariau pats” patyrimui. Norintys kažko “geriau” gali naudoti specializuotas programas :)
Jei patobulinsite šį kodą, ar šiaip turite pastabų – parašykite komentaruose kas ir kaip.

Komentarų: 9
Arvydas
Liepa 31, 2008, 10:56 ryte
Oj fun fun :) Priminei man gerus grafikos programavimo laikus :)
Blogeriai Rašo Nr. 3 | Tomo Čitavičiaus blogas
Liepa 31, 2008, 3:01 vakare
[...] Pasidaryk pats. Iki šiol nieko nežinojau apie fraktalus, bet dabar žinosiu ir būsiu “kietas” :D [...]
Dummas
Rugpjūtis 1, 2008, 9:43 vakare
Žiauriai patiko :] Lauksiu daugiau geometrikos grožių
Liudas
Rugsėjis 12, 2008, 8:28 ryte
“Čia z yra iteruojamas kompleksinis skaičius, o C – konstanta” hmm o tai ne julios fraktala gauname? kiek zinau mandelbrote kinta C dar kitaip R spindulys, o z yra pastovus. Siaip mandelbrotas apibrezia julios aibe, tai tiek
Lifelesss
Sausis 12, 2009, 5:04 vakare
Norėčiau pažaisti su paveiksliukais, tačiau kompiliuojant mane išmeta:
Usage:
C:\Python24\mandelbrot.py
Traceback (most recent call last):
File “C:\Python24\mandelbrot.py”, line 55, in -toplevel-
sys.exit()
SystemExit
Gal turi idėjų? :)
Armandas
Sausis 12, 2009, 10:20 vakare
Gal nenurodai dydžio? Leisk taip:
python mandelbrot.py 320
Lifelesss
Sausis 13, 2009, 12:05 ryte
Išties, dėkui :)
apskritai, kuo toliau tuo labiau susidomiu fraktalais ir chaoso teorija :)
Armandas
Sausis 13, 2009, 12:54 vakare
Puiku. Jei atrasi ką įdomaus – pasidalink.
IFS
Kovas 30, 2010, 10:44 ryte
Visai įspūdingas dalykas yra KIKAItachi fraktalų galerija (http://kikaitachi.org/fractals/lt). Ten visi fraktalai yra sugeneruoti tinklalapio lankytojų parenkant atsitiktines formules.