forked from: MoonPhase

by rodrigocardozo forked from MoonPhase (diff: 3)
♥0 | Line 400 | Modified 2011-11-17 22:57:37 | MIT License
play

ActionScript3 source code

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

// forked from flashrod's MoonPhase
package {
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.display.Loader;

    
    [SWF(backgroundColor="0x000000")]
    public class MoonPhase extends Sprite {

        private static const DELTA:Number = 1e-2; // 朔を求めるときの閾値

        
        public static const SIZE:int = 200;

        /** 初期化 */
        public function MoonPhase() {
            var ud:Date = new Date(); // 今日の日付
            var jd:JulianDay = JulianDay.create(ud);
            var a:Number = round360(calcAngle(jd)); // 朔からの角度(°)
            // 影と明るい部分がある月のイメージを作る
            var loader:Loader = new Loader();
            var url:String = "http://wonderfl.net/static/tmp/related_images/9400354c5bd4a35f9f6cdd7bf1bb8ede13be3c2em";
            loader.load(new URLRequest(url));
            addChild(loader);
            addChild(new Phase(a));
            // 角度から月齢を得る
            var label:TextField = new TextField();
            label.autoSize = TextFieldAutoSize.LEFT;
            label.text = ageStr(calcAge(jd, a));
            label.textColor = 0xFFFFFF;
            label.y = SIZE-16;
            addChild(label);
            var stat:TextField = new TextField();
            stat.autoSize = TextFieldAutoSize.LEFT;
            stat.text = new ISO8601Date(ud).toString();
            stat.textColor = 0xFFFFFF;
            addChild(stat);
        }

        /** 月齢を表記文字列にする
         */
        private function ageStr(a:Number):String {
            var s:String = String(a);
            var i:int = s.indexOf(".");
            if (i >= 0 && i < (s.length - 2)) {
                s = s.substring(0, i + 2);
            }
            return s;
        }

        /** 角度から月齢を計算する.
         * @param jd 今の日付時刻
         * @param a 角度(°)
         * @return 月齢(0.0~29.9くらい)
         */
        private function calcAge(jd:JulianDay, a:Number):Number {
            var d:Number = jd.doubleValue(); // 今のユリアン日
            // 朔のユリアン日を求める.
            for (var i:int = 0; i < 10; ++i) { // 無限ループにならないように、最大10回
                d -= a * 29 / 360;    // 概算で角度から朔までの日数を引く
                a = calcAngle(JulianDay.build(d));
                if (Math.abs(a) < DELTA) // 角度が0に近かったら朔とみなす
                    break;
            }
            return jd.doubleValue() - d; // 今の日から朔の日までの差が月齢
        }

        /** 指定された日の、地球から見た月と太陽のなす角度を得る.
         * @param jd 指定日
         * @return 角度(°)
         */
        public function calcAngle(jd:JulianDay):Number {
            var sun:Lucky = Sun.getPos(jd); // 地球から見た太陽の位置
            var moon:Lucky = Moon.getPos(jd); // 地球から見た月の位置
            var s:Number = moon.lng - sun.lng; // 朔からの角度
            return s;
        }

        /** 0から360の間に押さえ込む
         * @param a 角度(°)
         * @return aを0から360の間に押さえ込んだ値
         */
        public function round360(a:Number):Number {
            while (a < 0)
                a += 360;
            while (a > 360)
                a -= 360;
            return a;
        }
    }
}

/** 日付時刻の表記 */
class ISO8601Date {

    /** 日付時刻 */
    private var cal:Date;

    /**
     * @param cal 日付時刻
     */
    public function ISO8601Date(cal:Date) { this.cal = cal; }

    /**
     */
    public static function tttt(t:int):String {
        var sign:String = signChar(t);
        t = Math.abs(t);
        var h:int = t / 60;
        var m:int = t % 60;
        return sign + format2(h) + format2(m);
    }

