Forked from: Aquioux's 逆写像によるジュリア集合の描画(4分木) diff:11 逆写像によるジュリア集合の描画(8分木) Aquioux forked:0favorite:2lines:293license : MIT License modified : 2011-09-09 23:56:51 Embed Tweet // forked from Aquioux's 逆写像によるジュリア集合の描画(4分木) // forked from Aquioux's 逆写像によるジュリア集合の描画 package { // import aquioux.geom.Complex; // import aquioux.geom.MathComplex; import com.bit101.components.HSlider; import com.bit101.components.VSlider; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Rectangle; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")] /** * 逆写像によるジュリア集合の描画(8分木) * @author Aquioux(Yoshida, Akio) */ public class Main extends Sprite { // 描画領域サイズ private const WIDTH:int = 450; private const HEIGHT:int = 450; // スライダー関連 private const SLIDER_LONG:int = WIDTH; private const SLIDER_SHORT:int = stage.stageWidth - WIDTH; private const SLIDER_VALUE_MIN:Number = -2.0; private const SLIDER_VALUE_MAX:Number = 2.0; // 写像の世代数 private const GENERATION:int = 6; // 漸化式 の z private var Z:Complex = MathComplex.COMPLEX_0; // 漸化式 の c private var c_:Complex = new Complex(1.095, 0.975); // ビューア private var viewer_:Viewer; // 計算クラス private var julia_:Julia; // スライダー private var hslider_:HSlider; private var vslider_:VSlider; // 現在の c の値を表示するテキストフィールド private var textField1_:TextField; private var textField2_:TextField; // マウスダウン判定フラグ private var isDown_:Boolean = true; public function Main():void { // ビューアの生成 viewer_ = new Viewer(); addChild(viewer_); // Julia クラスの生成・セットアップ julia_ = new Julia(); julia_.viewer = viewer_; julia_.minX = julia_.minY = SLIDER_VALUE_MIN; julia_.maxX = julia_.maxY = SLIDER_VALUE_MAX; julia_.setup(WIDTH, HEIGHT); // スライダーの作成 // 横スライダー(複素数 c の実数部) hslider_ = new HSlider(this, 0, HEIGHT); hslider_.width = SLIDER_LONG; hslider_.height = SLIDER_SHORT; hslider_.setSliderParams(SLIDER_VALUE_MIN, SLIDER_VALUE_MAX, c_.real); hslider_.tick = 0.001; // 縦スライダー(複素数 c の虚数部) vslider_ = new VSlider(this, WIDTH, 0); vslider_.width = SLIDER_SHORT; vslider_.height = SLIDER_LONG; vslider_.setSliderParams(SLIDER_VALUE_MIN, SLIDER_VALUE_MAX, c_.imag); vslider_.tick = 0.001; // テキストフィールドの作成 textField1_ = new TextField(); textField2_ = new TextField(); textField1_.autoSize = TextFieldAutoSize.LEFT; textField2_.autoSize = TextFieldAutoSize.LEFT; var fontSize:int = 12; var textFormat:TextFormat = new TextFormat("_typewriter", fontSize, 0x000000); textField1_.defaultTextFormat = textFormat; textField2_.defaultTextFormat = textFormat; textField1_.y = 0; textField2_.y = fontSize * 1.25 >> 0; textField1_.selectable = false; textField2_.selectable = false; addChild(textField1_); addChild(textField2_); // マウスハンドラの設定 // スライダーに直接ハンドラを設定すると ENTER_FRAME のタイミングで更新がかかり、 // 処理負荷が大きくなるため、マウスアップ時にスライダハンドラを実行させる stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); stage.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler); // 初回状態の表示 mouseUpHandler(null); } // 描画 private function draw():void { // プロット開始 julia_.start(Z, c_, GENERATION); } // マウスハンドラ private function mouseDownHandler(e:MouseEvent):void { isDown_ = true; } private function mouseUpHandler(e:MouseEvent):void { if (isDown_) { hsliderHandler(); vsliderHandler(); isDown_ = false; } } private function mouseLeaveHandler(e:Event):void { mouseUpHandler(null); } // スライダーハンドラ private function hsliderHandler():void { var value:Number = hslider_.value; textField1_.text = "real : " + String(value); c_.real = value; draw(); } private function vsliderHandler():void { var value:Number = vslider_.value; textField2_.text = "imag : " + String(value); c_.imag = value; draw(); } } } //package { // import aquioux.geom.Complex; // import aquioux.geom.MathComplex; import flash.display.BitmapData; import flash.geom.Rectangle; /** * 逆写像によるジュリア集合描画クラス * @author Aquioux(Yoshida, Akio) */ /*public*/ class Julia { /** * 描画領域のX軸における最小値 */ public function set minX(value:Number):void {_minX = value;} private var _minX:Number = -2.0; /** * 描画領域のX軸における最大値 */ public function set maxX(value:Number):void {_maxX = value;} private var _maxX:Number = 2.0; /** * 描画領域のY軸における最小値 */ public function set minY(value:Number):void {_minY = value;} private var _minY:Number = -2.0; /** * 描画領域のY軸における最大値 */ public function set maxY(value:Number):void {_maxY = value;} private var _maxY:Number = 2.0; /** * 点をプロットする色 */ public function set plotColor(value:uint):void { _plotColor = value; } private var _plotColor:uint = 0x00000000; /** * 地の色 */ public function set backgraundColor(value:uint):void { _backgraundColor = value; } private var _backgraundColor:uint = 0xFFFFFFFF; /** * ビューア */ private var _viewer:Viewer; public function set viewer(value:Viewer):void { _viewer = value; } // オフセット値(プロット時使用) private var offsetX_:Number; private var offsetY_:Number; // ステップ値(計算時使用) private var stepX_:Number; private var stepY_:Number; // ビューアへ渡すデータを格納した Vector private var data_:Vector.<uint>; // 描画領域 private var width_:int; // 幅 private var height_:int; // 高 /** * セットアップ * @param width 描画領域幅 * @param hidth 描画領域高 */ public function setup(width:int, height:int):void { width_ = width; height_ = height; // ビューアの BitmapData 生成 if (!_viewer) new Error("setup 前にビューアを指定してください。"); _viewer.setup(width_, height_, false, _backgraundColor); // ビューア用 Vector の生成 data_ = new Vector.<uint>(width_ * height_, true); // オフセット値計算 offsetX_ = width_ / 2; offsetY_ = height_ / 2; // ステップ値計算 var rangeX:Number = (_maxX - _minX) / 2; var rangeY:Number = (_maxY - _minY) / 2; stepX_ = offsetX_ / rangeX; stepY_ = offsetY_ / rangeY; } /** * 描画(再帰処理)開始 * @param z 漸化式の z * @param c 漸化式の c * @param generation 再帰世代数 */ public function start(z:Complex, c:Complex, generation:int):void { // ビューア用 Vector 初期化 var len:int = data_.length; for (var i:int = 0; i < len; i++) data_[i] = _backgraundColor; // プロット plot(z, c, generation); // ビューアへ通知 _viewer.update(data_); } // 再帰処理 // 漸化式:z ← ±√(z - c) <z ← z^2 + c の逆写像> private function plot(z:Complex, c:Complex, generation:int):void { if (generation <= 0) {// 再帰終了時 var x:int = z.real * stepX_ + offsetX_ >> 0; var y:int = z.imag * stepY_ + offsetY_ >> 0; if ((0 <= x && x < width_) && (0 <= y && y < height_)) { // 描画座標値が描画領域をはみ出していない場合 data_[y * width_ + x] = _plotColor; } } else { // 再帰続行(8分木再帰) z = MathComplex.subtract(z, c); z = MathComplex.sqrt(z); var rl:Number = z.real; var im:Number = z.imag; generation--; plot(new Complex( rl, im), c, generation); plot(new Complex(-rl, -im), c, generation); plot(new Complex( rl, -im), c, generation); plot(new Complex(-rl, im), c, generation); plot(new Complex( im, rl), c, generation); plot(new Complex(-im, -rl), c, generation); plot(new Complex( im, -rl), c, generation); plot(new Complex(-im, rl), c, generation); } } } //} //package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Point; import flash.geom.Rectangle; /** * ビューア * @author YOSHIDA, Akio(Aquioux) */ /*public*/ class Viewer extends Bitmap { // BitmapData 関連 private var rect_:Rectangle; // ColorTransform, Blur 共用 /** * セットアップ * @param w 表示領域幅 * @param h 表示領域高 * @param transparent 表示領域透明サポート * @param fillColor 表示領域塗りつぶし色 */ public function setup(w:Number, h:Number, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF):void { bitmapData = new BitmapData(w, h, transparent, fillColor); rect_ = new Rectangle(0, 0, w, h); } /** * アップデート * @param data setVector 用 Vector */ public function update(data:Vector.<uint>):void { bitmapData.lock(); bitmapData.setVector(rect_, data); bitmapData.unlock(); } } //} //package aquioux.geom { /** * 複素数 * @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, im:Number) { _rl = rl; _im = im; } // 複製 public function clone():Complex { return new Complex(_rl, _im); } public function toString():String { return _rl + " + " + _im + "i"; } } //} //package aquioux.geom { /** * 複素数の演算 * @author Aquioux(Yoshida, Akio) */ /*public*/ final class MathComplex { // 定数 static public const COMPLEX_1:Complex = new Complex(1.0, 0.0); static public const COMPLEX_0:Complex = new Complex(0.0, 0.0); static public const PURELY_IMAGINARY:Complex = new Complex(0.0, 1.0); // 加算 static public function add(a:Complex, b:Complex):Complex { return new Complex( a.real + b.real, a.imag + b.imag ); } // 減算 static public function subtract(a:Complex, b:Complex):Complex { return new Complex( a.real - b.real, a.imag - b.imag ); } // 乗算 static public function multiply(a:Complex, b:Complex):Complex { return new Complex( a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real ); } // 除算 static public function divide(a:Complex, b:Complex):Complex { var val:Number = abs2(b); return new Complex( (a.real * b.real + a.imag * b.imag) / val, (a.imag * b.real - a.real * b.imag) / val ); } // 共役複素数を求める static public function conjugate(c:Complex):Complex { return new Complex( c.real, -c.imag ); } // 絶対値 static public function abs(c:Complex):Number { return Math.sqrt(abs2(c)); // |c| = √(c * c~) = √(c.real^2 + c.imag^2) } // 絶対値の二乗 static public function abs2(c:Complex):Number { return c.real * c.real + c.imag * c.imag; } // スケーリング(第1引数の実数部、虚数部をそれぞれ第2引数倍する) static public function scale(c:Complex, n:Number):Complex { return new Complex( c.real * n, c.imag * n ); } // 整数化(引数の実数部、虚数部それぞれの小数点以下を切り捨てる) static public function integer(c:Complex):Complex { return new Complex( c.real >> 0, c.imag >> 0 ); } // べき乗 static public function pow(c:Complex, n:int):Complex { var z:Complex = c.clone(); while(--n) z = multiply(z, c); return z; } // 平方根 static public function sqrt(c:Complex):Complex { var val1:Number; if (Math.abs(c.real) < 0.000001) { val1 = c.imag * Math.PI / (2 * Math.abs(c.imag)); } else { val1 = Math.atan2(c.imag, c.real); } val1 /= 2; var val2:Number = Math.pow(abs2(c), 1 / 4); return new Complex( Math.cos(val1) * val2, Math.sin(val1) * val2 ); } // 指数関数 static public function exp(c:Complex):Complex { var val:Number = Math.exp(c.real); return new Complex( Math.cos(c.imag) * val, Math.sin(c.imag) * val ); } // 三角関数(サイン) static public function sin(c:Complex):Complex { return new Complex( Math.sin(c.real) * (Math.exp(c.imag) + Math.exp(-c.imag)) / 2, Math.cos(c.real) * (Math.exp(c.imag) - Math.exp(-c.imag)) / 2 ); } // 三角関数(コサイン) static public function cos(c:Complex):Complex { return new Complex( Math.cos(c.real) * (Math.exp(c.imag) + Math.exp(-c.imag)) / 2, -Math.sin(c.real) * (Math.exp(c.imag) - Math.exp(-c.imag)) / 2 ); } // 三角関数(タンジェント) static public function tan(c:Complex):Complex { return divide(sin(c), cos(c)); } } //} Code Fullscreen Preview Fullscreen novita001 kuda fractal fractals フラクタル transparent draw setVector MouseEvent.MOUSE_LEAVE Math.exp width height clone Rectangle TextFormat Error unlock lock Math.tan toString MouseEvent Math.atan2 MouseEvent.MOUSE_UP MouseEvent.MOUSE_DOWN Math.cos