In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

アポロニウスのガスケット Apollonian Gasket (3)

user Interactive
Get Adobe Flash player
by Aquioux 17 Dec 2013
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/rd7Z
 */

// forked from Aquioux's アポロニウスのガスケット Apollonian Gasket (2)
// forked from Aquioux's アポロニウスのガスケット Apollonian Gasket (1)
package {
    //import aquioux.display.colorUtil.RGBWheel;
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#ffffff")]
    /**
     * アポロニウスのガスケット(3) 
     * ユーザーインタラクティブ
     * @author YOSHIDA, Akio
     */
    public class Main extends Sprite {
        // 再帰の終了判定(描画円の半径の最小値)
        static private const MIN_RADIUS:Number = 2.5;

        // 円の色初期値
        static private var colorStart_:Number = (Math.random() * 2 >> 0) * 180;
        // 円の色増分
        static private const ADD:int = 360 / 13 >> 0;
        
        // 円
        private var circleSpriteA_:CircleSprite;    // 正接円A
        private var circleSpriteB_:CircleSprite;    // 正接円B
        private var circleSpriteC_:CircleSprite;    // 正接円C
        private var draggingCircleSprite_:CircleSprite;    // ドラッグ中の正接円

        private var container_:Sprite;                // 円のコンテナ
        private var canvas_:Shape;                    // 円のキャンバス


        /**
         * コンストラクタ
         */
        public function Main() {
            setup();
            draw();
        }

        /**
         * セットアップ
         */
        private function setup():void {
            // ステージシフト値
            const SHIFT_X:Number = -10000;
            const SHIFT_Y:Number = -10000;
            // ステージ中央値
            const CENTER_X:Number = stage.stageWidth  / 2;
            const CENTER_Y:Number = stage.stageHeight / 2;

            // 円のコンテナ
            container_ = new Sprite();
            container_.x = SHIFT_X;
            container_.y = SHIFT_Y;
            container_.mouseEnabled = false;
            addChild(container_);
            // 円のキャンバス
            canvas_ = new Shape();
            container_.addChild(canvas_);

            // 正接円の生成
            circleSpriteA_ = new CircleSprite();
            circleSpriteB_ = new CircleSprite();
            circleSpriteC_ = new CircleSprite();
            circleSpriteA_.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            circleSpriteB_.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            circleSpriteC_.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            container_.addChild(circleSpriteA_);
            container_.addChild(circleSpriteB_);
            container_.addChild(circleSpriteC_);

            // 正接円の配置(極座標計算)
            var radianA:Number = -90 * Math.PI / 180;
            var radianB:Number =  30 * Math.PI / 180;
            var radianC:Number = 150 * Math.PI / 180;
            const LENGTH:int = 100;// stage.stageWidth * 0.27 >> 0;
            circleSpriteA_.x = CENTER_X + Math.cos(radianA) * LENGTH - SHIFT_X;
            circleSpriteA_.y = CENTER_Y + Math.sin(radianA) * LENGTH - SHIFT_Y;
            circleSpriteB_.x = CENTER_X + Math.cos(radianB) * LENGTH - SHIFT_X;
            circleSpriteB_.y = CENTER_Y + Math.sin(radianB) * LENGTH - SHIFT_Y;
            circleSpriteC_.x = CENTER_X + Math.cos(radianC) * LENGTH - SHIFT_X;
            circleSpriteC_.y = CENTER_Y + Math.sin(radianC) * LENGTH - SHIFT_Y;
        }
        // マウスハンドラ
        private function mouseDownHandler(event:MouseEvent):void {
            draggingCircleSprite_ = CircleSprite(event.target);
            draggingCircleSprite_.startDrag();
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
            stage.addEventListener(MouseEvent.MOUSE_UP,   mouseUpHandler);
            stage.addEventListener(Event.MOUSE_LEAVE,     mouseUpHandler);
        }
        private function mouseMoveHandler(event:MouseEvent):void {
            draw();
        }
        private function mouseUpHandler(event:MouseEvent):void {
            draggingCircleSprite_.stopDrag();
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
            stage.removeEventListener(MouseEvent.MOUSE_UP,   mouseUpHandler);
            stage.removeEventListener(Event.MOUSE_LEAVE,     mouseUpHandler);
        }

        /**
         * 描画
         */
        private function draw():void {
            // 正接円の半径の計算
            Calculator.calcTangentCircles(circleSpriteA_.circle, circleSpriteB_.circle, circleSpriteC_.circle);
            // 正接円の描画
            var color:uint = RGBWheel.getDegreeColor(colorStart_);
            circleSpriteA_.draw(color);
            circleSpriteB_.draw(color);
            circleSpriteC_.draw(color);

            canvas_.graphics.clear();

            // 外接円の生成
            var outer:Circle = Calculator.calcSoddyCircles(circleSpriteA_.circle, circleSpriteB_.circle, circleSpriteC_.circle, false);
            drawCircle(outer, 0);
            // 正接円以外の円の描画
            var degree:Number = 1;
            // 3正接円の再帰
            drawSoddyCircles(circleSpriteA_.circle, circleSpriteB_.circle, circleSpriteC_.circle, degree);
            // 二つの正接円と外接円の再帰
            degree++;
            drawSoddyCircles(circleSpriteA_.circle, circleSpriteB_.circle, outer, degree);    // その1
            drawSoddyCircles(circleSpriteB_.circle, circleSpriteC_.circle, outer, degree);    // その2
            drawSoddyCircles(circleSpriteC_.circle, circleSpriteA_.circle, outer, degree);    // その3

            colorStart_ += 0.5;
        }
        
        private function drawSoddyCircles(circleA:Circle, circleB:Circle, circleC:Circle, degree:int):void {
            // 内接円の生成
            var inner:Circle = Calculator.calcSoddyCircles(circleA, circleB, circleC);
            // 終了判定
            if (inner.radius < MIN_RADIUS) return;
            // 内接円の描画
            drawCircle(inner, RGBWheel.getDegreeColor(degree * ADD + colorStart_));
            // 3分木で再帰
            degree++;
            drawSoddyCircles(circleA, circleB, inner, degree);
            drawSoddyCircles(circleB, circleC, inner, degree);
            drawSoddyCircles(circleC, circleA, inner, degree);
        }

        private function drawCircle(circle:Circle, color:int):void {
            var g:Graphics = canvas_.graphics;
            g.lineStyle(0, 0x0);
            g.beginFill(color);
            g.drawCircle(circle.center.x, circle.center.y, circle.radius);
            g.endFill();
        }
    }
}



//package {
    //import aquioux.math.Complex;
    //import aquioux.math.ComplexMath;
    /**
     * 「デカルトの円定理」あるいは "Soddy Circles"
     * http://en.wikipedia.org/wiki/Descartes'_theorem
     * http://mathworld.wolfram.com/DescartesCircleTheorem.html
     * http://mathworld.wolfram.com/SoddyCircles.html
     * http://mathworld.wolfram.com/InnerSoddyCircle.html
     * http://mathworld.wolfram.com/OuterSoddyCircle.html
     * @author YOSHIDA, Akio
     */
    /*public*/ class Calculator {
        /**
         * 3つの正接円の中心座標からそれぞれの半径を算出
         * @param    circleA
         * @param    circleB
         * @param    circleC
         */
        static public function calcTangentCircles(circleA:Circle, circleB:Circle, circleC:Circle):void {
            // 2つの正接円間の距離(2つの正接円の半径の和)を算出
            var distAB:Number = dist(circleA.center, circleB.center);    // = circleA.radius + circleB.radius
            var distBC:Number = dist(circleB.center, circleC.center);    // = circleB.radius + circleC.radius
            var distCA:Number = dist(circleC.center, circleA.center);    // = circleC.radius + circleA.radius
            // 各正接円の半径を算出
            circleA.radius = (distCA + distAB - distBC) / 2;
            circleB.radius = (distAB + distBC - distCA) / 2;
            circleC.radius = (distBC + distCA - distAB) / 2;
        }
        // 2つの複素数間の距離を求める
        static private function dist(center1:Complex, center2:Complex):Number {
            return ComplexMath.abs(ComplexMath.subtract(center1, center2));
        }

        /**
         * 3つの正接円から、その内接円もしくは外接円の半径と中心座標を算出
         * @param    circleA
         * @param    circleB
         * @param    circleC
         * @param    isInner    3つの内接円の内接円を求めるのか、外接円を求めるのか。true:内接円、false:外接円
         * @return
         */
        static public function calcSoddyCircles(circleA:Circle, circleB:Circle, circleC:Circle, isInner:Boolean = true):Circle {
            // ----- 4番目の円の半径を求める -----
            // 4番目の円の曲率kを求める公式
            // (k1 + k2 + k3 + k4)^2 = 2 * (k1^2 + k2^2 + k3^2 + k4^2)
            // ↓
            // k4 = k1 + k2 + k3 ± 2 * √(k1*k2 + k2*k3 + k3*k1)

            // 各正接円の曲率
            var kA:Number = 1 / circleA.radius;        // k1
            var kB:Number = 1 / circleB.radius;        // k2
            var kC:Number = 1 / circleC.radius;        // k3
            
            // ±前の部分
            var kABC:Number = kA + kB + kC;            // k1 + k2 + k3
            // ±後の部分
            var kAB:Number = kA * kB;                // k1 * k2
            var kBC:Number = kB * kC;                // k2 * k3
            var kCA:Number = kC * kA;                // k3 * k1
            var sq1:Number = 2 * Math.sqrt(kAB + kBC + kCA);    // 2 * √(k1*k2 + k2*k3 + k3*k1)
            // k4 の計算結果(逆数にして半径に)
            if (!isInner) sq1 = -sq1;    // 外接円の場合
            var radiusD:Number = 1 / (kABC + sq1);

            // ----- 4番目の円の中心座標を求める -----
            // 4番目の円の中心座標(複素平面上)を求める公式
            // (z1*k1 + z2*k2 + z3*k3 + z4*k4)^2 = 2 * (z1^2*k1^2 + z2^2*k2^2 + z3^2*k3^2 + z4^2*k4^2)
            // ↓
            // z4 = (z1*k1 + z2*k2 + z3*k3 ± 2 * √(z1*k1 * z2*k2 + z2*k2 * z3*k3 + z3*k3 * z1*k1)) / k4

            // 分子のうち、±前の部分
            var zkA:Complex   = ComplexMath.scale(circleA.center, kA);    // z1 * k1
            var zkB:Complex   = ComplexMath.scale(circleB.center, kB);    // z2 * k2
            var zkC:Complex   = ComplexMath.scale(circleC.center, kC);    // z3 * k3
            var zkABC:Complex = ComplexMath.add(ComplexMath.add(zkA, zkB), zkC);
                                                                        // z1*k1 + z2*k2 + z3*k3
            // 分子のうち、±後の部分
            var zkAB:Complex = ComplexMath.multiply(zkA, zkB);    // z1*k1 * z2*k2
            var zkBC:Complex = ComplexMath.multiply(zkB, zkC);    // z2*k2 * z3*k3
            var zkCA:Complex = ComplexMath.multiply(zkC, zkA);    // z3*k3 * z1*k1
            var zkAABBCC:Complex = ComplexMath.add(ComplexMath.add(zkAB, zkBC), zkCA);
                                                                // z1*k1 * z2*k2 + z2*k2 * z3*k3 + z3*k3 * z1*k1
            var sq2:Complex = ComplexMath.scale(ComplexMath.pow(zkAABBCC, 1 / 2), 2);
                                                                // 2 * √(z1*k1 * z2*k2 + z2*k2 * z3*k3 + z3*k3 * z1*k1)
            // z4 の計算結果
            if (!isInner) sq2 = ComplexMath.scale(sq2, -1);    // 外接円の場合
            var zD:Complex = ComplexMath.scale(ComplexMath.add(zkABC, sq2), radiusD);

            return new Circle(zD, radiusD);
        }
    }
