Hlavní navigace

Fraktály v počítačové grafice XXVI

18. 4. 2006
Doba čtení: 12 minut

Sdílet

Ve dvacáté šesté části seriálu věnovaného fraktálům používaným (nejenom) v počítačové grafice si popíšeme první typ fraktálních množin nazývaných souhrnně termínem Magnet. Název těchto fraktálů je odvozen z jejich fyzikálního významu.

Obsah

1. Fraktální množiny typu Magnet
2. Iterační vztah platný pro fraktální množinu Magnet 1
3. Mandelbrotova verze fraktální množiny Magnet 1
4. První demonstrační příklad
5. Hodnota perturbace a Mandelbrotova verze fraktální množiny Magnet 1
6. Druhý demonstrační příklad
7. Juliova verze fraktální množiny Magnet 1
8. Třetí demonstrační příklad
9. Obsah dalšího pokračování tohoto seriálu

1. Fraktální množiny typu Magnet

V dnešní a také i následující části tohoto seriálu bude popsán další typ fraktálních množin vytvářených v komplexní rovině. Jedná se o fraktály, jež jsou v literatuře označeny názvem Magnet. Pojďme si nyní zjednodušeně vysvětlit, kde všude je možné tyto fraktály nalézt.

Jednou z mnoha vědních oblastí, ve kterých byly objeveny fraktální struktury, je obecně zkoumání změny stavu některých materiálů. Podrobně byla studována například změna stavu magnetického materiálu na materiál nemagnetický (přesněji, změna feromagnetika na diamagnetikum). Každý materiál, ať už se jedná o chemický prvek či sloučeninu, je v mikroskopickém pohledu složen z elementárních magnetů, které v závislosti na teplotě určují, zda je materiál jako celek magnetický či nikoliv. Při nízkých teplotách je materiál jako celek magnetický, ale při mikroskopickém pohledu existují jisté lokální fluktuace, kde nejsou elementární magnety uspořádané. Naopak, za dostatečně vysoké teploty je materiál jako celek nemagnetický, ale existují domény, kde jsou elementární magnety uspořádány.

Vlastnost magnetismu je tedy závislá na měřítku pohledu na materiál. Při kritické teplotě (takzvaná Curierova teplota) materiál přechází z magnetického stavu do nemagnetického a obráceně. Jestliže má materiál tuto teplotu, vypadá stejně ve všech měřítkách a má fraktální strukturu. Při této teplotě také nemůžeme jednoznačně dokázat, zda je materiál magnetický či nikoli. Dále popsané fraktály typu Magnet vznikly vizualizací vlastností magnetických materiálů při změně stavu (fáze) po jejich vyjádření komplexními čísly – to je ostatně celkem běžný matematický obrat v případech, že je řešení problému s reálnými čísly složité či nemožné.

Tato fraktální struktura existuje například i při změně skupenství látky, jako je tání ledu či vypařování vody. Základní stavy hmoty jsou z makroskopického hlediska tři (pevné, kapalné, plynné), můžeme přidat i plazmu a další (například degenerovaná hmota). Z mikroskopického hlediska je ovšem těchto stavů mnohem více. Fraktální strukturu hmoty potom můžeme vidět při přechodu hmoty z jednoho stavu do druhého stavu.

V následujících kapitolách budou popsány jednotlivé varianty prvního fraktálu typu Magnet.

2. Iterační vztah platný pro fraktální množinu Magnet 1

Fraktální množina Magnet 1 je v komplexní množině počítána a následně vykreslována způsobem, který jsme si podrobně popsali u klasické Mandelbrotovy množiny a množin Juliových. Každému bodu (tj. pixelu) zobrazenému na obrazovce je jednoznačně přiřazena určitá komplexní hodnota. Tato hodnota je považována za vstupní parametr iterační smyčky, která slouží k provedení testu, zda komplexní hodnota příslušná k danému pixelu vede ke konvergenci k fixním bodům množiny nebo zda naopak posloupnost hodnot zn diverguje (resp. se posloupnost stala periodickou, což se obecně nedá zjistit). Iterační vztah pro fraktální množinu Magnet 1 je mnohem složitější, než tomu bylo u dříve popisovaných množin, tj. množin Mandelbrotových a Juliových nebo i Barnsleyových množin (tam se sice vyskytovala podmínka, ale poměrně jednoduchá), protože je použito dělení komplexních čísel. Celý iterační vztah je možné zapsat následujícím způsobem:

fractals26_e.png