    /**
     * @return ISO8601形式日付文字列
     */
    public function toString():String {
        var y:int = cal.fullYear;
        var m:int = cal.month + 1;
        var d:int = cal.date;
        var h:int = cal.hours;
        var min:int = cal.minutes;
        var s:int = cal.seconds;
        var tz:String = tttt(cal.getTimezoneOffset());
        return y + "-" + format2(m) + "-" + format2(d)
            + " " + format2(h) + ":" + format2(min) + ":" + format2(s) + tz;
    }

    /** 頭に0をつけてでも二桁の数値表現にする
     * @param a a
     * @return formatted string
     */
    public static function format2(a:Number):String {
        var s:String = "0" + a.toString();
        return s.substring(s.length - 2);
    }

    /** 符号文字を戻す
     * @param a 実数
     * @return " ":正または零 、 "-":負
     */
    public static function signChar(a:Number):String {
        if (a < 0) {
            return "-";
        }
        return "+";
    }
}

/** ユリアン日 */
class JulianDay {
    public var fix:int;            // 整数部
    public var dec:Number;            // 小数部 decimal

    /** ユリアン日の整数部と小数部からユリアン日を生成する.
     * @param fix ユリアン日の整数部
     * @param dec ユリアン日の少数部
     * @return ユリアン日
     */
    public function JulianDay(fix:int, dec:Number) {
        this.fix = fix;
        this.dec = dec;
    }

    public static function build(a:Number):JulianDay {
        var fix:int = Math.floor(a);
        var dec:Number = a - fix;
        return new JulianDay(fix, dec);
    }

    /** 日付時刻からユリアン日を生成する.
     * @param ud 日付時刻
     * @return ユリアン日
     */
    public static function create(ud:Date):JulianDay {
        var year:int = ud.fullYearUTC;
        var month:int = ud.monthUTC+1; // Dateは1月が0
        var day:int = ud.dateUTC;
        var hour:int = ud.hoursUTC;
        var min:int = ud.minutesUTC;
        var sec:int = ud.secondsUTC;

        var j:int;              // ユリアン日整数部
        var d:Number;           // ユリアン日小数部

        var bc:Boolean = (year <= 0);

        /* グレゴリアンカレンダーの最初の日 */
        var gregory:Boolean = (year > 1582)
            || (year == 1582 && month > 10)
            || (year == 1582 && month == 10 && day >= 15);

        if (month <= 2) {
            year--;
            month += 12;
        }

        if (hour < 12) {
            j = 0;
            d = 0.5;
        } else {
            j = 1;
            d = -0.5;
        }
        d += (hour*3600 + min*60 + sec)/86400.0;

        j += bc ? int((year-3)/4) : int(year/4);
        if (gregory)
            j += 2 - int(year/100) + int(year/400);
        j += 1720994 + year*365 + (month+1)*30 + int((month+1)*3/5) + day;

        return new JulianDay(j, d);
    }

    /** ユリアン日からグリニッジ標準時カレンダーを得る.
     * @return 日付時刻
     */
    public function toUniversalTime():Date {
        var j:int = this.fix;
        var d:Number = this.dec;

        // 標準時計算用変数
        var year:int;
        var month:int;
        var day:int;
        var hour:int;
        var min:int;
        var sec:int;

        var c:int;
        var k:int;
        var e:int;
        var s:int;

        if (d >= 0.5) {
            j++;
            d -= 0.5;
        } else {
            d += 0.5;
        }
        if (j >= 2299161) {
            j = j + 1 + (j-1867216)/36524 - (j-1867216)/146096;
        }
        j += 1524;

        c = (int)((j - 122.1) / 365.25);
        k = 365*c + c/4;
        e = (int)((j - k) / 30.6001);

        year = c - 4716;
        month = e - 1;
        if (month > 12) {
            month -= 12;
            year++;
        }
        day = j - k - int(30.6*e);

        s = int(d * 86400 + 0.5);
        hour = s / 3600;
        min = (s % 3600) / 60;
        sec = s % 60;

        var cal:Date = new Date(); //.getInstance(TimeZone.getTimeZone("GMT"));
        cal.fullYearUTC = year;
        cal.monthUTC = month-1;
        cal.dateUTC = day;
        cal.hoursUTC = hour;
        cal.minutesUTC = min;
        cal.secondsUTC = sec;

        return cal;
    }

