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

forked from: forked from: Double Pendulum Symplectic Euler

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

// forked from makc3d's forked from: Double Pendulum Symplectic Euler
// forked from aont's Double Pendulum
package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.utils.Timer;
    [SWF(backgroundColor=0)]
    public class DoublePendulum extends Sprite
    {
        private var line_1:Sprite;
        private var line_2:Sprite;
        private var circle:Sprite;
        private var circleCoords:Array = [];
        private var line_ratio:Number;
        private var length_1:Number = 0.5;
        private var length_2:Number = 0.25;
        private var radius:Number = 2;
        
        private var mass_1:Number = 0.05;
        private var mass_2:Number = 0.01;
        
        private var color_1:Number = 0x7f0000;
        private var color_2:Number = 0xff0000;
        private var color_3:Number = 0xff7f00;
        
        private var theta:Number = 0;
        private var phi:Number = 0;
        
        private var d_theta:Number = 0;
        private var d_phi:Number = 0;
        
        private var center:Number;
        private var center_y:Number;
        
        private var dt:Number = 1.0/60;
        private var g:Number = 9.8;
        
        private var myTimer:Timer;
        
        private var gamma1:Number = 0;
        private var gamma2:Number = 0;
        private var friction:Number = 1 - 1e-3;
        private var bd:BitmapData;
        private var ct:ColorTransform;
        public function DoublePendulum()
        {
            this.parent.addEventListener(MouseEvent.CLICK, MouseClick);
                        
            this.center = 230;
            this.line_ratio = center /  (this.length_1+this.length_2);

            line_1 = CreateLine(this.length_1*line_ratio,color_1)
            line_2 = CreateLine(this.length_2*line_ratio,color_2);
            this.line_1.x = center;
            this.line_1.y = center;

            bd = new BitmapData (465, 465, true, 0); addChild (new Bitmap (bd));
            ct = new ColorTransform; ct.color = color_3;
            ct.alphaMultiplier = friction;

            circle = new Sprite; circle.graphics.beginFill (0xffffff);
            circle.graphics.drawCircle (0, 0, radius); addChild (circle);

            this.ReDraw();
            
            this.myTimer = new Timer(this.dt * 1000,0);
            this.myTimer.addEventListener(TimerEvent.TIMER,Tick);
            this.myTimer.start();
        }
        private function MouseClick(event:MouseEvent):void
        {
            theta = Math.atan2(center-event.localY,event.localX-center) + Math.PI /2;
            d_theta = 0;
            //d_phi = 0;
            this.ReDraw();
        }
        private function ReDraw():void
        {
            this.line_1.rotation = 90 - this.theta * 180 / Math.PI;

            
            this.line_2.rotation = 90 - this.phi * 180 / Math.PI;            
            this.line_2.x = center + this.length_1*line_ratio * Math.sin(this.theta) ;
            this.line_2.y = center + this.length_1 * line_ratio * Math.cos(this.theta) ;

            circle.x = line_2.x + length_2*line_ratio * Math.sin (phi);
            circle.y = line_2.y + length_2 * line_ratio * Math.cos (phi);
            if (circleCoords.length == 4) circleCoords.shift ();
            while (circleCoords.length != 4) circleCoords.push (new Point (circle.x, circle.y));
            var m:Matrix = new Matrix, n:Number = 40 / radius;
            for (var i:int = 1; i < n + 1; i++) {
                var p:Point = spline (circleCoords [0], circleCoords [1], circleCoords [2], circleCoords [3], i / n);
                m.tx = p.x; m.ty = p.y;
                bd.draw (circle, m);
            }
            bd.colorTransform (bd.rect, ct);
        }
        private function CreateLine(length:Number,color:uint):Sprite
        {
            var line:Sprite = new Sprite();
            with(line.graphics)
            {
                lineStyle(1, color);
                moveTo(0,0);
                lineTo(length,0);                
            }
            this.addChild(line);
            return line;
        }
        private function Advance():void
        {
            //var theta_new:Number
            //var phi_new:Number;
            d_theta += dt*
                (
                    -(mass_1+mass_2)*g*Math.sin(theta)/length_1
                    +mass_2*g*Math.cos(theta-phi)*Math.sin(phi)/length_1
                    -mass_2*Math.pow(d_theta,2)*Math.sin(2*(theta-phi))/2
                    -mass_2*Math.sin(theta-phi)*Math.pow(d_phi,2)*length_2/length_1
                ) / (mass_1 + mass_2 * Math.pow(Math.sin(theta-phi),2))
                -gamma1 * d_theta
                ;
            d_phi += dt*
                (
                    (mass_1+mass_2)*g*Math.cos(theta)*Math.sin(theta-phi)/length_2
                    +(mass_1+mass_2)*Math.sin(theta-phi)*Math.pow(d_theta,2)*length_1/length_2
                    +mass_2*Math.pow(d_phi,2)*Math.sin(2*(theta-phi))/2
                ) / (mass_1 + mass_2 * Math.pow(Math.sin(theta-phi),2))
                -gamma2 * d_phi
                ;
            d_theta *= friction;
            d_phi *= friction;
            theta = ModRadian(theta + d_theta * dt);
            phi = ModRadian(phi + d_phi * dt);            
        }
        
        private function ModRadian(rad:Number):Number
        {
            while(rad > Math.PI)
            {
                rad -= 2*Math.PI;
            }
            while(rad <= -Math.PI)
            {
                rad += 2*Math.PI;
            }
            return rad;
        }

        
        private function Tick(event:TimerEvent):void
        {            
            this.Advance();
            this.ReDraw();
        }
        /* 
        * Calculates 2D cubic Catmull-Rom spline.
        * @see http://www.mvps.org/directx/articles/catmull/ 
        */ 
        private function spline (p0:Point, p1:Point, p2:Point, p3:Point, t:Number):Point {
            return new Point (
                0.5 * ((          2*p1.x) +
                    t * (( -p0.x           +p2.x) +
                    t * ((2*p0.x -5*p1.x +4*p2.x -p3.x) +
                    t * (  -p0.x +3*p1.x -3*p2.x +p3.x)))),
                0.5 * ((          2*p1.y) +
                    t * (( -p0.y           +p2.y) +
                    t * ((2*p0.y -5*p1.y +4*p2.y -p3.y) +
                    t * (  -p0.y +3*p1.y -3*p2.y +p3.y))))
            );
        }
    }
}