1. Kubické Juliovy množiny s iteračním vztahem Zn+1=Zn3+C
V předchozím pokračování tohoto seriálu jsme si ukázali, jakým způsobem se počítá a následně také vykresluje rastrový obraz takzvané „kubické“ Mandelbrotovy množiny, v jejímž iteračním vztahu Zn+1=Znr+C je původní člen Zn2 nahrazen novým členem Zn3. Reálnou a imaginární složku komplexní hodnoty Z3 jsme odvodili následujícím způsobem:
Z3=(zre+izim)3=
=(zre+izim)2(zre+izim)=
=(zre2-zim2+2izrezim)(zre+izim)=
=zre3-izim3+3izre2zim-3zrezim2
Re(Z3): zre3-3zrezim2
Im(Z3): -zim3+3zre2zim
Kde i značí imaginární jednotku, pro kterou platí i2=-1. Pravidla pro výpočet reálné (Re(Z3)) a imaginární (Im(Z3)) složky byla použita ve funkci recalcCubicMandelbrot(), v níž se prováděl přepočet a následné překreslení kubické Mandelbrotovy množiny s případnou modifikací barvy pixelů, jež leží vně množiny – viz demonstrační příklady použité v předchozí části seriálu. Zcela stejná pravidla pro výpočet reálné a imaginární složky Z3 je možné samozřejmě využít i při výpočtu a zobrazení „kubické“ Juliovy množiny, jak je ostatně patrné na kódu funkce recalcCubicJulia() napsané v programovacím jazyku C. Kubická Juliova množina má stejný vztah ke kubické Mandelbrotově množině, jako má „klasická“ kvadratická Juliova množina ke kvadratické množině Mandelbrotově – Mandelbrotova množina v obou případech představuje mapu všech tvarů Juliových množin, která pro každou hodnotu komplexní konstanty C určuje, zda ke konstantě příslušející Juliova množina bude spojitá či nikoli. Před uvedením zdrojového tvaru funkce recalcCubicJulia() opět připomínám, že v programovém kódu nepoužívám rozšíření platná v normě C99 pro komplexní čísla, i když by to programový kód zjednodušilo:
//-----------------------------------------------------------------------------
// Výpočet a překreslení kubické Juliovy množiny
//-----------------------------------------------------------------------------
void recalcCubicJulia( pixmap *pix, // pixmapa pro vykreslování
int maxiter, // maximální počet iterací
double scale, // měřítko obrazce
double xpos, // posun obrazce
double ypos,
int palette, // barvová paleta
int rf, int gf, int bf, // příznaky barvových složek
double cx0,
double cy0) // aktuálně nastavená hodnota C
{
double zx, zy, zx2, zy2, zx3, zy3; // složky komplexní proměnné Z, Z^2 a Z^3
double zxn, zyn;
double cx, cy; // složky komplexní konstanty C
double zx0, zy0;
double xmin, ymin, xmax, ymax; // rohy vykreslovaného obrazce
// v komplexní rovině
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b;
calcCorner(xpos, ypos, scale, &xmin, &ymin, &xmax, &ymax);
zy0=ymin;
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
zx0=xmin;
for (x=0; x<pix->width; x++) { // pro všechny pixely na řádku
cx=cx0; // nastavit počáteční hodnotu Z(0)
cy=cy0;
zx=zx0;
zy=zy0;
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;
zx3=zx2*zx; // zkrácený výpočet třetí mocniny složek Z
zy3=zy2*zy;
zxn= zx3-3.0*zx*zy2+cx; // Z^3+C
zyn=-zy3+3.0*zx2*zy+cy;
if (zx2+zy2>4.0) break; // kontrola překročení meze divergence
zx=zxn;
zy=zyn;
}
if (iter==maxiter) // pixely uvnitř Juliovy
r=g=b=0; // množiny jsou černé
else // výpočet barev podle počtu iterací
mapPalette(palette, iter, &r, &g, &b);
r=r*rf; // uživatelem řízené vynulování
g=g*gf; // vybraných barvových složek
b=b*bf;
putpixel(pix, x, y, r, g, b);
zx0+=(xmax-xmin)/pix->width; // posun na další bod na řádku
}
zy0+=(ymax-ymin)/pix->height; // posun na další řádek
}
}
Funkce recalcCubicJulia() je použita v dnešním prvním demonstračním příkladu, screenshoty získané z tohoto demonstračního příkladu jsou zobrazeny na prvním a druhém obrázku.


