Beautifl - Flash Gallery

Thumbnail : Man O' War (multi julia type)
Man O' War (multi julia type)
Aquioux 2012-12-27 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package {
    //import aquioux.display.colorUtil.CycleRGB;
    //import aquioux.display.fractal.Buttons;
    //import aquioux.display.fractal.Engine;
    //import aquioux.display.fractal.InputBehavior;
    //import aquioux.display.fractal.Sliders;
    //import aquioux.display.fractal.Viewer;
    import com.bit101.components.PushButton;
    import flash.display.Sprite;
    import flash.events.Event;
    [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")]
    /**
     * Man O' War Fractal の描画
     * @see    http://aquioux.net/blog/?p=3166
     * @author YOSHIDA, Akio (Aquioux)
     */
    public class Main extends Sprite {
        // ビューアサイズ
        private const WIDTH:int  = 450;
        private const HEIGHT:int = 450;
        
        // 各連携クラス
        private var calculator_:Julia;                // フラクタル計算クラス
        private var viewer_:Viewer;                    // ビューアクラス
        private var inputBehavior_:InputBehavior;    // ユーザー入力挙動クラス
        private var engine_:Engine;                    // フラクタル描画エンジンクラス
        private var sliders_:Sliders;                // スライダー
        private var complexButtons_:Buttons;        // プリセットパラメータボタン(複素数c)

        // ボタン構築用データ
        // 漸化式
        private const PRESET_FORMULA_DATA:Array = [
            ["z ^ 2 + c",    Vector.<Number>([2])],
            ["z ^ 3 + c",    Vector.<Number>([3])],
            ["z ^ 4 + c",    Vector.<Number>([4])],
            ["z ^ 5 + c",    Vector.<Number>([5])],
            ["z ^ 6 + c",    Vector.<Number>([6])],
            ["z ^ 7 + c",    Vector.<Number>([7])]
        ];
        // 複素数c
        // 注意点:一番最初の値は、calclator の DEFAULT でなければならない
        private const PRESET_COMPLEX_DATA:Array = [
            ["0 + 0i",        Vector.<Number>([0, 0])],
            ["-0.12 + 0i",    Vector.<Number>([-0.12, 0])],
            ["0.075 + 0i",    Vector.<Number>([0.075, 0])],
            ["0 + 0.05i",    Vector.<Number>([0, 0.05])],
            ["0.15 + 0.11i",Vector.<Number>([0.15, 0.11])]
        ];
        
        
        // コンストラクタ
        public function Main() {
            // カラーマップ生成
            var degree:int  = 24;
            var step:Number = 360 / (degree + 1);
            var start:int = Math.random() * 360 >> 0;
            var colorMap:Vector.<uint> = new Vector.<uint>(degree, true);
            for (var i:int = 0; i < degree; i++) colorMap[i] = CycleRGB.getColor(i * step + start);

            // フラクタル計算クラス
            calculator_ = new Julia();
            calculator_.colorMap = colorMap;
            
            // ビューアクラス
            viewer_ = new Viewer(WIDTH, HEIGHT);
            viewer_.heightOnceDraw = 5;
            addChild(viewer_);
            
            // ユーザー入力挙動クラス
            inputBehavior_ = new InputBehavior(viewer_);
            
            // フラクタル描画エンジンクラス
            engine_ = new Engine();
            engine_.viewer     = viewer_;
            engine_.controller = inputBehavior_;
            engine_.calculator = calculator_;
            
            // スライダー
            // スライダー構築用データ
            var sliderData:Array = [
                [
                    WIDTH,                                                            // 幅
                    stage.stageHeight - HEIGHT,                                        // 高
                    calculator_.DEFAULT_RECT.x,                                        // 最小値
                    calculator_.DEFAULT_RECT.width + calculator_.DEFAULT_RECT.x,    // 最大値
                    calculator_.DEFAULT_REAL_NUMBER                                    // デフォルト値
                ],    // 実数軸
                [
                    stage.stageWidth - WIDTH,
                    HEIGHT,
                    calculator_.DEFAULT_RECT.y,
                    calculator_.DEFAULT_RECT.height + calculator_.DEFAULT_RECT.y,
                    calculator_.DEFAULT_IMAGINARY_NUMBER
                ]    // 虚数軸
            ];
            sliders_ = new Sliders(sliderData);
            addChild(sliders_);
            sliders_.realAction = realSliderHandler;
            sliders_.imagAction = imagSliderHandler;
            
            // プリセットパラメータボタン
            // ボタンパラメータ
            var buttonWidth:int  = 75;
            var buttonHeight:int = 20;
            // 漸化式
            var formulaButtons:Buttons = new Buttons(buttonWidth, buttonHeight, WIDTH, PRESET_FORMULA_DATA);
            addChild(formulaButtons);
            formulaButtons.action = presetFormulaButtonsHandler;

            // 複素数c
            complexButtons_ = new Buttons(buttonWidth, buttonHeight, WIDTH, PRESET_COMPLEX_DATA);
            complexButtons_.y = buttonHeight;
            addChild(complexButtons_);
            complexButtons_.action = presetComplexButtonsHandler;

            // リセットボタン
            // ズーム
            var zoomResetButton:PushButton = new PushButton(this, 0, 0, "ZoomReset", zoomResetButtonHandler);
            zoomResetButton.width  = buttonWidth;
            zoomResetButton.height = buttonHeight;
            zoomResetButton.y      = buttonHeight * 2;
            // 複素数c
            var complexResetButton:PushButton = new PushButton(this, buttonWidth, 0, "ComplexCReset", complexResetButtonHandler);
            complexResetButton.width  = buttonWidth;
            complexResetButton.height = buttonHeight;
            complexResetButton.x      = buttonWidth;
            complexResetButton.y      = buttonHeight * 2;
            
            // 初回の描画
            // 複素数c初期化
            calculator_.resetComplexC();
            // スライダー値更新
            sliders_.setRealValue(calculator_.c.real);
            sliders_.setImagValue(calculator_.c.imag);
            // プリセットパラメータボタンボタン初期選択
            formulaButtons.selectedButton(2);
            complexButtons_.selectedButton(3);
            // ズーム初期化
            zoomResetButtonHandler(null);
        }
        
        // スライダーハンドラ
        // 実数軸
        private function realSliderHandler(val:Number):void {
            complexButtons_.releaseSelectedButton()
            calculator_.c.real = val;
            engine_.start();
        }
        // 虚数軸
        private function imagSliderHandler(val:Number):void {
            complexButtons_.releaseSelectedButton()
            calculator_.c.imag = val;
            engine_.start();
        }
        
        // プリセットパラメータボタンハンドラ
        // 漸化式
        private function presetFormulaButtonsHandler(values:Vector.<Number>):void {
            calculator_.exponent = values[0];
            zoomResetButtonHandler(null);
        }
        // 複素数c
        private function presetComplexButtonsHandler(values:Vector.<Number>):void {
            calculator_.c.real = values[0];
            calculator_.c.imag = values[1];
            sliders_.setRealValue(calculator_.c.real);
            sliders_.setImagValue(calculator_.c.imag);
            engine_.start();
        }

        // リセットボタンハンドラ
        // ズーム
        private function zoomResetButtonHandler(event:Event):void {
            engine_.reset();
            engine_.start();
        }
        // 複素数c
        private function complexResetButtonHandler(event:Event):void {
            complexButtons_.selectedButton(0);
            calculator_.resetComplexC();
            sliders_.setRealValue(calculator_.c.real);
            sliders_.setImagValue(calculator_.c.imag);
            engine_.start();
        }
    }
}

//package {
    //import aquioux.display.fractal.ICalculator;
    //import aquioux.math.Complex;
    import flash.geom.Rectangle;
    /**
     * Man O' War Fractal 計算クラス
     * base : Multi Julia
     * デフォルト時、(-2.0, -2.0) ~ (2.0, 2.0) の領域を計算する
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class Julia implements ICalculator {
        /**
         * 描画範囲
         */
        public function get DEFAULT_RECT():Rectangle { return RECTANGLE; }
        private const RECTANGLE:Rectangle = new Rectangle(START_X, START_Y, (END_X - START_X), (END_Y - START_Y));
        // 個別の開始座標、終了座標
        private const START_X:Number = -2.0;        // 開始X座標値
        private const START_Y:Number = -2.0;        // 開始Y座標値
        private const END_X:Number   =  2.0;        // 終了X座標値
        private const END_Y:Number   =  2.0;        // 終了Y座標値
        
        /**
         * 漸化式の z の冪乗の指数
         */
        public function set exponent(value:int):void { _exponent = value; }
        private var _exponent:int = 3;
       
        /**
         * 漸化式の c
         */
        public function get c():Complex { return _c; }
        private var _c:Complex = new Complex(DEFAULT_REAL_NUMBER, DEFAULT_IMAGINARY_NUMBER);
        // 複素数 c デフォルト
        public const DEFAULT_REAL_NUMBER:Number      = 0.0;
        public const DEFAULT_IMAGINARY_NUMBER:Number = 0.0;

        /**
         * 集合に該当する部分の色(一般的には色なし=黒)
         */
        public function set color(value:uint):void { _color = value; }
        private var _color:uint = 0x000000;
        /**
         * 発散部分のカラーリングマップ
         */
        public function set colorMap(value:Vector.<uint>):void {
            _colorMap = value;
            degree_   = value.length;
        }
        private var _colorMap:Vector.<uint>;
        
        // 発散チェックループ回数(_colorMap.length の値)
        private var degree_:int;
        

        /**
         * 複素数 c をデフォルトに戻す
         */
        public function resetComplexC():void {
            _c.real = DEFAULT_REAL_NUMBER;
            _c.imag = DEFAULT_IMAGINARY_NUMBER;
        }
        
        /**
         * 指定座標の計算をおこなう
         * @param    x    X座標値
         * @param    y    Y座標値
         * @return    計算結果
         */
        public function calculate(x:Number, y:Number):uint {
            var r:int = formula(x, y, _c.real, _c.imag);
            return (r >= 0) ? _colorMap[r] : _color;
        }
        /**
         * 漸化式:z(n+1) = z(n)^n + z(n-1) + 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 zPrevRl:Number = 0;
            var zPrevIm:Number = 0;
            var i:int = degree_;
            while (i--) {
                // 発散の評価(|z| > 2 = |z|^2 > 4)
                var zRlSqr:Number = zRl * zRl;
                var zImSqr:Number = zIm * zIm;
                var zSqr:Number   = zRlSqr + zImSqr;
                if (zSqr > 4) break;
                
                // 漸化式(ド・モアブルの定理)
                // 局座標値化
                var radian1:Number = Math.atan2(zIm, zRl);
                var dist1:Number   = Math.sqrt(zSqr);
                // 冪乗計算
                // 偏角
                var radian2:Number = radian1 * _exponent;
                // 距離
                var dist2:Number = dist1;
                var j:int = _exponent;
                while (--j) dist2 *= dist1;
                // 直交座標値化
                var zNextRl:Number = Math.cos(radian2) * dist2 + zPrevRl + cRl;
                var zNextIm:Number = Math.sin(radian2) * dist2 + zPrevIm + cIm;
                zPrevRl = zRl;
                zPrevIm = zIm;
                zRl = zNextRl;
                zIm = zNextIm;
            }
            return i;
            // break で脱しなかった(発散しなかった)場合、while を回りきるので i は -1 になる
        }
    }
//}

//package aquioux.display.fractal {
    import flash.geom.Rectangle;
    /**
     * フラクタル計算クラスの interface
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ interface ICalculator {
        function get DEFAULT_RECT():Rectangle;                // 描画範囲デフォルト値
        function set color(value:uint):void;                // 集合該当する部分の色
        function set colorMap(value:Vector.<uint>):void;    // 発散部分のカラーリングマップ
        function calculate(x:Number, y:Number):uint;        // 計算部
    }
//}

//package aquioux.display.fractal {
    import flash.events.Event;
    import flash.geom.Rectangle;
    /**
     * フラクタル描画エンジンクラス
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class Engine {
        /**
         * フラクタル計算クラス
         */
        public function set calculator(value:ICalculator):void { _calculator = value; }
        private var _calculator:ICalculator;
        
        /**
         * ユーザー入力挙動クラス
         */
        public function set controller(value:InputBehavior):void {
            _controller = value;
            _controller.addEventListener(InputBehavior.MOVING,  moveHandler);
            _controller.addEventListener(InputBehavior.ZOOMING, zoomHandler);
            _controller.addEventListener(Event.CHANGE, start);
        }
        private var _controller:InputBehavior;
        
        /**
         * ビューアクラス
         */
        public function set viewer(value:Viewer):void {
            _viewer = value;
            _viewer.addEventListener(Event.CHANGE, draw);
            displayWidth_  = _viewer.width;
            displayHeight_ = _viewer.height;
            dataLen_ = displayWidth_ * _viewer.drawRect.height;
            data_    = new Vector.<uint>(dataLen_, true);
        }
        private var _viewer:Viewer;
        
        /**
         * 描画計算領域を示す Rectangle
         */
        public function set rect(value:Rectangle):void {
            // 引数保持
            _rect = value;
            // 複素平面の走査開始座標を設定する
            startX_ = _rect.x;
            startY_ = _rect.y;
            // 複素平面の走査加算値を計算する
            stepX_ = _rect.width  / (displayWidth_  - 1);
            stepY_ = _rect.height / (displayHeight_ - 1);
        }
        private var _rect:Rectangle;
        

        // ビューア描画用データ
        private var data_:Vector.<uint>;
        // 描画ピクセル数(data_.length)
        private var dataLen_:int;
        
        // ビューアサイズ
        private var displayWidth_:int;        // 幅
        private var displayHeight_:int;        // 高

        // 複素平面の走査計算開始座標
        private var startX_:Number;            // 実数座標
        private var startY_:Number;            // 虚数座標

        // 複素平面の走査計算加算値
        private var stepX_:Number;            // 実数軸
        private var stepY_:Number;            // 虚数軸

        
        /**
         * 描画計算領域のリセット
         */
        public function reset():void {
            rect = _calculator.DEFAULT_RECT;
        }

        /**
         * 描画開始
         * @param    event    イベント
         */
        public function start(event:Event = null):void {
            if (event) {    // _controller の Event.CHANGE からの呼び出し
                var r:Rectangle = _controller.rect.clone();
                r.x = r.x * stepX_ + _rect.x;
                r.y = r.y * stepY_ + _rect.y;
                r.width  *= stepX_;
                r.height *= stepY_;
                rect = r;
            }
            _viewer.start();
        }
        // 描画実行
        private function draw(event:Event):void {
            // 描画部分の計算
            var drawOffset:int = _viewer.drawRect.y;
            for (var i:int = 0; i < dataLen_; i++) {
                var posX:int = i % displayWidth_;
                var posY:int = drawOffset + i / displayWidth_ >> 0;
                data_[i] = _calculator.calculate(posX * stepX_ + startX_, posY * stepY_ + startY_);
            }
            _viewer.draw(data_);
        }


        // 移動
        private function moveHandler(e:Event):void {
            _viewer.move(_controller.rect);
        }
        // 拡大・縮小
        private function zoomHandler(e:Event):void {
            _viewer.zoom(_controller.rect);
        }
    }
//}

//package aquioux.display.fractal {
    import flash.display.DisplayObject;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    /**
     * ユーザー入力挙動クラス
     * マウスドラッグ
     *   矩形を描く、マウスボタンを離すとその矩形領域を全体として表示(拡大)
     * cntl ボタン+マウスドラッグ
     *   表示領域の移動(移動)
     * マウスホイール
     *   マウスカーソル位置を中心に拡大(↑)・縮小(↓)
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class InputBehavior extends EventDispatcher {
        /**
         * 移動カスタムイベント
         */
        public static const MOVING:String  = "moving";
        /**
         * ズームカスタムイベント
         */
        public static const ZOOMING:String = "zooming";

        /**
         * マウス挙動 Rectangle
         */ 
        public function get rect():Rectangle { return _rect; }
        private var _rect:Rectangle = new Rectangle();


        // 矩形描画、移動に係る変数
        private var startX_:Number;        // ドラッグ開始X座標
        private var startY_:Number;        // ドラッグ開始Y座標
        private var moveX_:Number;        // ドラッグによる移動量(X軸方向)
        private var moveY_:Number;        // ドラッグによる移動量(Y軸方向)
        private var isCtrlDown_:Boolean = false;    // cntl キーダウン
        
        // マウス入力挙動対象
        private var target_:DisplayObject;
        

        /**
         * コンストラクタ
         * @param    target    マウス入力挙動対象
         */
        public function InputBehavior(target:DisplayObject) {
            // マウス入力挙動対象
            target_ = target;
            // マウスイベントハンドラ登録
            target_.addEventListener(MouseEvent.MOUSE_DOWN,  mouseDownHandler);
            target_.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
            // キーボードイベントハンドラ登録
            target_.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            target_.stage.addEventListener(KeyboardEvent.KEY_UP,   keyUpHandler);
        }


        // マウスイベントハンドラ
        private function mouseDownHandler(event:MouseEvent):void {
            // 起点待避
            startX_ = target_.mouseX;
            startY_ = target_.mouseY;

            // マウスイベントハンドラ登録
            if (isCtrlDown_) {    // 移動
                _rect.width  = target_.width;
                _rect.height = target_.height;
                target_.addEventListener(MouseEvent.MOUSE_MOVE, moving);        // 移動中
                target_.addEventListener(MouseEvent.MOUSE_UP,   moved);            // 移動終了
            } else {            // 拡大
                target_.addEventListener(MouseEvent.MOUSE_MOVE, zooming);        // 拡大中
                target_.addEventListener(MouseEvent.MOUSE_UP,   zoomed);        // 拡大終了
            }
        }

        // マウスイベントハンドラ
        // 移動中
        private function moving(event:MouseEvent):void {
            // 移動量の計算
            moveX_ = startX_ - target_.mouseX;
            moveY_ = startY_ - target_.mouseY;
            // _rect 調整
            _rect.x = moveX_;
            _rect.y = moveY_;
            // イベント送出
            dispatchEvent(new Event(MOVING));
        }
        // 移動終了
        private function moved(event:MouseEvent):void {
            // マウスイベントハンドラ解除
            target_.removeEventListener(MouseEvent.MOUSE_MOVE, moving);
            target_.removeEventListener(MouseEvent.MOUSE_UP,   moved);
            // イベント送出
            update();
        }

        // 拡大中
        private function zooming(event:MouseEvent):void {
            // 移動量の計算
            moveX_ = target_.mouseX - startX_;
            moveY_ = target_.mouseY - startY_;
            // 選択領域を正方形にする
            // 絶対値を求める
            var isMinusWidth:Boolean  = moveX_ < 0 ? true : false;
            var isMinusHeight:Boolean = moveY_ < 0 ? true : false;
            if (isMinusWidth)  moveX_ *= -1;
            if (isMinusHeight) moveY_ *= -1;
            // 幅・高のうち大きい方を正方形の辺とする
            var edge:Number = moveX_ > moveY_ ? moveX_ : moveY_;
            moveX_ = edge;
            moveY_ = edge;
            // _rect 調整
            _rect.x      = startX_;
            _rect.y      = startY_;
            _rect.width  = moveX_;
            _rect.height = moveY_;
            if (isMinusWidth)  _rect.x -= _rect.width;
            if (isMinusHeight) _rect.y -= _rect.height;
            // イベント送出
            dispatchEvent(new Event(ZOOMING));
        }
        // 拡大終了
        private function zoomed(event:MouseEvent):void {
            // マウスイベントハンドラ解除
            target_.removeEventListener(MouseEvent.MOUSE_MOVE, zooming);
            target_.removeEventListener(MouseEvent.MOUSE_UP,   zoomed);
            // イベント送出
            update();
        }

        
        // マウスホイールイベントハンドラ
        private function mouseWheelHandler(event:MouseEvent):void {
            // マウスホイールの移動量をスケールに変換
            var delta:Number = event.delta * 0.5;
            delta = (delta < 0) ? -delta : 1 / delta;
            // _rect を計算
            var nowWidth:Number  = target_.width  * delta;
            var nowHeight:Number = target_.height * delta;
            _rect.x      = target_.mouseX - nowWidth  / 2;
            _rect.y      = target_.mouseY - nowHeight / 2;
            _rect.width  = nowWidth;
            _rect.height = nowHeight;
            // イベント送出
            update();
        }
        
        // イベント送出(マウスアップ時)
        private function update():void {
            dispatchEvent(new Event(Event.CHANGE));
        }
        

        // キーボードイベントハンドラ
        // キーダウン
        private function keyDownHandler(event:KeyboardEvent):void {
            if (event.ctrlKey) isCtrlDown_ = true;
        }
        // キーアップ
        private function keyUpHandler(event:KeyboardEvent):void {
            if (isCtrlDown_) isCtrlDown_ = false;
        }
    }
//}

//package aquioux.display.fractal {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.ColorTransform;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    /**
     * ビューア
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class Viewer extends Sprite {
        /**
         * 1度の draw で描画する高さ(drawRect.y への加算値)
         */
        public function get heightOnceDraw():int { return _heightOnceDraw; }
        public function set heightOnceDraw(value:int):void {
            _heightOnceDraw  = value;
            _drawRect.height = value;
        }
        private var _heightOnceDraw:int = 1;

        /**
         * キャンバス描画 Rectangle(1度に描画するエリアを示す Rectangle)
         */
        public function get drawRect():Rectangle { return _drawRect; }    // read only
        private var _drawRect:Rectangle;
        
        // キャンバス
        private var canvas_:BitmapData;
        private var canvasRect_:Rectangle;

        // 移動ガイド
        private var moveGuideBm_:Bitmap;
        private var moveGuideBmd_:BitmapData;
        // 移動ガイド表示中か否か
        private var isMove_:Boolean = false;
        
        // ズームガイド
        private var zoomGuideGraphics_:Graphics;
        
        // 描画のために使いまわす Point
        private var destPoint_:Point = new Point();

        // 画面を暗くする効果用
        private const FADE:ColorTransform = new ColorTransform(0.75, 0.75, 0.75);

        
        /**
         * コンストラクタ
         * @param    w    描画幅
         * @param    h    描画高
         */
        public function Viewer(w:int, h:int) {
            // キャンバス生成
            canvas_ = new BitmapData(w, h, false, 0x0);
            addChild(new Bitmap(canvas_));
            canvasRect_ = canvas_.rect;
            
            // キャンバス描画 Rectangle 生成
            _drawRect = new Rectangle(0, 0, w, _heightOnceDraw);

            // 移動ガイド生成
            moveGuideBmd_ = canvas_.clone();
            moveGuideBm_  = new Bitmap(moveGuideBmd_);
            moveGuideBm_.alpha = 0;
            addChild(moveGuideBm_);
            
            // ズームガイド生成
            var zoomGuideShape:Shape = new Shape();
            zoomGuideShape.blendMode = BlendMode.INVERT;
            addChild(zoomGuideShape);
            zoomGuideGraphics_ = zoomGuideShape.graphics;
        }

        /**
         * 移動時の挙動
         * @param    rect    挙動を制御する Rectangle
         */
        public function move(rect:Rectangle):void {
            if (!isMove_) {    // 移動開始時
                // キャンバス全体を暗くする
                canvas_.colorTransform(canvasRect_, FADE);
                // ガイドの生成(キャンバスをそのまま写す)
                destPoint_.x = 0;
                destPoint_.y = 0;
                moveGuideBmd_.copyPixels(canvas_, canvasRect_, destPoint_);
                moveGuideBm_.alpha = 0.5;
                isMove_ = true;
            }
            
            // 移動ガイドの移動
            moveGuideBm_.x = -rect.x;
            moveGuideBm_.y = -rect.y;
        }
        
        /**
         * ズーム時の挙動
         * @param    rect    挙動を制御する Rectangle
         */
        public function zoom(rect:Rectangle):void {
            // ズーム用枠の表示
            zoomGuideGraphics_.clear();
            zoomGuideGraphics_.lineStyle(0, 0x0);
            zoomGuideGraphics_.drawRect(rect.x, rect.y, rect.width, rect.height);
        }
        

        /**
         * 描画開始
         */
        public function start():void {
            if (isMove_) {    // 移動から呼び出されたとき
                // destPoint を更新
                destPoint_.x = moveGuideBm_.x;
                destPoint_.y = moveGuideBm_.y;
                // 移動ガイドをキャンバスに描画
                canvas_.lock();
                canvas_.copyPixels(moveGuideBmd_, canvasRect_, destPoint_);
                canvas_.unlock();
                // 移動ガイドの後処理
                moveGuideBm_.alpha = 0;
                moveGuideBm_.x = 0;
                moveGuideBm_.y = 0;
                isMove_ = false;
            } else {        // ズームから呼び出されたとき
                // ズームガイドに表示された枠を消す
                zoomGuideGraphics_.clear();
                // キャンバスを暗くする
                canvas_.colorTransform(canvasRect_, FADE);
            }
            
            // キャンバス描画 Rectangle の初期化
            _drawRect.y = 0;
            // ENTER_FRAME イベント開始
            addEventListener(Event.ENTER_FRAME, function():void { dispatchEvent(new Event(Event.CHANGE)); } );
        }
        /**
         * 描画実行
         * @param    data    キャンバスを描くための Vector.<uint>
         */
        public function draw(data:Vector.<uint>):void {
            // 指定領域の更新
            canvas_.lock();
            canvas_.setVector(_drawRect, data);
            canvas_.unlock();
            // キャンバス描画 Rectangle の更新
            _drawRect.y += _heightOnceDraw;
            // 終了判定
            if (_drawRect.y >= canvas_.width) removeEventListener(Event.ENTER_FRAME, arguments.callee);
        }
    }
