Forked from: Aquioux's Pokorny Fractal (Type Mandelbrot) diff:179 Pokorny Fractal (Type Multibrot) Aquioux forked:0favorite:2lines:229license : MIT License modified : 2011-12-06 20:04:18 Embed Tweet // forked from Aquioux's Pokorny Fractal (Type Mandelbrot) package { import com.bit101.components.PushButton; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.geom.Rectangle; [SWF(width = "465", h = "465", frameRate = "30", backgroundColor = "#000000")] /** * Pokorny Fractal(Type Multibrot) * @see http://aquioux.net/blog/?p=2137 * @author Aquioux(Yoshida, Akio) */ public class Main extends Sprite { // マンデルブロ集合でない部分の色 private var colors_:Vector.<uint>; // 計算クラス private var pokorny_:Pokorny; // 走査クラス private var scan_:Scan; // 表示用 BitmapData private var bmd_:BitmapData; private var rect_:Rectangle; // bmd_ 用 Rectangle // 前回押したボタン private var prevButton_:PushButton; public function Main():void { // カラーセット var cc:Vector.<uint> = Vector.<uint>([0xFF0000, 0xFFFF00, 0x0000FF]); colors_ = new Vector.<uint>(); var degree:int = 36; for (var i:int = 0; i < degree; i++) colors_[i] = cc[i % 3]; colors_.fixed = true; // ステージサイズ var w:int = stage.stageWidth; var h:int = stage.stageHeight; // Pokorny クラスのセットアップ pokorny_ = new Pokorny(); pokorny_.colors = colors_; // Scan クラスのセットアップ scan_ = new Scan(); scan_.calculator = pokorny_; scan_.setup(w, h); // Viewer の作成 bmd_ = new BitmapData(w, h, false, 0x0); addChild(new Bitmap(bmd_)); rect_ = new Rectangle(0, 0, w, h); // ボタンの作成 var buttonWidth:int = 78; var button0:PushButton = new PushButton(this, 0, h - 20, "z ^ 2 + c", button0Handler); var button1:PushButton = new PushButton(this, buttonWidth, h - 20, "z ^ 3 + c", button1Handler); var button2:PushButton = new PushButton(this, buttonWidth * 2, h - 20, "z ^ 4 + c", button2Handler); var button3:PushButton = new PushButton(this, buttonWidth * 3, h - 20, "z ^ 5 + c", button3Handler); var button4:PushButton = new PushButton(this, buttonWidth * 4, h - 20, "z ^ 6 + c", button4Handler); var button5:PushButton = new PushButton(this, buttonWidth * 5, h - 20, "z ^ 7 + c", button5Handler); button0.width = buttonWidth; button1.width = buttonWidth; button2.width = buttonWidth; button3.width = buttonWidth; button4.width = buttonWidth; button5.width = buttonWidth; // 初回状態の表示 button1Handler(null); button1.selected = true; changeButton(button1); } // 描画 private function draw():void { bmd_.lock(); bmd_.setVector(rect_, scan_.update()); bmd_.unlock(); } // ボタンハンドラ private function button0Handler(e:Event):void { if (e) changeButton(PushButton(e.target)); pokorny_.expo = 2; scan_.offsetX = 0.0; draw(); } private function button1Handler(e:Event):void { if (e) changeButton(PushButton(e.target)); pokorny_.expo = 3; scan_.offsetX = 0.5; draw(); } private function button2Handler(e:Event):void { if (e) changeButton(PushButton(e.target)); pokorny_.expo = 4; scan_.offsetX = 0.5; draw(); } private function button3Handler(e:Event):void { if (e) changeButton(PushButton(e.target)); pokorny_.expo = 5; scan_.offsetX = 0.5; draw(); } private function button4Handler(e:Event):void { if (e) changeButton(PushButton(e.target)); pokorny_.expo = 6; scan_.offsetX = 0.5; draw(); } private function button5Handler(e:Event):void { if (e) changeButton(PushButton(e.target)); pokorny_.expo = 7; scan_.offsetX = 0.5; draw(); } // カレントボタンの変更 private function changeButton(currentButton:PushButton):void { if (prevButton_) prevButton_.enabled = true; currentButton.enabled = false; prevButton_ = currentButton; } } } //package { //import aquioux.math.Complex; import flash.geom.Rectangle; /** * Pokorny Fractal 描画クラス * 漸化式 : z ← 1 / (z^2 + c) * 「Creating Fractals」 Roger T. Stevens 著 による * _scale = 1.0 のとき (-2.5, -2) ~ (1.5, 2) の領域を対象に計算する * @author Aquioux(Yoshida, Akio) */ /*public*/ class Pokorny implements ICalculator { /** * 描画範囲 */ public function get rect():Rectangle { return RECTANGLE; } private const RECTANGLE:Rectangle = new Rectangle(MIN_X, MIN_Y, (MAX_X - MIN_X), (MAX_Y - MIN_Y)); // 個別の開始座標、終了座標 private const MIN_X:Number = -2.5; // X軸最小値 private const MIN_Y:Number = -2.0; // Y軸最小値 private const MAX_X:Number = 1.5; // X軸最大値 private const MAX_Y:Number = 2.0; // Y軸最大値 /** * ポコーニィのフラクタルに該当する部分の色(一般的には色なし=黒) */ private var _color:uint = 0x000000; public function set color(value:uint):void { _color = value; } /** * 発散部分の色階調 */ private var _colors:Vector.<uint>; public function set colors(value:Vector.<uint>):void { _colors = value; degree_ = value.length; } /** * 漸化式の z の冪乗の指数 */ public function set expo(value:int):void { _expo = value; } private var _expo:int = 2; // 発散チェックループ回数(_colors.length の値) private var degree_:int; /** * Scan クラスからの走査データを受け、計算をおこなう * @param x X座標値 * @param y Y座標値 * @return 計算結果 */ public function calculate(x:Number, y:Number):uint { var r:int = formula(0, 0, x, y); return (r >= 0) ? _colors[r] : _color; } /** * 漸化式 z ← 1 / (z^n + c) * @param zRl 複素数 z の実数部 * @param zIm 複素数 z の虚数部 * @param cRl 複素数 c の実数部 * @param cIm 複素数 c の虚数部 * @return 発散評価値 * @private */ private function formula(zRl:Number, zIm:Number, cRl:Number, cIm:Number):int { // 漸化式の計算要素の複素数 var zRlSqr:Number; // 実数部の2乗 var zImSqr:Number; // 虚数部の2乗 var zSqr:Number; // zRlSqr + zImSqr var z1Rl:Number; // 実数部 var z1Im:Number; // 虚数部 var z1Norm:Number; // |z1|^2 // ド・モアブルの定理 var r1:Number; // 局座標形式複素数の距離(計算前) var t1:Number; // 局座標形式複素数の偏角(計算前) var r2:Number; // 局座標形式複素数の距離(計算後) var t2:Number; // 局座標形式複素数の偏角(計算後) var i:int = degree_; while (i--) { // 発散の評価 zRlSqr = zRl * zRl; zImSqr = zIm * zIm; zSqr = zRlSqr + zImSqr; if (zSqr > 4) break; // 漸化式実行 // z^n + c // 複素数を局座標化 r1 = Math.sqrt(zSqr); t1 = Math.atan2(zIm, zRl); // 冪乗計算 r2 = r1; // 距離 var j:int = _expo; while (--j) r2 *= r1; t2 = t1 * _expo; // 偏角 // 直交座標に戻し、_c を加算 z1Rl = Math.cos(t2) * r2 + cRl; z1Im = Math.sin(t2) * r2 + cIm; // z = 1 / (z^n + c) z1Norm = z1Rl * z1Rl + z1Im * z1Im; zRl = z1Rl / z1Norm; zIm = -z1Im / z1Norm; // 発散の評価 //if (zRl * zRl + zIm * zIm > 4) break; // 発散の評価が先頭にあると画面引き、末尾にあると画面寄せ // c が冪乗の中にあると((z+c)^2 など) c の変動に伴い中心が移動 // c が冪乗の中にないと(z^2 + c など) c の変動しても中心は固定 } return i; // break で脱しなかった(発散しなかった)場合、while を回りきるので -1 になる } } //} //package { import flash.geom.Rectangle; /** * 計算クラスの interface * @author YOSHIDA, Akio (Aquioux) */ /*public*/ interface ICalculator { function get rect():Rectangle; function calculate(x:Number, y:Number):uint; } //} //package { import flash.geom.Rectangle; /** * 二次元走査クラス * @author Aquioux(Yoshida, Akio) */ /*public*/ class Scan { /** * 計算クラス */ private var _calculator:ICalculator; public function set calculator(value:ICalculator):void { _calculator = value; rect = _calculator.rect; } /** * 描画領域(_scale = 1.0 における値) */ private var _rect:Rectangle; public function set rect(value:Rectangle):void { _rect = value; } /** * 表示位置オフセットX座標値 */ private var _offsetX:Number = 0.0; public function set offsetX(value:Number):void { _offsetX = value; calcValue(); } /** * 表示位置オフセットY座標値 */ private var _offsetY:Number = 0.0; public function set offsetY(value:Number):void { _offsetY = value; calcValue(); } /** * スケール値 */ private var _scale:Number = 1.0; public function set scale(value:Number):void { _scale = value; calcValue(); } // ----- その他変数 ----- // 計算加算値 private var stepX_:Number; // X軸 private var stepY_:Number; // Y軸 // 走査開始座標 private var startX_:Number; // X座標 private var startY_:Number; // Y座標 // 表示領域 private var displayWidth_:int; // 幅 private var displayHeight_:int; // 高 // ビューアへ渡すデータ private var data_:Vector.<uint>; // data_ のインデックス private var idx_:int; /** * 初期化 * @param width 表示幅 * @param height 表示高 */ public function setup(width:int, height:int):void { // 表示サイズ displayWidth_ = width; displayHeight_ = height; // data_ の生成 data_ = new Vector.<uint>(width * height, true); // 複素数平面走査用の各変数を計算する calcValue(); } /** * 複素数平面を走査し、その値を計算クラスの渡す * @return 計算クラスから返ってきた値を格納した Vector */ public function update():Vector.<uint> { idx_ = 0; for (var y:int = 0; y < displayHeight_; y++) { for (var x:int = 0; x < displayWidth_; x++) { data_[idx_++] = _calculator.calculate(startX_ + x * stepX_, startY_ + y * stepY_); } } return data_; } // 複素数平面走査用の変数を計算する private function calcValue():void { stepX_ = (_rect.width / _scale) / displayWidth_; stepY_ = (_rect.height / _scale) / displayHeight_; startX_ = (_rect.width * 0.5 + _rect.x + _offsetX) - displayWidth_ * 0.5 * stepX_; startY_ = (_rect.height * 0.5 + _rect.y + _offsetY) - displayHeight_ * 0.5 * stepY_; } } //} //package aquioux.math { /** * 複素数 * @author Aquioux(Yoshida, Akio) */ /*public*/ final class Complex { // 実数部 public function get real():Number { return _rl; } public function set real(value:Number):void { _rl = value; } private var _rl:Number; // 虚数部 public function get imag():Number { return _im; } public function set imag(value:Number):void { _im = value; } private var _im:Number; // コンストラクタ public function Complex(rl:Number = 0, im:Number = 0) { _rl = rl; _im = im; } // 複製 public function clone():Complex { return new Complex(_rl, _im); } public function toString():String { return _rl + " + " + _im + "i"; } } //} Code Fullscreen Preview Fullscreen andrewexex88.. hidrodixtion.. : awesomefractal awesome fractal fractals フラクタル target Rectangle height fixed Event width clone toString Math.atan2 Math.sqrt Vector Math.cos length addChild Math.sin String Sprite uint int Number