[数学]内サイクロイド(hypocycloid)
内サイクロイド(hypocycloid)を絵画します
* 右下の分数で、大円に対する小円の半径を設定できます
* 赤い点はドラッグすることで、移動できます
* 1/2とかが面白いかもしれません
/**
* 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);
}
}
}
}