Hlavní navigace

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

15. 2. 2006
Doba čtení: 10 minut

Sdílet

V sedmnáctém pokračování seriálu o fraktálech používaných (nejenom) v počítačové grafice si popíšeme tři způsoby, pomocí nichž je možné modifikovat výpočet a tím i výsledný tvar Mandelbrotovy množiny. Popisované způsoby budou použity i pro vytvoření trojice zajímavých animací.

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.

fractals17_1
Obrázek 1: Detail Mandelbrotovy množiny s nenulovou hodnotou perturbation

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 recalcMandelbrot­Perturbation() 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 recalcMandelbrot­Perturbation(). 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.

fractals17_2
Obrázek 2: Screenshot prvního demonstračního příkladu

Na 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ů:

Parametry
Číslo obrázku Střed a zvětšení Perturbation Počet iterací
1  –0.84972634450­000000/-0.21635949050­000000/563.3417 0.03/0 255
3  –0.84988067063­249730/-0.21610365035­559480/2339.764 0.03/0 200
4  –0.19736137150­000000/-0.65680499250­000000/2591.483 0/0.1 500
5  –1.30452/-0.0731618/555.4548 0/0.05 255
6 +0.34283324800­000000/+0.04698910285­000000/4017.638 0/0.02 255

fractals17_3
Obrázek 3: Detail Mandelbrotovy množiny s nenulovou hodnotou perturbation

fractals17_4
Obrázek 4: Detail Mandelbrotovy množiny s nenulovou hodnotou perturbation

fractals17_5
Obrázek 5: Detail Mandelbrotovy množiny s nenulovou hodnotou perturbation

fractals17_6
Obrázek 6: Detail Mandelbrotovy množiny s nenulovou hodnotou perturbation

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 recalcMandelbrot­HorizVertDist() 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
    }
}
//----------------------------------------------------------------------------- 

fractals17_7
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
    }
}
//----------------------------------------------------------------------------- 

fractals17_8
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.

ict ve školství 24

7. Literatura a odkazy na Internetu

  1. 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
  2. Peitgen Heinz-Otto, Richter Peter:
    „The Beauty of Fractals“,
    Springer-Verlag, New York, 1986, ISBN 0–387–15851–0
  3. Peitgen Heinz-Otto, Jurgens Hartmut, Saupe Dietmar:
    „Fractals For The Classroom“,
    Springer-Verlag, New York, 1988
  4. Peitgen Heinz-Otto, Jurgens Hartmut, Saupe Dietmar:
    „Chaos and Fractals: New Frontiers of Science“,
    Springer-Verlag, New York, 1992
  5. Wegner Timothy, Peterson Mark:
    „Fractal Creations, First Edition“,
    The Waite Group Press, 1991
  6. Giffin Noel a kol.:
    „The Spanky Fractal Database“,
    http://spanky­.triumf.ca/
  7. Jones Damien M. a kol.:
    „Fractalus“,
    http://www.frac­talus.com
  8. Tyler Bert, Wegner Tim a kol.:
    „Fractint (fractal generator for DOS, Windows and Unix)“,
    http://www.frac­tint.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.

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.