Mandelbrotova množina a jak na ní - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

Mandelbrotova množina a jak na ní

sdl now

28. března 2002, 00.00 | Tento nádherný fraktál je velice snadné vytvořit. V SDL stačí napsat jen asi 100 řádek kódu a náš program bude umět i zoomování do libovolného místa, které určíme myší....

Tento nádherný fraktál je velice snadné vytvořit. Pro každý pixel počítáme tuto rovnici (iterujem)

Zn+1=Zn2+C

do té doby než se Z dostane mimo obrazovku. Nutno podotknout, že Z i C jsou komplexní čísla a na počátku je Z=0 a C odpovídá souřadnicím bodu, pro který počítáme barvu. Po té co se Z dostane mimo obrazovku zobrazíme v bodě C barvu podle počtu kroků, jež to trvalo. Pokud Z neopustí obrazovku do námi stanoveného kroku vykreslíme černou barvu, neboť se jedná o vnitřek fraktálu. Nutno podotknout, že pokud Z opustí obrazovku bude se většinou zvětšovat do nekonečna a tedy oblast fraktalu nenáleží, dá se testovat i zda Z>2, což je hlavně na krajích přesnější,ale pomalejší.

Jelikož Céčko nepracuje s komplexními čísli vyjádříme si rovnici pro výpočet takto

Zi=2*Zi1*Zr1+Ci;
Zr=(Zr1*Zr1)-(Zi1*Zi1)+cr;

Přičemž index i znamená imaginární část, index r reálnou část a index 1 označuje předchozí hodnotu (n-1)

Teď se již můžeme vrhnout do napsání funkce, která nám naš fraktál zobrazí.

SDL_Surface *screen;

void DrawSet(double pos_x,double pos_y,double zoom)
{
  int x,y,c;
  double cr,ci,zr,zi,zr1,zi1,screenw,screenh;
  Uint32 *misto;

  if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);

  misto=(Uint32 *)screen->pixels;
  screenw=screen->w/2;
  screenh=screen->h/2;

  for (y=0;y<screen->h;y++)
  for (x=0;x<screen->w;x++)
  {
    cr=(double(x)-screenw)*zoom+pos_x*screenw;
    ci=(double(y)-screenh)*zoom+pos_y*screenh;
    zr1=0;zi1=0;
    c=0;
    do{
      zi=2*zi1*zr1+ci;
      zr=(zr1*zr1)-(zi1*zi1)+cr;
      c++;
      zr1=zr;
      zi1=zi;
    }while (((zi>0?zi:-zi)*zoom<screenh) && ((zr>0?zr:-zr)*zoom<screenw) && c<128);
    //pokud pocet kroku presahne 128 lezi bod uvnitr mnoziny a cyklus konci,
    //snizenim max. poctu kroku se program zrychli,ale pri vetsim zoomu zaniknou detaily

    *misto=(256-(c*2))<<8;
    misto++;
    //misto 128-c lze doplnit jakykoliv dalsi predpis, pro barvu mnoziny
  }

  if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);

}

A teďka trochu komentáře, na začátku zamkneme surface a zacílíme ukazatel misto na první pixel zobrazovacího surfacu screen. Dále pro všechny pixely surfacu počítáme naší rovnici s tím, že do počátečních podmínek zahrneme zvetšení zoom a  posun pos_x, pos_y. Nakonec každý pixel vykreslíme a přesuneme ukazatel misto na další pixel, poté surface odemkneme. Je třeba podotknout, že pokud bod [zr,zi] neopustí obrazovku do 128 kroků (maximální počet iretací) cyklus skončí, pokud bychom mez položili větší musíme to zohlednit při počítání barvy, zmenšení konstanty nám program zrychlí, ale též nás ochudí o detaily na hranicích mandelbrotovy množiny.

 Aby dojem z fraktálu vynikl napíšeme krátkou aplikaci na jeho zobrazení a přibližování.

Zde je zdrojový kód

#include <stdlib.h>
#include "SDL.h"

int main(int argc, char *argv[])
{
  SDL_Event event;
  double zoom;
  double pozice[200];
  int p_pozice=0,bt,mousex,mousey;

  //inicializuje grafiku SDL pokud nastane chyba program ji vypíše a ukoncí se
  if (SDL_Init(SDL_INIT_VIDEO)< 0 ) {
    fprintf(stderr, "Problem: %s\n", SDL_GetError());
    exit(1);
  }
  atexit(SDL_Quit);
  SDL_WM_SetCaption("Tutorial 3 - Mandelbrote Set",NULL);
  //nastaví rozlišení 320x200 s 16b barevné hloubky
  screen = SDL_SetVideoMode(320, 200, 32,SDL_HWSURFACE);

  zoom=0.02;
  pozice[0]=0;
  pozice[1]=0;
  DrawSet(pozice[p_pozice*2],pozice[p_pozice*2+1],zoom);
  SDL_Flip(screen);
  //ceká se do uvolnení jakékoliv klávesy
  while (SDL_PollEvent(&event),event.type!=SDL_KEYUP)
  {
    bt=SDL_GetMouseState(&mousex,&mousey);
    //na leve tlacitko mysi se priblizuje
    if (bt==1 && p_pozice<99)
    {
      p_pozice++;
      zoom*=0.5;
      pozice[p_pozice*2] =(double(mousex)/screen->w*2-1)*zoom+pozice[p_pozice*2-2];
      pozice[p_pozice*2+1]=(double(mousey)/screen->h*2-1)*zoom+pozice[p_pozice*2-1];
      DrawSet(pozice[p_pozice*2],pozice[p_pozice*2+1],zoom);
      SDL_Flip(screen);
    }
    //na prave oddaluje
    if (bt==4 && p_pozice>0)
    {
      p_pozice--;
      zoom*=2;
      DrawSet(pozice[p_pozice*2],pozice[p_pozice*2+1],zoom);
      SDL_Flip(screen);
    }
  }
  return 0;
}

Myslím, že program je víceméně jasný, používá se v něm pole pozice pro uložení středu obrazovky tedy bodu, ve kterém fraktál kreslíme. Počet položek 100 ani nevyužijeme, neboť při dvojnásobném zvětšení pro každé přiblížení dříve dosáhneme přesnosti typu double, což se projeví zpixelovatěním obrázku. Pokud nerozumíte některým příkazům SDL, tak nahlédněte do předchozích článků o SDL nebo do přehledného anglického helpu k této unitě.

Zde je program ke stažení fraktal.zip (124KB)


Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: