Mandelbrot fractal

by antalg
This is the result of me playing around with complex numbers and the Mandelbrot fractal.

Arrows or mouse: move around
Sliders to change:
 zoom (scale)
 iterations (n)
 cut off limit (r)

[I have now removed my complex number class]
[I still have the code on my computer.]
[So if you're interested in it, send me a message!]

My class for complex numbers can do:

The basic operations:
addition
subtraction
multiplication & vector scaling
division
exponentiation (through polar form and de Moivre's formula)

Special operations:
argument
absolute value
conjugate
conjugate multiplication

(I haven't implemented complex numbers in polar form yet, and I doubt it will happen at all. It's just me playing around, after all!)
♥0 | Line 143 | Modified 2011-11-25 07:34:00 | MIT License
play

ActionScript3 source code

/**
 * Copyright antalg ( http://wonderfl.net/user/antalg )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/oLjH
 */

package {
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.events.Event;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.text.TextField;
    import flash.display.Sprite;
    import com.bit101.components.HUISlider;
    
    public class Mandelbrot extends Sprite {
        public function Mandelbrot() {
            _data = new BitmapData(WIDTH, HEIGHT);
            addChild(new Bitmap(_data));
            
            render();
            
            var vals:Array = [_scale, _n , _r];
            var maxes:Array = [40, 150, 100];
            
            _sliders.push(new HUISlider (null, 0, 0, "Scale", updSliders));
            _sliders.push(new HUISlider (null, 0, 0, "N (iterations)", updSliders));
            _sliders.push(new HUISlider (null, 0, 0, "R (limit)", updSliders));
            for(var i:int = 0; i<3; i++) {
                _sliders[i].setSliderParams(0.1, maxes[i], vals[i]);
                _sliders[i].y = i*20;
                _sliders[i].width = 465;
                
                addChild(_sliders[i]);
            }
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyD);
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseD);
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseU);
        }
        
        private var _sliders:Array = new Array();
        
        private var _dx:Number = 0;
        private var _dy:Number = 0;
        
        private var _scale:Number = 0.8;
        private var _r:Number = 20;
        private var _n:Number = 35;
        
        private var _data:BitmapData;
        private const WIDTH:int = 465;
        private const HEIGHT:int = 465;
        
        private var _startPos:Point;
        private var _startD:Point;
        
        private function mouseD(e:MouseEvent):void {
            if(stage.mouseY > 60) {
                _startPos = new Point(stage.mouseX, stage.mouseY);
                _startD = new Point(_dx, _dy);
            
                stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseM);
            }
        }
        
        private function mouseU(e:MouseEvent):void {
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseM);
        }
        
        private function mouseM(e:MouseEvent):void {
            var dx:Number = 2.3/_scale/WIDTH;
            var dy:Number = 2.4/_scale/HEIGHT;
            
            _dx = _startD.x + (_startPos.x - stage.mouseX)*dx;
            _dy = _startD.y + (_startPos.y - stage.mouseY)*dy;
            
            render();
        }
        
        private function keyD(e:KeyboardEvent):void {
            switch(e.keyCode) {
                case 37:    // Left
                    _dx-=0.1/_scale;
                    break;
                case 38:    // Up
                    _dy-=0.1/_scale;
                    break;
                case 39:    // Right
                    _dx+=0.1/_scale;
                    break;
                case 40:    // Down
                    _dy+=0.1/_scale;
                    break;
            }
            
            render();
        }
        
        private function updSliders(e:*):void {
            _scale = _sliders[0].value;
            _n = _sliders[1].value;
            _r = _sliders[2].value;
            
            render();
        }
        
        private function render():void {
            renderFractal( -1.8/_scale  + _dx, -1.2/_scale + _dy, 0.5/_scale + _dx, 1.2/_scale + _dy, _n, _r);
        }
        
        private function renderFractal(sX:Number, sY:Number, eX:Number, eY:Number, n:int, r:Number):void {
            var x:int;
            var y:int;
            var dx:Number = (eX-sX)/WIDTH;
            var dy:Number = (eY-sY)/HEIGHT;
            
            _data.lock();
            r*=r;
            
            var vec:Vector.<uint> = new Vector.<uint>(HEIGHT*WIDTH);
            
            for (x = 0; x<WIDTH;x++) {
                for (y = 0; y<HEIGHT;y++) {
                    vec[x+y*WIDTH] = calcColor(sX+x*dx, sY+y*dy, n, r);
                }
            }
            
            _data.setVector(new Rectangle(0, 0, WIDTH ,HEIGHT), vec);
            _data.unlock();
        }
        
        private function calcColor(cR:Number, cI:Number, n:int, r:Number):uint {
            var zR:Number = cR;
            var zI:Number = cI;
            
            var zR2:Number;
            var zI2:Number;
            
            var m:int = 1;
            for(; m<n; m++) {
                zR2 = zR*zR;
                zI2 = zI*zI;
                
                zI = 2*zR*zI + cI;
                zR = zR2 - zI2 + cR;
                
                if(zR2 + zI2 > r) {
                    var phi:Number = m-Math.log(Math.log(Math.sqrt(zR*zR+zI*zI))/Math.log(n))/Math.LN2;
                    var b:int = (phi*70)%((colMax<<1)-1);
                    b = b<=colMax?b:( ((colMax<<1)-1)-b );
                    return (255<<24)|(b<<16)|(b<<8)|(b/2);
                }
            }
            
            return 0xFFFFFFFF;
        }
        private const colMax:int = 200;
        
        ////////////////////////////////////////////////////
        
        private var traceTextField:TextField;
        private function setupTrace(color:uint, x:int = 0, y:int = 0, width:int = 200, height:int = 400):void {
            traceTextField = new TextField();
            addChild(traceTextField);
            
            traceTextField.textColor = color;
            traceTextField.x = x;
            traceTextField.y = y;
            traceTextField.width = width;
            traceTextField.height = height;
        }
        private function clear():void {
            traceTextField.text = "";
        }
        private function trace(output:*):void {
            traceTextField.text = output;
        }
        private function traceA(output:*):void {
            traceTextField.appendText(output+"\n");
        }
    }
}