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

[数学]内サイクロイド(hypocycloid)

内サイクロイド(hypocycloid)を絵画します
* 右下の分数で、大円に対する小円の半径を設定できます
* 赤い点はドラッグすることで、移動できます
* 1/2とかが面白いかもしれません
Get Adobe Flash player
by kura07 27 Jun 2010
/**
 * Copyright kura07 ( http://wonderfl.net/user/kura07 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/aEvn
 */

/*
 * 内サイクロイド(hypocycloid)を絵画します
 * 右下の分数で、大円に対する小円の半径を設定できます
 * 赤い点はドラッグすることで、移動できます
 * 1/2とかが面白いかもしれません
 */
package {
    
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFormat;
    
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#ffffff")]
    
    public class Hypocycloid extends Sprite {
        
        // 親円
        private const pr:Sprite = new Sprite();
        private const prg:Graphics = pr.graphics;
        private const prR:Number = 150;
        
        // 子円
        private const ch:Sprite = new Sprite();
        private const chg:Graphics = ch.graphics;
        private var chR:Number = 150 / 5.0;
        
        // 子円のポイント
        private const chp:Sprite = new Sprite();
        private const chpg:Graphics = chp.graphics;
        private var chpR:Number = chR;
        
        // 軌跡
        private const locus:Sprite = new Sprite();
        private const locusg:Graphics = locus.graphics;
        
        // 半径入力テキストフィールド
        private const inputs:Sprite = new Sprite();
        private const inputsg:Graphics = inputs.graphics;
        private const tshi:TextField = new TextField();
        private const tbo:TextField = new TextField();
        
        // ボタン
        private const btn:Sprite = new Sprite();
        private const btng:Graphics = btn.graphics;
        
        function Hypocycloid() {
            
            var tfmt:TextFormat;
            
            // 親円
            pr.x = pr.y = 230;
            prg.lineStyle(2, 0x000000);
            prg.drawCircle(0, 0, prR);
            addChild(pr);
            
            // 子円
            ch.addChild(chp);
            addChild(ch);
            drawChCircle(chR);
            drawPoint(chR);
            
            // ポイントのドラッグイベント
            chp.buttonMode = true;
            chp.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
            
            // 軌跡
            addChild(locus);
            locus.mouseEnabled = false;
            
            // 半径入力テキストフィールド
            inputs.x = 350; inputs.y = 405;
            for each(var t:TextField in [tshi, tbo]) {
                //t.backgroundColor = 0xffffff;
                t.background = true; t.type = "input";
                t.width = 40; t.height = 20; t.restrict = "1-9"; t.maxChars = 1;
                tfmt = new TextFormat(); tfmt.align = "center"; tfmt.size = 16;
                t.defaultTextFormat = tfmt; t.text = (t == tshi ? 1 : 5) + "";
                t.x = -5; t.y = t == tshi ? 0 : 25;
                inputs.addChild(t);
                t.addEventListener(Event.CHANGE, refreshCh);
                t.addEventListener(MouseEvent.CLICK, function(e:Event):void {
                    e.target.setSelection(0, 1);
                });
            }
            addChild(inputs);
            inputsg.lineStyle(1, 0x555555);
            inputsg.moveTo( -5, 22); inputsg.lineTo(35, 22);
            
            // ボタン
            btn.x = 400; btn.y = 430;
            btng.lineStyle(1, 0x555555); btng.beginFill(0xffffff);
            btng.drawRect(0, 0, 50, 20);
            setBtnState(true);
            addChild(btn);
            
            // ラベル
            var label:TextField = new TextField(); tfmt = new TextFormat(null, 16, 0x000000);
            label.mouseEnabled = false;
            label.defaultTextFormat = tfmt; label.text = "まわす"; label.x = 1;
            label.width = 50; label.height = 20;
            btn.addChild(label);
            
            // はじめだけ勝手に回す
            startDrawLocus(new MouseEvent(MouseEvent.CLICK));
            
        }
        
        // 子円の絵画
        private function drawChCircle(r:Number):void {
            
            chg.clear();
            ch.x = 230 + prR - r; ch.y = 230;
            chg.lineStyle(2, 0x0000ff); chg.beginFill(0xaaaaff);
            chg.drawCircle(0, 0, r);
            
        }
        
        // ポイントの絵画
        private function drawPoint(r:Number):void {
            
            chpg.clear();
            chpg.lineStyle(2, 0x0000ff);
            chpg.moveTo(0, 0); chpg.lineTo(r, 0);
            chpg.lineStyle(); chpg.beginFill(0xff0000);
            chpg.drawCircle(r, 0, 5);
            
        }
        
        // ポイントのドラッグ
        private function beginDrag(e:MouseEvent):void {
            stage.addEventListener(MouseEvent.MOUSE_UP, endDrag);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, underDrag);
        }
        private function endDrag(e:MouseEvent):void {
            stage.removeEventListener(MouseEvent.MOUSE_UP, endDrag);
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, underDrag);
        }
        private var limit:Number = 230 - prR + chR;
        private function underDrag(e:MouseEvent):void {
            chpR = Math.max( -limit, Math.min(limit, stage.mouseX - ch.x)); drawPoint(chpR);
        }
        
        // テキストが変更
        private function refreshCh(e:Event):void {
            
            var shi:Number = Number(tshi.text), bo:Number = Number(tbo.text);
            
            if (!shi || !bo || shi >= bo) {
                setBtnState(false);
                return;
            }
            
            var r:Number = prR * shi / bo;
            chR = chpR = r; drawChCircle(r); drawPoint(r);
            
            // 何回転すればいいか計算
            for (var i:uint = 1; true; i++) if ((bo * i) % shi == 0) break;
            times = i;
            
            // リミット
            limit = 230 - prR + chR;
            
            setBtnState(true);
            
        }
        
        // ボタンの有効化/無効化
        private function setBtnState(state:Boolean):void {
            
            if (state == true) {
                btn.alpha = 1;
                btn.addEventListener(MouseEvent.CLICK, startDrawLocus);
                btn.buttonMode = true;
            }
            else {
                btn.alpha = 0.3;
                btn.removeEventListener(MouseEvent.CLICK, startDrawLocus);
                btn.buttonMode = false;
            }
        }
        
        // 軌跡の絵画アニメーション開始
        private function startDrawLocus(e:MouseEvent):void {
            
            // 軌跡クリアー
            locusg.clear(); locusg.lineStyle(2, 0xff5555); locusg.moveTo(230 + prR - chR + chpR, 230);
            
            // イベント
            addEventListener(Event.ENTER_FRAME, drawLocus);
            
            // テキスト
            for each(var t:TextField in [tshi, tbo]) t.type = "dynamic";
            
            // ポイントのドラッグイベント
            chp.buttonMode = false;
            chp.removeEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
            
            // ボタン
            setBtnState(false);
            
            // 単位(計算式は適当)
            if(chR >= Math.abs(chpR)) unit = Math.sqrt(chR) / Math.sqrt(25) * 3 * speed;
            else unit = Math.sqrt(-Math.pow(Math.sqrt(chR) - Math.sqrt(Math.abs(chpR)), 2) / chR * 5 + chR) / Math.sqrt(25) * 3 * speed;
            
        }
        
        // 軌跡の絵画アニメーション
        private var nowAngle:Number = 0;
        private var unit:Number = 3;
        private var times:uint = 1;
        private var speed:Number = 1;
        private function drawLocus(e:Event):void {
            
            // 子円の回転
            var r:Number = prR - chR;
            var x:Number = r * Math.cos(nowAngle * Math.PI / 180);
            var y:Number = r * Math.sin(nowAngle * Math.PI / 180);
            var a:Number = (1 - prR / chR) * nowAngle;
            ch.x = 230 + x; ch.y = 230 + y; ch.rotation = a;
            nowAngle += unit;
            
            // 軌跡の絵画
            locusg.lineTo(230 + x + chpR * Math.cos(a * Math.PI / 180), 230 + y + chpR * Math.sin(a * Math.PI / 180));
            
            // 終了
            if (nowAngle >= 360 * times + unit) {
                
                // 元に戻す
                nowAngle = 0;
                ch.x = 230 + prR - chR; ch.y = 230; ch.rotation = 0;
                
                // イベント
                removeEventListener(Event.ENTER_FRAME, drawLocus);
                
                // ポイントのドラッグイベント
                chp.buttonMode = true;
                chp.addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
                
                // テキスト
                for each(var t:TextField in [tshi, tbo]) t.type = "input";
                
                // ボタン
                setBtnState(true);
                
            }
            
        }
    }
}