Click here to Skip to main content
16,019,983 members
Articles / General Programming / Algorithms

The astounding Pickover's biomorphs

Rate me:
Please Sign up or sign in to vote.
5.00/5 (14 votes)
27 Nov 2017CPOL2 min read 33.3K   152   9   12
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)


Written By
Software Developer (Senior) Free lance
Spain Spain
I'm working with computers since the 80's of the past century, when I received as a present a 48K Spectrum which changed all my life plans, from a scientific career to a technical one. I started working in assembler language, in low lewel systems, mainly in the electromedical field. Today I work as a freelance, mainly in .NET Framework / database solutions, using the C# language.

I'm interested in scientific computer applications, and I,m learning AI and data analytics technics. I also own a technical blog, http://software-tecnico-libre.es/en/stl-index, where I publish some of the practice works of this learning process.

Comments and Discussions

 
QuestionMade a Lazarus Version of Biomorph Pin
Edy24-Sep-24 17:38
Edy24-Sep-24 17:38 
AnswerRe: Made a Lazarus Version of Biomorph Pin
Miguel Diaz Kusztrich24-Sep-24 18:09
professionalMiguel Diaz Kusztrich24-Sep-24 18:09 
GeneralRe: Made a Lazarus Version of Biomorph Pin
Edy24-Sep-24 20:23
Edy24-Sep-24 20:23 
GeneralRe: Made a Lazarus Version of Biomorph Pin
Edy26-Sep-24 19:28
Edy26-Sep-24 19:28 
Questionvery nice Pin
avisal30-Nov-17 6:06
professionalavisal30-Nov-17 6:06 
AnswerRe: very nice Pin
Miguel Diaz Kusztrich30-Nov-17 23:30
professionalMiguel Diaz Kusztrich30-Nov-17 23:30 
GeneralRe: very nice Pin
avisal1-Dec-17 2:17
professionalavisal1-Dec-17 2:17 
QuestionExcellent article, fascinating graphics + 5 ... one suggestion Pin
BillWoodruff28-Nov-17 8:07
professionalBillWoodruff28-Nov-17 8:07 
I implemented the colorization code suggested by Marc Clifton, and then updated/revised by you.

Note: By bracketing the image rendering like this:
SuspendLayout();

    pbImage.Image = await BiomorphAsync(new Complex(rnd.NextDouble() * (rnd.Next(3) + 1), rnd.NextDouble() * (rnd.Next(3) + 1)), rnd.Next(9));
    
ResumeLayout();
I observe a speed increase in the rendering: not something I expected. I thought I could get a little more speed by allocating the Image once, then calling 'Initialize on it to reset the bits: that did not work; instead the image was drawn over the current image ... which did have its own charm Smile | :)
«While I complain of being able to see only a shadow of the past, I may be insensitive to reality as it is now, since I'm not at a stage of development where I'm capable of seeing it.» Claude Levi-Strauss (Tristes Tropiques, 1955)

AnswerRe: Excellent article, fascinating graphics + 5 ... one suggestion Pin
Miguel Diaz Kusztrich29-Nov-17 6:49
professionalMiguel Diaz Kusztrich29-Nov-17 6:49 
QuestionVery nice! Pin
Marc Clifton28-Nov-17 2:39
mvaMarc Clifton28-Nov-17 2:39 
AnswerRe: Very nice! Pin
Miguel Diaz Kusztrich28-Nov-17 3:14
professionalMiguel Diaz Kusztrich28-Nov-17 3:14 
GeneralRe: Very nice! Pin
Marc Clifton28-Nov-17 4:15
mvaMarc Clifton28-Nov-17 4:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.