Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / algorithm

The astounding Pickover's biomorphs

5.00/5 (14 votes)
27 Nov 2017CPOL2 min read 33.3K   152  
An infinite set of biological shape fractals in the complex plain

Introduction

The algorithm I will present here was developed at the end of the 80's for the researcher Clifford Pickover. It allows to generate a wide set of biological like forms looking as some kind of microbian creatures, or maybe abstract paintings.

The procedure is very simple. We start with some complex variable function, F(z), as, say, Sin(z) + z2 + c, being c a constant, and, using the standard convergence study of Julia sets, we process the function recursively a given number of iterations or until we found that the function diverges, as the module is greather than a given value.

The key is that Pickover modified the algorithm adding a final condition about the size of the real and imaginary part of the result, but he made a mistake, confusing the OR and the AND operator, and is for this error that we can obtain such an expectacular result.

The project is written in c# using Visual Studio 2015.

Using the code

This demo application actually is nothing more than a slideshow of images generated with randomly selected functions among a set of ten. The c constant is selected at random, and this is the key to obtain a lot of diferent shapes even with the same function and the same subset of the complex plain.

First, I have defined the limits xmin, xmax, ymin, ymax for each of the ten functions in an array named _limits:

C#
private double[,] _limits = new double[10, 4] { { 2, 4, -5, -3 },
    { -2, 2, -2, 2 },
    { -1.7, 1.7, -1.7, 1.7 },
    { -3, 3, -3, 3 },
    { -5, 5, -5, 5 },
    { -10, 10, -10, 10 },
    { -3, 3, -3, 3 },
    { -1.5, 1.5, -1.5, 1.5 },
    { -1.2, 1.2, -1.2, 1.2 },
    { -8, 8, -8, 8 }};

To deal with complex numbers, I have chosen the Complex struct in the System.Numerics namespace. The method Fz implements the ten functions I have chosen. Really, you haven't to think a lot to define those function. Almost all you write will work fine:

C#
private Complex Fz(Complex z, Complex c, int f)
{
    switch (f)
    {
        case 0:
            return Complex.Sin(z) + Complex.Pow(z, 2) + c;
        case 1:
            return Complex.Pow(z, 2) + Complex.Pow(z, 6) + c;
        case 2:
            return Complex.Pow(z, 2) + Complex.Pow(z, 5) + c;
        case 3:
            return Complex.Pow(z, 3) + c;
        case 4:
            return Complex.Sin(z) + Complex.Pow(z, 5) + c;
        case 5:
            return Complex.Sin(z) - Complex.Cos(z) + Complex.Pow(z, 2) + c;
        case 6:
            return Complex.Pow(z, 3) - Complex.Cos(z) + Complex.Pow(z, 2) + c;
        case 7:
            return Complex.Pow(z, 6) - Complex.Pow(z, 4) + Complex.Sinh(z) + c;
        case 8:
            return Complex.Pow(z, 10) - Complex.Sinh(z) + c;
        default:
            return Complex.Cos(z) + Complex.Pow(z, 4) + c;
    }
}

And this is the method that makes the calculations and draws the result. I have chosen to use async / await asynchronous programming in order to let the application responsive while showing the pictures.

Instead of using the SetPixel method of the Bitmap class, I have used an optimized way by using an array of integers containing the pixel colors. At the end of the process, this data is copied into the Bitmap using a single operation.

C#
private Task<Bitmap> BiomorphAsync(Complex c, int f)
{
    return Task.Run(() =>
    {
        int[] bmpbits = new int[640 * 480];
        for (int ix = 0; ix < bmpbits.Length; ix++)
        {
            bmpbits[ix] = Color.White.ToArgb();
        }
        double xmin = _limits[f, 0];
        double xmax = _limits[f, 1];
        double ymin = _limits[f, 2];
        double ymax = _limits[f, 3];
        double px = (xmax - xmin) / 639;
        double py = (ymax - ymin) / 479;
        for (int p = 0; p < 640; p++)
        {
            for (int q = 0; q < 480; q++)
            {
                Complex z = new Complex(xmin + p * px, ymin + q * py);
                for (int k = 1; k < 50; k++)
                {
                    z = Fz(z, c, f);
                    if (z.Magnitude > 100)
                    {
                        break;
                    }
                }
                if (Math.Abs(z.Real) < 100 || Math.Abs(z.Imaginary) < 100)
                {
                    bmpbits[p + 640 * (479 - q)] = Color.Black.ToArgb();
                }
            }
        }
        Bitmap bmp = new Bitmap(640, 480);
        BitmapData bd = bmp.LockBits(new Rectangle(0, 0, 640, 480),
            ImageLockMode.ReadWrite,
            PixelFormat.Format32bppRgb);
        Marshal.Copy(bmpbits, 0, bd.Scan0, bmpbits.Length);
        bmp.UnlockBits(bd);
        return bmp;
    });
}

The process is started in the Load event of the form, and loops until the FormClosing event is fired. The c constant is created at random, and the function is selected the same way.

C#
private async void frmBio_Load(object sender, EventArgs e)
{
    _stopBio = false;
    Random rnd = new Random();
    while (!_stopBio)
    {
        pbImage.Image = await BiomorphAsync(new Complex(rnd.NextDouble() * (rnd.Next(3) + 1),
            rnd.NextDouble() * (rnd.Next(3) + 1)),
            rnd.Next(9));
        await WaitmsAsync(1000);
    }
}
private void frmBio_FormClosing(object sender, FormClosingEventArgs e)
{
    _stopBio = true;
}

Now. lets the algorithm talking by itself:

Image 2Image 3Image 1

Image 4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Image 5

 

 

 

 

 

 

 

 

 

 

 

 

 

 

And that's all, thanks for reading!!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)