//}


//package  {
    //import aquioux.math.Complex;
    /**
     * 円クラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class Circle {
        /**
         * 中心座標
         */
        public function get center():Complex { return _center; }
        public function set center(value:Complex):void { _center = value; }
        private var _center:Complex;

        /**
         * 半径
         */
        public function get radius():Number { return _radius; }
        public function set radius(value:Number):void { _radius = value; }
        private var _radius:Number;
        

        /**
         * コンストラクタ
         * @param    center    中心座標
         * @param    radius    半径
         */
        public function Circle(center:Complex = null, radius:Number = 0.0) {
            _center = (center) ? center : new Complex(0.0, 0.0);
            _radius = radius;
        }
    }
//}


//package {
    //import aquioux.math.Complex;
    import flash.display.Graphics;
    import flash.display.Sprite;
    /**
     * 円スプライトクラス
     * @author YOSHIDA, Akio
     */
    /*public*/ class CircleSprite extends Sprite {
        /**
         * 円の情報
         */
        public function get circle():Circle {
            _circle.center.x = this.x;
            _circle.center.y = this.y;
            return _circle;
        }
        public function set circle(value:Circle):void { _circle = value; }
        private var _circle:Circle = new Circle();


        /**
         * コンストラクタ
         */
        public function CircleSprite():void {
            this.buttonMode = true;
        }

        /**
         * 描画
         */
        public function draw(color:uint = 0x0):void {
            var g:Graphics = this.graphics;
            g.clear();
            g.lineStyle(0, 0x0);
            g.beginFill(color);
            g.drawCircle(0, 0, _circle.radius);
            g.endFill();
        }
    }