Ve výše uvedeném vzorci leží hodnoty proměnných zn, zn+1 a c v komplexní rovině. Oproti množinám Mandelbrotovým a Juliovým se mění i podmínka pro ukončení iterační smyčky, protože fraktální množina Magnet 1 má jeden z fixních bodů ležících na souřadnici 1+0i – Mandelbrotova množina má naopak fixní bod nulový (my jsme test na fixní bod prozatím do demonstračních příkladů neimplementovali). To má za následek změnu konkrétní implementace iterační smyčky, která je uvedena v následující kapitole.

3. Mandelbrotova verze fraktální množiny Magnet 1

V předchozí kapitole byl uveden iterační vztah platný pro fraktální množinu Magnet 1. Tento iterační vztah, ve kterém se vyskytují komplexní proměnné, je možné rozepsat na rovnice platné pro reálnou a imaginární složku výsledku. Po dalším zjednodušení výpočtů, které mají vliv mj. i na výkonnost výsledného algoritmu, získáme následující fragment programu napsaného v programovacím jazyku C:

    double zx, zy, zx2, zy2, zxn, zyn;  // složky komplexní proměnné Z a Z^2
    double cx0, cy0;                    // vstupní parametr iterační smyčky
    double tzx, tzy, bzx, bzy;          // čitatel a jmenovatel zlomku
    double div;                         // hodnota, kterou se bude výsledek dělit
                                        // před umocněním

    zx2=zx*zx;                          // zkrácený výpočet druhé mocniny složek Z
    zy2=zy*zy;
    tzx=zx2-zy2+cx0-1;                  // top=z(n)^2+c-1 (čitatel zlomku)
    tzy=2.0*zx*zy+cy0;
    bzx=2.0*zx+cx0-2;                   // bot=2z(n+1)+c-2 (jmenovatel zlomku)
    bzy=2.0*zy+cy0;
    div=bzx*bzx+bzy*bzy;                // z(n)=top/bot
    if (div<MIN_VALUE) break;           // zajistit, aby nedošlo k dělení nulou
    zxn=(tzx*bzx+tzy*bzy)/div;
    zyn=(tzy*bzx-tzx*bzy)/div;
    zx=(zxn+zyn)*(zxn-zyn);             // z(n+1)=z(n)^2 => výsledek iteračního vztahu
    zy=2.0*zxn*zyn; 

Všimněte si, že pokud by ve výše uvedeném kódu mělo dojít k dělení nulou (resp. k dělení velmi malou hodnotou, která se k nule přibližuje), dojde k ukončení iterační smyčky. K tomuto programovému kódu se dále musí přidat další dvě podmínky, které slouží k ukončení iterační smyčky. Jednu z podmínek již známe: pokud velikost hodnoty zn přesáhne předem zadanou hodnotu, je iterační smyčka ukončena a posloupnost hodnot zn je považována za divergentní. U Mandelbrotovy množiny se používal test |zn|>=2, u fraktálních množin typu Magnet se však (především z estetického hlediska) v tomto testu používají vyšší hodnoty bailout, typicky 100 a více. Druhou přidanou podmínkou je test na konvergenci k fixnímu bodu. Tato podmínka se provádí vyčíslením vzdálenosti hodnoty zn k bodu 1+0i. Po doplnění nezbytných podmínek pro ukončení iterační smyčky je již možné kód iterační smyčky začlenit do kompletní céčkovské funkce, která provádí výpočet a následné vykreslení obrázku Mandelbrotovy verze fraktální množiny Magnet 1:

//-----------------------------------------------------------------------------
// Překreslení Mandelbrotovy verze fraktální množiny Magnet 1
//-----------------------------------------------------------------------------
void recalcMagnetM1(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, zxn, zyn;          // složky komplexní proměnné Z a Z^2
    double cx0, cy0;
    double xmin, ymin, xmax, ymax;              // rohy vykreslovaného obrazce
                                                // v komplexní rovině
    double div;                                 // hodnota, kterou se bude výsledek
                                                // dělit před umocněním
    double tzx, tzy, bzx, bzy;                  // čitatel a jmenovatel zlomku
    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
            zx=0.0;                             // nastavit počáteční hodnotu Z(0)
            zy=0.0;
            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>100) break;         // test na bailout
                if (((zx-1.0)*(zx-1.0)+zy*zy)<0.001) break; // test na fixní bod
                tzx=zx2-zy2+cx0-1;              // top=z(n)^2+c-1
                tzy=2.0*zx*zy+cy0;
                bzx=2.0*zx+cx0-2;               // bot=2z(n+1)+c-2
                bzy=2.0*zy+cy0;
                div=bzx*bzx+bzy*bzy;            // z(n)=top/bot
#define MIN_VALUE 1.0-100
                if (div<MIN_VALUE) break;       // zajistit, aby nedošlo k dělení nulou
                zxn=(tzx*bzx+tzy*bzy)/div;
                zyn=(tzy*bzx-tzx*bzy)/div;
                zx=(zxn+zyn)*(zxn-zyn);         // z(n+1)=z(n)^2
                zy=2.0*zxn*zyn;
            }
            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
    }
} 

