Junio 22, 2018, 08:41:52 pm

Autor Tema: Mandelbrot set  (Leído 3760 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Mandelbrot set
« en: Julio 25, 2014, 03:55:10 pm »
El programa calcula el conjunto de Mandelbrot y lo visualiza.
Las teclas "Re Pag" y "Av Pag" acercan y alejan la imagen, y las teclas de direccion mueven la imagen. Para salir hay que apretar escape.

Cada vez que uno acerca o aleja la imagen el programa tiene que calcular toda la pantalla, pero al mover la imagen el programa solo vuelve a calcular la parte que antes no estaba en la pantalla.

Si no lo quieren compilar, les dejo el ejecutable: You are not allowed to view links. Register or Login

EDIT: Dejo dos imagenes (las tome con "imprimir pantalla"), una de las cuales ahora uso como fondo de pantalla :D





Código: You are not allowed to view links. Register or Login
#include <SDL/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

inline void assert(bool condition, const char *str)
{
    if(condition) return;
    puts(str);
    exit(EXIT_FAILURE);
}

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}

double length(double x, double y)
{
    return sqrt(x*x+y*y);
}

//inline void mandelbrot_function(double cx, double cy, double &retx, double &rety)
//{
//    double retx_aux;
//
//    retx_aux=retx*retx-rety*rety+cx;
//    rety=rety*retx+retx*rety+cy;
//    retx=retx_aux;
//}

inline void mandelbrot_function(double cx, double cy, double *retx, double *rety)
{
    double retx_aux;

    retx_aux=(*retx)*(*retx)-(*rety)*(*rety)+cx;
    *rety=(*rety)*(*retx)+(*retx)*(*rety)+cy;
    *retx=retx_aux;
}

const unsigned int max_mandelbrot_iteration=256;
double mandel_iteration(double x, double y)
{
//    return length(x,y)<1?1:0;
    double retx, rety;
    retx=rety=0;
    for(unsigned int i=0;i<max_mandelbrot_iteration;i++)
    {
        mandelbrot_function(x,y,&retx,&rety);
        if(length(retx,rety)>2) return i/(double)max_mandelbrot_iteration;
    }
    return 1;
}


