Pokorny Fractal (Type Mandelbrot) Aquioux forked:1favorite:3lines:268license : MIT License modified : 2011-12-05 19:38:34 Embed Tweet package { //import aquioux.display.colorUtil.CycleRGB; 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", height = "465", frameRate = "30", backgroundColor = "#000000")] /** * Pokorny Fractal(Type Mandelbrot) * @see http://wonderfl.net/c/gVkh * @see http://aquioux.net/blog/?p=2126 * @author Aquioux(Yoshida, Akio) */ public class Main extends Sprite { // マンデルブロ集合でない部分の色 private var colors0_:Vector.<uint>; private var colors1_:Vector.<uint>; private var colors2_:Vector.<uint>; // 計算クラス private var pokorny_:Pokorny; // 走査クラス private var scan_:Scan; // 表示用 BitmapData private var bmd_:BitmapData; private var rect_:Rectangle; // bmd_ 用 Rectangle // 前回押したボタン private var prevButtonColor_:PushButton; private var prevButtonScale_:PushButton; public function Main():void { // カラーセットパターン1 var cc:Vector.<uint> = Vector.<uint>([0xFF0000, 0xFFFF00, 0x0000FF]); colors0_ = new Vector.<uint>(); degree = 36; for (var i:int = 0; i < degree; i++) colors0_[i] = cc[i % 3]; colors0_.fixed = true; // カラーセットパターン2 colors1_ = new Vector.<uint>(); var degree:int = 36; var step:Number = 0xFF / degree; for (i = 0; i < degree; i++) { var c:uint = step * i; colors1_[i] = 0xFF << 16 | c << 8 | c; } colors1_.fixed = true; // カラーセットパターン3 colors2_ = new Vector.<uint>(); degree = 36; step = 360 / degree; for (i = 0; i < degree; i++) colors2_[i] = CycleRGB.getColor(i * step + 180); colors2_.reverse(); colors2_.fixed = true; // ステージサイズ var sw:int = stage.stageWidth; var sh:int = stage.stageHeight; // mandelBrot クラスの生成 pokorny_ = new Pokorny(); pokorny_.colors = colors0_; // Scan クラスの生成とセットアップ scan_ = new Scan(); scan_.calculator = pokorny_; scan_.setup(sw, sh); // Viewer の作成 bmd_ = new BitmapData(sw, sh, false, 0x0); addChild(new Bitmap(bmd_)); rect_ = new Rectangle(0, 0, sw, sh); // ボタンの作成 var buttonWidth:int = 50; var buttonColor0:PushButton = new PushButton(this, 0, 0, "3 tone", buttonColor0Handler); var buttonColor1:PushButton = new PushButton(this, buttonWidth, 0, "monotone", buttonColor1Handler); var buttonColor2:PushButton = new PushButton(this, buttonWidth * 2, 0, "colorful", buttonColor2Handler); var buttonScale0:PushButton = new PushButton(this, 0, 20, "* 1", buttonScale0Handler); var buttonScale1:PushButton = new PushButton(this, buttonWidth, 20, "* 2", buttonScale1Handler); var buttonScale2:PushButton = new PushButton(this, buttonWidth * 2, 20, "* 10", buttonScale2Handler); var buttonScale3:PushButton = new PushButton(this, buttonWidth * 3, 20, "* 50", buttonScale3Handler); buttonColor0.width = buttonWidth; buttonColor1.width = buttonWidth; buttonColor2.width = buttonWidth; buttonScale0.width = buttonWidth; buttonScale1.width = buttonWidth; buttonScale2.width = buttonWidth; buttonScale3.width = buttonWidth; // 初回状態の表示 buttonColor2Handler(null); buttonColor2.selected = true; changeButtonColor(buttonColor2); buttonScale0Handler(null); buttonScale0.selected = true; changeButtonScale(buttonScale0); } // 描画 private function draw():void { bmd_.lock(); bmd_.setVector(rect_, scan_.update()); bmd_.unlock(); } // ボタンハンドラ(色) private function buttonColor0Handler(e:Event):void { if (e) changeButtonColor(PushButton(e.target)); pokorny_.colors = colors0_; draw(); } private function buttonColor1Handler(e:Event):void { if (e) changeButtonColor(PushButton(e.target)); pokorny_.colors = colors1_; draw(); } private function buttonColor2Handler(e:Event):void { if (e) changeButtonColor(PushButton(e.target)); pokorny_.colors = colors2_; draw(); } // ボタンハンドラ(スケール) private function buttonScale0Handler(e:Event):void { if (e) changeButtonScale(PushButton(e.target)); scan_.scale = 1.0; scan_.offsetX = 0.0; scan_.offsetY = 0.0; draw(); } private function buttonScale1Handler(e:Event):void { if (e) changeButtonScale(PushButton(e.target)); scan_.scale = 2.0; scan_.offsetX = 0.0; scan_.offsetY = 0.0; draw(); } private function buttonScale2Handler(e:Event):void { if (e) changeButtonScale(PushButton(e.target)); scan_.scale = 10.0; scan_.offsetX = -0.55; scan_.offsetY = -0.15; draw(); } private function buttonScale3Handler(e:Event):void { if (e) changeButtonScale(PushButton(e.target)); scan_.scale = 50.0; scan_.offsetX = -1.25; scan_.offsetY = 0.0; draw(); } // カレントボタンの変更 private function changeButtonColor(currentButton:PushButton):void { if (prevButtonColor_) prevButtonColor_.enabled = true; currentButton.enabled = false; prevButtonColor_ = currentButton; } private function changeButtonScale(currentButton:PushButton):void { if (prevButtonScale_) prevButtonScale_.enabled = true; currentButton.enabled = false; prevButtonScale_ = 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; } // 発散チェックループ回数(_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^2 + 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 z1Rl:Number; // 実数部 var z1Im:Number; // 虚数部 var z1Norm:Number; // |z1|^2 var i:int = degree_; while (i--) { // 発散の評価 zRlSqr = zRl * zRl; zImSqr = zIm * zIm; if (zRlSqr + zImSqr > 4) break; // 漸化式実行 // z^2 + c z1Rl = zRlSqr - zImSqr + cRl; z1Im = 2 * zRl * zIm + cIm; // z = 1 / (z^2 + 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"; } } //} //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 andrewexex88.. smart_ant : 的BitmapData hidrodixtion.. : coolfractal cool fractal fractals フラクタル 的BitmapData target Rectangle height alpha Event fixed reverse clone Math.cos Vector toString width Math.PI length addChild String Sprite uint int Number sort new page view favorite forked pv482 Pokorny Fractal (Type Multibro.. Aquioux forked:0 favorite:2lines:229 (diff:179) tag: awesome fractal fractals フラクタル