Příklady Mandelbrotových verzí fraktální množiny Magnet 1 jsou uvedeny na prvním a druhém obrázku.

fractals26_1.png

Obrázek 1: Mandelbrotova verze fraktální množiny Magnet 1

fractals26_2.png

Obrázek 2: Další pohled na Mandelbrotovu verzi fraktální množiny Magnet 1

4. První demonstrační příklad

Céčkovská funkce recalcMagnetM1(), jejíž výpis byl uveden ve třetí kapitole, 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í základní pohled na Mandelbrotovu verzi fraktální množiny Magnet 1. Ovládání tohoto demonstračního příkladu je podobné jako v minule prezentovaných demonstračních příkladech, screenshot je zobrazen na třetím obrázku.

fractals26_3.png

Obrázek 3: Screenshot prvního demonstračního příkladu s Mandelbrotovou verzí fraktální množiny Magnet 1

5. Hodnota perturbace a Mandelbrotova verze fraktální množiny Magnet 1

Již v několika předchozích dílech tohoto seriálu jsme si řekli, že tvar libovolné Mandelbrotovy množiny (resp. fraktálu vytvářeného na podobném principu jako Mandelbrotova množina) je možné měnit pomocí takzvané hodnoty perturbation. Dříve vysvětlený princip je samozřejmě možné aplikovat i na Mandelbrotovu verzi fraktální množiny Magnet 1, což je z praktického hlediska ukázáno na následující céčkovské funkci recalcMagnetM1P(), která jako své vstupní parametry bere i hodnoty pcx a pcy představující komplexní hodnotu perturbace. Tyto hodnoty ovlivňují vstupní podmínky iterační smyčky a tím pádem mají velký dopad na výsledný tvar fraktální množiny – viz ilustrační obrázky 4 a 5.

//-----------------------------------------------------------------------------
// Překreslení fraktální množiny Magnet 1 s možností nastavení perturbace
//-----------------------------------------------------------------------------
void recalcMagnetM1P(pixmap *pix,               // pixmapa pro vykreslování
                  int    maxiter,               // maximální počet iterací
                  double scale,                 // měřítko obrazce
                  double xpos,                  // posun obrazce
                  double ypos,
                  double pcx,                   // nastavená hodnota perturbace
                  double pcy,
                  int    palette,               // barvová paleta
                  int    rf, int gf, int bf)    // příznaky barvových složek
{
    double zx, zy, zx2, zy2, zxn, zyn;          // složky komplexní proměnné Z a Z^2
    double cx0, cy0;
    double xmin, ymin, xmax, ymax;              // rohy vykreslovaného obrazce v komplexní
                                                // rovině
    double div;                                 // hodnota, kterou se bude výsledek dělit
                                                // před umocněním
    double tzx, tzy, bzx, bzy;                  // čitatel a jmenovatel zlomku
    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
            zx=pcx;                             // nastavit počáteční hodnotu Z(0)
            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>100) break;         // test na bailout
                if (((zx-1.0)*(zx-1.0)+zy*zy)<0.001) break; // test na fixní bod
                tzx=zx2-zy2+cx0-1;              // top=z(n)^2+c-1
                tzy=2.0*zx*zy+cy0;
                bzx=2.0*zx+cx0-2;               // bot=2z(n+1)+c-2
                bzy=2.0*zy+cy0;
                div=bzx*bzx+bzy*bzy;            // z(n)=top/bot
#define MIN_VALUE 1.0-100
                if (div<MIN_VALUE) break;       // zajistit, aby nedošlo k dělení nulou
                zxn=(tzx*bzx+tzy*bzy)/div;
                zyn=(tzy*bzx-tzx*bzy)/div;
                zx=(zxn+zyn)*(zxn-zyn);         // z(z+1)=z(n)^2
                zy=2.0*zxn*zyn;
            }
            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
    }
} 

fractals26_4.png

Obrázek 4: Mandelbrotova verze fraktální množiny Magnet 1 s nenulovou hodnotou perturbace

fractals26_5.png

Obrázek 5: Odlišný pohled na Mandelbrotovu verzi fraktální množiny Magnet 1 s nenulovou hodnotou perturbace

6. Druhý demonstrační příklad

Praktická aplikace nastavení hodnoty perturbace, jež byla ukázána na funkci recalcMagnetM1P(), je implementována v dnešním druhém demonstračním příkladu. Po překladu a následném spuštění tohoto příkladu se vypočte dvojice fraktálních množin typu Magnet 1. Na levou množinu není hodnota perturbation aplikována (je nulová), kdežto obraz pravé fraktální 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 druhého demonstračního příkladu je zobrazen na šestém obrázku.