int main ( int argc, char** argv )
{
    const unsigned int screen_width=800;
    const unsigned int screen_height=600;
    const int screen_center_x=(int)screen_width/2;
    const int screen_center_y=(int)screen_height/2;
    int center_x=0, fromx, tox;
    int center_y=0, fromy, toy;
    double step=.00390625;
    double mandelbrot_number;
    bool done, first;
    double coord_x, coord_y;
    bool keys[324];
    char title_buffer[256];
    for(int i=0;i<324;i++) keys[i]=false;

    assert(SDL_Init(SDL_INIT_VIDEO)>=0, "ERROR: Unable to init SDL.");
    atexit(SDL_Quit);
    SDL_Surface* screen = SDL_SetVideoMode(screen_width, screen_height, 32, SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN);
    assert(screen, "ERROR: Unable to set ???x??? video.");
    sprintf(title_buffer, "Mandelbrot, step: %.16f", step);
    SDL_WM_SetCaption(title_buffer, 0);
//    SDL_WM_SetCaption("Mandelbrot", 0);
    const Uint32 black=SDL_MapRGB(screen->format, 0, 0, 0);
    const Uint32 white=SDL_MapRGB(screen->format, 255, 255, 255);

    done=false;
    first=true;
    while (!done)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_QUIT:
                done = true;
                break;
            case SDL_KEYDOWN:
                keys[event.key.keysym.sym]=true;
                if(event.key.keysym.sym == SDLK_ESCAPE) done = true;
                break;
            case SDL_KEYUP:
                keys[event.key.keysym.sym]=false;
                break;
            }
        }

        if(first)
        {
            first=false;
            for(int x=0;x<(int)screen_width;x++) for(int y=0;y<(int)screen_height;y++)
            {
                coord_x=(x-screen_center_x-center_x)*step;
                coord_y=(y-screen_center_y-center_y)*step;

                mandelbrot_number=mandel_iteration(coord_x, coord_y);
                if(mandelbrot_number==1) putpixel(screen, x, y, white);
                else putpixel(screen, x, y, SDL_MapRGB(screen->format, 0, 255*mandelbrot_number, 255*mandelbrot_number));
            }
        }

        if((keys[SDLK_PAGEUP] or keys[SDLK_PAGEDOWN]) and not (keys[SDLK_PAGEUP] and keys[SDLK_PAGEDOWN]))
        {
            if(keys[SDLK_PAGEUP]) step*=2, center_x/=2, center_y/=2;
            else if(keys[SDLK_PAGEDOWN]) step/=2, center_x*=2, center_y*=2;
            sprintf(title_buffer, "Mandelbrot, step: %.16f", step);
            SDL_WM_SetCaption(title_buffer, 0);

            keys[SDLK_PAGEUP]=keys[SDLK_PAGEDOWN]=false;
            SDL_FillRect(screen, 0, black);
            for(int x=0;x<(int)screen_width;x++) for(int y=0;y<(int)screen_height;y++)
            {
                coord_x=(x-screen_center_x-center_x)*step;
                coord_y=(y-screen_center_y-center_y)*step;

                mandelbrot_number=mandel_iteration(coord_x, coord_y);
                if(mandelbrot_number==1) putpixel(screen, x, y, white);
                else putpixel(screen, x, y, SDL_MapRGB(screen->format, 0, 255*mandelbrot_number, 255*mandelbrot_number));
            }
        }

        if((keys[SDLK_LEFT] or keys[SDLK_RIGHT]) and not (keys[SDLK_LEFT] and keys[SDLK_RIGHT]))
        {
            if(keys[SDLK_RIGHT]) center_x-=8;
            else if(keys[SDLK_LEFT]) center_x+=8;

            fromx=0, tox=screen_width;
            if(keys[SDLK_RIGHT])
            {
                SDL_Rect fromrect={8,0,screen_width,screen_height};
                SDL_Rect torect{0,0,screen_width-8,screen_height};
                SDL_BlitSurface(screen,&fromrect,screen,&torect);
                fromx=screen_width-8;
                tox=screen_width;
            }
            else if(keys[SDLK_LEFT])
            {
                SDL_Rect fromrect={0,0,screen_width-8,screen_height};
                SDL_Rect torect{8,0,screen_width,screen_height};
                SDL_BlitSurface(screen,&fromrect,screen,&torect);
                fromx=0;
                tox=8;
            }

            for(int x=fromx;x<tox;x++) for(int y=0;y<(int)screen_height;y++)
            {
                coord_x=(x-screen_center_x-center_x)*step;
                coord_y=(y-screen_center_y-center_y)*step;

                mandelbrot_number=mandel_iteration(coord_x, coord_y);
                if(mandelbrot_number==1) putpixel(screen, x, y, white);
                else putpixel(screen, x, y, SDL_MapRGB(screen->format, 0, 255*mandelbrot_number, 255*mandelbrot_number));
            }
        }


        if((keys[SDLK_UP] or keys[SDLK_DOWN]) and not (keys[SDLK_UP] and keys[SDLK_DOWN]))
        {
            if(keys[SDLK_DOWN]) center_y-=8;
            else if(keys[SDLK_UP]) center_y+=8;

            fromy=0, toy=screen_height;
            if(keys[SDLK_DOWN])
            {
                SDL_Rect fromrect={0,8,screen_width,screen_height};
                SDL_Rect torect{0,0,screen_width,screen_height-8};
                SDL_BlitSurface(screen,&fromrect,screen,&torect);
                fromy=screen_height-8;
                toy=screen_height;
            }
            else if(keys[SDLK_UP])
            {
                SDL_Rect fromrect={0,0,screen_width,screen_height-8};
                SDL_Rect torect{0,8,screen_width,screen_height};
                SDL_BlitSurface(screen,&fromrect,screen,&torect);
                fromy=0;
                toy=8;
            }

            for(int x=0;x<(int)screen_width;x++) for(int y=fromy;y<toy;y++)
            {
                coord_x=(x-screen_center_x-center_x)*step;
                coord_y=(y-screen_center_y-center_y)*step;

                mandelbrot_number=mandel_iteration(coord_x, coord_y);
                if(mandelbrot_number==1) putpixel(screen, x, y, white);
                else putpixel(screen, x, y, SDL_MapRGB(screen->format, 0, 255*mandelbrot_number, 255*mandelbrot_number));
            }
        }
        SDL_Flip(screen);
        SDL_Delay(20);
    }
    return 0;
}

 :cura:
« Última modificación: Julio 25, 2014, 06:18:53 pm por Avoidance25 »
You are not allowed to view links. Register or Login
por ejemplo, se habla de emprender la You are not allowed to view links. Register or Login con el "fusil de carne" y se insta a una mujer a introducir You are not allowed to view links. Register or Login en su You are not allowed to view links. Register or Login

Desconectado .xAk.

  • el engendro
  • Moderador
  • *****
  • Mensajes: 7316
  • Sexo: Masculino
  • F0r3v3R NeWbI3
    • Ver Perfil
