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:
And that's all, thanks for reading!!!