Dibujando el Fractal de Sierpinski en C#

 

Me topé con esta web http://www.student.kuleuven.be/~m0216922/CG/sierpinski.html que muestra cómo dibujar el fractal de Sierpinski usando C++ y recursividad. El código es bastante simple, así que decidí implementarlo en .Net.

La idea principal para dibujar el triángulo de Sierpinski está en este párrafo:

En realidad el código fuente ya está hecho. La idea era pasarlo a C# y, como valor añadido, meterle punteros.

Primero creé una ventana "Form1" con un PictureBox llamado "PicS":

 

Aparte, creé una clase llamada Sierpinski, donde está el código para dibujar el fractal. Form1 sólo posee este código:

La variable "unaVez" se encarga de que el fractal sólo se dibuje una vez al ejecutar el programa.

El código original de la clase Sierpinski es:

using System;

using System.Drawing; 

namespace Sierpinsky

{

    unsafe class Sierpinski

    {

        public Graphics Draw(Graphics g, int ancho, int alto)

        {

            Graphics g0 = g;

            Point* esq = stackalloc Point[3];          

            esq[0].X = 50;

            esq[0].Y = alto - 10;

            esq[1].X = ancho - 10;

            esq[1].Y = alto - 10;

            esq[2].X = ancho / 2;

            esq[2].Y = 10; 

            Sierp(g0, esq, 0);

            g = g0;                                  

            return g;

        }       

        private void Sierp(Graphics g0, Point* p, int n)

        {

            Pen pen = new Pen(Color.Black, 1);

            g0.DrawLine(pen, p[0], p[1]);

            g0.DrawLine(pen, p[1], p[2]);

            g0.DrawLine(pen, p[2], p[0]); 

            Point* p2 = stackalloc Point[3];

 

            if (n<7)

            {

                p2[0].X = (p[0].X + p[1].X) / 2 + (p[1].X - p[2].X) / 2;

                p2[0].Y = (p[0].Y + p[1].Y) / 2 + (p[1].Y - p[2].Y) / 2;

                p2[1].X = (p[0].X + p[1].X) / 2 + (p[0].X - p[2].X) / 2;

                p2[1].Y = (p[0].Y + p[1].Y) / 2 + (p[0].Y - p[2].Y) / 2;

                p2[2].X = (p[0].X + p[1].X) / 2;

                p2[2].Y = (p[0].Y + p[1].Y) / 2;

                Sierp(g0, p2, n+1);

               

                p2[0].X = (p[1].X + p[2].X) / 2 + (p[1].X - p[0].X) / 2;

                p2[0].Y = (p[1].Y + p[2].Y) / 2 + (p[1].Y - p[0].Y) / 2;

                p2[1].X = (p[1].X + p[2].X) / 2 + (p[2].X - p[0].X) / 2;

                p2[1].Y = (p[1].Y + p[2].Y) / 2 + (p[2].Y - p[0].Y) / 2;

                p2[2].X = (p[1].X + p[2].X) / 2;

                p2[2].Y = (p[1].Y + p[2].Y) / 2;

                Sierp(g0, p2, n+1);

 

                p2[0].X = (p[0].X + p[2].X) / 2 + (p[2].X - p[1].X) / 2;

                p2[0].Y = (p[0].Y + p[2].Y) / 2 + (p[2].Y - p[1].Y) / 2;

                p2[1].X = (p[0].X + p[2].X) / 2 + (p[0].X - p[1].X) / 2;

                p2[1].Y = (p[0].Y + p[2].Y) / 2 + (p[0].Y - p[1].Y) / 2;

                p2[2].X = (p[0].X + p[2].X) / 2;

                p2[2].Y = (p[0].Y + p[2].Y) / 2;

                Sierp(g0, p2, n + 1);      

            } 

        } 

    }

}

 

Y el resultado es éste:

Por ahí debo haber puesto al revés una suma, pero de salir, salió.

 

Si a la función "Sierp" le hago la siguiente modificación:

private void Sierp(Graphics g0, Point* p, int n)

{

    Pen pen = new Pen(Color.Black, 1);

    g0.DrawLine(pen, p[0], p[1]);

    g0.DrawLine(pen, p[1], p[2]);

    g0.DrawLine(pen, p[2], p[0]); 

    Point* p2 = stackalloc Point[3];

 

    if (n<7)

    {

        p2[0].X = (p[0].X + p[1].X) / 2 + (p[1].X - p[2].X) / 2;

        p2[0].Y = (p[0].Y + p[1].Y) / 2 + (p[1].Y - p[2].Y) / 2;

        p2[1].X = (p[0].X + p[1].X) / 2 + (p[0].X - p[2].X) / 2;

        p2[1].Y = (p[0].Y + p[1].Y) / 2 + (p[0].Y - p[2].Y) / 2;

        p2[2].X = (p[0].X + p[1].X) / 2;

        p2[2].Y = (p[0].Y + p[1].Y) / 2;

        Sierp(g0, p2, n+1);

       

        p2[0].X = (p[0].X + p[2].X) / 2 + (p[1].X - p[0].X) / 2;

        p2[0].Y = (p[0].Y + p[2].Y) / 2 + (p[1].Y - p[0].Y) / 2;

        p2[1].X = (p[0].X + p[2].X) / 2 + (p[2].X - p[0].X) / 2;

        p2[1].Y = (p[0].Y + p[2].Y) / 2 + (p[2].Y - p[0].Y) / 2;

        p2[2].X = (p[0].X + p[2].X) / 2;

        p2[2].Y = (p[0].Y + p[2].Y) / 2;

        Sierp(g0, p2, n+1);

 

        p2[0].X = (p[1].X + p[2].X) / 2 + (p[2].X - p[1].X) / 2;

        p2[0].Y = (p[1].Y + p[2].Y) / 2 + (p[2].Y - p[1].Y) / 2;

        p2[1].X = (p[1].X + p[2].X) / 2 + (p[0].X - p[1].X) / 2;

        p2[1].Y = (p[1].Y + p[2].Y) / 2 + (p[0].Y - p[1].Y) / 2;

        p2[2].X = (p[1].X + p[2].X) / 2;

        p2[2].Y = (p[1].Y + p[2].Y) / 2;

        Sierp(g0, p2, n + 1);               

    } 

}

 

El resultado será:

No está mal :)

 

Lo mismo se puede conseguir modificando un poquito la función Sierp, simplemente añadiendo un puntero:

El proyecto (hecho en Visual Studio Express 2008 e incluye todos los punteros) se puede descargar de aquí. A diferencia del código en C++, mi código usa una sola función (la función recursiva) para dibujar el fractal.