2変数関数 Two variable function

by Aquioux
去りゆく wonderfl に感謝をこめて。
ってなわけで、この期に及んで投稿しました。
2変数関数グラフの描画。要するに数楽アートの仮想版です。
全8個のうち5個は数楽アートにあるものなので、ちょっとご紹介。

saddle1 鞍点(1)
http://amzn.to/2msvZf0

saddle2 鞍点(2)
http://amzn.to/2msNvzP

parabola 放物面
http://amzn.to/2msu22f

ripple 波紋
http://amzn.to/2mszDpu

gaussian1 ガウス分布
http://sugakuart.com/products09.html

あとは、まったく独立した unevenness 凹凸 とガウス分布のバリエーション2つです。

書籍『美しすぎる数学 「数楽アート」を生んだ日本の底力』(中公新書ラクレ)もどうぞ。
http://amzn.to/2msyo9y
♥0 | Line 575 | Modified 2017-03-10 20:52:31 | MIT License
play

ActionScript3 source code

/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/CmWU
 */

package {
    import com.bit101.components.Label;
    import com.bit101.components.PushButton;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.ColorTransform;
    [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")]
    /**
     * 2変数関数 Two variable function
     * @author YOSHIDA, Akio(Aquioux)
     */
    public class Main extends Sprite {

        private var viewer_:Viewer;        // ビューアクラス

        private var figure_:Coordinate;
        private var indices_:Vector.<Vector.<int>>;    // 線を引くためのインデックス
        
        private var prevButton_:PushButton;
        private var label_:Label;

        private var fade1_:ColorTransform = new ColorTransform(0.5, 0.9, 1, 0.95);    // 青
        private var fade2_:ColorTransform = new ColorTransform(1, 0.93, 0.5, 0.95);    // 黄
        private var fade3_:ColorTransform = new ColorTransform(1, 0.5, 0.25, 0.95);    // 赤
        private var fade4_:ColorTransform = new ColorTransform(0.25, 1, 0.5, 0.95);    // 緑
        

        // コンストラクタ
        public function Main() {
            // ステージサイズ
            var sw:int = stage.stageWidth;
            var sh:int = stage.stageHeight;
            
            // プロジェクションクラス設定
            Projection.offsetX = sw >> 1;
            Projection.offsetY = sh >> 1;
            Projection.offsetZ = 150;

            // マウス挙動クラス生成
            MouseBehavior.setup(this.stage);

            // ビューアクラス作成
            viewer_ = new Viewer(sw, sh);
            addChild(viewer_);
            
            
            // ボタン
            var buttonWidth:int = 58;
            var button0:PushButton = new PushButton(this, buttonWidth * 0, 0, "saddle1", button0Action);
            button0.width = buttonWidth;
            addChild(button0);

            var button1:PushButton = new PushButton(this, buttonWidth * 1, 0, "saddle2", button1Action);
            button1.width = buttonWidth;
            addChild(button1);

            var button2:PushButton = new PushButton(this, buttonWidth * 2, 0, "parabola", button2Action);
            button2.width = buttonWidth;
            addChild(button2);

            var button3:PushButton = new PushButton(this, buttonWidth * 3, 0, "ripple", button3Action);
            button3.width = buttonWidth;
            addChild(button3);

            var button4:PushButton = new PushButton(this, buttonWidth * 4, 0, "unevenness", button4Action);
            button4.width = buttonWidth;
            addChild(button4);

            var button5:PushButton = new PushButton(this, buttonWidth * 5, 0, "gaussian1", button5Action);
            button5.width = buttonWidth;
            addChild(button5);

            var button6:PushButton = new PushButton(this, buttonWidth * 6, 0, "gaussian2", button6Action);
            button6.width = buttonWidth;
            addChild(button6);

            var button7:PushButton = new PushButton(this, buttonWidth * 7, 0, "gaussian3", button7Action);
            button7.width = buttonWidth;
            addChild(button7);
            
            // ラベル
            var labelHeight:int = 16;
            label_ = new Label(this, 0, sh - labelHeight, "");
            label_.height = labelHeight;
            addChild(label_);
            
            // 最初の状態
            button0Action(null);
            buttonCommonAction(button0);

            // ENTER_FRAME
            addEventListener(Event.ENTER_FRAME, update);
        }

        // 更新
        private function update(event:Event):void {
            MouseBehavior.update();
            viewer_.update(Projection.update(MouseBehavior.moveX, MouseBehavior.moveY), indices_);
        }
        
        // ボタンアクション
        private function button0Action(event:Event):void {
            figure_ = new Saddle1();
            label_.text = "Saddle1 : z = a * x * y, a = 1";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button1Action(event:Event):void {
            figure_ = new Saddle2();
            label_.text = "Saddle2 : z = a * (x^2 - y^2), a = 0.5";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button2Action(event:Event):void {
            figure_ = new Parabola();
            label_.text = "Parabola : z = a * (x^2 + y^2), a = 0.5";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button3Action(event:Event):void {
            figure_ = new Ripple();
            label_.text = "Ripple : z = a * cos(sqrt(x^2 + y^2)), a = 1";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button4Action(event:Event):void {
            figure_ = new Unevenness();
            label_.text = "Unevenness : a * sin(x) * sin(y), a = 1";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button5Action(event:Event):void {
            figure_ = new Gaussian1();
            label_.text = "Gaussian1 : a * exp(-(x^2 + y^2) / b), a = 3, b = 2";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button6Action(event:Event):void {
            figure_ = new Gaussian2();
            label_.text = "Gaussian2 : a * x * exp(-(x^2 + y^2) / b), a = 3, b = 2";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        private function button7Action(event:Event):void {
            figure_ = new Gaussian3();
            label_.text = "Gaussian3 : a * (x * y) * exp(-(x^2 + y^2) / b), a = 5, b = 2";
            if (event) buttonCommonAction(PushButton(event.target));
        }
        
        // 全ボタン共通アクション
        private function buttonCommonAction(currentButton:PushButton):void {
            resetButton(currentButton);
            resetFigure();
            var rnd:int = Math.random() * 4 >> 0;
            switch(rnd) {
                case 0: viewer_.fade = fade1_; break;
                case 1: viewer_.fade = fade2_; break;
                case 2: viewer_.fade = fade3_; break;
                case 3: viewer_.fade = fade4_; break;
            }
        }
        // ボタンのリセット
        private function resetButton(currentButton:PushButton):void {
            if (prevButton_) prevButton_.enabled = true;
            currentButton.enabled = false;
            prevButton_ = currentButton;
        }
        // 形状の入れ替え
        private function resetFigure():void {
            figure_.create();
            indices_ = figure_.indices;
            Projection.verts = figure_.verts;
        }
    }
}


//package {
    import flash.geom.Matrix3D;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Utils3D;
    import flash.geom.Vector3D;
    /**
     * 三次元座標を二次元座標に投射する
     * @author YOSHIDA, Akio(Aquioux)
     */
    /*public*/ class Projection {
        /**
         * X座標オフセット値
         */
        static public function get offsetX():Number { return _offsetX; }
        static public function set offsetX(value:Number):void { _offsetX = value; }
        static private var _offsetX:Number = 0;
        /**
         * Y座標オフセット値
         */
        static public function get offsetY():Number { return _offsetY; }
        static public function set offsetY(value:Number):void { _offsetY = value; }
        static private var _offsetY:Number = 0;
        /**
         * Z座標オフセット値
         */
        static public function get offsetZ():Number { return _offsetZ; }
        static public function set offsetZ(value:Number):void { _offsetZ = value; }
        static private var _offsetZ:Number = 150;

        /**
         * 頂点の座標(三次元座標)
         */
        static public function set verts(verts:Vector.<Number>):void {
            // Utils3D.projectVectors 用パラメータ初期化
            _verts      = verts;
            var len:int = _verts.length;
            projectedVerts_ = new Vector.<Number>(len * 2 / 3, true);
            uvts_           = new Vector.<Number>(len, true);
            matrix3D_       = new Matrix3D();

            // PerspectiveProjection 生成
            projection_ = new PerspectiveProjection();
            projection_.fieldOfView = 75;    // 値を大きくするほど遠近法の歪みが大きくなる
            projectionMatrix3D_ = projection_.toMatrix3D();
            
            // 移動計算用変数の初期化
            vx_ = 0.0;
            vy_ = 0.0;
        }
        static private var _verts:Vector.<Number>;

        // Utils3D.projectVectors 用パラメータ
        static private var matrix3D_:Matrix3D;
        static private var projectedVerts_:Vector.<Number>;
        static private var uvts_:Vector.<Number>;

        // PerspectiveProjection
        static private var projection_:PerspectiveProjection;
        static private var projectionMatrix3D_:Matrix3D;

        // 移動計算用
        static private var vx_:Number = 0.0;
        static private var vy_:Number = 0.0;


        /**
         * 更新
         * @param    moveX    移動量(X軸)
         * @param    moveY    移動量(Y軸)
         */
        static public function update(moveX:Number, moveY:Number):Vector.<Number> {
            // 移動量適用
            vx_ += moveX;
            vy_ -= moveY;

            // 移動量を適用した回転の計算と適用
            matrix3D_.identity();
            matrix3D_.appendRotation(vy_, Vector3D.X_AXIS);
            matrix3D_.appendRotation(vx_, Vector3D.Y_AXIS);
            matrix3D_.appendTranslation(0, 0, _offsetZ);
            matrix3D_.append(projectionMatrix3D_);
            Utils3D.projectVectors(matrix3D_, _verts, projectedVerts_, uvts_);

            // 回転を適用した座標データを zsort
            var len:uint = projectedVerts_.length / 2;    // 頂点の数
            for (var i:int = 0; i < len; i++) {
                var idx:int = i * 2;
                projectedVerts_[idx]     += _offsetX;
                projectedVerts_[idx + 1] += _offsetY;
            }

            return projectedVerts_;
        }
    }
//}


//package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Shape;
    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 {
        /**
         * 残像の有無
         */
        public function set isAfterimage(value:Boolean):void { _isAfterimage = value; }
        private var _isAfterimage:Boolean = true;
        
        /**
         * 残像生成のための Blur フィルター
         */
        public function set blur(value:BlurFilter):void { _blur = value; }
        private var _blur:BlurFilter = new BlurFilter(2, 2, BitmapFilterQuality.LOW);
        
        /**
         * 残像生成のための ColorTransform
         */
        public function set fade(value:ColorTransform):void { _fade = value; }
        private var _fade:ColorTransform = new ColorTransform(0.5, 0.9, 1, 0.95);


        // 線を描画する Shape
        private var drawShape_:Shape;
        private var g_:Graphics;
        
        // BitmapData
        private var bufferBmd_:BitmapData;    // バッファ用
        private var viewBmd_:BitmapData;    // 表示用
        
        // BitmapData 描画に使う変数
        private var rect_:Rectangle;
        private const ZERO_POINT:Point = new Point(0, 0);
        
        private const BACK_COLOR:uint = 0x000000;
        private const LINE_COLOR:uint = 0xffffff;

        
        /**
         * コンストラクタ
         */
        public function Viewer(w:int, h:int) {
            // 線を描画する Shape
            drawShape_ = new Shape();
            g_ = drawShape_.graphics;

            // BitmapData
            bufferBmd_ = new BitmapData(w, h, false, BACK_COLOR);
            viewBmd_   = bufferBmd_.clone();
            addChild(new Bitmap(viewBmd_));

            // BitmapData 描画に使う変数
            rect_ = new Rectangle(0, 0, w, h);
            
            // ボタンモード
            this.buttonMode = true;
        }

        /**
         * 更新
         * @param    data    描画データ(X座標,Y座標の2項目を一次元配列で)
         */
        public function update(vertices:Vector.<Number>, indices:Vector.<Vector.<int>>):void {
            // 線の描画
            var isFirst:Boolean = true;
            g_.clear();
            g_.lineStyle(0, LINE_COLOR, 0.5);
            for each (var idxs:Vector.<int> in indices) {
                for each (var idx:int in idxs) {
                    var posX:Number = vertices[idx * 2];
                    var posY:Number = vertices[idx * 2 + 1];
                    if (isFirst) {
                        g_.moveTo(posX, posY);
                        isFirst = false;
                    } else {
                        g_.lineTo(posX, posY);
                    }
                }
                isFirst = true;
            }
            
            // 表示
            if (_isAfterimage) {
                // 表示部分
                // 前回の状態に現在の状態を被せて描く
                bufferBmd_.draw(drawShape_);
                // 表示 BitmapData を最新の状態で塗りつぶす
                viewBmd_.copyPixels(bufferBmd_, rect_, ZERO_POINT);
                // 残像部分
                // バッファに対して Blur を適用し、次回のためにぼかす
                bufferBmd_.applyFilter(viewBmd_, rect_, ZERO_POINT, _blur);
                // バッファに対して ColorTransForm を適用し、次回のためにアルファ値を落とす
                bufferBmd_.colorTransform(rect_, _fade);
            } else {
                // 前フレームの描画をクリア
                viewBmd_.fillRect(rect_, BACK_COLOR);
                // 表示
                viewBmd_.draw(drawShape_);
            }
            
        }
    }
//}


//package {
    /**
     * 頂点座標データ生成の抽象クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Coordinate {
        /**
         * 頂点座標を格納するリスト(X, Y, Z座標を1次元形式で格納)
         */
        public function get verts():Vector.<Number> { return _verts; }
        protected var _verts:Vector.<Number> = new Vector.<Number>();

        /**
         * 頂点をどの順番でつなぐかを示すインデックス
         */
        public function get indices():Vector.<Vector.<int>> { return _indices; }
        protected var _indices:Vector.<Vector.<int>> = new Vector.<Vector.<int>>();


        /**
         * 座標データ生成(定義はサブクラスで)
         */
        public function create():void {
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * x * y 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Saddle1 extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 40;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 40;    // Y軸上の置かれる点の数
            const RANGE:Number  = 1;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 50;
            
            var a:Number = 1;

            // 座標の生成
            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * posX * posY;
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * (x^2 - y^2) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Saddle2 extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 40;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 40;    // Y軸上の置かれる点の数
            const RANGE:Number  = 1;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 50;
            
            var a:Number = 0.5;

            // 座標の生成
            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * (posX * posX - posY * posY);
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * (x^2 + y^2) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Parabola extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 40;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 40;    // Y軸上の置かれる点の数
            const RANGE:Number  = 1;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 50;
            
            var a:Number = 0.5;

            // 座標の生成
            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * (posX * posX + posY * posY);
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * cos(sqrt(x^2 + y^2)) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Ripple extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 50;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 50;    // Y軸上の置かれる点の数
            const RANGE:Number  = 15;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 4;
            
            var a:Number = 1;

            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * Math.cos(Math.sqrt(posX * posX + posY * posY));
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * sin(x) * sin(y) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Unevenness extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 50;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 50;    // Y軸上の置かれる点の数
            const RANGE:Number  = 8;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 8;
            
            var a:Number = 1;

            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * Math.sin(posX) * Math.sin(posY);
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * exp(-(x^2 + y^2) / b) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Gaussian1 extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 40;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 40;    // Y軸上の置かれる点の数
            const RANGE:Number  = 4;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 15;

            var a:Number = 3;
            var b:Number = 2;
            
            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * Math.exp((-(posX * posX + posY * posY)) / b);
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * x * exp(-(x^2 + y^2) / b) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Gaussian2 extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 40;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 40;    // Y軸上の置かれる点の数
            const RANGE:Number  = 4;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 15;

            var a:Number = 3;
            var b:Number = 2;
            
            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * posX * Math.exp((-(posX * posX + posY * posY)) / b);
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}

//package {
    /**
     * 2変数関数
     * z = a * (x * y) * exp(-(x^2 + y^2) / b) 頂点座標データ生成クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Gaussian3 extends Coordinate {
        /**
         * 頂点座標データ生成
         */
        override public function create():void {
            const NUM_OF_X:int  = 40;    // X軸上の置かれる点の数
            const NUM_OF_Y:int  = 40;    // Y軸上の置かれる点の数
            const RANGE:Number  = 4;    // X軸、Y軸上の置かれる点は -RANGE ~ RANGE の範囲
            const STEP_X:Number = (RANGE * 2) / (NUM_OF_X - 1);
            const STEP_Y:Number = (RANGE * 2) / (NUM_OF_Y - 1);
            const SCALE:Number  = 15;

            var a:Number = 5;
            var b:Number = 2;
            
            for (var y:int = 0; y < NUM_OF_Y; y++) {
                var posY:Number = y * STEP_Y - RANGE;
                for (var x:int = 0; x < NUM_OF_X; x++) {
                    var posX:Number = x * STEP_X - RANGE;
                    var posZ:Number = a * (posX * posY) * Math.exp((-(posX * posX + posY * posY)) / b);
                    _verts.push(posX * SCALE, posY * SCALE, posZ * SCALE);
                }
            }
            _verts.fixed  = true;

            // 線を引くためのインデックスの生成
            // X軸方向
            var idxs:Vector.<int> = new Vector.<int>();
            for (y = 0; y < NUM_OF_Y; y++) {
                for (x = 0; x < NUM_OF_X; x++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            // Y軸方向
            for (x = 0; x < NUM_OF_X; x++) {
                for (y = 0; y < NUM_OF_Y; y++) {
                    idxs.push(NUM_OF_X * y + x);
                }
                _indices.push(idxs.concat());
                idxs.length = 0;
            }
            _indices.fixed = true;
        }
    }
//}


//package aquioux.sketch {
    import flash.display.DisplayObject;
    import flash.display.Stage;
    import flash.events.MouseEvent;
    /**
     * マウス挙動クラス
     * @author YOSHIDA, Akio(Aquioux)
     */
    /*public*/ class MouseBehavior {
        /**
         * マウス移動量(X軸)
         */
        static public function get moveX():Number { return _moveX; }
        static private var _moveX:Number = 0.0;
        /**
         * マウス移動量(Y軸)
         */
        static public function get moveY():Number { return _moveY; }
        static private var _moveY:Number = 0.0;

        // 前回の MOUSW_MOVE 時のマウス座標
        static private var prevMouseX_:Number = 0.0;
        static private var prevMouseY_:Number = 0.0;

        // マウスをダウンしているか否か
        static private var isMouseDown_:Boolean = false;

        // マウスイベントの対象ステージ
        static private var stage_:DisplayObject;

        // 摩擦係数
        static private const FRICTION:Number = 0.98;


        /**
         * 初期化
         * @param    stage    マウスイベントの対象ステージ
         */
        static public function setup(stage:DisplayObject):void {
            // マウスイベントの対象
            stage_ = stage;
            // マウスハンドラ登録
            stage_.addEventListener(MouseEvent.MOUSE_DOWN, function():void { isMouseDown_ = true; });
            stage_.addEventListener(MouseEvent.MOUSE_UP,   function():void { isMouseDown_ = false; });
            stage_.addEventListener(MouseEvent.MOUSE_MOVE, function():void {
                if (!isMouseDown_) {
                    prevMouseX_ = stage_.mouseX;
                    prevMouseY_ = stage_.mouseY;
                }
            });
        }

        /**
         * 更新
         */
        static public function update():void {
            if (isMouseDown_) {
                _moveX = stage_.mouseX - prevMouseX_;
                _moveY = stage_.mouseY - prevMouseY_;
                prevMouseX_ = stage_.mouseX;
                prevMouseY_ = stage_.mouseY;
            } else {
                _moveX *= FRICTION;
                _moveY *= FRICTION;
            }
        }
    }
//}

Forked