test_case08

by h_kamizono forked from test (diff: 436)
ref 
Flash Math & Physics Design ActionScript 3.0による数学・物理学表現[実践編]
♥0 | Line 362 | Modified 2010-08-05 06:07:57 | MIT License
play

ActionScript3 source code

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

// forked from h_kamizono's test
// ref 
// Flash Math & Physics Design ActionScript 3.0による数学・物理学表現[実践編]


package {
    import flash.trace.Trace;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    public class Pendulum extends MovieClip {
        private var base:Sprite = new Sprite();
        private var pt:Array = new Array();
        private var pigment:Number = 0;
        private var rotatePt:PhysicalPoint = new PhysicalPoint();
        private var preAngle:Number;
        private const minDotNum:Number = 3;
        private var bitmapdata:BitmapData;
        private var blackCover:Sprite = new Sprite();
        private var pressed:Boolean = false;
        private var curMouse:Point;
        private var preMouse:Point;
        
        public function Pendulum() {
            // write as3 code here..
            bitmapdata = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
            addChild(new Bitmap(bitmapdata));
            blackCover.graphics.lineStyle(0, 0, 0);
            blackCover.graphics.beginFill(0, .05);
            blackCover.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            blackCover.graphics.endFill();
            
            rotatePt.kb = 0.98;
            preAngle = rotatePt.angle;
            curMouse = new Point(this.mouseX, this.mouseY);
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
            
            var delTimer:Timer = new Timer(10000);
            delTimer.addEventListener(TimerEvent.TIMER, delLoop);
            delTimer.start();
            var timer:Timer = new Timer(33);
            timer.addEventListener(TimerEvent.TIMER, loop);
            timer.start(); 
        }
        
        private function onMDown(ev:MouseEvent) :void {
            pressed = true;
            pt.push(new Point(ev.target.mouseX, ev.target.mouseY));
            var dire:Number = rotatePt.angle;
            while (dire > Math.PI) dire -= Math.PI*2;
            while (dire < -Math.PI) dire += Math.PI*2;
            if (dire < Math.PI/2 && dire > -Math.PI/2)
                rotatePt.setKakuKasokudo(-100);
            else 
                rotatePt.setKakuKasokudo(100);
            changeState();
        }
        
        private function onMUp(ev:MouseEvent) :void {
            pressed = false;
        }
        
        private function delLoop(event:TimerEvent) :void {
            if (pt.length > minDotNum) {
                pt.shift();
                changeState();
            }
        }
        
        private function changeState() :void {
            if (pt.length > 1) {
                var ppt:Array = Functions.getPolygon(pt);
                var jpt:Point = Functions.getCentroid(ppt);
                if (jpt != null) {
                    var dire:Number = Math.atan2(jpt.y - pt[pt.length - 1].y,
                                                 jpt.x - pt[pt.length - 1].x);
                                                 
                    rotatePt.angle = dire;
                    preAngle = dire;
                }
            }
        }
        
        private function loop(event:TimerEvent) :void {
            preMouse = curMouse;
            curMouse = new Point(this.mouseX, this.mouseY);
            var ppt:Array = Functions.getPolygon(pt);
            var jpt:Point = Functions.getCentroid(ppt);
            // 個人的には必要ないかも
            if (pressed) {
                for (var i:Number = 0; i < pt.length; ++i) {
                    pt[i].x += curMouse.x - preMouse.x;
                    pt[i].y += curMouse.y - preMouse.y;
                }
                var mAngle:Number = Math.atan2(curMouse.y - preMouse.y,
                                               curMouse.x - preMouse.x);
                mAngle += Math.PI;
                var par:Number = Point.distance(curMouse, jpt)*
                                 Point.distance(preMouse, curMouse) * 0.01;
                //rotatePt.setKakuKasokudo2(mAngle, par);
            }
            rotatePt.setKakuKasokudo2(Math.PI/2, 10);
            
            for (var j:Number = 0; j < pt.length - 1; ++j) {
                var p1x:Number = pt[j].x - pt[pt.length - 1].x;
                var p1y:Number = pt[j].y - pt[pt.length - 1].y;
                var p2x:Number = p1x * Math.cos(rotatePt.angle - preAngle) -
                                 p1y * Math.sin(rotatePt.angle - preAngle);
                var p2y:Number = p1x * Math.sin(rotatePt.angle - preAngle) +
                                 p1y * Math.cos(rotatePt.angle - preAngle);
                var p3x:Number = p2x + pt[pt.length - 1].x;
                var p3y:Number = p2y + pt[pt.length - 1].y;
                pt[j].x = p3x; pt[j].y = p3y;
            }
            
            pigment += 1;
            var col:uint = Functions.hsbToRgb(pigment, 1, 1);
            base.graphics.clear();
            
            if (jpt != null) {
                base.graphics.lineStyle(0, 0, 0);
                base.graphics.beginFill(0x000000);
                base.graphics.drawCircle(jpt.x, jpt.y, 3);
                base.graphics.endFill();
            }
            if (ppt != null) {
                base.graphics.lineStyle(1, col, 0.5);
                base.graphics.moveTo(ppt[0].x, ppt[0].y);
                base.graphics.beginFill(col, 0.1);
                for (var k:Number = 1; k < ppt.length; ++k) {
                    base.graphics.lineTo(ppt[k].x, ppt[k].y);
                }
                base.graphics.lineTo(ppt[0].x, ppt[0].y);
                base.graphics.endFill();
            }
            for (var m:Number = 0; m < pt.length; ++m) {
                base.graphics.lineStyle(0, 0, 0);
                base.graphics.beginFill(col, 0.5);
                base.graphics.drawCircle(pt[m].x, pt[m].y, 4);
                base.graphics.endFill();
            }
            bitmapdata.draw(blackCover);
            bitmapdata.draw(base);
            preAngle = rotatePt.angle;
        }


        
    }
}

