Hénon Map Aquioux forked:0favorite:3lines:268license : MIT License modified : 2011-11-05 21:21:38 Embed Tweet package { import caurina.transitions.Tweener; import flash.display.Sprite; import flash.events.Event; [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")] /** * エノン写像(Hénon Map) * @see http://aquioux.net/blog/?p=2080 * @author YOSHIDA, Akio(Aquioux) */ public class Main extends Sprite { private var viewer_:Viewer; // ビューア private var buttons_:Buttons; // ボタン private var sliders_:Sliders; // スライダー public function Main():void { setup(); addEventListener(Event.ENTER_FRAME, update); } // セットアップ private function setup():void { // ステージサイズ var w:int = stage.stageWidth; var h:int = stage.stageHeight; // エンジンの初期化 Engine.setup(); // ビューアの作成 viewer_ = new Viewer(w, h); addChild(viewer_); // ボタンの作成 buttons_ = new Buttons(); buttons_.action = drawByButton; buttons_.y = h - buttons_.height; addChild(buttons_); // スライダーの作成 sliders_ = new Sliders(); sliders_.action = drawBySlider; sliders_.reset(); addChild(sliders_); } // アップデート private function update(e:Event):void { viewer_.update(Engine.data); } // ボタンに起因する描画の実行 // エンジンの変数の値をトゥイーン private function drawByButton(values:Vector.<Number>):void { Tweener.addTween(Engine, { "a":values[0], "b":values[1], time:1.5, transition:"easeOutCubic", onStart:viewer_.reset, onUpdate:sliders_.reset }); } // スライダーに起因する描画の実行 private function drawBySlider():void { buttons_.reset(); } } } //package { /** * エンジン(Hénon Map) * @author YOSHIDA, Akio(Aquioux) */ /*public*/ class Engine { /** * 計算に使用するパラメータ a */ static public function get a():Number { return _a; } static public function set a(value:Number):void { _a = value; update(); // 再計算 } static private var _a:Number; /** * 計算に使用するパラメータ b */ static public function get b():Number { return _b; } static public function set b(value:Number):void { _b = value; update(); // 再計算 } static private var _b:Number; /** * 計算に使用する各パラメータの最小値、最大値、既定値 */ static public function get A_MIN():Number { return PARAMS[0]; } static public function get A_MAX():Number { return PARAMS[1]; } static public function get A_DEFAULT():Number { return PARAMS[2]; } static public function get B_MIN():Number { return PARAMS[3]; } static public function get B_MAX():Number { return PARAMS[4]; } static public function get B_DEFAULT():Number { return PARAMS[5]; } static private const PARAMS:Vector.<Number> = Vector.<Number>([ 0.0, 2.0, 1.4, // a 0.0, 1.0, 0.3 // b ]); /** * 座標データ Vector */ static public function get data():Vector.<Number> { return _data; } static private var _data:Vector.<Number>; /** * パーティクル数 */ static public function get numOfParticle():int { return numOfParticle_; } static private var numOfParticle_:int = 30000; // 漸化式用変数 static private var x_:Number; // X座標値 static private var y_:Number; // Y座標値 // スケール static private const SCALE:Number = 100; /** * セットアップ */ static public function setup():void { _data = new Vector.<Number>(numOfParticle_ * 2, true); paramDefault(); } /** * 計算 * @return 結果の座標を一次元配列で格納した Vector */ static public function update():void { x_ = 0;// Math.random() * 0.25 - 0.125; y_ = 0;// Math.random() * 0.25 - 0.125; var len:int = numOfParticle_ * 2; for (var i:int = 0; i < len; i += 2) { var xn:Number = 1 - _a * x_ * x_ + y_; var yn:Number = _b * x_; x_ = xn; y_ = yn; _data[i] = x_ * SCALE; _data[i + 1] = y_ * SCALE * -2; } } /** * パラメータを既定値に戻す */ static public function paramDefault():void { _a = A_DEFAULT; _b = B_DEFAULT; update(); // 再計算 } /** * パラメータをランダムな値にする */ static public function paramRandom():void { _a = Math.random() * (A_MAX - A_MIN) + A_MIN; _b = Math.random() * (B_MAX - B_MIN) + B_MIN; update(); // 再計算 } } //} //package { //import aquioux.display.colorUtil.CycleRGB; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.filters.BitmapFilterQuality; import flash.filters.BlurFilter; import flash.geom.ColorTransform; import flash.geom.Point; import flash.geom.Rectangle; /** * ビューア * @author YOSHIDA, Akio(Aquioux) */ /*public*/ class Viewer extends Sprite { /** * ColorTransform によるフェードアウトのための定義 */ public function set fade(value:ColorTransform):void { _fade = value; } private var _fade:ColorTransform = new ColorTransform(0.95, 0.95, 0.95); /** * Blur filter によるフェードアウトのための定義 */ public function set blur(value:BlurFilter):void { _blur = value; } private var _blur:BlurFilter = new BlurFilter(8, 8, BitmapFilterQuality.HIGH); // 描画色用の変数 private var start_:Number; // 開始位置 private var add_:Number; // start_ への増分 private var renge_:Number; // 循環色相の範囲(角度) private var dir_:int; // グラデーションの方向 // BitmapData 関連 private var bmd_:BitmapData; // 表示 BitmapData private var bufferBmd_:BitmapData; // バッファ private var rect_:Rectangle; // ColorTransform, Blur 共用 private const ZERO_POINT:Point = new Point(0, 0); // 表示オフセット private var offsetX_:Number; // X座標オフセット private var offsetY_:Number; // Y座標オフセット /** * コンストラクタ * @param sw ステージ幅 * @param sh ステージ高 */ public function Viewer(sw:int, sh:int) { // BitmapData 関連 bufferBmd_ = new BitmapData(sw, sh, true, 0xFF000000); bmd_ = bufferBmd_.clone(); rect_ = new Rectangle(0, 0, sw, sh); addChild(new Bitmap(bmd_)); // 各オフセット offsetX_ = sw / 2; offsetY_ = sh / 2; // 描画色関連 CycleRGB.alpha = 0xCC; start_ = Math.random() * 360 >> 0; reset(); } /** * アップデート * @param data 描画座標データ */ public function update(data:Vector.<Number>):void { // bufferBmd_ の更新 bufferBmd_.lock(); bufferBmd_.fillRect(bufferBmd_.rect, 0x00000000); var len:uint = data.length; start_ += add_; for (var i:int = 0; i < len; i += 2) { var px:int = (data[i] + offsetX_) >> 0; var py:int = (data[i + 1] + offsetY_) >> 0; var offsetColor:Number = (px + py * dir_) * renge_; //var offsetColor:Number = (px * height / width - py * width / height) * renge_; bufferBmd_.setPixel32(px, py, CycleRGB.getColor32(offsetColor + start_)); } bufferBmd_.unlock(); // bmd_ の更新 bmd_.lock(); bmd_.colorTransform(rect_, _fade); bmd_.applyFilter(bmd_, rect_, ZERO_POINT, _blur); bmd_.draw(bufferBmd_); bmd_.unlock(); } /** * 描画色用変数の再設定 */ public function reset():void { add_ = ((Math.random() * 100 >> 0) + 10) / 100; renge_ = ((Math.random() * 270 >> 0) + 90) / 360; dir_ = (Math.random() < 0.5) ? -1 : 1; dir_ = (Math.random() < 0.3) ? dir_ : 0; } } //} //package { import com.bit101.components.HUISlider; import com.bit101.components.Slider; import flash.display.Sprite; import flash.events.Event; import flash.utils.Dictionary; /** * コントロール用スライダー * @author YOSHIDA, Akio(Aquioux) */ /*public*/ class Sliders extends Sprite { /** * スライダーアクション(外部で定義した処理) */ public function set action(value:Function):void { _action = value; } private var _action:Function; // スライダーの値を小数第何位まで有効にするか private const PRECISION:int = 3; private const TICK:Number = 1 / Math.pow(10, PRECISION); // スライダーに対応させるエンジン・プロパティ private const PROPS:Array = ["a", "b"]; private const DELIMITER:String = ":"; // スライダー格納配列 private var sliders:Dictionary; /** * コンストラクタ */ public function Sliders() { var params:Vector.<Number> = Vector.<Number>([ Engine.A_MIN, Engine.A_MAX, Engine.a, Engine.B_MIN, Engine.B_MAX, Engine.b ]); sliders = new Dictionary(); for (var i:int = 0; i < PROPS.length; i++) { var prop:String = PROPS[i]; var slider:HUISlider = new HUISlider(this, 25, i * 15, prop + DELIMITER, handler); slider.width = 430; slider.labelPrecision = PRECISION; slider.tick = TICK; slider.setSliderParams(params[i * 3], params[i * 3 + 1], params[i * 3 + 2]); sliders[prop] = slider; } } /** * リセット(Engine 内の数値に伴ったスライダー値にリセット) */ public function reset():void { for each (var prop:String in PROPS) sliders[prop].value = Engine[prop]; } // ハンドラ private function handler(e:Event):void { var target:HUISlider = HUISlider(e.target); var prop:String = target.label.split(DELIMITER)[0]; Engine[prop] = target.value; _action(); } } //} //package { import com.bit101.components.PushButton; import flash.display.Sprite; import flash.events.Event; import flash.utils.Dictionary; /** * コントロール用ボタン * @author YOSHIDA, Akio(Aquioux) */ /*public*/ class Buttons extends Sprite { /** * ボタンアクション(外部で定義した処理) */ public function set action(value:Function):void { _action = value; } private var _action:Function; // エンジンのラベルとプロパティ値のペア private const PAIR:Array = [ ["Default", Vector.<Number>([1.4, 0.3])], ["No.1-1", Vector.<Number>([1.12, 0.3])], ["No.1-2", Vector.<Number>([1.425, 0.3])], ["No.2-1", Vector.<Number>([1.2, 0.4])], ["No.2-2", Vector.<Number>([1.245, 0.4])], ["No.3-1", Vector.<Number>([1.0, 0.51])], ["No.3-2", Vector.<Number>([1.045, 0.51])], ["No.4-1", Vector.<Number>([0.98, 0.55])], ["No.4-2", Vector.<Number>([0.98, 0.555])] ]; private var values:Dictionary; // 前回押したボタン private var prevButton_:PushButton; /** * インストラクタ */ public function Buttons() { // ボタンの作成 var buttonWidth:int = 52; var buttonHeight:int = 20; var idx:int = 0; values = new Dictionary(); for (var x:int = 0; x < PAIR.length; x++) { var b:PushButton = new PushButton(this, buttonWidth * x, buttonHeight * y, PAIR[idx][0], handler); b.width = buttonWidth; b.height = buttonHeight; values[b] = PAIR[idx][1]; idx++; } } /** * リセット(前回押したため無効になっているボタンを有効にする) */ public function reset():void { if (prevButton_) prevButton_.enabled = true; } // ハンドラ private function handler(e:Event):void { var target:PushButton = PushButton(e.target); handlerAction(target); _action(values[target]); } /** * ボタンアクション(内部で完了する処理) * 押されたボタンを押せなくし、前回押したボタンを押せるようにする * @param target 押されたボタン * @private */ private function handlerAction(target:PushButton):void { reset(); target.enabled = false; prevButton_ = target; } } //} //package aquioux.display.colorUtil { /** * コサインカーブで色相環的な RGB を計算 * @author Aquioux(YOSHIDA, Akio) */ /*public*/ class CycleRGB { /** * 32bit カラーのためのアルファ値(0~255) */ static public function get alpha():uint { return _alpha; } static public function set alpha(value:uint):void { _alpha = (value > 0xFF) ? 0xFF : value; } private static var _alpha:uint = 0xFF; private static const PI:Number = Math.PI; // 円周率 private static const DEGREE120:Number = PI * 2 / 3; // 120度(弧度法形式) /** * 角度に応じた RGB を得る * @param angle HSV のように角度(度数法)を指定 * @return 色(0xNNNNNN) */ public static function getColor(angle:Number):uint { var radian:Number = angle * PI / 180; var r:uint = (Math.cos(radian) + 1) * 0xFF >> 1; var g:uint = (Math.cos(radian + DEGREE120) + 1) * 0xFF >> 1; var b:uint = (Math.cos(radian - DEGREE120) + 1) * 0xFF >> 1; return r << 16 | g << 8 | b; } /** * 角度に応じた RGB を得る(32bit カラー) * @param angle HSV のように角度(度数法)を指定 * @return 色(0xNNNNNNNN) */ public static function getColor32(angle:Number):uint { return _alpha << 24 | getColor(angle); } } //} Code Fullscreen Preview Fullscreen atakanckilic.. djankey hidrodixtion.. : awesomemath awesome chaos map math カオス ストレンジアトラクタ 写像 target Dictionary alpha BlurFilter Vector clone addChild split Rectangle Math.cos Math.pow Tweener.addTween Event width Math.PI height time String addEventListener Event.ENTER_FRAME