    /** ユリアン日を実数で表す.
     * @return ユリアン日を実数で表す値
     */
    public function doubleValue():Number {
        return fix + dec;
    }

    /** ユリアン日を表示用の文字列化に変換する.
     * @return 表示用文字列
     */
    public function toString():String {
        return "<JulianDay fix="+fix+" dec="+dec+"/>";
    }
}

/** 黄経と黄緯クラス
 */
class Lucky {
    public var lng:Number;  // 黄経(単位 度)
    public var lat:Number;  // 黄緯(単位 度)
    public var dist:int; // 地心距離(月/太陽中心間の距離)(単位 キロメートル)

    /** 黄経黄緯を生成する.
     * @param lng 黄経(単位 度)
     * @param lat 黄緯(単位 度)
     * @param dist 地心距離(月/太陽中心間の距離)(単位 キロメートル)
     */
    public function Lucky(lng:Number, lat:Number, dist:int) {
        this.lng = lng;
        this.lat = lat;
        this.dist = dist;
    }

    /** 黄経黄緯を表示できる文字列を得る */
    public function toString():String {
        return "<Lucky lng="+lng+" lat="+lat+" dist="+dist+"/>";
    }
}

/** 太陽位置計算クラス
 * 海上保安庁水路部による太陽の位置の略算式
 */
class Sun {

    private static const K:int = 0;
    private static const A:int = 1;
    private static const B:int = 2;

    private static const l:Array = [
         [  1.9147,  35999.05, 267.52 ], [ -0.0048,  35999.05, 267.52 ],
         [  0.0200,  71998.1,  265.1  ], [  0.0020,  32964.0,  158.0  ],
         [  0.0018,     19.0,  159.0  ], [  0.0018, 445267.0,  208.0  ],
         [  0.0015,  45038.0,  254.0  ], [  0.0013,  22519.0,  352.0  ],
         [  0.0007,  65929.0,   45.0  ], [  0.0007,   3035.0,  110.0  ],
         [  0.0007,   9038.0,   64.0  ], [  0.0006,  33718.0,  316.0  ],
         [  0.0005,    155.0,  118.0  ], [  0.0005,   2281.0,  221.0  ],
         [  0.0004,  29930.0,   48.0  ], [  0.0004,  31557.0,  161.0  ]];
    private static const c:Array = [
         [  0.016706,  35999.05, 177.53 ], [ -0.000042,  35999.05, 177.53 ],
         [  0.000139,  71998.0,  175.0  ], [  0.000031, 445267.0,  298.0  ],
         [  0.000016,  32964.0,   68.0  ], [  0.000016,  45038.0,  164.0  ],
         [  0.000005,  22519.0,  233.0  ], [  0.000005,  33718.0,  226.0  ]];

    /** 太陽の位置を得る.
     * @param jd ユリアン日.
     * @return 黄経黄緯
     */
    public static function getPos( jd:JulianDay):Lucky {
        var j:int = jd.fix;
        var d:Number = jd.dec;

        var t:Number = (j + d - 2451545.0)/36525.0;
        var s:Number = 280.4659 + 36000.7695 * t;

        for (var i:int = 0; i < 16; i++) {
            var r:Number = l[i][A] * t + l[i][B];
            s += l[i][K] * Math.cos(r * 0.017453292519943);
        }
        while (s < 0)
            s += 360.0;
        while (s >= 360.0)
            s -= 360.0;
        var lng:Number = s;

        s = 1.000140;
        for ( i = 0; i < 8; i++) {
            r = c[i][A] * t + c[i][B];
            s += c[i][K] * Math.cos(r * 0.017453292519943);
        }
        var dist:int = (int)(s * 149597870.0);

        return new Lucky(lng, 0, dist);
    }
}

/** 月位置計算クラス.
 * 海上保安庁水路部による月の位置の略算式
 */
class Moon {

    private static const K:int = 0;
    private static const A:int = 1;
    private static const B:int = 2;

    private static const ln:Array = [
         [ 6.2888, 477198.868, 44.963 ],[ 1.274,  413335.35,  10.74 ],
         [ 0.6583, 890534.22, 145.7  ], [ 0.2136, 954397.74, 179.93 ],
         [ 0.1851,  35999.05,  87.53 ], [ 0.1144, 966404.0,  276.5  ],
         [ 0.0588,  63863.5,  124.2  ], [ 0.0571, 377336.3,   13.2  ],
         [ 0.0533,1367733.1,  280.7  ], [ 0.0458, 854535.2,  148.2  ],
         [ 0.0409, 441199.8,   47.4  ], [ 0.0347, 445267.1,   27.9  ],
         [ 0.0304, 513179.9,  222.5  ], [ 0.0154,  75870.0,   41.0  ],
         [ 0.0125,1443603.0,   52.0  ], [ 0.0110, 489205.0,  142.0  ],
         [ 0.0107,1303870.0,  246.0  ], [ 0.0100,1431597.0,  315.0  ],
         [ 0.0085, 826671.0,  111.0  ], [ 0.0079, 449334.0,  188.0  ],
         [ 0.0068, 926533.0,  323.0  ], [ 0.0052,  31932.0,  107.0  ],
         [ 0.0050, 481266.0,  205.0  ], [ 0.0040,1331734.0,  283.0  ],
         [ 0.0040,1844932.0,   56.0  ], [ 0.0040,    133.0,   29.0  ],
         [ 0.0038,1781068.0,   21.0  ], [ 0.0037, 541062.0,  259.0  ],
         [ 0.0028,   1934.0,  145.0  ], [ 0.0027, 918399.0,  182.0  ],
         [ 0.0026,1379739.0,   17.0  ], [ 0.0024,  99863.0,  122.0  ],
         [ 0.0023, 922466.0,  163.0  ], [ 0.0022, 818536.0,  151.0  ],
         [ 0.0021, 990397.0,  357.0  ], [ 0.0021,  71998.0,   85.0  ],
         [ 0.0021, 341337.0,   16.0  ], [ 0.0018, 401329.0,  274.0  ],
         [ 0.0016,1856938.0,  152.0  ], [ 0.0012,1267871.0,  249.0  ],
         [ 0.0011,1920802.0,  186.0  ], [ 0.0009, 858602.0,  129.0  ],
         [ 0.0008,1403732.0,   98.0  ], [ 0.0007, 790672.0,  114.0  ],
         [ 0.0007, 405201.0,   50.0  ], [ 0.0007, 485333.0,  186.0  ],
         [ 0.0007,  27864.0,  127.0  ], [ 0.0006, 111869.0,   38.0  ],
         [ 0.0006,2258267.0,  156.0  ], [ 0.0005,1908795.0,   90.0  ],
         [ 0.0005,1745069.0,   24.0  ], [ 0.0005, 509131.0,  242.0  ],
         [ 0.0004,  39871.0,  223.0  ], [ 0.0004,  12006.0,  187.0  ],
         [ 0.0003, 958465.0,  340.0  ], [ 0.0003, 381404.0,  354.0  ],
         [ 0.0003, 349472.0,  337.0  ], [ 0.0003,1808933.0,   58.0  ],
         [ 0.0003, 549197.0,  220.0  ], [ 0.0003,   4067.0,   70.0  ],
         [ 0.0003,2322131.0,  191.0  ]];
    private static const la:Array = [
         [ 5.1281, 483202.019,  3.273], [ 0.2806, 960400.89, 138.24 ],
         [ 0.2777,   6003.15,  48.31 ], [ 0.1733, 407332.20,  52.43 ],
         [ 0.0554, 896537.4,  104.0  ], [ 0.0463,  69866.7,   82.5  ],
         [ 0.0326,1373736.2,  239.0  ], [ 0.0172,1437599.8,  273.2  ],
         [ 0.0093, 884531.0,  187.0  ], [ 0.0088, 471196.0,   87.0  ],
         [ 0.0082, 371333.0,   55.0  ], [ 0.0043, 547066.0,  217.0  ],
         [ 0.0042,1850935.0,   14.0  ], [ 0.0034, 443331.0,  230.0  ],
         [ 0.0025, 860538.0,  106.0  ], [ 0.0022, 481268.0,  308.0  ], 
         [ 0.0022,1337737.0,  241.0  ], [ 0.0021, 105866.0,   80.0  ], 
         [ 0.0019, 924402.0,  141.0  ], [ 0.0018, 820668.0,  153.0  ], 
         [ 0.0018, 519201.0,  181.0  ], [ 0.0018,1449606.0,   10.0  ], 
         [ 0.0015,  42002.0,   46.0  ], [ 0.0015, 928469.0,  121.0  ], 
         [ 0.0015, 996400.0,  316.0  ], [ 0.0014,  29996.0,  129.0  ], 
         [ 0.0013, 447203.0,    6.0  ], [ 0.0013,  37935.0,   65.0  ], 
         [ 0.0011,1914799.0,   48.0  ], [ 0.0010,1297866.0,  288.0  ], 
         [ 0.0009,1787072.0,  340.0  ], [ 0.0008, 972407.0,  235.0  ], 
         [ 0.0007,1309873.0,  205.0  ], [ 0.0006, 559072.0,  134.0  ], 
         [ 0.0006,1361730.0,  322.0  ], [ 0.0005, 848532.0,  190.0  ], 
         [ 0.0005, 419339.0,  149.0  ], [ 0.0005, 948395.0,  222.0  ], 
         [ 0.0004,2328134.0,  149.0  ], [ 0.0004,1024264.0,  352.0  ], 
         [ 0.0003, 932536.0,  282.0  ], [ 0.0003,1409735.0,   57.0  ], 
         [ 0.0003,2264270.0,  115.0  ], [ 0.0003,1814936.0,   16.0  ], 
         [ 0.0003, 335334.0,   57.0  ]];
    private static const lc:Array = [
         [ 0.051820, 477198.868,134.963], [ 0.009530, 413335.35, 100.74 ],
         [ 0.007842, 890534.22, 235.7  ], [ 0.002824, 954397.74, 269.93 ],
         [ 0.000858,1367733.1,   10.7  ], [ 0.000531, 854535.2,  238.2  ],
         [ 0.000400, 377336.3,  103.2  ], [ 0.000319, 441199.8,  137.4  ],
         [ 0.000271, 445267.0,  118.0  ], [ 0.000263, 513198.0,  312.0  ],
         [ 0.000197, 489205.0,  232.0  ], [ 0.000173,1431597.0,   45.0  ],
         [ 0.000167,1303870.0,  336.0  ], [ 0.000111,  35999.0,  178.0  ],
         [ 0.000103, 826671.0,  201.0  ], [ 0.000084,  63864.0,  214.0  ],
         [ 0.000083, 926533.0,   53.0  ], [ 0.000078,1844932.0,  146.0  ],
         [ 0.000073,1781068.0,  111.0  ], [ 0.000064,1331734.0,   13.0  ],
         [ 0.000063, 449334.0,  278.0  ], [ 0.000041, 481266.0,  295.0  ],
         [ 0.000034, 918399.0,  272.0  ], [ 0.000033, 541062.0,  349.0  ],
         [ 0.000031, 922466.0,  253.0  ], [ 0.000030,  75870.0,  131.0  ],
         [ 0.000029, 990397.0,   87.0  ], [ 0.000026, 818536.0,  241.0  ],
         [ 0.000023, 553069.0,  266.0  ], [ 0.000019,1267871.0,  339.0  ],
         [ 0.000013,1403732.0,  188.0  ], [ 0.000013, 341337.0,  106.0  ],
         [ 0.000013, 401329.0,    4.0  ], [ 0.000012,2258267.0,  246.0  ],
         [ 0.000011,1908795.0,  180.0  ], [ 0.000011, 858602.0,  219.0  ],
         [ 0.000010,1745069.0,  114.0  ], [ 0.000009, 790672.0,  204.0  ],
         [ 0.000007,2322131.0,  281.0  ], [ 0.000007,1808933.0,  148.0  ],
         [ 0.000006, 485333.0,  276.0  ], [ 0.0000006, 99863.0,  212.0  ],
         [ 0.000005, 405201.0,  140.0  ]];

