Fl025_Main.as (Main)

Fl025_Main.as
/**
 * @date 18/11/2008
 * @author borealkiss
 * @link http://blog.boreal-kiss.com/
 */
package {
    import flash.display.Sprite;
    import flash.display.DisplayObjectContainer;
    import flash.events.MouseEvent;
    import com.borealkiss.display.GeodeticCurve;
    [SWF(width="600",height="600",backgroundColor="0x0")]

    public class Fl025_Main extends Sprite{
        private const LIMIT:int = 60;
        private const STAGE_WIDTH:Number = 600;
        private const STAGE_HEIGHT:Number = 600;
        private const OFFSET_X:Number = 10
        private const OFFSET_Y:Number = 100;
        private var _curves:Array;
        
        public function Fl025_Main(){
            _curves = new Array();
            
            var container:Sprite = new Sprite();
            this.addChild(container);
            
            for (var i:int=0; i<LIMIT; i++){
                var shape:GeodeticCurve = new GeodeticCurve(STAGE_WIDTH);
                container.addChild(shape);
                _curves.push(shape);
                
                //Must be tuned.
                shape.y = STAGE_HEIGHT*i/LIMIT + OFFSET_Y;
            }
            
            container.scaleX = container.scaleY = 0.5;
            container.x = STAGE_WIDTH/2 - container.width/2;
            container.y = STAGE_HEIGHT/2 - container.height/2;
            this.addMask(container);
            stage.addEventListener(MouseEvent.CLICK,onClick);
        }
        
        private function onClick(e:MouseEvent):void{
            GeodeticCurve.yCrossSection = Math.random()*GeodeticCurve.BITMAP_HEIGHT;
            for (var i:int=0; i<_curves.length; i++){
                _curves[i].init();
            }
        }
        
        //Mask rectangle must be smaller than the container 
        //in order to hide the boundaries of the container.
        private function addMask(target:DisplayObjectContainer):void{
            //Must be tuned
            var paddingX:Number = 10;
            var paddingY:Number = -10;
            
            var mask:Sprite = new Sprite();
            this.addChild(mask);
            mask.graphics.beginFill(0x0);
            mask.graphics.drawRect(0,0,target.width - paddingX,target.height - paddingY);
            mask.graphics.endFill();
            mask.x = STAGE_WIDTH/2 - mask.width/2;
            mask.y = STAGE_HEIGHT/2 - mask.height/2;
            target.mask = mask;
        }
    }
}

com.borealkis.display.GeodeticCurve.as

/**
 * @date 18/11/2008
 * @author borealkiss
 * @link http://blog.boreal-kiss.com/
 */ 
package com.borealkiss.display{
    import flash.display.Shape;
    import flash.display.Graphics;
    import flash.display.BitmapData;
    import com.borealkiss.display.PerlinNoiseData;
    
    public class GeodeticCurve extends Shape{
        public static const BITMAP_HEIGHT:int = 100;
        public static var yCrossSection:Number;
        protected var _bitmapData:BitmapData;
        protected var _bitmapWidth:int;
        
        /**
         * Constructor
         */ 
        public function GeodeticCurve(width:int){
            if (isNaN(GeodeticCurve.yCrossSection)){
                GeodeticCurve.yCrossSection = Math.random()*BITMAP_HEIGHT;
            }
            _bitmapWidth = width;
            this.init();
        }
        
        public function init():void{
            var g:Graphics = this.graphics;
            g.clear();
            var numOctaves:int = 4;//Higher values make bump of the curve finer.
            var randomSeed:int = Math.floor(10*Math.random() + 1);//1<=randomSeed<=10
            _bitmapData = new PerlinNoiseData(_bitmapWidth,BITMAP_HEIGHT,
                                                _bitmapWidth/5,BITMAP_HEIGHT/5,numOctaves,randomSeed);
            this.draw(g);
        }
        
        protected function draw(g:Graphics):void{
            g.lineStyle(0,0xF5F5F5);
            var y:int = int(GeodeticCurve.yCrossSection);
                        
            g.beginFill(0x0);
            g.moveTo(0,0)
            for (var x:int=0; x<_bitmapWidth; x++){
                g.lineTo(x,-1*getHeight(x,y));
            }
            g.lineTo(x,0);
            g.endFill();
        }
        
        protected function getHeight(x:int,y:int):Number{
            //Must be tuned.
            var offsetY:Number = 50;
            var amplitude:Number = 10;
            var decay:Number = 0.4;
            var color:uint = _bitmapData.getPixel(x,y);
            var r:Number = color >> 16;//0<=r<=255
            var numerator:Number = amplitude*(Math.exp(r/(decay*255)) - 1);
            var dumper:Number = 1e-4;
            var denominator:Number = dumper*Math.pow(x-(_bitmapWidth/2),2) + 1;
            
            return numerator / denominator + offsetY;
        }
    }
}

com.borealkis.display.PerlinNoiseData.as

/**
 * @date 18/11/2008
 * @author borealkiss
 * @link http://blog.boreal-kiss.com/
 */ 
package com.borealkiss.display{
    import flash.display.BitmapData;
    
    /**
     * Create BitmapData filled with a specific perlin noise.
     */ 
    public class PerlinNoiseData extends BitmapData{
        protected var _width:int;
        protected var _height:int;
        protected var _baseX:Number;
        protected var _baseY:Number;
        protected var _numOctaves:uint;
        protected var _randomSeed:int;
        protected var _stitch:Boolean;
        protected var _fractalNoise:Boolean;
        protected var _channelOptions:uint;
        protected var _grayScale:Boolean;
        
        /**
         * Constructor
         */ 
        public function PerlinNoiseData(width:int,height:int,baseX:Number,baseY:Number,
                        numOctaves:uint=1,randomSeed:int=1,stitch:Boolean=true,
                        fractalNoise:Boolean=false,channelOptions:uint=7,grayScale:Boolean=true){
            _width = width;
            _height = height;
            _baseX = baseX;
            _baseY = baseY;
            _numOctaves = numOctaves;
            _randomSeed = randomSeed;
            _stitch = stitch;
            _fractalNoise = fractalNoise;
            _channelOptions = channelOptions;
            _grayScale = grayScale;
            super(_width,_height,false,0x0);
            init();
        }
        
        protected function init():void{
            this.perlinNoise(_baseX,_baseY,_numOctaves,_randomSeed,_stitch,_fractalNoise,_channelOptions,_grayScale);
        }
        
        /**
         * @param red Use red channel.
         * @param green User green channel.
         * @param blue Use blue channel.
         * @return uint ChanneOptions for BitmapData.perlinNoise().
         */ 
        public static function getChannelOptions(red:Boolean,green:Boolean,blue:Boolean):uint{
            return uint(red) + 2*uint(green) + 4*uint(blue);
        }
    }
}
Powered by blog Boreal Kiss 2008.