This post is inspired by the very nice blog post A Ray Tracer in C#3.0.

The Escape time algorithm is very simple, but depending on its input it can generate very complex images.

Although not mandatory, the first thing to create is a class from complex numbers. The complex number class contains the following members:

public class Complex

{

public Complex(double real, double img)

public Complex Multiply(Complex c)

public Complex Add(Complex c)

public double Norm()

public double NormSquared()

public static Complex operator *(Complex c1,Complex c2)

public static Complex operator +(Complex c1, Complex c2)

public double Real

public double Img

}

Now we need something to convert from the image coordinate system to the real coordinate system. To do this the following function was created:

public static Func<double, double> InterpFunc(double x1,double y1,double x2,double y2)

{

double m = (y2 - y1) / (x2 - x1);

double b = y1 - (m * x1);

return (x => m * x + b);

}

The

`InterpFunc`

method creates a function that maps values from one coordinate system to the other.The code that creates the image is the following:

void CreateFractal(double minX, double minY,double maxX, double maxY,int imageWidth, int imageHeight)

{

Func<double, double> xF = MathUtils.InterpFunc(0, minX, imageWidth, maxX);

Func<double, double> yF = MathUtils.InterpFunc(0, minY, imageHeight, maxY);

foreach (var p in from yi in Enumerable.Range(0, imageHeight)

from xi in Enumerable.Range(0, imageWidth)

select new

{

x = xi,

y = yi,

xD = xF(xi),

yD = yF(yi)

})

{

Complex p0 = new Complex(p.xD, p.yD);

Func<Complex, Complex> function = functionConstructor(p0);

int i = ApplyFunction(function, p0)

.TakeWhile(

(x, j) => j < maxIteration && x.NormSquared() < 4.0)

.Count();

HandlePixel(p.x, p.y, i);

}

}

Basically

`select `

expression generates the coordinates for all the points in the image . The `functionConstructor`

function is used to create the function that will be applied to generate the fractal. One example of this functions is the one used for the Mandelbrot fractal `f(x) = x^2 + p0`

. The escape time is calculated by counting the number of elements in the generated sequence of function applications before the value escaped.The

`ApplyFunction`

method is interesting since is the one that creates the sequence of recursive function applications required for this algorithm. The method looks like this:

IEnumerable<Complex> ApplyFunction(Func<Complex, Complex> function,Complex initial)

{

Complex last = initial;

while (true)

{

last = function(last);

yield return last;

}

}

By running this algorithm using the Mandelbrot formula:

Func<Complex,Func<Complex,Complex>> fc =

p0 => (c => c.Multiply(c).Add(p0));

EscapeTimeFractal p = new EscapeTimeFractal(300, 300, fc);

p.MinX = -0.03;

p.MinY = 0.68;

p.MaxX = 0.03;

p.MaxY = 0.62;

p.Run();

The generated image is the following:

By running it using the Szegedi Butterfly 1 formula:

Func<Complex,Func<Complex,Complex>> fc =

p0 =>

(c => (new Complex(

((c.Img * c.Img) - Math.Sqrt(Math.Abs(c.Real))),

((c.Real * c.Real) - Math.Sqrt(Math.Abs(c.Img)))))

+ p0);

EscapeTimeFractal p = new EscapeTimeFractal(300, 300,fc);

p.MinX = -2;

p.MinY = 2;

p.MaxX =2;

p.MaxY = -2;

p.MaxIteration = 127;

p.OutputFileName = @"c:\temp\output.bmp";

p.Run();

The generated image is the following:

The code for this experiment can be found here.