class Functions {
    public static function hsbToRgb(h:Number,
                                    s:Number,
                                    b:Number) :uint {
        while (h < 0) {
            h+=360;
        }
        while (h >= 360) {
            h -= 360;
        }
        var h2:Number = Math.floor(h/60);
        var f:Number = h/60 - h2;
        var parFull:Number = 255;
        var parEmp:Number = 0;
        var parZoka:Number = 255*f;
        var parGensho:Number = 255*(1-f);
        var red:Number = 0;
        var green:Number = 0;
        var blue:Number = 0;
        
        switch (h2) {
          case 0:
            red = parFull; green = parZoka; blue = parEmp;
            break;
          case 1:
            red = parGensho; green = parFull; blue = parEmp;
            break;
          case 2:
            red = parEmp; green = parFull; blue = parZoka;
            break;
          case 3:
            red = parEmp; green = parGensho; blue = parFull;
            break;
          case 4:
            red = parZoka; green = parEmp; blue = parFull;
            break;
          case 5:
            red = parFull; green = parEmp; blue = parGensho;
            break;
        }
        var max:Number = Math.max(Math.max(red, green), blue);
        red = max - (max - red)*s;
        green = max - (max - green)*s;
        blue = max - (max - blue)*s;
        red *= b; green *= b; blue *= b;
        var ret:uint = int(red) << 16 | int(green) << 8 | int(blue);
        return ret; 
    }
    
