Obsah
1. Parametrizace Mandelbrotovy množiny
2. Nastavení hodnoty „perturbation“
3. Změna podmínky použité pro ukončení iterační smyčky
4. Vzdálenost od horizontální či vertikální přímky
5. Vzdálenost od zadaného bodu v komplexní rovině
6. animace, Animace, ANIMACE
7. Literatura a odkazy na Internetu
8. Obsah dalšího pokračování tohoto seriálu
1. Parametrizace Mandelbrotovy množiny
V předchozích částech tohoto seriálu jsme si ukázali několik metod ovlivňujících způsob vybarvení bodů (pixelů) ležících jak uvnitř Mandelbrotovy množiny, tak i vně. Samotný charakteristický tvar tohoto jistě velmi zajímavého fraktálního útvaru se však při použití popisovaných metod nijak nezměnil – stále se jednalo o jakousi hrušku s přilehlými, přibližně kruhovými obrazci. V dnešním pokračování seriálu o fraktálech si ukážeme několik způsobů, kterými lze ovlivnit tvar Mandelbrotovy množiny, tj. hranici mezi body ležícími vně a uvnitř. Ve druhé kapitole bude popsána metoda, při níž se nastavuje takzvaná hodnota „perturbation“ (rozrušení resp. poškození původní struktury) a ve třetí i čtvrté kapitole metoda používající rozšířenou podmínku pro ukončení iterační smyčky.
2. Nastavení hodnoty „perturbation“
Velmi často používanou metodou sloužící ke změně tvaru Mandelbrotovy množiny, je nastavení takzvané hodnoty „perturbation“ (jde o anglické slovo značící rozrušení nebo poškození). Pomocí upravené funkce vypočítávající body uvnitř a vně množiny je možné vykreslovat i nespojité varianty Mandelbrotovy množiny – jak jsem se již zmínil v předchozí části tohoto seriálu, je matematicky dokázáno, že Mandelbrotova množina je spojitá. Princip použití hodnoty „perturbation“ je poměrně jednoduchý: zatímco je klasická Mandelbrotova množina vykreslována jako množství bodů (pixelů), jejichž nulový orbit nediverguje, u metody využívající hodnotu „perturbation“ se nepočítá s nulovým orbitem, ale orbitem začínajícím v předem zadaném a obecně nenulovém bodě P=[pcx, pcy]; pozice tohoto bodu odpovídá komplexnímu číslu pcx+i×pcy. Upravená procedura pro výpočet a překreslení obarvené Mandelbrotovy množiny může vypadat následovně, přičemž programové řádky, na nichž se „perturbation“ nastavuje, jsou zobrazeny tučně:
//-----------------------------------------------------------------------------
// Výpočet a překreslení Mandelbrotovy množiny s možností změny tvaru množiny
// pomocí hodnoty "perturbace".
//-----------------------------------------------------------------------------
void recalcMandelbrotPerturbation(
pixmap *pix, // pixmapa určená pro vykreslování
int maxiter, // maximální počet iterací
double pcx, // nastavená hodnota perturbace
double pcy)
{
double zx, zy, zx2, zy2; // složky komplexní proměnné Z a Z^2
double cx, cy; // složky komplexní konstanty C
double cx0, cy0;
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b; // barvové složky vykreslovaného pixelu
cy0=-2.0; // hranice zobrazené části množiny na imaginární ose
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
cx0=-2.0; // hranice zobrazené části množiny na reálné ose
for (x=0; x<pix->width; x++) { // pro všechny pixely na obrazovém řádku
cx=cx0; // nastavit počáteční hodnotu Z(P)
cy=cy0;
zx=pcx;
zy=pcy; // nastavení hodnoty perturbace
for (iter=0; iter<maxiter; iter++) {// iterační smyčka
zx2=zx*zx; // zkrácený výpočet druhé mocniny složek Z
zy2=zy*zy;
if (zx2+zy2>4.0) break; // kontrola překročení meze divergence
zy=2.0*zx*zy+cy; // výpočet Z(n+1)
zx=zx2-zy2+cx;
}
r=127+127.0*sin(iter/30.0); // výpočet červené barvové složky pixelu
g=iter*30; // výpočet zelené barvové složky pixelu
b=127-127.0*sin(iter/30.0); // výpočet modré barvové složky pixelu
if (iter==maxiter)
putpixel(pix, x, y, 0, 0, 0); // body ležící uvnitř Mandelbrotovy množiny
else // jsou vykresleny černou barvou
putpixel(pix, x, y, r, g, b);
cx0+=(4.0)/pix->width; // posun na další bod (pixel) na obrazovém řádku
}
cy0+=(4.0)/pix->height; // posun na další obrazový řádek
}
}
//-----------------------------------------------------------------------------
Výše uvedená funkce recalcMandelbrotPerturbation() je použita i v dnešním prvním demonstračním příkladu. Po překladu a spuštění tohoto příkladu se zobrazí dva pohledy na Mandelbrotovu množinu. Levý pohled zobrazuje klasickou spojitou Mandelbrotovu množinu, pravý pohled potom množinu vypočtenou pomocí funkce recalcMandelbrotPerturbation(). Pohybem myši se stlačeným levým tlačítkem po prvním obrázku Mandelbrotovy množiny se mění pozice bodu P=[pcx, pcy] v komplexní rovině a tím i tvar pravé Mandelbrotovy množiny.
Obrázek 2: Screenshot prvního demonstračního příkladuNa dalších obrázcích jsou zobrazeny různé pohledy na nespojitou Mandelbrotovu množinu s nastavenou nenulovou hodnotou „perturbation“. Důležité parametry použité při generování těchto obrázků:
Číslo obrázku | Střed a zvětšení | Perturbation | Počet iterací |
---|---|---|---|
1 | –0.84972634450000000/-0.21635949050000000/563.3417 | 0.03/0 | 255 |
3 | –0.84988067063249730/-0.21610365035559480/2339.764 | 0.03/0 | 200 |
4 | –0.19736137150000000/-0.65680499250000000/2591.483 | 0/0.1 | 500 |
5 | –1.30452/-0.0731618/555.4548 | 0/0.05 | 255 |
6 | +0.34283324800000000/+0.04698910285000000/4017.638 | 0/0.02 | 255 |
3. Změna podmínky použité pro ukončení iterační smyčky
Další možností, jak změnit tvar Mandelbrotovy množiny, je modifikace podmínek nutných pro ukončení iterační smyčky. Z předchozích částí seriálu víme, že iterační smyčka je ukončena buď po dosažení zadaného maximálního množství iterací, nebo v případě, že je splněna podmínka divergence, tj. |zi|>2. V dalších dvou kapitolách jsou popsány dvě metody vytvářející zajímavě vypadající obrázky, které jsem objevil při studiu Mandelbrotovy množiny. Nedělám si však nárok na prvenství, myšlenky na modifikaci podmínek v iterační smyčce se objevují již po dlouhou dobu.
4. Vzdálenost od horizontální či vertikální přímky
Tato metoda modifikace tvaru Mandelbrotovy množiny spočívá v tom, že se testuje, zda se každý iterovaný bod v posloupnosti zi nepřiblížil k zadané horizontální či vertikální přímce. Tyto přímky jsou specifikovány pouze jedním bodem P'=[pcx, pcy], který je umístěn v místě jejich průniku. Dále uvedená funkce recalcMandelbrotHorizVertDist() je použita v dnešním druhém demonstračním příkladu, který je, podobně jako příklad první, interaktivní, tj. pohybem myši po Mandelbrotově množině se mění pozice bodu P'=[pcx, pcy] v komplexní rovině. Vzhledem k tomu, že se testuje okolí jakéhosi kříže položeného v komplexní rovině, odpovídají tomu také výsledné obrázky – i na nich je patrný kříž, který je však díky iteracím, při nichž dochází k natáčení bodů, rozdělen na velké množství vzájemně pootočených a posunutých ramen.
//-----------------------------------------------------------------------------
// Výpočet a překreslení Mandelbrotovy množiny se změněnou podmínkou pro
// ukončení iterační smyčky. Jako doplněk k původní podmínkce je přidán test
// na vzdálenost k vertikánlní přímce y=pcy a horizontální přímce x=pcx.
//-----------------------------------------------------------------------------
void recalcMandelbrotHorizVertDist(
pixmap *pix, // pixmapa určená pro vykreslování
int maxiter, // maximální počet iterací
double pcx, // vzdálenost vertikální přímky od počátku
double pcy) // vzdálenost horizontální přímky od počátku
{
double zx, zy, zx2, zy2; // složky komplexní proměnné Z a Z^2
double cx, cy; // složky komplexní konstanty C
double cx0, cy0;
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b; // barvové složky vykreslovaného pixelu
cy0=-2.0; // hranice zobrazené části množiny na imaginární ose
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
cx0=-2.0; // hranice zobrazené části množiny na reálné ose
for (x=0; x<pix->width; x++) { // pro všechny pixely na obrazovém řádku
cx=cx0; // nastavit počáteční hodnotu Z(0)
cy=cy0;
zx=zy=0.0; // nastavení nulového orbitu
for (iter=0; iter<maxiter; iter++) {// iterační smyčka
zx2=zx*zx; // zkrácený výpočet druhé mocniny složek Z
zy2=zy*zy;
if (iter>1) // rozšiřující podmínka ukončení iterační smyčky
if (fabs(zx+pcx)<0.01 || fabs(zy+pcy)<0.01) // test na vzdálenost od přímek
break;
if (zx2+zy2>4.0) break; // kontrola překročení meze divergence
zy=2.0*zx*zy+cy; // výpočet Z(n+1)
zx=zx2-zy2+cx;
}
r=127+127.0*sin(iter/30.0); // výpočet červené barvové složky pixelu
g=iter*30; // výpočet zelené barvové složky pixelu
b=127-127.0*sin(iter/30.0); // výpočet modré barvové složky pixelu
if (iter==maxiter)
putpixel(pix, x, y, 0, 0, 0); // body ležící uvnitř Mandelbrotovy množiny
else // jsou vykresleny černou barvou
putpixel(pix, x, y, r, g, b);
cx0+=(4.0)/pix->width; // posun na další bod (pixel) na obrazovém řádku
}
cy0+=(4.0)/pix->height; // posun na další obrazový řádek
}
}
//-----------------------------------------------------------------------------
Obrázek 7: Screenshot druhého demonstračního příkladu
5. Vzdálenost od zadaného bodu v komplexní rovině
Další metodou, která je použita ve třetím demonstračním příkladu, je generován obrázek Mandelbrotovy množiny, v němž se objevují kruhy s různým poloměrem. Metoda spočívá v modifikaci iterační smyčky tak, že je smyčka ukončena v případě, že se iterovaný bod posloupnosti zn přiblížil k zadanému bodu P''=[pcx, pcy]. Funkce pro generování Mandelbrotovy množiny tímto způsobem vypadá následovně:
//-----------------------------------------------------------------------------
// Výpočet a překreslení Mandelbrotovy množiny se změněnou podmínkou pro
// ukončení iterační smyčky. Jako doplněk k původní podmínce je přidán test
// na vzdálenost od zadaného bodu [pcx, pcy].
//-----------------------------------------------------------------------------
void recalcMandelbrotDistPoint(
pixmap *pix, // pixmapa určená pro vykreslování
int maxiter, // maximální počet iterací
double pcx, // bod, od kterého se počítá vzdálenost
double pcy)
{
double zx, zy, zx2, zy2; // složky komplexní proměnné Z a Z^2
double cx, cy; // složky komplexní konstanty C
double cx0, cy0;
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b; // barvové složky vykreslovaného pixelu
cy0=-2.0; // hranice zobrazené části množiny na imaginární ose
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
cx0=-2.0; // hranice zobrazené části množiny na reálné ose
for (x=0; x<pix->width; x++) { // pro všechny pixely na obrazovém řádku
cx=cx0; // nastavit počáteční hodnotu Z(0)
cy=cy0;
zx=zy=0.0; // nastavení nulového orbitu
for (iter=0; iter<maxiter; iter++) {// iterační smyčka
zx2=zx*zx; // zkrácený výpočet druhé mocniny složek Z
zy2=zy*zy;
if (iter>1) // rozšiřující podmínka ukončení iterační smyčky
if (dist(zx, zy, pcx, pcy)<0.05) // výpočet vzdálenosti od zadaného bodu
break;
if (zx2+zy2>4.0) break; // kontrola překročení meze divergence
zy=2.0*zx*zy+cy; // výpočet Z(n+1)
zx=zx2-zy2+cx;
}
r=127+127.0*sin(iter/30.0); // výpočet červené barvové složky pixelu
g=iter*30; // výpočet zelené barvové složky pixelu
b=127-127.0*sin(iter/30.0); // výpočet modré barvové složky pixelu
if (iter==maxiter)
putpixel(pix, x, y, 0, 0, 0); // body ležící uvnitř Mandelbrotovy množiny
else // jsou vykresleny černou barvou
putpixel(pix, x, y, r, g, b);
cx0+=(4.0)/pix->width; // posun na další bod (pixel) na obrazovém řádku
}
cy0+=(4.0)/pix->height; // posun na další obrazový řádek
}
}
//-----------------------------------------------------------------------------
Obrázek 8: Screenshot třetího demonstračního příkladu
6. animace, Animace, ANIMACE
Všechny tři výše uvedené demonstrační příklady byly naprogramovány jako interaktivní aplikace, ve kterých se změna hodnoty perturbace, popř. doplňkových podmínek pro ukončení iterační smyčky, prováděla pomocí myši. Změnu hodnot ovlivňujících výpočet Mandelbrotovy množiny je však možné provádět automaticky a vytvářet tak animace i bez přímého zásahu uživatele. Další tři demonstrační příklady (a k nim přináležející animace) byly vytvořeny tak, že se parametry pcx a pcy průběžně měnily, přičemž zobrazení těchto parametrů do komplexní roviny vytvořilo spirálu začínající v bodě 1,5+0i a končící v bodě 0+0i; celkem je vytvořeno pět „otáček“ spirály. Na spirále je vytvořeno přesně tolik bodů, kolik má mít výsledná animace snímků. Tato hodnota je uložena v symbolické konstantě FRAMES a je ji možno nastavit na jakékoli přirozené číslo větší než 1. Část kódu, která zajišťuje vytvoření pixmapy, výpočet bodů na spirále, vygenerování Mandelbrotovy množiny pro parametry pcx a pcy a následné uložení snímku animace, vypadá následovně:
puts("processing:");
// vytvoření a prvotní smazání pixmapy
pix=createPixmap(PIXMAP_WIDTH, PIXMAP_HEIGHT);
clearPixmap(pix);
// průběžná změna hodnot a současné vytváření obrázků pro animaci
for (i=0; i<FRAMES; i++) {
sprintf(name, "%s%03d%s", FILE_NAME, i, ".tga");
printf("%3d\t", i);
pcx=amp*cos(10.0*3.1415*i/FRAMES); // spirála končící v bodě 0+0i
pcy=amp*sin(10.0*3.1415*i/FRAMES);
amp=1.5-1.5*i/FRAMES;
recalcMandelbrot(pix, MAXITER, pcx, pcy);
savePixmap(pix, name);
}
puts("\ndone!\n");
Čtvrtý demonstrační příklad je použit pro vytvoření animace, s Mandelbrotovou množinou, při jejímž generování se průběžně mění hodnota perturbace. Funkce provádějící výpočet Mandelbrotovy množiny je u tohoto příkladu stejná jako v dnešním prvním demonstračním příkladu – viz druhá kapitola.
Pátý demonstrační příklad posloužil k vytvoření animace s Mandelbrotovou množinou, u níž se v každé iteraci testovalo, zda se iterovaný bod zn nepřiblížil k horizontální či vertikální přímce y=pcy resp. x=pcx. Funkce pro výpočet Mandelbrotovy množiny odpovídá funkci uvedené ve čtvrté kapitole.
Podobným způsobem vznikla i další animace, která byla vykreslena v šestém demonstračním příkladu. V příslušné funkci pro výpočet Mandelbrotovy množiny se prováděl test, zda se iterovaný bod zn nepřiblížil k bodu P''=[pcx, pcy] na pevně zadanou vzdálenost. Funkce použitá pro výpočet Mandelbrotovy množiny tímto způsobem byla uvedena v páté kapitole.
7. Literatura a odkazy na Internetu
- Barnsley Michael, Devaney R. L., Mandelbrot Benoit B., Peitgenn Heinz-Otto, Saupe Dietmar, Voss Richard:
„The Science of Fractal Images“,
Springer-Verlag, New York, 1988 - Peitgen Heinz-Otto, Richter Peter:
„The Beauty of Fractals“,
Springer-Verlag, New York, 1986, ISBN 0–387–15851–0 - Peitgen Heinz-Otto, Jurgens Hartmut, Saupe Dietmar:
„Fractals For The Classroom“,
Springer-Verlag, New York, 1988 - Peitgen Heinz-Otto, Jurgens Hartmut, Saupe Dietmar:
„Chaos and Fractals: New Frontiers of Science“,
Springer-Verlag, New York, 1992 - Wegner Timothy, Peterson Mark:
„Fractal Creations, First Edition“,
The Waite Group Press, 1991 - Giffin Noel a kol.:
„The Spanky Fractal Database“,
http://spanky.triumf.ca/ - Jones Damien M. a kol.:
„Fractalus“,
http://www.fractalus.com - Tyler Bert, Wegner Tim a kol.:
„Fractint (fractal generator for DOS, Windows and Unix)“,
http://www.fractint.org
8. Obsah dalšího pokračování tohoto seriálu
V dalším pokračování tohoto seriálu se konečně dostaneme k vysvětlení vztahu mezi Mandelbrotovou množinou, konstantou π a některými číselnými posloupnostmi.