2. Rozepsání komplexní hodnoty Z4 na reálnou a imaginární část
Uvedením demonstračního příkladu vykreslujícího kubickou Juliovu množinu opouštíme část věnovanou fraktálům vytvářeným za pomoci iteračního vztahu Zn+1=Zn3+C a začneme se věnovat Mandelbrotovým a samozřejmě také Juliovým množinám, které vzniknou při použití vyšší mocniny hodnoty Z, konkrétně Zn+1=Zn4+C. Podobně jako u kubických Mandelbrotových a Juliových množin, i v tomto případě je nutné provést rozpis komplexní hodnoty Z4 na její reálnou a imaginární složku. To se provede následujícím způsobem:
Z4=(zre+izim)4=
=(zre+izim)2(zre+izim)2=
=(zre2-zim2+2izrezim)(zre2-zim2+2izrezim)=
=zre4-zre2zim2+2izre3zim-zre2zim2+zim4-2izrezim3+2izre3zim-2izrezim3-4zre2zim2=
=zre4+zim4-6zre2zim2+ 4izre3zim-4izrezim3
Re(Z4): zre4+zim4-6zre2zim2
Im(Z4): 4zre3zim-4zrezim3
3. Mandelbrotova množina s iteračním vztahem Zn+1=Zn4+C
Výše uvedené vztahy pro reálnou a imaginární složku komplexního výrazu Z4 jsou použity ve funkci recalcMandelbrot4A(), jejíž zdrojový kód vypadá následovně (všimněte si způsobu použití pomocných proměnných zx2, zy2, zxn a zyn uvnitř iterační smyčky):
//-----------------------------------------------------------------------------
// Překreslení Mandelbrotovy množiny s iteračním vztahem Z=Z^4+C přímým
// dosazením do vztahu pro reálnou a imaginární složku Z^4.
//-----------------------------------------------------------------------------
void recalcMandelbrot4A( pixmap *pix, // pixmapa pro vykreslování
int maxiter, // maximální počet iterací
double scale, // měřítko obrazce
double xpos, // posun obrazce
double ypos,
int palette, // barvová paleta
int rf, int gf, int bf) // příznaky barvových složek
{
double zx, zy, zx2, zy2, zx4, zy4; // složky komplexní proměnné Z, Z^2 a Z^4
double zxn, zyn;
double cx, cy; // složky komplexní konstanty C
double cx0, cy0;
double xmin, ymin, xmax, ymax; // rohy vykreslovaného obrazce v komplexní
// rovině
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b;
calcCorner(xpos, ypos, scale, &xmin, &ymin, &xmax, &ymax);
cy0=ymin;
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
cx0=xmin;
for (x=0; x<pix->width; x++) { // pro všechny pixely na řádku
cx=cy0; // nastavit počáteční hodnotu Z(0)
cy=cx0;
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 (zx2+zy2>4.0) break; // kontrola překročení meze divergence
zxn=zx2*zx2+zy2*zy2-6.0*zx2*zy2;// přímý výpočet Z^4
zyn=4.0*zx2*zx*zy-4.0*zx*zy2*zy;
zx=zxn+cx;
zy=zyn+cy;
}
if (iter==maxiter) // pixely uvnitř Mandelbrotovy
r=g=b=0; // množiny jsou černé
else // výpočet barev podle počtu iterací
mapPalette(palette, iter, &r, &g, &b);
r=r*rf; // uživatelem řízené vynulování
g=g*gf; // vybraných barvových složek
b=b*bf;
putpixel(pix, x, y, r, g, b);
cx0+=(xmax-xmin)/pix->width; // posun na další bod na řádku
}
cy0+=(ymax-ymin)/pix->height; // posun na další řádek
}
}
Pokud si však uvědomíme, že i v oboru komplexních čísel platí vztah Z4=Z2×Z2, je možné funkci pro výpočet Mandelbrotovy množiny upravit (zjednodušit) takovým způsobem, který je patrný z výpisu funkce recalcMandelbrot4B(). Tato funkce je použita v dnešním druhém demonstračním příkladu, po jehož spuštění se vykreslí Mandelbrotova množina, se kterou je možné manipulovat stejným způsobem, jako tomu bylo u většiny předchozích demonstračních příkladů. Screenshoty z tohoto demonstračního příkladu jsou zobrazeny na třetím, čtvrtém a pátém obrázku.
//-----------------------------------------------------------------------------
// Překreslení Mandelbrotovy množiny s iteračním vztahem Z=Z^4+C s upraveným
// vztahem Z^4=Z^2*Z^2
//-----------------------------------------------------------------------------
void recalcMandelbrot4B( pixmap *pix, // pixmapa pro vykreslování
int maxiter, // maximální počet iterací
double scale, // měřítko obrazce
double xpos, // posun obrazce
double ypos,
int palette, // barvová paleta
int rf, int gf, int bf) // příznaky barvových složek
{
double zx, zy, zx2, zy2, zx4, zy4; // složky komplexní proměnné Z, Z^2, Z^3 a Z^4
double zxn, zyn;
double cx, cy; // složky komplexní konstanty C
double cx0, cy0;
double xmin, ymin, xmax, ymax; // rohy vykreslovaného obrazce v komplexní
// rovině
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b;
calcCorner(xpos, ypos, scale, &xmin, &ymin, &xmax, &ymax);
cy0=ymin;
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
cx0=xmin;
for (x=0; x<pix->width; x++) { // pro všechny pixely na řádku
cx=cy0; // nastavit počáteční hodnotu Z(0)
cy=cx0;
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 (zx2+zy2>4.0) break; // kontrola překročení meze divergence
zxn=zx2-zy2;
zyn=2.0*zx*zy; // nyní máme vypočteno Z^2
zx4=zxn*zxn;
zy4=zyn*zyn;
zy=2.0*zxn*zyn+cy; // zde je už vypočteno Z^4
zx=zx4-zy4+cx;
}
if (iter==maxiter) // pixely uvnitř Mandelbrotovy
r=g=b=0; // množiny jsou černé
else // výpočet barev podle počtu iterací
mapPalette(palette, iter, &r, &g, &b);
r=r*rf; // uživatelem řízené vynulování
g=g*gf; // vybraných barvových složek
b=b*bf;
putpixel(pix, x, y, r, g, b);
cx0+=(xmax-xmin)/pix->width; // posun na další bod na řádku
}
cy0+=(ymax-ymin)/pix->height; // posun na další řádek
}
}



