Website development and design blog, tutorials and inspiration

Fractals: Infinity Made Visible

Exploring the infinate worlds of fractals, art or mathematics?

By , 8th May 2003 in Software Engineering

Fractals are like alien worlds, strange yet familiar. You can zoom into a fractal endlessly, producing fascinating variations of colour, texture and shape.

Most mathematical formulae when plotted produce wave-like lines, curves, arcs and other simple shapes. Fractals by contrast produce extremely complex lacy colourful patterns. You never really see the same thing twice. They are often natural looking, imitating patterns produced in nature such as ferns or coastlines. Despite this, they are extremely simple to program, as we'll see here.

What is a fractal?

A fractal can be described as "the adventures of a small number in a complex plane." A fractal is a peculiar and very dense graph generated by a mathematical process. Although the graph are infinitely complex, the underlying algorithms are short and relatively simple.

When you want to see the relationship between numbers, to see mathematical expressions, you can put them into a chart or plot. A simple plot is shown below, distance against elevation.

A simple elevation plot showing distance in the x-axis and elevation in the y-axis

By going along the line you can see the altitude of various points change with distance.

Not all numbers used my mathematicians are those we are familiar with. For example to translate waveforms into audio, or to analyse radio signals it is necessary to use "imaginary" numbers.

Complex and Imaginary Numbers

In the 16th century, mathematicians began trying to describe the square root of minus one. When you multiply a number by itself, you square it; 4 * 4 is 16. You can describe this relationship in the opposite way, 4 is the square root of 16. It seems obvious that there is a square root for any number. Squares and roots have been used for thousands of years, but attention was focused on -1 which although paradoxical, eventually proved quite useful.

What is the square root of -1? When you square a positive number, you always get a positive number. When you multiply a negative number by a negative number, you also get a positive number. So, the number you need to multiply by itself to get -1 cannot be positive, nor can it be negative. In other words it is not a real number, it is imaginary.

When you combine imaginary numbers with real nu,bers, you get points on a grid. Real numbers describe the horizontal axis, while imaginary numbers describe the vertical distance. This creates a complex number, and they are an important concept, used in almost every field of mathematics and applied science, from voice processing, image compression, radar analysis, even earthquake monitoring.

A fractal is built pixel by pixel via the repeated transformation of a complex number. Several things can happen when you transform a complex number by multiplying it by itself.

  1. If it is a real number larger than 1, it will grow towards an infinitely large number.
  2. If it is less than one (a fraction) it will shrink towards an infinitely small number close to zero, but never reaching zero.
  3. If it is exactly one, it will remain one. 1 * 1 is 1 and always will be.

The Mandelbrot Set

All numbers that are negative are described as a "set" of negative numbers. The Mandelbrot set is a group of numbers which when plugged into the Mandelbrot equation remain bounded, that is they don't escape to infinity. The numbers which move towards zero, or those which oscillate, when painted in, create the classic Mandelbrot shape.

z = z^2 + c

We want to display these fractals on the screen. We can think of the complex plane as a grid, with real numbers shown horizontally and imaginary numbers shown vertically. To calculate the Mandelbrot set, we'll first choose a zone within the grid to paint in. For each point in this area we assign the corrsponding complex number to c and starting with z = 0, we repeat the transformation against this value enough times to discover whether or not this particular position will escape to infinity. it if will, we colour it white to show it is outside of the Mandelbrot set. If it won't escape we colour it black to show that it is part of the set. The number of times we run this test is the number of iterations.

The result is an intricate shape known as the Mandelbrot set. The irregular line between the black and the white areas is the boundary between the two attractors (infinity and zero). As you can see, it is by no means as simple as a circle.

Classic Black and White Mandelbrot Set
Classic Black and White Mandelbrot Set

Programming the Mandelbrot Set

Let's first start with the black and white Mandelbrot set. The only parameters to define are:

  1. The area of the complex plane (xMin, xMax, yMin, yMax)
  2. The resolution of the image (nx, ny)
  3. The maximum iterations required to determine if the value escapes or is bounded (maxIter)

Thirty two iterations is a good starting point. Larger values produce more accurate results, however require more calculation time.

I know this is in VisualBasic, it's the language I was using at the time. Later examples use Delphi and Pascal.

  1. Sub GenerateMAndelbrot ()
  2. BLACK = RGB(0,0,0): WHITE = RGB(255,255,255)
  3. Dim X As Double, Y As Double
  4. Dim ix As Integer, iy As Integer
  5. Dim MaxIter As Integer
  6.  
  7. ' Define picture resolution
  8. nx = 256
  9. ny = 256
  10.  
  11. ' Select area of the complex plane to map
  12. xmin = -1.5
  13. xmax = .5
  14. ymin = -1
  15. ymax = 1
  16.  
  17. ' Maximum number of iterations
  18. MaxIter = 32
  19.  
  20. ' For each point in the selected area
  21. For iy = 0 To ny - 1
  22. Y = (ymin + iy * (ymax - ymin) / (ny - 1))
  23.  
  24. For ix = 0 To nx - 1
  25. X = (xmin + ix * (xmax - xmin) / (nx - 1))
  26. ' Now check if it escapes to infinity
  27. M - Mandelbrot(X, Y, MaxIter)
  28. If M = MaxIter Then
  29. Picture1.PSet(ix,iy), BLACK
  30. Else
  31. Picture1.PSet(ix,iy), WHITE
  32. End If
  33. Next
  34. DoEvents
  35. Next
  36. End Sub
  37.  
  38. Function Mandelbrot (ByVal cx As Double, ByVal cy As Double, ByVal MaxIter As Integer) As Integer
  39. Dim x2 As Double, y2 As Double
  40. Dim temp As Double
  41. Dim X As Double, Y As Double
  42.  
  43. X = 0
  44. Y = 0
  45. x2 = 0
  46. y2 = 0
  47. iter = 0
  48.  
  49. While ((iter < MaxIter) And (Abs(x2) + Abs(y2) < 100000))
  50. temp = x2 - y2 + cx
  51. Y = 2 * X * Y + cy
  52. X = temp
  53. x2 = X * X
  54. y2 = Y * Y
  55. iter = iter + 1
  56. Wend
  57. Mandelbrot = iter
  58. End Function

The first function essentially goes through each pixel in the complex plain and runs the Mandelbrot calculation. If the value returned from this function does not escape to infinity it assigns that pixel the black colour, while if it does escape to infinity it is assigned the WHITE colour.

The actual calculation is done by the Mandelbrot function. The loop tests to see if the calculated value from the Mandelbrot equation escapes to infinity before the maximum iterations is reached. If it is, it returns the number of iterations, if it doesn't then it returns the max iterations. For this example, the value of 100000 is good enough to represent infinity.

Colouring Fractals

Black and White fractals are all well and good, but coloured fractals are often breathtaking. Where does the colour come from?

Different colours represent different escape velocities. That is, the calculation not only tests to see if a point escapes to infinity, it also tests how fast it escapes. These mysterious variations of escape velocity give fractals their beauty and complexity.

These code examples show code written in Borland Delphi. The fully working example can be downloaded at the end of the article.

  1. procedure TfrmMain.DrawMandel;
  2. var
  3. x,y: real;
  4. ix,iy,nx,ny,ipx,px: integer;
  5. aColor: TColor;
  6. begin
  7. nx := frmMain.FractalImage.Width;
  8. ny := frmMain.FractalImage.Height;
  9. DRAWINGF := TRUE;
  10. px := 0;
  11. begin
  12. nx := frmMain.FractalImage.Width;
  13. ny := frmMain.FractalImage.Height;
  14. for iy := 0 to ny-1 do
  15. begin
  16. if STOPNOW = TRUE then break;
  17. Y := (ymin +iy * (ymax -ymin) / (ny - 1));
  18. for ix := 0 to nx-1 do
  19. begin
  20. X := (xmin + ix * (xmax - xmin) / (nx - 1));
  21. aColor := CalcColorMandel(X,Y,maxiter);
  22. frmMain.FractalImage.Canvas.Pixels[ix,iy] := aColor;
  23. frmMain.Progress.Progress := trunc(((iy/frmMain.FractalImage.Height)*100)+1);
  24. frmMain.ProgressShow.Progress := frmMain.Progress.Progress;
  25. end;
  26. Application.ProcessMessages;
  27. end;
  28. end;
  29. DRAWINGF := FALSE;
  30. STOPNOW := FALSE;
  31. btnStop.Visible := FALSE;
  32. btnDraw.Visible := TRUE;
  33. px := 64;
  34. end;
  35.  
  36. function TfrmMain.CalcColorMandel(cx,cy: double; maxiter: integer): TColor;
  37. var
  38. x2,y2,temp,x,y : double;
  39. iter: integer;
  40. begin
  41. x := 0;
  42. y := 0;
  43. x2 := 0;
  44. y2 := 0;
  45. iter := 0;
  46. while ((iter < maxiter) and ((abs(x2) + abs(y2)) < 100000)) do
  47. begin
  48. temp := x2 - y2 + cx;
  49. y := (2 * x * y) + cy;
  50. x := temp;
  51. x2 := x * x;
  52. y2 := y * y;
  53. inc(iter);
  54. end;
  55. if PaletteType = 2 then result := trunc((iter+80)*colorFactor);
  56. if PaletteType = 1 then
  57. begin
  58. if ((iter > 60) AND (iter < maxiter)) then result := 255 * 255 * 255
  59. else if ((iter < 56) AND (iter > 53)) then result := 240 * 255 * 255
  60. else if ((iter < 52) AND (iter > 47)) then result := 244 * 255 * 255
  61. else if ((iter < 48) AND (iter > 45)) then result := 192 * 255 * 255
  62. else if ((iter < 44) AND (iter > 41)) then result := 176 * 255 * 255
  63. else if ((iter < 40) AND (iter > 37)) then result := 160 * 255 * 255
  64. else if ((iter < 36) AND (iter > 33)) then result := 144 * 255 * 255
  65. else if ((iter < 32) AND (iter > 29)) then result := 128 * 255 * 255
  66. else if ((iter < 28) AND (iter > 25)) then result := 112 * 255 * 255
  67. else if ((iter < 24) AND (iter > 21)) then result := 96 * 255 * 255
  68. else if ((iter < 20) AND (iter > 17)) then result := 80 * 255 * 255
  69. else if ((iter < 16) AND (iter > 13)) then result := 64 * 255 * 255
  70. else if ((iter < 12) AND (iter > 9)) then result := 32 * 255 * 255
  71. else if ((iter < 8) AND (iter > 5)) then result := 16 * 255 * 255
  72. else if (iter < 4) then result := 0
  73. else result := 0;
  74. end;
  75. end;

What we see here is the colour method testing how many iterations were needed before the value escapes to infinity. Based on this it assigns a colour value (R*G*B)

Download Delphi Fractals

Comments

There are no comments for this post. Be the first!

Leave a Reply

Your email address will not be published.