- Home
- Tutorials
- Flash
- Intermediate
- Creating a Mandelbrot-set
Creating a Mandelbrot-set

A Mandelbrot-set
Milan Toth
Milan Toth is the Chief Flash Developer of Jasmin Media Group, he created one of the world's biggest flash media server system. He loves Eclipse and OS X, AS3 and JAVA, sci-fi and horror, metal and electronic.
Complex numbers have two parts: a real and an imaginery part: z = ( r , i )
Addition: z1 + z2 = ( r1 + r2 , i1 + i2 )
Multiplication: z1 * z2 = ( r1 * r2 - i1 * i2 , r1 * i2 + r2 * i1 ).
Based on these operations we can simplify the Mandelbrot function.
z(2) = z(1) * z(1) + c
( z(2)r , z(2)i ) = ( z(1)r , z(1)i )( z(1)r , z(1)i ) + ( cr , ci );
( z(2)r , z(2)i ) = ( z(1)r * z(1)r - z(1)i * z(1)i , z(1)r * z(1)i + z(1)r * z(1)i ) + ( cr , ci );
z(2)r = z(1)r * z(1)r - z(1)i * z(1)i + cr;
z(2)i = z(1)r * z(1)i + z(1)r * z(1)i + ci = 2 * z(1)r * z(1)i + ci;
| zi | > 2 -> we have to stay in the circle with the radius 2
| zi | = sqrt( zr * zr + zi * zi ) > 2;
| zi | exp( 2 ) = zr * zr + zi * zi > 4
Let's translate it to AS3.
package
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
public class Mandelbrot extends Sprite
{
// display dimensions, set this as default size
private static var DWTH:Number = 550;
private static var DHTH:Number = 380;
// maximum function cycles
private static var CYCLES:Number = 128;
// the set's bitmapdata
private var bitmapData:BitmapData;
public function Mandelbrot ( )
{
// creating new bitmap instance
var setBitmap:Bitmap = new Bitmap( );
// creating new bitmapdata
bitmapData = new BitmapData( DWTH , DHTH , false , 0x000000 );
// attaching bitmapdata to bitmap
setBitmap.bitmapData = bitmapData;
// attaching bitmap to display list
addChild( setBitmap );
// start drawing
drawSet( -2 , 1 , -1 , 1 );
}
public function drawSet ( rmin:Number , // interval minimum on real axis
rmax:Number , // interval maximum on real axis
imin:Number , // interval minimum on imaginary axis
imax:Number ):void
{
// real axis stepping
var rStep:Number = ( rmax - rmin ) / DWTH;
// imaginary axis stepping
var iStep:Number = ( imax - imin ) / DHTH;
// actual real coordinate
var r:Number;
// actual imaginary coordinate
var i:Number;
// looping thorugh every display point
for ( var px:int = 0 ; px < DWTH ; px++ )
{
r = rmin + px * rStep;
for ( var py:int = 0 ; py < DHTH ; py++ )
{
i = imin + py * iStep;
var color:uint;
var cycles:int = getCycles( r , i );
// if cycles == CYCLES, the function tends to infinity
if ( cycles == CYCLES ) color = 0x000000;
// in not, we generate a greenish colour with bitwise left shit
else color = cycles << 16 | ( cycles + 50 ) << 8 | cycles;
// putting pixel
bitmapData.setPixel( px , py , color );
}
}
}
// calculating function cycle number
public function getCycles ( r:Number , i:Number ):uint
{
var zr:Number = 0;
var zi:Number = 0;
var cr:Number = r;
var ci:Number = i;
// z's old values
var ozr:Number = 0;
var ozi:Number = 0;
// z's old square values
var zrsq:Number = 0;
var zisq:Number = 0;
for ( var a:int = 0 ; a < CYCLES ; a++ )
{
zi = ozr * ozi * 2 + ci;
zr = zrsq - zisq + cr;
zrsq = zr * zr;
zisq = zi * zi;
ozr = zr;
ozi = zi;
if ( ( zrsq + zisq ) > 4 ) break;
}
return a;
}
}
}
Try it. Beautiful, eh? You can make it more detailed, if you set CYCLES higher, but it will also be slower. Check it under attachments.
And what about that bitwise-shift thing? Simple, we needed a 24 bit length colour code from a number under 128. So, i shifted 128 with 16 bits, to the "red" range ( 2(25) - 2(16) ), then i added 50, because i wanted green to be the dominant color, then shifted left with 8 bits to the green range ( 2(15) - 2(8) ), and i left it in the "blue" range, and made a logical "OR" between these values.