fractals26_6.png

Obrázek 6: Screenshot druhého demonstračního příkladu s Mandelbrotovou verzí fraktální množiny Magnet 1

7. Juliova verze fraktální množiny Magnet 1

Ve výše uvedených příkladech je při vstupu do iterační smyčky komplexní proměnná z nastavena na konstantní hodnotu z0, která je pro celý fraktál (tj. pro všechny pixely) stejná. Můžeme však vytvořit i Juliovu verzi fraktální množiny Magnet 1, při které zůstává hodnota komplexní konstanty c pro celý počítaný obrázek zachována a naopak se mění počáteční hodnota z0. Juliovy varianty této fraktální množiny jsou ukázány na sedmém a osmém obrázku, funkce, která tyto obrázky vytváří, se jmenuje recalcMagnetJ1():

//-----------------------------------------------------------------------------
// Překreslení Juliovy verze fraktální množiny Magnet 1
//-----------------------------------------------------------------------------
void recalcMagnetJ1(pixmap *pix,                // pixmapa pro vykreslování
                  int    maxiter,               // maximální počet iterací
                  double scale,                 // měřítko obrazce
                  double xpos,                  // posun obrazce
                  double ypos,
                  double cx,
                  double cy,                    // poloha bodu v komplexní rovině
                  int    palette,               // barvová paleta
                  int    rf, int gf, int bf)    // příznaky barvových složek
{
    double zx, zy, zx2, zy2, zxn, zyn;          // složky komplexní proměnné Z a Z^2
    double zx0, zy0;
    double xmin, ymin, xmax, ymax;              // rohy vykreslovaného obrazce v komplexní
                                                // rovině
    double div;                                 // hodnota, kterou se bude výsledek dělit
                                                // před umocněním
    double tzx, tzy, bzx, bzy;                  // čitatel a jmenovatel zlomku
    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
            zx=zx0;                             // nastavit počáteční hodnotu Z(0)
            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>100) break;         // test na bailout
                if (((zx-1.0)*(zx-1.0)+zy*zy)<0.001) break; // test na fixní bod
                tzx=zx2-zy2+cx-1;               // top=z(n)^2+c-1
                tzy=2.0*zx*zy+cy;
                bzx=2.0*zx+cx-2;                // bot=2z(n+1)+c-2
                bzy=2.0*zy+cy;
                div=bzx*bzx+bzy*bzy;            // z(n)=top/bot
#define MIN_VALUE 1.0-100
                if (div<MIN_VALUE) break;       // zajistit, aby nedošlo k dělení nulou
                zxn=(tzx*bzx+tzy*bzy)/div;
                zyn=(tzy*bzx-tzx*bzy)/div;
                zx=(zxn+zyn)*(zxn-zyn);         // z(n+1)=z(n)^2
                zy=2.0*zxn*zyn;
            }
            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
    }
} 

fractals26_7.png

Obrázek 7: Juliova verze fraktální množiny Magnet 1

fractals26_8.png

Obrázek 8: Odlišný pohled na Juliovu verzi fraktální množiny Magnet 1

8. Třetí demonstrační příklad

Výše uvedená funkce recalcMagnetJ1() je použita v dnešním třetím a posledním demonstračním příkladu. Po překladu a spuštění tohoto příkladu se zobrazí okno o rozměrech 512×384 pixelů, v jehož levé části se nalézá pohled na fraktální množinu Magnet M1 a v pravé části pohled na fraktální množinu Magnet J1. Ve spodní části okna se nachází základní informace o nastavených parametrech použitých pro generování a zobrazení obou fraktálních množin. Tyto množiny, z nichž každá má rozlišení 256×256 pixelů, jsou, podobně jako původní Mandelbrotova množina a Juliovy množiny, mezi sebou svázány stejným iteračním vztahem a hodnotou komplexní konstanty c. Pohybem kurzoru myši po fraktální množině Magnet M1, tj. po levé polovině okna, se mění komplexní konstanta c, která je ihned použita pro dynamický přepočet fraktální množiny Magnet J1. Screenshot ze třetího demonstračního příkladu je zobrazen na devátém obrázku.

ict ve školství 24

fractals26_9.png

Obrázek 9: Screenshot třetího demonstračního příkladu s Juliovou verzí fraktální množiny Magnet 1

9. Obsah dalšího pokračování tohoto seriálu

V následujícím pokračování tohoto seriálu si popíšeme další variantu fraktálních množin typu Magnet. Bude se jednat o množiny Magnet M2 a Magnet J2.

ikonka

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.