    public static function getPolygon(pt:Array) :Array {
        if (pt.length > 0) {
            var maxPt:Point = null;
            var minPt:Point = null;
            var retPt:Array = new Array();
            
            var minVal:Number = 100000;
            var maxVal:Number = -100000;
            for (var i:Number = 0; i < pt.length; ++i) {
                if (minVal > pt[i].x) {
                    minVal = pt[i].x;
                    minPt = pt[i];
                } else if (minVal == pt[i].x) {
                    if (minPt.y < pt[i].y) {
                        minPt = pt[i];
                    }
                }
                if (maxVal < pt[i].x) {
                    maxVal = pt[i].x;
                    maxPt = pt[i];
                }
            }
            retPt.push(minPt);
            var korePt:Point = null;
            for (var j:Number = 0; j < pt.length; ++j) {
                if (minPt == maxPt) break;
                var maxK:Number = -100000;
                for (var k:Number = 0; k < pt.length; ++k) {
                    if (minPt != pt[k]) {
                        if (pt[k].x > minPt.x) {
                            if (maxK < (pt[k].y - minPt.y) / (pt[k].x - minPt.x)) {
                                maxK = (pt[k].y - minPt.y) / (pt[k].x - minPt.x);
                                korePt = pt[k];                                
                            }
                        }
                    }
                }
                retPt.push(korePt);
                minPt = korePt;
            }
            minVal = 100000;
            maxVal = -100000;
            for (var m:Number = 0; m < pt.length; ++m) {
                if (minVal > pt[m].x)  {
                    minVal = pt[m].x;
                    minPt = pt[m];
                }
                if (maxVal < pt[m].x) {
                    maxVal = pt[m].x;
                    maxPt = pt[m];
                } else if (maxVal == pt[m].x) {
                    if (maxPt.y > pt[m].y) {
                        maxPt = pt[m];
                    }
                }
            }
            
            if (retPt[retPt.length - 1] != maxPt) {
                retPt.push(maxPt);
            }
            
            korePt = null;
            for (var n:Number = 0 ; n < pt.length; ++n) {
                if (minPt == maxPt) break;
                maxK = -100000;
                for (var q:Number = 0; q < pt.length; ++q) {
                    if (maxPt != pt[q]) {
                        if (pt[q].x < maxPt.x) {
                            if (maxK < (pt[q].y - maxPt.y) / (pt[q].x - maxPt.x)) {
                                maxK = (pt[q].y - maxPt.y) / (pt[q].x - maxPt.x);
                                korePt = pt[q];                                
                            }
                        }
                    }
                }
                retPt.push(korePt);
                maxPt = korePt;
            }
            
            if (retPt.length > 1 &&
                retPt[retPt.length - 1].x == retPt[0].x &&
                retPt[retPt.length - 1].y == retPt[0].y) {
                retPt.pop();
            }
            return retPt;
        } else {
            return null;
        }
    }
    
    public static function getCentroid(pt:Array) :Point {
        if (pt != null) {
            if (pt.length == 0) {
                return new Point(0, 0);
            } else if (pt.length == 1) {
                return new Point(pt[0].x, pt[0].y);
            } else if (pt.length == 2) {
                return new Point((pt[0].x + pt[1].x)/2, (pt[0].y + pt[1].y)/2);
            } else {
                
                var ptSize:Number = pt.length;
                /*
                var s:Number = 0;
                for (var i:Number = 0; i < ptSize; ++i) {
                    s += (pt[i].x + pt[(i+1) % ptSize].x) * (pt[(i+1) % ptSize].y - pt[i].y);
                }
                */
                /*
                for (var i:Number = 0; i < ptSize; ++i) {
                    s += (pt[i].x * pt[(i+1) % ptSize].y) - (pt[(i+1) % ptSize].x * pt[i].y);
                }
                */
                // area
                var s:Number = pt[0].x * (pt[1].y - pt[ptSize-1].y);
                // centroid
                var gx:Number = pt[0].y * (pt[ptSize-1].x - pt[1].x) * (pt[ptSize-1].x + pt[0].x + pt[1].x);
                var gy:Number = -pt[0].x * (pt[ptSize-1].y - pt[1].y) * (pt[ptSize-1].y + pt[0].y + pt[1].y);
                                
                
                for (var i:Number = 1; i < ptSize - 1; ++i) {
                    s += pt[i].x * (pt[i+1].y - pt[i-1].y);
                    
                    gx += pt[i].y * (pt[i-1].x - pt[i+1].x) * (pt[i-1].x + pt[i].x + pt[i+1].x);
                    gy += -pt[i].x * (pt[i-1].y - pt[i+1].y) * (pt[i-1].y + pt[i].y + pt[i+1].y);
                }
                s += pt[ptSize - 1].x * (pt[0].y - pt[ptSize - 2].y);
                s /= 2;
                
                gx += pt[ptSize-1].y * (pt[ptSize-2].x - pt[0].x) * (pt[ptSize-2].x + pt[ptSize-1].x + pt[0].x);
                gy += -pt[ptSize-1].x * (pt[ptSize-2].y - pt[0].y) * (pt[ptSize-2].y + pt[ptSize-1].y + pt[0].y);
                
                
                /*
                var gx:Number = 0; var gy:Number = 0;
                for (var j:Number = 0; j < ptSize; ++j) {
                    // mul 4, add or sub 3, %op 4 
                    gx += (pt[j].x * pt[j].x +
                           pt[j].x * pt[(j+1)%ptSize].x + 
                           pt[(j+1)%ptSize].x * pt[(j+1)%ptSize].x) *
                           (pt[(j+1) % ptSize].y - pt[j].y);
                    gy += (pt[j].y * pt[j].y +
                           pt[j].y * pt[(j+1)%ptSize].y + 
                           pt[(j+1)%ptSize].y * pt[(j+1)%ptSize].y) *
                           (-pt[(j+1) % ptSize].x + pt[j].x);
                }*/  
                
                
                gx /= s*6; gy /= s*6;
                return new Point(gx, gy);
            }
        } else {
            return null;
        }
    }

}
 

