Click here to Skip to main content
13,350,822 members (65,109 online)
Click here to Skip to main content
Add your own
alternative version

Stats

3.2K views
90 downloads
8 bookmarked
Posted 27 Nov 2017

The astounding Pickover's biomorphs

, 27 Nov 2017
Rate this:
Please Sign up or sign in to vote.
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:

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:

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.

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.

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)

Share

About the Author

Miguel Diaz Kusztrich
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.

You may also be interested in...

Comments and Discussions

 
Questionvery nice Pin
avisal30-Nov-17 7:06
professionalavisal30-Nov-17 7:06 
AnswerRe: very nice Pin
Miguel Diaz Kusztrich1-Dec-17 0:30
professionalMiguel Diaz Kusztrich1-Dec-17 0:30 
GeneralRe: very nice Pin
avisal1-Dec-17 3:17
professionalavisal1-Dec-17 3:17 
QuestionExcellent article, fascinating graphics + 5 ... one suggestion Pin
BillWoodruff28-Nov-17 9:07
mvpBillWoodruff28-Nov-17 9:07 
AnswerRe: Excellent article, fascinating graphics + 5 ... one suggestion Pin
Miguel Diaz Kusztrich29-Nov-17 7:49
professionalMiguel Diaz Kusztrich29-Nov-17 7:49 
QuestionVery nice! Pin
Marc Clifton28-Nov-17 3:39
protectorMarc Clifton28-Nov-17 3:39 
AnswerRe: Very nice! Pin
Miguel Diaz Kusztrich28-Nov-17 4:14
professionalMiguel Diaz Kusztrich28-Nov-17 4:14 
GeneralRe: Very nice! Pin
Marc Clifton28-Nov-17 5:15
protectorMarc Clifton28-Nov-17 5: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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.180111.1 | Last Updated 28 Nov 2017
Article Copyright 2017 by Miguel Diaz Kusztrich
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid