TAChart Tutorial: ColorMapSeries, Zooming

From Lazarus wiki
Revision as of 00:39, 11 October 2012 by Wp (talk | contribs) (Calculation of Mandelbrot set)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Calculation of the Mandelbrot set

The Mandelbrot set is calculated for each 2d point c = (c.x, c.y) by applying the following recipe:

  1. Begin by assigning the coordinates of c to another point z = (z.x, z.y) = (c.x, c.y).
  2. Calculate the "square" of z by means of the following formula: z² = ((z.x)²-(z.y)², 2*(z.x)*(z.y)) (this formula may appear to be a bit strange, but if you are familiar with complex numbers then you will see that it is the square of a complex number). Then add the coordinates of c to those of . The result of this step is z² + c
  3. Now take that result and put it into the calculation in step 2 again.
  4. Repeat this procedure again and again until you can distinguish whether the trace of the movement of the point z in the 2d plane diverges into infinity or not.

In the figure we show some examples of that trace:

Mandelbrot Tracks.png
  • The red and fuchsia curves eventually move away from the origin, these paths are "unbounded". It can be shown that once the path has crossed a critical distance of 2 from the origin it will never turn back and will escape into infinity. Usually the calculation counts the iterations until the distance from the origin exceeds 2. The number of iterations is mapped to a color which is used to draw the pixel at the starting point.
  • The blue path, on the other hand, converges towards the origin. The green curve does not converge, but remains within the escape radius. Therefore, both cases are called "bounded". The iterative calculation would go on forever, therefore it is stopped after a maximum count of iterations. The starting points are said to belong to the Mandelbrot set and are drawn in black color.

Here is the function that we will use to determine whether a point c is in the Mandelbrot set or not. The function result is the iteration count divided by the maximum iteration count. The result 1.0 indicates that c belongs to the Mandelbrot set.

const
  MANDELBROT_NUM_ITERATIONS = 100;
  MANDELBROT_ESCAPE_RADIUS = 2.0;
  MANDELBROT_LIMIT = sqr(MANDELBROT_ESCAPE_RADIUS);     

function MandelBrot(c:TDoublePoint): Integer;
var
  iteration: Integer;
  j: Integer;
  z: TDoublePoint;
begin
  Iteration := 0;
  z := DoublePoint(0.0, 0.0);
  for j:=0 to MANDELBROT_NUM_ITERATIONS-1 do begin
    z := DoublePoint(
      sqr(z.X) - sqr(z.Y) + c.X,
      2 * z.X * z.Y + c.Y
    );
    if sqr(z.X) + sqr(z.Y) > MANDELBROT_LIMIT then begin
      Result := Iteration / MANDELBROT_NUM_ITERATIONS;
      exit;
    end;
    inc(Iteration);
  end;
  Result := 1.0; 
end;

We will also need a function which maps the result of the Mandelbrot function to a color. A nice color gradient can be obtained by the following procedure which is an interpolation of rgb values applied to two intervals. The input parameter AValue must be number between 0 and 1. (The function InterpolateRGB belongs to the TAChart package and is found in the unit TAChartUtils):

const
  STARTCOLOR = clBlue;
  MIDDLECOLOR = clRed;
  ENDCOLOR = clYellow;
  MIDDLEVALUE = 0.3; 

function ValueToColor(AValue: Double; AMiddleValue: Double;
  AStartColor, AMiddleColor, AEndColor: TColor): TColor;
begin
  if AValue < AMiddleValue then
    Result := InterpolateRGB(AStartColor, AMiddleColor, 
      AValue/AMiddleValue)
  else
    Result := InterpolateRGB(AMiddleColor, AEndColor, 
      (AValue - AMiddleValue) / (1.0 - AMiddleValue) 
    );
end;