//}


//package aquioux.math {
    /**
     * 複素数
     * @author YOSHIDA, Akio
     */
    /*public*/ final class Complex {
        /**
         * 実数部
         */
        // 実数
        public function get real():Number { return _real; }
        public function set real(value:Number):void { _real = value; }
        // 直交座標におけるX座標
        public function get x():Number { return _real; }
        public function set x(value:Number):void { _real = value; }
        // 局座標における長さ
        public function get length():Number { return _real; }
        public function set length(value:Number):void { _real = value; }
        // 実数部
        private var _real:Number;

        /**
         * 数部
         */
        // 虚数
        public function get imag():Number { return _imag; }
        public function set imag(value:Number):void { _imag = value; }
        // 直交座標におけるY座標
        public function get y():Number { return _imag; }
        public function set y(value:Number):void { _imag = value; }
        // 局座標における偏角
        public function get angle():Number { return _imag; }
        public function set angle(value:Number):void { _imag = value; }
        // 虚数部
        private var _imag:Number;


        /**
         * コンストラクタ
         * @param    real    実数部
         * @param    imag    虚数部
         */
        public function Complex(real:Number = 0.0, imag:Number = 0.0) {
            _real = real;
            _imag = imag;
        }

        /**
         * 複製
         * @return    複製した複素数
         */
        public function clone():Complex {
            return new Complex(_real, _imag);
        }

        /**
         * toString
         * @return    文字列表示
         */
        public function toString():String {
            return String(_real) + " + " + String(_imag) + " i";
        }
    }
//}


//package aquioux.math {
    /**
     * 複素数の定数と演算
     * @author YOSHIDA, Akio
     */
    /*public*/ final class ComplexMath {
        // ----- 定数 -----
        /**
         * ゼロ
         */
        static public const  ZERO:Complex = new Complex(0.0, 0.0);
        /**
         * 純実数1
         */
        static public const  PURE_REAL:Complex = new Complex(1.0, 0.0);
        /**
         * 純虚数i
         */
        static public const  PURE_IMAGINARY:Complex = new Complex(0.0, 1.0);


        /**
         * 加算
         * @param    a    加算項1
         * @param    b    加算項2
         * @return    加算結果
         */
        static public function add(a:Complex, b:Complex):Complex {
            return new Complex(
                a.real + b.real,
                a.imag + b.imag
            );
        }
        /**
         * 減算
         * @param    a    減算項1
         * @param    b    減算項2
         * @return    減算結果
         */
        static public function subtract(a:Complex, b:Complex):Complex {
            return new Complex(
                a.real - b.real,
                a.imag - b.imag
            );
        }
        /**
         * 乗算
         * @param    a    乗算項1
         * @param    b    乗算項2
         * @return    乗算結果
         */
        static public function multiply(a:Complex, b:Complex):Complex {
            var aRl:Number = a.real;
            var aIm:Number = a.imag;
            var bRl:Number = b.real;
            var bIm:Number = b.imag;
            return new Complex(
                aRl * bRl - aIm * bIm,
                aRl * bIm + aIm * bRl
            );
        }
        /**
         * 除算
         * @param    a    除算項1
         * @param    b    除算項2
         * @return    除算結果
         */
        static public function divide(a:Complex, b:Complex):Complex {
            return multiply(a, reciprocal(b));
        }

        /**
         * スケーリング(第2引数が実数である乗算)
         * @param    c    複素数
         * @param    n    実数
         * @return    乗算結果
         */
        static public function scale(c:Complex, n:Number):Complex {
            return new Complex(
                c.real * n,
                c.imag * n
            );
        }


        /**
         * 絶対値の2乗
         * @param    c    複素数
         * @return    絶対値の2乗
         */
        // c * c~ = c.real^2 + c.imag^2
        static public function absSquare(c:Complex):Number {
            var rl:Number = c.real;
            var im:Number = c.imag;
            return rl * rl + im * im;
        }
        /**
         * 絶対値(=長さ)
         * @param    c    複素数
         * @return    絶対値
         */
        // |c| = √(c * c~) = √(c.real^2 + c.imag^2)
        static public function abs(c:Complex):Number {
            return Math.sqrt(absSquare(c));
        }


        /**
         * 共役複素数
         * @param    c    複素数
         * @return    共役複素数
         */
        static public function conjugate(c:Complex):Complex {
            return new Complex(
                 c.real,
                -c.imag
            );
        }
        /**
         * 逆数
         * @param    c    複素数
         * @return    逆数
         */
        static public function reciprocal(c:Complex):Complex {
            var val:Number = absSquare(c);
            return new Complex(
                 c.real / val,
                -c.imag / val
            );
        }

        /**
         * 冪乗
         * @param    c    複素数
         * @param    exponent    冪指数
         * @return    冪乗結果
         */
        static public function pow(c:Complex, exponent:Number):Complex {
            // 極座標形式で計算
            var cc:Complex = cartesianToPolar(c);
            var length:Number = Math.pow(cc.length, exponent);
            var angle:Number  = cc.angle * exponent;
            return new Complex(
                length * Math.cos(angle),
                length * Math.sin(angle)
            );
        }


        /**
         * 直交座標形式から極座標形式へ
         * @param    c    直交座標形式の複素数
         * @return    極座標形式の複素数
         */
        // 対数関数との関連性
        static public function cartesianToPolar(c:Complex):Complex {
            var cc:Complex = new Complex();
            cc.length = abs(c);                        // 長さ
            cc.angle  = Math.atan2(c.imag, c.real);    // 偏角
            return cc;
        }
        /**
         * 極座標形式から直交座標形式へ
         * @param    c    極座標形式の複素数
         * @return    直交座標形式の複素数
         */
        // 指数関数との関連性
        static public function polarToCartesian(c:Complex):Complex {
            var length:Number = c.length;
            var angle:Number  = c.angle;
            return new Complex(
                length * Math.cos(angle),
                length * Math.sin(angle)
            );
        }


        /**
         * 対数関数
         * @param    c    複素数
         * @return    対数値
         */
        // 実数部は絶対値、虚数部は偏角
        static public function log(c:Complex):Complex {
            var cc:Complex = cartesianToPolar(c);
            return new Complex(
                Math.log(cc.length),
                cc.angle
            );
        }
        /**
         * 指数関数
         * @param    c    複素数
         * @return    指数値
         */
        // e^length * (cos(angle) + sin(angle)i)
        static public function exp(c:Complex):Complex {
            var val:Number = Math.exp(c.real);
            var im:Number  = c.imag;
            return new Complex(
                val * Math.cos(im),
                val * Math.sin(im)
            );
        }
    }
//}


