In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

flash on 2011-3-16

Calculating fractional mandelbrot using
polar vs cartesian form of complex numbers.

Click below slider to zoom in.

@author makc
Get Adobe Flash player
by makc3d 16 Mar 2011
    Embed
package  
{
	import com.bit101.components.HSlider;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.utils.setTimeout;

	/**
	 * Calculating fractional mandelbrot using
	 * polar vs cartesian form of complex numbers.
	 * 
	 * Click below slider to zoom in.
	 * 
	 * @author makc
	 */
	public class Test extends Sprite 
	{
		public var bmp:BitmapData;
		public var pow:HSlider;

		public var x0:Number = 0;
		public var y0:Number = 0;
		public var z0:Number = 100;

		public function Test () 
		{
			addChild (new Bitmap (bmp = new BitmapData (465, 464)));

			// quick test of PolarComplex' add()
			var foo:PolarComplex = new PolarComplex; foo.init (1,  2);
			var bar:PolarComplex = new PolarComplex; bar.init (4, -7);
			foo.add (bar); trace (foo.re (), foo.im ()); // 5, -5

			pow = new HSlider (this, 10, 10, change);
			pow.setSliderParams (2, 3, 2);
			pow.width = 445;
			pow.tick = 0.01;

			render ();

			stage.addEventListener (MouseEvent.CLICK, zoom);
		}

		public function change (whatever:* = null):void {
			setTimeout (render, 100);
			pow.enabled = false;
		}

		public function render ():void {
			doMandelbrot (x0, y0, z0, pow.value, new CartesianComplex, new CartesianComplex);
			doMandelbrot (x0, y0, z0, pow.value, new PolarComplex, new PolarComplex, 232);
			pow.enabled = true;
		}

		public function zoom (whatever:*):void {
			if (mouseY > pow.x + pow.height) {
				var i:int = mouseX;
				var j:int = mouseY % 232;
				var cx:Number = x0 + (i - 232.5) / z0;
				var cy:Number = y0 + (j - 116.0) / z0;
				z0 *= 2;
				x0 = cx;
				y0 = cy;
				change ();
			}
		}

		public function doMandelbrot (centerX:Number, centerY:Number, zoom:Number, power:Number, Z:IComplex, C:IComplex, startY:int = 0):void {
			bmp.lock ();
			for (var i:int = 0; i < 465; i++)
			for (var j:int = 0; j < 232; j++) {
				var cx:Number = centerX + (i - 232.5) / zoom;
				var cy:Number = centerY + (j - 116.0) / zoom;
				C.init (cx, cy);
				Z.init (cx, cy);
				var m:int = 0, n:int = 20;
				while (m < n) {
					// Z = Z^P + C
					Z.pow (power); Z.add (C);
					// bail out?
					cx = Z.re ();
					cy = Z.im ();
					if (cx * cx + cy * cy > 4) break;
					m++;
				}
				bmp.setPixel (i, j + startY, 0x10101 * int (255 * m / n));
			}
			bmp.unlock ();
		}
	}
}

interface IComplex {
	function init (x:Number, y:Number):void;
	function add (c:IComplex):void;
	function pow (p:Number):void;
	function re ():Number;
	function im ():Number;
}

class CartesianComplex implements IComplex {
	private var x:Number = 0;
	private var y:Number = 0;

	public function init (x:Number, y:Number):void {
		this.x = x;
		this.y = y;
	}
	public function add (c:IComplex):void {
		this.x += c.re ();
		this.y += c.im ();
	}
	public function pow (p:Number):void {
		var ap:Number = p * Math.atan2 (y, x);
		var rp:Number = Math.pow (x * x + y * y, p / 2);
		this.x = rp * Math.cos (ap);
		this.y = rp * Math.sin (ap);
	}
	public function re ():Number { return this.x; }
	public function im ():Number { return this.y; }
}

class PolarComplex implements IComplex {
	private var a:Number = 0;
	private var r:Number = 0;
	
	public function init (x:Number, y:Number):void {
		a = Math.atan2 (y, x);
		r = Math.sqrt (x * x + y * y);
	}
	public function add (c:IComplex):void {
		// I have no magic formula
		// so let's do it hard way
		var ax:Number = re ();
		var ay:Number = im ();
		var bx:Number = c.re ();
		var by:Number = c.im ();
		// c = a + b
		var cx:Number = ax + bx;
		var cy:Number = ay + by;
		// r = |c|, but normalize a 1st
		ax /= r;
		ay /= r;
		r = Math.sqrt (cx * cx + cy * cy);
		// rotate a 90° left and store in b
		bx = -ay;
		by = +ax;
		// transform c into basis a, b
		var dx:Number = cx * ax + cy * ay;
		var dy:Number = cx * bx + cy * by;
		// finally, calculate new angle
		a = a + Math.atan2 (dy, dx);
	}
	public function pow (p:Number):void {
		a = a * p;
		r = Math.pow (r, p);
	}
	public function re ():Number { return r * Math.cos (a); }
	public function im ():Number { return r * Math.sin (a); }
}