4. Juliovy množiny s iteračním vztahem Zn+1=Zn4+C
V předchozí kapitole jsme si ukázali způsob výpočtu a následného vykreslení Mandelbrotovy množiny s využitím iteračního vztahu Zn+1=Zn4+C. Tentýž iterační vztah je samozřejmě možné použít i pro vytvoření odpovídající Juliovy množiny, což je ukázáno na níže uvedené funkci recalcJulia4(). Tato funkce slouží k vykreslení Juliových množin, jejichž tvar je odvislý od hodnoty parametrů cx0 a cy0 podobně, jako tomu bylo u kvadratické Juliovy množiny – pokud komplexní konstanta C=cx0+icy0 leží uvnitř Mandelbrotovy množiny, je příslušná Juliova množina spojitá a naopak. O kousek dále vypsaná funkce recalcJulia4() je použita v dnešním třetím demonstračním příkladu, po jehož překladu a následném spuštění se v levé části okna vykreslí Mandelbrotova množina a v pravé části množina Juliova. Pohybem kurzoru myši (se stlačeným levým tlačítkem) po obrazu Mandelbrotovy množiny se mění hodnota komplexní konstanty C, která je následně použita pro výpočet a překreslení Juliovy množiny. Screenshoty ze třetího demonstračního příkladu jsou zobrazeny na šestém a sedmém obrázku. Na těchto obrázcích stojí za povšimnutí, že symetrie Mandelbrotovy množiny je o jedničku menší než symetrie odpovídající Juliovy množiny – tak tomu ostatně bylo i u iteračních vztahů Zn+1=Zn2+C a Zn+1=Zn3+C.
//-----------------------------------------------------------------------------
// Překreslení Juliovy množiny s iteračním vztahem Z=Z^4+C
//-----------------------------------------------------------------------------
void recalcJulia4(pixmap *pix, // pixmapa pro vykreslování
int maxiter, // maximální počet iterací
double scale, // měřítko obrazce
double xpos, // posun obrazce
double ypos,
int palette, // barvová paleta
int rf, int gf, int bf, // příznaky barvových složek
double cx0,
double cy0) // aktuálně nastavená hodnota C
{
double zx, zy, zx2, zy2, zx4, zy4; // složky komplexní proměnné Z, Z^2, Z^3 a Z^4
double zxn, zyn;
double cx, cy; // složky komplexní konstanty C
double zx0, zy0;
double xmin, ymin, xmax, ymax; // rohy vykreslovaného obrazce v komplexní
// rovině
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b;
calcCorner(xpos, ypos, scale, &xmin, &ymin, &xmax, &ymax);
zy0=ymin;
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
zx0=xmin;
for (x=0; x<pix->width; x++) { // pro všechny pixely na řádku
cx=cx0; // nastavit počáteční hodnotu Z(0)
cy=cy0;
zx=zx0; // nastavení nulového orbitu
zy=zy0;
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
zxn=zx2-zy2;
zyn=2.0*zx*zy; // nyní máme vypočteno Z^2
zx4=zxn*zxn;
zy4=zyn*zyn;
zy=2.0*zxn*zyn+cy; // zde je už vypočteno Z^4
zx=zx4-zy4+cx;
}
if (iter==maxiter) // pixely uvnitř Mandelbrotovy
r=g=b=0; // množiny jsou černé
else // výpočet barev podle počtu iterací
mapPalette(palette, iter, &r, &g, &b);
r=r*rf; // uživatelem řízené vynulování
g=g*gf; // vybraných barvových složek
b=b*bf;
putpixel(pix, x, y, r, g, b);
zx0+=(xmax-xmin)/pix->width; // posun na další bod na řádku
}
zy0+=(ymax-ymin)/pix->height; // posun na další řádek
}
}