//package aquioux.display.colorUtil {
    /**
     * コサインカーブで色相環的に RGB を計算
     * @author YOSHIDA, Akio
     */
    /*public*/ class RGBWheel {
        /**
         * 彩度(HSV の彩度 S と同じ扱い)
         */
        static public function get s():Number { return _s; }
        static public function set s(value:Number):void {
            _s = ColorMath.adjust1(value);
        }
        static private var _s:Number = 1.0;

        /**
         * 明度(HSV の彩度 V と同じ扱い)
         */
        static public function get v():Number { return _v; }
        static public function set v(value:Number):void {
            _v = ColorMath.adjust1(value);
        }
        static private var _v:Number = 1.0;

        /**
         * 角度に応じた RGB を得る(度数法指定)
         * @param    angle    角度(度数法)
         * @return    色(0xRRGGBB)
         */
        static private const TO_RADIAN:Number = Math.PI / 180;        // 度数を弧度に
        static public function getDegreeColor(angle:Number):uint {
            var r:uint = (Math.cos( angle        * TO_RADIAN) + 1) * 0xff >> 1;
            var g:uint = (Math.cos((angle + 120) * TO_RADIAN) + 1) * 0xff >> 1;
            var b:uint = (Math.cos((angle - 120) * TO_RADIAN) + 1) * 0xff >> 1;
            if (_s != 1.0) {
                r += calcShiftS(r);
                g += calcShiftS(g);
                b += calcShiftS(b);
            }
            if (_v != 1.0) {
                r -= calcShiftV(r);
                g -= calcShiftV(g);
                b -= calcShiftV(b);
            }
            return r << 16 | g << 8 | b;
        }
        /**
         * 角度に応じた RGB を得る(弧度法指定)
         * @param    radian    角度(弧度法)
         * @return    色(0xRRGGBB)
         */
        static private const RADIAN120:Number = Math.PI * 2 / 3;        // 120度を弧度で
        static public function getRadianColor(radian:Number):uint {
            var r:uint = (Math.cos(radian)             + 1) * 0xff >> 1;
            var g:uint = (Math.cos(radian + RADIAN120) + 1) * 0xff >> 1;
            var b:uint = (Math.cos(radian - RADIAN120) + 1) * 0xff >> 1;
            if (_s != 1.0) {
                r += calcShiftS(r);
                g += calcShiftS(g);
                b += calcShiftS(b);
            }
            if (_v != 1.0) {
                r -= calcShiftV(r);
                g -= calcShiftV(g);
                b -= calcShiftV(b);
            }
            return r << 16 | g << 8 | b;
        }


        /**
         * 彩度の反映
         * @param    gray    諧調(0~255)
         * @return    諧調のシフト値
         * @private
         */
        static private function calcShiftS(gray:uint):uint {
            return (0xff - gray) * (1 - _s) >> 0;
        }
        /**
         * 明度の反映
         * @param    gray    諧調(0~255)
         * @return    諧調のシフト値
         * @private
         */
        static private function calcShiftV(gray:uint):uint {
            return gray * (1 - _v) >> 0;
        }
    }
//}


