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

3D Self Organizing Map - Arrange 2D Array

Get Adobe Flash player
by greentec 20 Apr 2015
/**
 * Copyright greentec ( http://wonderfl.net/user/greentec )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/qZ83
 */

// forked from greentec's Self Organizing Map - Arrange 2D Array
// forked from greentec's Self Organizing Map
package 
{
    import away3d.cameras.Camera3D;
    import away3d.containers.Scene3D;
    import away3d.containers.View3D;
    import away3d.controllers.HoverController;
    import away3d.debug.AwayStats;
    import away3d.entities.Mesh;
    import away3d.lights.DirectionalLight;
    import away3d.materials.ColorMaterial;
    import away3d.materials.lightpickers.StaticLightPicker;
    import away3d.primitives.SkyBox;
    import away3d.primitives.SphereGeometry;
    import away3d.primitives.CubeGeometry;
    import away3d.textures.BitmapCubeTexture;
    import away3d.utils.Cast;
    import com.bit101.components.Label;
    import flash.display.*;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    
    
    /**
     * ...
     * @author ypc
     */
    [SWF(width = "465", height = "465")]
    public class Main extends Sprite 
    {
        private var view:View3D;
        private var scene:Scene3D;
        private var camera:Camera3D;
        private var awayStats:AwayStats;
        
        private var cameraController:HoverController;
        
        private var light:DirectionalLight;
        private var lightPicker:StaticLightPicker;
        
        private var skyboxTexture:BitmapCubeTexture;
        
        private var nodeSphereArray:Array;
        
        
        //navigation variables
        private var move:Boolean = false;
        private var lastPanAngle:Number;
        private var lastTiltAngle:Number;
        private var lastMouseX:Number;
        private var lastMouseY:Number;
        
        
        private var outputNeuronWidthNum:int = 25;
        private var outputNeuronHeightNum:int = 25;
        private var outputNeuronNum:int = outputNeuronWidthNum * outputNeuronHeightNum;
        private var inputNeuronNum:int = 25000;
        
        public var inputLayer:Layer;
        public var outputLayer:Layer;
        
        public var startLearningRate:Number = 0.05;
        public var learningRate:Number = 0.05;
        public var oneFrameIter:int = 10;
        public var iterMax:int = inputNeuronNum / oneFrameIter - 1;
        public var iter:int = -1;
        
        public var startRadius:Number = (outputNeuronWidthNum + outputNeuronWidthNum) / 2;
        public var radius:Number = startRadius;
        public var timeConstant:Number = iterMax / Math.log(startRadius); 
        
        public var proceedNumLabel:Label;
        public var resetLabel:Label;
        //public var resetButton:PushButton;
        
        //private var source:BitmapData = new BitmapData(465, 465, false, 0x000000);
        
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            
            Wonderfl.disable_capture();

            //addChild(new Bitmap(source));

            
            
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            
            proceedNumLabel = new Label(this, 465 - 100, 10, "");
            resetLabel = new Label(this, 465 - 100, 22, "Press R to Reset");
            //resetButton = new PushButton(this, 465 - 100, 30, "Reset", onReset);
            
            initEngine();
            initLight();
            initMaterial();
            initObject();
            initListener();
            
            initNeuron();
            
        }
        
        private function initEngine():void
        {
            view = new View3D();
            view.antiAlias = 4;
            
            scene = view.scene;
            camera = view.camera;
            camera.lens.far = 5000;
                        
            cameraController = new HoverController(camera);
            cameraController.distance = 1000;
            //cameraController.minTiltAngle = 10;
            //cameraController.maxTiltAngle = 90;
            cameraController.panAngle = 45;
            cameraController.tiltAngle = 20;
            
            awayStats = new AwayStats(view);
            
        }
        
        private function initLight():void
        {
            light = new DirectionalLight( -0.5, -1, -1);
            light.color = 0xffffff;
            light.ambient = 1;
            scene.addChild(light);
            
            lightPicker = new StaticLightPicker([light]);
        }
        
        private function initMaterial():void
        {
            var noiseBitmapData:BitmapData = new BitmapData(64, 64, false);
            noiseBitmapData.noise(Math.random() * int.MAX_VALUE, 0, 64, 7, true);
            var red:BitmapData = new BitmapData(64, 64, false, 0x990000);
            red.draw(noiseBitmapData, null, null, BlendMode.SUBTRACT);
            var green:BitmapData = new BitmapData(64, 64, false, 0x009900);
            green.draw(noiseBitmapData, null, null, BlendMode.SUBTRACT);
            var blue:BitmapData = new BitmapData(64, 64, false, 0x000099);
            blue.draw(noiseBitmapData, null, null, BlendMode.SUBTRACT);
            var yellow:BitmapData = new BitmapData(64, 64, false, 0x999900);
            yellow.draw(noiseBitmapData, null, null, BlendMode.SUBTRACT);
            var magenta:BitmapData = new BitmapData(64, 64, false, 0x990099);
            magenta.draw(noiseBitmapData, null, null, BlendMode.SUBTRACT);
            var cyan:BitmapData = new BitmapData(64, 64, false, 0x009999);
            cyan.draw(noiseBitmapData, null, null, BlendMode.SUBTRACT);
            
            //var bitmap:Bitmap = new Bitmap(red);
            //bitmap.x = stage.stageWidth - bitmap.width;
            //addChild(bitmap);
            
            skyboxTexture = new BitmapCubeTexture(Cast.bitmapData(red),
                                                  Cast.bitmapData(green),
                                                  Cast.bitmapData(blue),
                                                  Cast.bitmapData(yellow),
                                                  Cast.bitmapData(magenta),
                                                  Cast.bitmapData(cyan));
            
            
            //
            
        }
        
        private function initObject():void
        {
            scene.addChild(new SkyBox(skyboxTexture));
            
            nodeSphereArray = [];
            var nodeSphere:Mesh;
            
            var i:int;
            var red:int;
            var green:int;
            var blue:int;
            var tx:int;
            var ty:int;
            var colorMaterial:ColorMaterial;
            for (i = 0; i < outputNeuronNum; i += 1)
            {
                //nodeSphere = new Mesh(new SphereGeometry(20), new ColorMaterial(Math.random() * 0x0000ff));
                
                tx = i % outputNeuronWidthNum;
                ty = i / outputNeuronWidthNum;
                red = tx / outputNeuronWidthNum * 255;
                green = ty / outputNeuronWidthNum * 255;
                blue = Math.abs(tx - ty) / outputNeuronWidthNum * 255;
                
                colorMaterial = new ColorMaterial(red << 16 | green << 8 | blue);
                colorMaterial.lightPicker = lightPicker;
                
                nodeSphere = new Mesh(new SphereGeometry(20), colorMaterial);
                //nodeSphere = new Mesh(new CubeGeometry(30, 30, 30, 1, 1, 1, false), colorMaterial);
                
                nodeSphereArray.push(nodeSphere);
                scene.addChild(nodeSphere);
            }
            
            
        }
        
        private function initListener():void
        {
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            stage.addEventListener(Event.RESIZE, resizeHandler);
            stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            addEventListener(Event.ENTER_FRAME, render);
            
            
            addChild(view);
            addChild(awayStats);
        }
        
        private function onKeyDown(e:KeyboardEvent):void
        {
            if (e.keyCode == 82) //R or r : Reset!
            {
                onReset();
            }
        }
        
        private function initNeuron():void
        {
            var i:int;
            var neuron:Neuron;
            
            inputLayer = new Layer();
            for (i = 0; i < inputNeuronNum; i += 1)
            {
                neuron = new Neuron(3);
                inputLayer.neurons.push(neuron);
           }
            
            outputLayer = new Layer();
            for (i = 0; i < outputNeuronNum; i += 1)
            {
                neuron = new Neuron(3);
                outputLayer.neurons.push(neuron);
            }
            
            
            
        }
        
        private function moveNode():void
        {
            var i:int;

           var nodeSphere:Mesh;
           
            for (i = 0; i < outputNeuronNum; i += 1)
            {
                nodeSphere = nodeSphereArray[i];
                nodeSphere.x = outputLayer.neurons[i].w[0] * 1000;
                nodeSphere.y = outputLayer.neurons[i].w[1] * 1000;
                nodeSphere.z = outputLayer.neurons[i].w[2] * 1000;
            }
            
        }
        
        private function render(e:Event):void
        {
            if (move)
            {
                cameraController.panAngle = 0.3 * (stage.mouseX - lastMouseX) + lastPanAngle;
                cameraController.tiltAngle = 0.3 * (stage.mouseY - lastMouseY) + lastTiltAngle;
            }
            
            learn();
            
            moveNode();
            
            view.render();
            //view.renderer.queueSnapshot(source);
        }
        
        private function learn():void
        {
            var i:int;
            var j:int;
            var input:Neuron;
            var neuron:Neuron;
            var bmuNumber:Number;
            var bmuIndex:int;
            var dx:int;
            var dy:int;
            var v:Number;
            var N:Number;
            var dist:Number;
            var influence:Number;
            var bmuNeuron:Neuron;
            
            iter += 1;
            
            if (iter <= iterMax)
            {
                for (i = 0; i < oneFrameIter; i += 1)
                {
                    input = inputLayer.neurons[iter * oneFrameIter + i];
                    bmuNumber = 99999;
                    
                    for (j = 0; j < outputNeuronNum; j += 1)
                    {
                        neuron = outputLayer.neurons[j];
                        neuron.redDist = input.w[0] - neuron.w[0];
                        neuron.greenDist = input.w[1] - neuron.w[1];
                        neuron.blueDist = input.w[2] - neuron.w[2];
                        neuron.euclideanDist = Math.sqrt(neuron.redDist * neuron.redDist + neuron.greenDist * neuron.greenDist + neuron.blueDist * neuron.blueDist);
                        
                        if (bmuNumber > neuron.euclideanDist)
                        {
                            bmuNumber = neuron.euclideanDist;
                            bmuIndex = j;
                        }
                    }
                    
                    bmuNeuron = outputLayer.neurons[bmuIndex];
                    //trace(bmuIndex, bmuNeuron, bmuNeuron.w[0], bmuNeuron.w[1]);
                    //var num:int = 0;
                    for (j = 0; j < outputNeuronNum; j += 1)
                    {
                        if (j != bmuIndex)
                        {
                            neuron = outputLayer.neurons[j];
                            
                            
                            dx = (bmuIndex % outputNeuronWidthNum) - (j % outputNeuronWidthNum);
                            dx = (dx ^ dx >> 31) - (dx >> 31); // == MAth.abs(dx)
                            dy = int(bmuIndex / outputNeuronWidthNum) - int(j / outputNeuronWidthNum);
                            dy = (dy ^ dy >> 31) - (dy >> 31);
                            //dist = Math.sqrt(dx * dx + dy * dy);
                            dist = dx + dy;
                            
                            if (dist < radius)
                            {
                                influence = Math.exp(( -1 * Math.sqrt(dist)) / (2 * radius * iter));
                                neuron.w[0] += learningRate * influence * neuron.redDist;
                                neuron.w[1] += learningRate * influence * neuron.greenDist;
                                neuron.w[2] += learningRate * influence * neuron.blueDist;
                                //trace(neuron.w[0], neuron.w[1]);
                                //num += 1;
                            }
                        }
                        //neuron.w[0] = neuron.w[0] > 1 ? 1 : (neuron.w[0] < -1 ? -1 : neuron.w[0]);
                        //neuron.w[1] = neuron.w[1] > 1 ? 1 : (neuron.w[1] < -1 ? -1 : neuron.w[1]);
                        
                        //v = (dx + dy) / 18;
                        //N = Math.exp( -v);
                        
                        //neuron.w[0] += learningRate * N * neuron.redDist;
                        //neuron.w[1] += learningRate * N * neuron.greenDist;
                    }
                    //trace(num);
                    //trace(bmuNeuron.w[0], bmuNeuron.w[1]);
                }
                
                //drawNodes(i-1, bmuIndex);
                
                learningRate = startLearningRate * Math.exp( -iter / timeConstant); 
                radius = startRadius * Math.exp( -iter / timeConstant);
                
                proceedNumLabel.text = "Proceed #" + String(iter) + "/" + String(iterMax);
            }
            //else
            //{
                //if (hasEventListener(Event.ENTER_FRAME) == true)
                //{
                    //removeEventListener(Event.ENTER_FRAME, onLoop);
                //}
            //}
        }
        
        private function onMouseWheel(e:MouseEvent):void
        {
            cameraController.distance -= e.delta * 15;
            
            if (cameraController.distance < 500)
            {
                cameraController.distance = 500;
            }
            else if (cameraController.distance > 3000)
            {
                cameraController.distance = 3000;
            }
        }
        
        private function onMouseDown(e:MouseEvent):void
        {
            lastPanAngle = cameraController.panAngle;
            lastTiltAngle = cameraController.tiltAngle;
            lastMouseX = stage.mouseX;
            lastMouseY = stage.mouseY;
            move = true;
            
        }
        
        private function onMouseUp(e:MouseEvent):void
        {
            move = false;
        }
        
        private function resizeHandler(e:Event):void
        {
            view.width = stage.stageWidth;
            view.height = stage.stageHeight;
        }
        
        private function onReset():void
        {
            var i:int;
            if (hasEventListener(Event.ENTER_FRAME) == true)
            {
                removeEventListener(Event.ENTER_FRAME, render);
            }
            
            var neuron:Neuron;
            
            for (i = 0; i < inputNeuronNum; i += 1)
            {
                neuron = inputLayer.neurons[i];
                neuron.resetW(2);
            }
            
            for (i = 0; i < outputNeuronNum; i += 1)
            {
                neuron = outputLayer.neurons[i];
                neuron.resetW(2);
            }
            
            iter = 0;
            learningRate = startLearningRate;
            radius = startRadius;
            
            if (hasEventListener(Event.ENTER_FRAME) == false)
            {
                addEventListener(Event.ENTER_FRAME, render);
            }
        }
        
        
    }
    
}
Class
{
    /**
     * ...
     * @author ypc
     */
    class Neuron
    {
        public var w:Object;
        public var input:Number;
        public var output:Number;
        public var euclideanDist:Number;
        public var redDist:Number;
        public var greenDist:Number;
        public var blueDist:Number;
        
        public function Neuron(n:int)
        {
            this.w = new Object();
           
            
            if (n > 0)
            {
                var i:int;
                
                for (i = 0; i < n; i += 1)
                {
                    this.w[i] = Math.random() * 2 - 1;
                    
                }
            }
        }
        
        public function resetW(n:int):void
        {
            var i:int;
            
            for (i = 0; i < n; i += 1)
            {
                this.w[i] = Math.random() * 2 - 1;
                
            }
        }
        
    }

}

Class
{
    /**
     * ...
     * @author ypc
     */
    class Layer 
    {
        public var neurons:Array;
        
        public function Layer() 
        {
            this.neurons = [];
        }
        
    }

}