//}

//package aquioux.display.fractal {
    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 var prevButton_:PushButton;
        
        // ボタンの配列
        private var buttonList_:Vector.<PushButton>

        // _action への引数を格納する Dictionary
        private var valueList_:Dictionary;
        
        
        /**
         * コンストラクタ
         * @param    buttonWidth    ひとつのボタンの幅
         * @param    buttonHeight    ひとつのボタンの高さ
         * @param    stageWidth    ボタンを配置する幅
         * @param    data    ボタンが担う値
         */
        public function Buttons(buttonWidth:int, buttonHeight:int, stageWidth:int, data:Array) {
            var numOfButtonRow:int     = stageWidth / buttonWidth >> 0;        // 1行に配置されるボタンの数
            var numOfButtonLastRow:int = data.length % numOfButtonRow;        // 最後の行に配置されるボタンの数
            var numOfButtonCol:int     = data.length / numOfButtonRow >> 0;    // ボタンが配置されるの列の数
            var yLimit:int = (numOfButtonLastRow == 0) ? numOfButtonCol : numOfButtonCol + 1;
            var xLimit:int = numOfButtonRow;
            var idx:int    = 0;
            valueList_  = new Dictionary();
            buttonList_ = new Vector.<PushButton>();
            for (var y:int = 0; y < yLimit; y++) {
                if ((numOfButtonLastRow != 0) && (y == numOfButtonCol)) xLimit = numOfButtonLastRow;
                for (var x:int = 0; x < xLimit; x++) {
                    var b:PushButton = new PushButton(this, buttonWidth * x, buttonHeight * y, data[idx][0], handler);
                    b.width  = buttonWidth;
                    b.height = buttonHeight;
                    valueList_[b]    = data[idx][1];
                    buttonList_[idx] = b;
                    idx++;
                }
            }
        }
        
        /**
         * 指定のボタンを、外部から押した状態にする
         */
        public function selectedButton(idx:int):void {
            if (idx < buttonList_.length) {
                buttonAction(buttonList_[idx]);
            } else {
                throw new Error("指定したインデックス値がボタンの数より大きい値です。");
            }
        }
        /**
         * 現在選択されているボタンを、外部から解除する
         */
        public function releaseSelectedButton():void {
            if (prevButton_) prevButton_.enabled = true;
        }

        // ボタンハンドラ
        private function handler(e:Event):void {
            buttonAction(PushButton(e.target));
        }

        // ボタンを押したときの挙動
        private function buttonAction(target:PushButton):void {
            // 前回押されたボタンを有効にする
            releaseSelectedButton();
            // 今回押されたボタンを無効にする
            target.enabled = false;
            prevButton_ = target;
            // 外部から指定したボタンアクションを実行する
            _action(valueList_[target]);
        }
    }