    /** 月の位置を得る.
     * @param jd ユリアン日.
     * @return 黄経黄緯
     */
    public static function getPos( jd:JulianDay):Lucky {
        var lng:Number;
        var lat:Number;

        var j:int = jd.fix;
        var d:Number = jd.dec;

        var t:Number = (j + d - 2451545.0)/36525.0;
        var s:Number = 218.3162 + 481267.8809 * t;
        var r:Number;
        for (var i:int = 0; i < 61; i++) {
            r = ln[i][A] * t + ln[i][B];
            s += ln[i][K] * Math.cos(r * 0.017453292519943);
        }
        while (s < 0)
            s += 360.0;
        while (s >= 360.0)
            s -= 360.0;
        lng = s;
    
        s = 0.0;
        for ( i = 0; i < 45; i++) {
            r = la[i][A] * t + la[i][B];
            s += la[i][K] * Math.cos(r * 0.017453292519943);
        }
        while (s < 0)
            s += 360.0;
        while (s >= 360.0)
            s -= 360.0;
        lat = s;

        s = 0.950725;
        for ( i = 0; i < 43; i++) {
            r = lc[i][A] * t + lc[i][B];
            s += lc[i][K] * Math.cos(r * 0.017453292519943);
        }
        var dist:int = (int)(6378.14 / Math.sin(s * 0.017453292519943));

        return new Lucky(lng, lat, dist);
    }
}