Re:Mandelbrot set
« Respuesta #1 en: Julio 26, 2014, 03:50:54 am »
 :D los problemas que hay con los de no-ip no van contigo (contrataste :)) entes los regalaban los subdominios). Gracias por el trabajo :)) muy interesante.

SaludOS
« Última modificación: Julio 26, 2014, 03:52:49 am por .xAk. »
Is the truth out there?

Desconectado @Aps

  • Me das tu password?
  • **
  • Mensajes: 267
  • Sexo: Masculino
  • (?)
    • Ver Perfil
Re:Mandelbrot set
« Respuesta #2 en: Agosto 03, 2014, 08:54:27 pm »
Esto está genial ... en serio que sí.

Agradecería si podrías explicar un poco la parte matemática del programa o el algoritmo que usaste para dibujarlo.

Reitero muy buen trabajo :O

Saludos.
There is not other!

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re:Mandelbrot set
« Respuesta #3 en: Agosto 05, 2014, 08:58:03 am »
Este video lo explica muy bien, pero está en ingles: You are not allowed to view links. Register or Login
Es de hecho el video que me dió la idea de hacer este programa, y el video que me enseño que es el conjunto de mandelbrot (la definición matematica).

Basicamente el conjunto de mandelbrot es un subconjunto de los numeros complejos. La imagen es la representacion de este conjunto en un plano cartesiano: El area blanca es el area donde los puntos estan dentro del conjunto, y el area negra es el area que esta fuera del conjunto.

El algoritmo calcula para cada pixel si el punto esta dentro o fuera del conjunto. Lo hace de manera iterativa, y si dentro de 256 iteracionas no puede probar que el punto está fuera del conjunto le da al pixel el color blanco. En caso de que el punto esté fuera del conjunto, le da al pixel un tono de cian que depende de cuantas iteraciones fueron necesarias para probar que el punto está fuera del conjunto.

El codigo es algo largo y complicado por algunas optimizaciones que hice, pero basicamente hace esto para cada pixel:
Código: You are not allowed to view links. Register or Login
coord_x=(x-screen_center_x-center_x)*step; //calcula a que coordenana corresponde el pixel
coord_y=(y-screen_center_y-center_y)*step; //calcula a que coordenana corresponde el pixel
mandelbrot_number=mandel_iteration(coord_x, coord_y); //devuelve la proporcion de iteraciones que fueron necesarias (#iteraciones/256)
if(mandelbrot_number==1) putpixel(screen, x, y, white); //Si luego de 256 iteraciones no se pudo probar que el pixel esta fuera del conjunto -> el pixel recibe el color blanco
else putpixel(screen, x, y, SDL_MapRGB(screen->format, 0, 255*mandelbrot_number, 255*mandelbrot_number)); //Si hicieron falta menos de 256 iteraciones, el tono de cian depende de la cantidad de iteraciones que fueron necesarias

Al iniciar el programa el centro de la pantalla está en el centro del plano cartesiano, y cada pixel tiene un largo (y ancho) de 0.00390625 unidades.

 :cura:

Desconectado @Aps

  • Me das tu password?
  • **
  • Mensajes: 267
  • Sexo: Masculino
  • (?)
    • Ver Perfil
Re:Mandelbrot set
« Respuesta #4 en: Agosto 08, 2014, 12:28:40 am »
Genial, ya me ha quedado claro. No sé cómo no había visto ese video de NumberPhile, deberé revisar el canal con más frecuencia.

Sólo una duda me agobia, qué pasa con las sucesiones que sí pertencen al conjunto y necesitan más de 256 iteracciones para comprobarse? cambié el número a un valor más alto pero no ví mucha diferencia en el resultado con relación a 256. ¿es ése un valor óptimo o algo parecido? ó.ó

Saludos.

Desconectado Avoidance25

  • Moderador
  • *****
  • Mensajes: 1248
  • Sexo: Masculino
  • Da gehört eiskrem aber nicht hin xD
    • Ver Perfil
    • sytes
Re:Mandelbrot set
« Respuesta #5 en: Agosto 09, 2014, 10:03:44 am »

Lo óptimo sería hacer infinitas iteraciones, 256 es un valor razonable que no hace que el programa sea excesivamente lento pero aun así dé una representación gráfica aproximada acceptable.

Aun con 256 iteraciones, se empiezan a ver errores en la representación gráfica al acercar mucho la imagen. Si queres tener una mejor idea de como esta constante afecta a la imagen te sujiero reducir su valor y observar los cambios.

En la wikidedia encontré este gif que muestra el conjunto de mandelbrot aproximado con distintas cantidades de iteraciones:


 :cura: