15,037,178 members
Articles / General Programming / Algorithms
Article
Posted 27 Nov 2017

25.6K views
9 bookmarked

The astounding Pickover's biomorphs

Rate me:
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)
{
{
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),
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:

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

Share

 Software Developer (Senior) Free lance 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.

 First Prev Next
 very nice avisal30-Nov-17 6:06 avisal 30-Nov-17 6:06
 Re: very nice Miguel Diaz Kusztrich30-Nov-17 23:30 Miguel Diaz Kusztrich 30-Nov-17 23:30
 Re: very nice avisal1-Dec-17 2:17 avisal 1-Dec-17 2:17
 Excellent article, fascinating graphics + 5 ... one suggestion BillWoodruff28-Nov-17 8:07 BillWoodruff 28-Nov-17 8:07
 Re: Excellent article, fascinating graphics + 5 ... one suggestion Miguel Diaz Kusztrich29-Nov-17 6:49 Miguel Diaz Kusztrich 29-Nov-17 6:49
 To speed up, you can try to use a Parallel.For loop instead of the external for loop in the BiomorphAsyn method: Copy Code ```for (int p = 0; p < 640; p++) { ... }``` change with: Copy Code ```Parallel.For(0, 640, p => { ... });``` but I think that the algorithm is fast enough. In fact, I had to put a WaitAsync method to wait one second between two images. By the by, there is a mistake in my code, the rnd.Next(9), at the end of the BiomorphAsync call, must be rnd.Next(10), to cover all the 10 functions.
 Very nice! Marc Clifton28-Nov-17 2:39 Marc Clifton 28-Nov-17 2:39
 Re: Very nice! Miguel Diaz Kusztrich28-Nov-17 3:14 Miguel Diaz Kusztrich 28-Nov-17 3:14
 Re: Very nice! Marc Clifton28-Nov-17 4:15 Marc Clifton 28-Nov-17 4:15
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Sep-21 18:13 Refresh 1