import flash.display.Shape;

/** 月の満ち欠けを表現するイメージフィルタ.
 */
class Phase extends Shape {

    public static const R:int = MoonPhase.SIZE/2; // 半径(ピクセル単位)
    public static const R2:int = R*R; // 半径の自乗

    /**
     * @param angle 朔からの角度(°)(0~360)
     */
    public function Phase(angle:int) {
        var quoter:int = angle / 90; // 見た目の象限(03)
        var cos:Number = Math.cos(angle * Math.PI / 180);
        // 半透明の黒で影部を描く
        graphics.lineStyle(1, 0x000000, 0.6);
        for (var j:int = 0; j < MoonPhase.SIZE; ++j) {
            var y:Number = j - R;
            var y2:Number = y * y;
            var x:Number = cos * Math.sqrt(R2 - y2);

            switch (quoter) {
            case 0:
                graphics.moveTo(0, j);
                graphics.lineTo(R + x, j);
                break;
            case 1:
                graphics.moveTo(0, j);
                graphics.lineTo(R + x, j);
                break;
            case 2:
                graphics.moveTo(R - x, j);
                graphics.lineTo(MoonPhase.SIZE, j);
                break;
            case 3:
                graphics.moveTo(R - x, j);
                graphics.lineTo(MoonPhase.SIZE, j);
                break;
            }
        }
    }
}