//package aquioux.display.colorUtil {
    /**
     * 色にまつわる各種計算クラス(static クラス)
     * "HEX"   : uint 0xRRGGBB(16bitカラー)
     * "HEX32" : uint 0xAARRGGBB(32bitカラー)
     * "RGB"   : Vector.<uint>([r, b, g])
     * "ARGB"  : Vector.<uint>([r, b, g, a])
     * "HSV"   : Vector.<Number>([h, s, v])
     * @author YOSHIDA, Akio
     */
    /*public*/ class ColorMath {
        /**
         * コンストラクタ
         */
        public function ColorMath() {
            throw new Error("ColorMath クラスは static クラスです。");
        }


        // ++++++++++ "HEX" と "RGB" との相互変換 ++++++++++ //
        /**
         * "HEX" を "RGB" に変換する
         * @param    hex    "HEX"
         * @return    "RGB"
         */
        static public function hexToRgb(hex:uint):Vector.<uint> {
            var r:uint = (hex >> 16) & 0xff;
            var g:uint = (hex >>  8) & 0xff;
            var b:uint =  hex        & 0xff;
            return Vector.<uint>([r, g, b]);
        }
        /**
         * "RGB" を "HEX" に変換する
         * @param    rgb    "RGB"
         * @return    "HEX"
         */
        static public function rgbToHex(rgb:Vector.<uint>):uint {
            var r:uint = adjust255(rgb[0]);
            var g:uint = adjust255(rgb[1]);
            var b:uint = adjust255(rgb[2]);
            return r << 16 | g << 8 | b;
        }


        // ++++++++++ "HEX32" と "ARGB" との相互変換 ++++++++++ //
        /**
         * "HEX32" を "ARGB" に変換する
         * @param    hex    "ARGB"
         * @return    "ARGB"
         */
        static public function hex32ToRgb(hex:uint):Vector.<uint> {
            var a:uint = (hex >> 24) & 0xff;
            var r:uint = (hex >> 16) & 0xff;
            var g:uint = (hex >>  8) & 0xff;
            var b:uint =  hex        & 0xff;
            return Vector.<uint>([r, g, b, a]);
        }
        /**
         * "ARGB" を "HEX32" に変換する
         * @param    rgba    "ARGB"
         * @return    "ARGB"
         */
        static public function rgbToHex32(rgba:Vector.<uint>):uint {
            var a:uint = adjust255(rgba[3]);
            var r:uint = adjust255(rgba[0]);
            var g:uint = adjust255(rgba[1]);
            var b:uint = adjust255(rgba[2]);
            return a << 24 | r << 16 | g << 8 | b;
        }


        // ++++++++++ "RGB" と "HSV" との相互変換 ++++++++++ //
        /**
         * "RGB" を "HSV" に変換する
         * @param    rgb    "RGB"
         * @return    "HSV"
         * @see    http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
         */
        static public function rgbToHsv(rgb:Vector.<uint>):Vector.<Number> {
            // R,G,B 正規化(各値を 0 ~ 255 の範囲にする)
            var r:Number = adjust255(rgb[0]);
            var g:Number = adjust255(rgb[1]);
            var b:Number = adjust255(rgb[2]);

            // R,G,B 要素中の最大値と最小値およびその差を求める
            var minVal:Number = g < b ? g : b;
            if (r < minVal) minVal = r;                // 最大の値
            var maxVal:Number = g > b ? g : b;
            if (r > maxVal) maxVal = r;                // 最小の値
            var diffVal:Number = maxVal - minVal;    // 差分

            // H,S,V 計算
            if(diffVal == 0) {
                var h:Number = 0;
                var s:Number = 0;
                var v:Number = 0;
            } else {
                if (r == maxVal) {
                    h = 60 * (g - b) / diffVal;
                } else if (g == maxVal) {
                    h = 60 * (b - r) / diffVal + 120;
                } else {
                    h = 60 * (r - g) / diffVal + 240;
                }
                s = diffVal / maxVal;
                v = maxVal  / 0xff;
            }
            return Vector.<Number>([h, s, v]);
        }
        /**
         * "HSV" を "RGB" に変換する
         * @param    rgb    "HSV"
         * @return    "RGB"
         * @see    http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
         */
        static public function hsvToRgb(hsv:Vector.<Number>):Vector.<uint> {
            // H,S,V 正規化
            var h:Number = adjust360(hsv[0]);
            var s:Number = adjust1(hsv[1]);
            var v:Number = adjust1(hsv[2]);

            // R,G,B 計算
            if (s == 0) {
                var r:Number = v;
                var g:Number = v;
                var b:Number = v;
            } else {
                h /= 60;
                var i:int = h % 6 >> 0;
                var f:Number = h - i;
                var p:Number = v * (1 - s);
                var q:Number = v * (1 - s * f);
                var t:Number = v * (1 - s * (1 - f));
                switch(i) {
                    case 0:    r = v;    g = t;    b = p;    break;
                    case 1:    r = q;    g = v;    b = p;    break;
                    case 2:    r = p;    g = v;    b = t;    break;
                    case 3:    r = p;    g = q;    b = v;    break;
                    case 4:    r = t;    g = p;    b = v;    break;
                    case 5:    r = v;    g = p;    b = q;    break;
                }
            }
            return Vector.<uint>([r * 0xff >> 0, g * 0xff >> 0, b * 0xff >> 0]);
        }


        // ++++++++++ "HEX" と "HSV" との相互変換 ++++++++++ //
        /**
         * "HEX" を "HSV" に変換する
         * @param    hex    "HEX"
         * @return    "HSV"
         */
        static public function hexToHsv(hex:uint):Vector.<Number> {
            return rgbToHsv(hexToRgb(hex));
        }
        /**
         * "HSV" を "HEX" に変換する
         * @param    hsv    "HSV"
         * @return    "HEX"
         */
        static public function hsvToHex(hsv:Vector.<Number>):uint {
            return rgbToHex(hsvToRgb(hsv));
        }


        // ++++++++++ ヘルパー ++++++++++ //
        /**
         * 数値を 0.0 <= value < 360.0 の範囲に収める
         * @param    value
         * @return    チェック後の値
         * @private
         */
        static public function adjust360(value:Number):Number {
            value %= 360;
            if (value < 0) value += 360;
            return value;
        }
        /**
         * 数値を 0.0 <= value <= 1.0 の範囲に収める
         * @param    value
         * @return    チェック後の値
         * @private
         */
        static public function adjust1(value:Number):Number {
            if (value < 0.0) value = 0.0;
            if (value > 1.0) value = 1.0;
            return value;
        }
        /**
         * 数値を 0 <= value <= 255 の範囲に収める
         * @param    value
         * @return    チェック後の値
         * @private
         */
        static public function adjust255(value:uint):uint {
            if (value <   0) value =   0;
            if (value > 255) value = 255;
            return value;
        }
    }
//}