5. Hodnota perturbation a její vztah k Mandelbrotově množině s iteračním vztahem Zn+1=Zn4+C
V minulém pokračování tohoto seriálu jsme si řekli, že tvar Mandelbrotovy množiny dané vztahem Zn+1=Zn3+C je možné změnit pomocí takzvané hodnoty „perturbation“ prakticky stejným způsobem jako u „klasické“ kvadratické Mandelbrotovy množiny. Princip vysvětlený minule samozřejmě můžeme aplikovat i na Mandelbrotovu množinu s iteračním vztahem Zn+1=Zn4+C. Praktická aplikace tohoto principu je ukázána na funkci recalcMandelbrotPert(). Tato funkce je použita v dnešním čtvrtém (a současně posledním) demonstračním příkladu. Po překladu a následném spuštění tohoto příkladu se vypočte dvojice Mandelbrotových množin. Na levou Mandelbrotovu množinu není hodnota perturbation aplikována (je nulová), kdežto obraz pravé Mandelbrotovy množiny je ovlivněn (nenulovou) hodnotou perturbation. Tuto hodnotu je možné měnit pohybem myši současně se stlačeným levým tlačítkem. Screenshot ze čtvrtého demonstračního příkladu je zobrazen na osmém obrázku.
//-----------------------------------------------------------------------------
// Překreslení Mandelbrotovy množiny s iteračním vztahem Z=Z^4+C. Při výpočtu
// pixelů uvnitř Mandelbrotovy množiny je možné změnit hodnotu perturbation.
//-----------------------------------------------------------------------------
void recalcMandelbrotPert( pixmap *pix, // pixmapa pro vykreslování
int maxiter, // maximální počet iterací
double scale, // měřítko obrazce
double xpos, // posun obrazce
double ypos,
int palette, // barvová paleta
int rf, int gf, int bf, // příznaky barvových složek
double pcx, double pcy) // hodnota perturbace
{
double zx, zy, zx2, zy2, zx4, zy4; // složky komplexní proměnné Z, Z^2, Z^3 a Z^4
double zxn, zyn;
double cx, cy; // složky komplexní konstanty C
double cx0, cy0;
double xmin, ymin, xmax, ymax; // rohy vykreslovaného obrazce v komplexní
// rovině
int x, y; // počitadla sloupců a řádků v pixmapě
int iter; // počitadlo iterací
unsigned char r, g, b;
calcCorner(xpos, ypos, scale, &xmin, &ymin, &xmax, &ymax);
cy0=ymin;
for (y=0; y<pix->height; y++) { // pro všechny řádky v pixmapě
cx0=xmin;
for (x=0; x<pix->width; x++) { // pro všechny pixely na řádku
cx=cx0; // nastavit počáteční hodnotu Z(0)
cy=cy0;
zx=pcx; // nastavit hodnotu perturbace
zy=pcy;
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
zxn=zx2-zy2;
zyn=2.0*zx*zy; // nyní máme vypočteno Z^2
zx4=zxn*zxn;
zy4=zyn*zyn;
zy=2.0*zxn*zyn+cy; // zde je už vypočteno Z^4
zx=zx4-zy4+cx;
}
if (iter==maxiter) // pixely uvnitř Mandelbrotovy
r=g=b=0; // množiny jsou černé
else // výpočet barev podle počtu iterací
mapPalette(palette, iter, &r, &g, &b);
r=r*rf; // uživatelem řízené vynulování
g=g*gf; // vybraných barvových složek
b=b*bf;
putpixel(pix, x, y, r, g, b);
cx0+=(xmax-xmin)/pix->width; // posun na další bod na řádku
}
cy0+=(ymax-ymin)/pix->height; // posun na další řádek
}
}

6. Obsah dalšího pokračování tohoto seriálu
Ústředním tématem příštího pokračování tohoto seriálu bude odvození vztahu, který je možné použít pro vytváření Mandelbrotových a Juliových množin s neceločíselnou mocninou u iteračního vztahu Zn+1=Znr+C. Také si ukážeme zajímavé animace Mandelbrotovy a Juliovy množiny při průběžné změně mocniny Znr.