//}

//package aquioux.display.fractal {
    import com.bit101.components.HSlider;
    import com.bit101.components.Label;
    import com.bit101.components.VSlider;
    import flash.display.BlendMode;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    /**
     * 複素数c用スライダー
     * @author YOSHIDA, Akio (Aquioux)
     */
    /*public*/ class Sliders extends Sprite {
        /**
         * 実数軸スライダーアクション(外部で定義する)
         */
        public function set realAction(value:Function):void { _realAction = value; }
        private var _realAction:Function;
        /**
         * 虚数軸スライダーアクション(外部で定義する)
         */
        public function set imagAction(value:Function):void { _imagAction = value; }
        private var _imagAction:Function;

        // スライダー
        private var hSlider_:HSlider;        // 横
        private var vSlider_:VSlider;        // 縦
        // ラベル
        private var hLabel_:Label;            // 横スライダー用
        private var vLabel_:Label;            // 縦スライダー用
        
        // マウスダウンフラグ
        private var isMouseDownH_:Boolean;    // 横スライダー用
        private var isMouseDownV_:Boolean;    // 縦スライダー用
        

        /**
         * コンストラクタ
         * @param    values    各種パラメータ
         */
        public function Sliders(values:Array) {
            // 横スライダー(複素数cの実数部)
            hSlider_ = new HSlider(this, 0, values[1][1]);
            hSlider_.width  = values[0][0];
            hSlider_.height = values[0][1];
            hSlider_.tick   = 0.001;
            hSlider_.setSliderParams(values[0][2], values[0][3], values[0][4]);

            // 縦スライダー(複素数cの虚数部)
            vSlider_ = new VSlider(this, values[0][0], 0);
            vSlider_.width  = values[1][0];
            vSlider_.height = values[1][1];
            vSlider_.tick   = 0.001;
            vSlider_.setSliderParams(values[1][2], values[1][3], values[1][4]);

            // マウスハンドラ
            // スライダーに直接ハンドラを設定すると ENTER_FRAME のタイミングで更新がかかり、
            // 処理負荷が大きくなるため、マウスアップ時にスライダハンドラを実行させる
            hSlider_.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHHandler);
            vSlider_.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownVHandler);
            hSlider_.addEventListener(MouseEvent.MOUSE_UP,   mouseUpHHandler);
            vSlider_.addEventListener(MouseEvent.MOUSE_UP,   mouseUpVHandler);
            
            // ラベルパラメータ
            var labelHeight:int = 15;
            var offset:int = 5;
            // 横スライダー用ラベル
            hLabel_ = new Label(this, 0, hSlider_.y - (labelHeight * 2 + offset));
            hLabel_.blendMode = BlendMode.INVERT;
            // 縦スライダー用ラベル
            vLabel_ = new Label(this, 0, hSlider_.y - (labelHeight     + offset));
            vLabel_.blendMode = BlendMode.INVERT;
        }
        
        /**
         * 外部からのスライダー値更新(実数軸)
         * @param    val    更新値
         */
        public function setRealValue(val:Number):void {
            hSlider_.value = val;
            hlabelUpdate(val);
        }
        /**
         * 外部からのスライダー値更新(虚数軸)
         * @param    val    更新値
         */
        public function setImagValue(val:Number):void {
            vSlider_.value = val;
            vlabelUpdate(val);
        }
        
        // スライダーハンドラ
        private function hsliderHandler():void {
            var val:Number = hSlider_.value
            // ラベル更新
            hlabelUpdate(val);
            // 外部から指定したスライダーアクションを実行する
            _realAction(val);
        }
        private function vsliderHandler():void {
            var val:Number = vSlider_.value
            // ラベル更新
            vlabelUpdate(val);
            // 外部から指定したスライダーアクションを実行する
            _imagAction(val);
        }
        
        // ラベル書換
        private function hlabelUpdate(val:Number):void {
            hLabel_.text = "real : " + String(val);
        }
        private function vlabelUpdate(val:Number):void {
            vLabel_.text = "imag : " + String(val);
        }

        // マウスハンドラ
        private function mouseDownHHandler(event:MouseEvent):void {
            isMouseDownH_ = true;
            isMouseDownV_ = false;
        }
        private function mouseDownVHandler(event:MouseEvent):void {
            isMouseDownV_ = true;
            isMouseDownH_ = false;
        }
        private function mouseUpHHandler(event:MouseEvent):void {
            if (isMouseDownH_) hsliderHandler();
            isMouseDownH_ = false;
        }
        private function mouseUpVHandler(event:MouseEvent):void {
            if (isMouseDownV_) vsliderHandler();
            isMouseDownV_ = false;
        }
    }
//}

//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);
        }
    }
//}