import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;
class PhysicalPoint extends Point {
    private var vx:Number, vy:Number;
    private var ax:Number, ay:Number;
    private var b:Number;
    private var preTime:Number;
    private var timer:Timer;
    
    private var preX:Number, preY:Number;
    
    public var kb:Number;
    public var angle:Number;
    public var preAngle:Number;
    public var kakusokudo:Number;
    public var kakukasokudo:Number;
    
    private var limitter:Number = 0.3;
    
    function PhysicalPoint(xx: Number = 0, yy:Number = 0, an:Number = 0) {
        x = xx; y = yy;
        preX = xx; preY = yy;
        b = 0.9;
        vx = 0; vy = 0;
        ax = 0; ay = 0;
        
        angle = an;
        preAngle = an;
        kb = 0.9;
        kakusokudo = 0;
        kakukasokudo = 0;
        
        preTime = new Date().getTime();
        timer = new Timer(33);
        timer.addEventListener(TimerEvent.TIMER, loop);
        timer.start();
        
    }
    
    public function loop(event:TimerEvent) :void {
        var nowTime:Number = new Date().getTime();
        var t:Number = (nowTime - preTime)/1000;
        
        if (t > limitter) t = limitter;
        
        preX = x;
        preY = y;
        
        x += (vx + 0.5*ax*t)*t;
        y += (vy + 0.5*ay*t)*t;
        
        vx += ax*t; vy += ay*t;
        vx *= b;    vy *= b;
        ax = 0;     ay = 0;
        preAngle = angle;
        angle += (kakusokudo + 0.5*kakukasokudo*t) *t;
        kakusokudo += kakukasokudo*t;
        
        kakusokudo *= kb;
        kakukasokudo = 0;
        preTime = nowTime;
    }
    
    public function setKasokudo(aax:Number = 0, aay:Number = 0) :void {
        ax += aax;
        ay += aay;
    }
    
    public function setKasokudoByPolar(r:Number=0, dire:Number = 0) :void {
        ax += r*Math.cos(dire);
        ay += r*Math.sin(dire);
    }
    
    public function setKakuKasokudo(aan:Number = 0) :void {
        kakukasokudo += aan;
    }
    
    public function setKakuKasokudo2(dire:Number, val:Number) :void {
        var aan:Number = val * Math.sin(dire - angle);
        setKakuKasokudo(aan);
    }

}