目次
サンプル・プログラム:実行例

📅 の右側のテキストボックスをクリックすると、「PHPで日付入力:カレンダーから選択」で紹介したカレンダー入力を使った日付入力ができる。
このホロスコープは、左が春分点(黄経0度)で、反時計回りに黄道十二宮を配置している。
サンプル・プログラム
horoscope.php | サンプル・プログラム本体 |
pahooAstronomy.php | 天文計算クラス pahooAstronomy。 使い方は「PHPでホロスコープを描く」などを参照。include_path が通ったディレクトリに配置すること。 |
pahooCalendar.php | 暦計算クラス pahooCalendar。 暦計算クラスの使い方は「PHPで日出没・月出没・月齢・潮を計算」を参照。include_path が通ったディレクトリに配置すること。 |
jsdate.js | 年月日セレクタを用意するJavaScript。 使い方は「jQueryで年月日セレクタを用意する」を参照。 |
/svg/*.svg | 黄道十二宮・惑星・月・太陽の記号(SVGファイル)。 |
サンプル・プログラムの流れ
- 各惑星の日心座標を計算する。
- 各惑星(太陽、月を含む)の地心座標を計算する。
- ホロスコープを描く。
準備:定数
0037: //ホロスコープID
0038: define('HOROSCOPE', 'horoscope');
0039:
0040: //ホロスコープを計算する時刻(日本標準時)
0041: define('HOUR', 21);
0042:
0043: //ホロスコープの表示サイズ(単位:ピクセル)
0044: define('RADIUS', 300); //外側の円の半径
0045: define('WIDTH1', 50); //星座を描く部分の幅
0046:
0047: //ホロスコープの表示色
0048: define('COLOR1', '#FFDD88'); //星座配置部分の色
0049: define('COLOR2', '#FFFFCC'); //惑星配置部分の色
0050: define('COLOR3', '#FFBB00'); //境界線の色
0051: define('COLOR4', '#0000FF'); //星座アイコンの色
0052: define('COLOR5', '#0000CC'); //惑星アイコンの色
0053:
0054: //ホロスコープの表示色
0055: define('SVGPATH', './svg/'); //SVGアイコン・ファイルのパス名
0056:
0057: //誕生日の星座(初期値)
0058: define('DEF_ZODIAC', 'Aries');
準備:アイコン・ファイルなど
0313: //黄道十二宮
0314: $Zodiac = array(
0315: // 英名 十二宮名 和名 記号 開始月日 開始黄経
0316: array('Aries', '白羊宮', 'おひつじ座', 'U+2648', '0321', 0),
0317: array('Taurus', '金牛宮', 'おうし座', 'U+2649', '0420', 30),
0318: array('Gemini', '双児宮', 'ふたご座', 'U+264A', '0521', 60),
0319: array('Cancer', '巨蟹宮', 'かに座', 'U+264B', '0622', 90),
0320: array('Leo', '獅子宮', 'しし座', 'U+264C', '0723', 120),
0321: array('Virgo', '処女宮', 'おとめ座', 'U+264D', '0823', 150),
0322: array('Libra', '天秤宮', 'てんびん座', 'U+264E', '0923', 180),
0323: array('Scorpio', '天蝎宮', 'さそり座', 'U+264F', '1024', 210),
0324: array('Sagittarius', '人馬宮', 'いて座', 'U+2650', '1123', 240),
0325: array('Capricorn', '磨羯宮', 'やぎ座', 'U+2651', '1222', 270),
0326: array('Aquarius', '宝瓶宮', 'みずがめ座', 'U+2652', '0120', 300),
0327: array('Pisces', '双魚宮', 'うお座', 'U+2653', '0219', 300)
0328: );
0330: //惑星・太陽・月
0331: $Planets = array(
0332: // 英名 和名 記号 カラー
0333: array('Sun', '太陽', 'U+2609', 'D68E31'),
0334: array('Moon', '月', 'U+263D', 'DCDCDC'),
0335: array('Mercury', '水星', 'U+263F', 'FFFF00'),
0336: array('Venus', '金星', 'U+2640', '00FF00'),
0337: array('Mars', '火星', 'U+2642', 'FF0000'),
0338: array('Jupiter', '木星', 'U+2643', 'F312D8'),
0339: array('Saturn', '土星', 'U+2644', '8B0000'),
0340: array('Uranus', '天王星', 'U+2645', '00FFFF'),
0341: array('Neptune', '海王星', 'U+2646', '00139F'),
0342: array('Pluto', '冥王星', 'U+2647', '000000'),
0343: array('Earth', '地球', 'U+1F728', '000000')
0344: );
これらのファイルを、定数 SVGPATH に格納しておく。
準備:pahooAstronomy クラス
0010: require_once('pahooCalendar.php');
0011:
0012: // pahooAstronomyクラス ======================================================
0013: class pahooAstronomy extends pahooCalendar {
解説:惑星の日心座標を求める
0017: // 平均軌道要素
0018: var $PlanetOrbitalElements = array(
0019: 'Mercury' => array(
0020: 252.2509, +4.0932377062, +0.000303, //L 平均黄経
0021: 77.4561, +1.556401, +0.000295, //ω 近日点黄経
0022: 48.3309, +1.186112, +0.000175, //Ω 昇交点黄経
0023: 7.0050, +0.001821, //i 軌道傾角
0024: 0.205632, +0.00002040, //e 軌道離心率
0025: +0.387098, 0.0 //a 軌道長半径
0026: ),
0027: 'Venus' => array(
0028: 181.9798, +1.602168732, +0.000310, //L 平均黄経
0029: 131.5637, +1.402152, -0.001076, //ω 近日点黄経
0030: 76.6799, +0.901044, +0.000406, //Ω 昇交点黄経
0031: 3.3947, +0.001004, //i 軌道傾角
0032: 0.006772, -0.00004778, //e 軌道離心率
0033: 0.723330, 0.0 //a 軌道長半径
0034: ),
0035: 'Mars' => array(
0036: 355.4330, +0.524071085, +0.000311, //L 平均黄経
0037: 336.0602, +1.840968, +0.000135, //ω 近日点黄経
0038: 49.5581, +0.772019, +0.0, //Ω 昇交点黄経
0039: 1.8497, -0.000601, //i 軌道傾角
0040: 0.093401, +0.00009048, //e 軌道離心率
0041: +1.523679, 0.0 //a 軌道長半径
0042: ),
0043: 'Jupiter' => array(
0044: 34.3515, +0.083129439, +0.000223, //L 平均黄経
0045: 14.3312, +1.612635, +0.001030, //ω 近日点黄経
0046: 100.4644, +1.020977, +0.000403, //Ω 昇交点黄経
0047: 1.3033, -0.005496, //i 軌道傾角
0048: 0.048498, +0.00016323, //e 軌道離心率
0049: 5.202603, 0.0 //a 軌道長半径
0050: ),
0051: 'Saturn' => array(
0052: 50.0774, +0.033497907, +0.000519, //L 平均黄経
0053: 93.0572, +1.963761, +0.000838, //ω 近日点黄経
0054: 113.665, +0.877088, -0.000121, //Ω 昇交点黄経
0055: 2.4889, -0.003736, //i 軌道傾角
0056: 0.055548, -0.00034664, //e 軌道離心率
0057: 9.554909, -0.0000021 //a 軌道長半径
0058: ),
0059: 'Uranus' => array(
0060: 314.0550, +0.011769036, +0.000304, //L 平均黄経
0061: 173.0053, +1.486378, +0.000214, //ω 近日点黄経
0062: 74.0060, +0.521127, +0.001339, //Ω 昇交点黄経
0063: 0.7732, +0.000774, //i 軌道傾角
0064: 0.046381, -0.00002729, //e 軌道離心率
0065: 19.218446, -0.000003 //a 軌道長半径
0066: ),
0067: 'Neptune' => array(
0068: 304.3487, +0.006020077, +0.000309, //L 平均黄経
0069: 48.1203, +1.426296, +0.000384, //ω 近日点黄経
0070: 131.784, +1.102204, +0.000260, //Ω 昇交点黄経
0071: 1.7700, -0.009308, //i 軌道傾角
0072: 0.009456, +0.00000603, //e 軌道離心率
0073: 30.110387, 0.0 //a 軌道長半径
0074: ),
0075: 'Pluto' => array(
0076: 238.4670, +0.00401596, -0.0091, //L 平均黄経
0077: 224.1416, +1.3901, +0.0003, //ω 近日点黄経
0078: 110.3182, +1.3507, +0.0004, //Ω 昇交点黄経
0079: 17.1451, -0.0055, //i 軌道傾角
0080: 0.249005, +0.000039, //e 軌道離心率
0081: 39.540343, +0.003131 //a 軌道長半径
0082: )
0083: );
0085: /**
0086: * ケプラー運動方程式の解法(漸化法)
0087: * @param double $l 平均近点離角
0088: * @param double $e 軌道離心率
0089: * @return double 離心近点離角
0090: */
0091: function __kepler($l, $e) {
0092: $u0 = $l;
0093: do {
0094: $du = ($l - $u0 + rad2deg($e * sin(deg2rad($u0)))) / (1 - $e * cos(deg2rad($u0)));
0095: $u1 = $u0 + $du;
0096: $u0 = $u1;
0097: } while(abs($du) < 1e-15);
0098:
0099: return $u1;
0100: }
0102: /**
0103: * 惑星の日心黄道座標を計算
0104: * @param string $planet 惑星名
0105: * @param int $year, $month, $day グレゴリオ暦による年月日
0106: * @param double $hour, $min, $sec 時分秒(世界時)
0107: * @return array(黄経,黄緯,動径)/FALSE:惑星名の間違い
0108: */
0109: function zodiacSun($planet, $year, $month, $day, $hour, $min, $sec) {
0110: //平均軌道要素
0111: if (! isset($this->PlanetOrbitalElements[$planet])) return FALSE;
0112: $tbl = $this->PlanetOrbitalElements[$planet];
0113:
0114: //計算開始
0115: $d = $this->Gregorian2JD($year, $month, $day, $hour, $min, $sec) - 2451544.5;
0116: $T = $d / 36525.0;
0117:
0118: //平均軌道要素
0119: $L = $this->__angle($tbl[0] + $tbl[1] * $d + $tbl[2] * pow($T, 2));
0120: $omega = $this->__angle($tbl[3] + $tbl[4] * $T + $tbl[5] * pow($T, 2));
0121: $OMEGA = $this->__angle($tbl[6] + $tbl[7] * $T + $tbl[8] * pow($T, 2));
0122: $i = $tbl[9] + $tbl[10] * $T;
0123: $e = $this->__angle($tbl[11] + $tbl[12] * $T);
0124: $a = $tbl[13] + $tbl[14] * $T;
0125: if ($planet == 'Uranus') {
0126: $n = 255.65443 / pow($tbl[13], 1.5);
0127: $a = $tbl[13] + $tbl[14] * $n * $T;
0128: }
0129:
0130: $M = $this->__angle($L - $omega); //平均近点離角
0131: $E = $this->__kepler($M, $e); //離心近点離角
0132:
0133: $V = $this->__angle(2 * rad2deg(atan(pow((1 + $e) / (1 - $e), 0.5) * tan(deg2rad($E / 2)))));
0134:
0135: $U = $omega + $V - $OMEGA; //黄緯引数
0136: $r = $a * (1 - pow($e, 2)) / (1 + $e * cos(deg2rad($V))); //動径
0137: $b = rad2deg(asin(sin(deg2rad($i)) * sin(deg2rad($U)))); //黄緯
0138: $l = $OMEGA + rad2deg(atan(cos(deg2rad($i)) * sin(deg2rad($U)) / cos(deg2rad($U))));
0139: if (cos(deg2rad($U)) < 0) $l += 180; //黄経
0140:
0141: return array($l, $b, $r);
0142: }





惑星は、太陽を焦点の1つとする楕円軌道を描く。これは、1639年(寛永16年)に発表されたケプラーの法則の第1法則である。

日心黄道座標を求めるには、まず、指定された日時の軌道6要素(黄経






この計算式は『天文年鑑』に掲載されている。水星から海王星までは2019年(平成31年)版を、冥王星は2006年(平成18年)に準惑星に降格された後は掲載されていないため2002年(平成14年)版を参考にした。計算に使う係数はグローバル変数 $PlanetOrbitalElements に、計算式そのものはメソッド zodiacSun に実装した。

軌道6要素から日心黄道座標を求める計算式を示す。
















真近点角


解説:惑星の地心座標を求める
0144: /**
0145: * 惑星の地心黄道座標を計算
0146: * @param string $planet 惑星名
0147: * @param int $year, $month, $day グレゴリオ暦による年月日
0148: * @param double $hour, $min, $sec 時分秒(世界時)
0149: * @return array(黄経,黄緯,動径)
0150: */
0151: function zodiacEarth($planet, $year, $month, $day, $hour, $min, $sec) {
0152: //日心黄道座標
0153: $items = $this->zodiacSun($planet, $year, $month, $day, $hour, $min, $sec);
0154: if (($items == FALSE) || (count($items) != 3)) return FALSE;
0155:
0156: $l = $items[0]; //日心黄経
0157: $b = $items[1]; //日心黄緯
0158: $r = $items[2]; //日心動径
0159:
0160: //太陽の黄経・黄緯
0161: $ls = $this->longitude_sun($year, $month, $day, $hour + $this->TDIFF, $min, $sec);
0162: $rs = $this->distance_sun($year, $month, $day, $hour + $this->TDIFF, $min, $sec);
0163:
0164: //直交座標へ変換
0165: $X = $r * cos(deg2rad($b)) * cos(deg2rad($l)) + $rs * cos(deg2rad($ls));
0166: $Y = $r * cos(deg2rad($b)) * sin(deg2rad($l)) + $rs * sin(deg2rad($ls));
0167: $Z = $r * sin(deg2rad($b));
0168:
0169: //地心黄道座標変換
0170: $r1 = sqrt(pow($X, 2) + pow($Y, 2) + pow($Z, 2)); //動径
0171: $b1 = rad2deg(asin($Z / $r1)); //黄緯
0172: $l1 = rad2deg(atan($Y / $X));
0173: if ($X < 0) $l1 += 180;
0174: $l1 = $this->__angle($l1); //黄経
0175:
0176: return array($l1, $b1, $r1);
0177: }

準備:ホロスコープを描く
0472: /**
0473: * ホロスコープを描く
0474: * @param int $year, $month, $day グレゴリオ暦による年月日
0475: * @param string $zd 星座名(英名)
0476: * @return string HTML BODY
0477: */
0478: function drawHoroscope($year, $month, $day, $zd) {
0479: $id = HOROSCOPE;
0480: $radius = RADIUS;
0481: $width1 = WIDTH1;
0482: $color1 = COLOR1;
0483: $color2 = COLOR2;
0484: $color3 = COLOR3;
0485: $js1 = drawZodiac();
0486: $js2 = drawPlanets($year, $month, $day, $zd);
0487: $js =<<< EOT
0488: <script>
0489: onload = function() {
0490: initJsdate({$year}, {$month}, {$day}); //年月日セレクタ
0491:
0492: var canvas = document.getElementById('{$id}');
0493: if ( ! canvas || ! canvas.getContext ) { return false; }
0494: var ctx = canvas.getContext('2d');
0495: var r = {$radius};
0496: var cx = r;
0497: var cy = r;
0498: var x, y;
0499:
0500: ctx.strokeStyle ='{$color3}';
0501:
0502: ctx.fillStyle = '{$color1}';
0503: ctx.beginPath();
0504: ctx.arc(cx, cx, r, 0, Math.PI * 2, false);
0505: ctx.stroke();
0506: ctx.fill();
0507:
0508: ctx.fillStyle = '{$color2}';
0509: ctx.beginPath();
0510: ctx.arc(cx, cy, r - {$width1}, 0, Math.PI * 2, false);
0511: ctx.stroke();
0512: ctx.fill();
0513:
0514: //12分割
0515: for (var i = 0; i < 12; i++) {
0516: var th = Math.PI - Math.PI * 2 / 12 * i;
0517: x = r + r * Math.cos(th);
0518: y = r + r * Math.sin(th);
0519: ctx.moveTo(cx, cy);
0520: ctx.lineTo(x, y);
0521: ctx.stroke();
0522: }
0523: //黄道十二宮
0524: {$js1}
0525: //惑星・太陽・月
0526: {$js2}
0527: }
0528: </script>
0529:
0530: EOT;
0531:
0532: return $js;
0533: }

ユーザー関数 drawHoroscope では、まず、「jQueryで年月日セレクタを用意する」で紹介した年月日選択プルダウンをJavaScriptに実装する。

続いて、ホロスコープの円盤を描き、黄道十二宮と惑星・太陽・月のアイコンを配置する。
準備:黄道十二宮と惑星・太陽・月
0451: /**
0452: * 黄道十二宮アイコンを配置
0453: * @param int $year, $month, $day グレゴリオ暦による年月日
0454: * @return string 描画スクリプト
0455: */
0456: function drawZodiac() {
0457: global $Zodiac;
0458:
0459: $id = HOROSCOPE; //CANVASのID
0460: $rd = RADIUS - (WIDTH1 * 0.5); //中心からの距離
0461: $size = WIDTH1 * 0.7; //アイコンのサイズ
0462: $color = COLOR4; //アイコンのカラー
0463: $js = '';
0464: for ($i = 0; $i < 12; $i++) {
0465: $name = $Zodiac[$i][0];
0466: $js .= drawIcon($i * 30 + 15, $rd, $name, $size, $color, $id);
0467: }
0468:
0469: return $js;
0470: }
0411: /**
0412: * 惑星アイコンを配置+ラッキーカラー計算
0413: * @param int $year, $month, $day グレゴリオ暦による年月日
0414: * @param string $zd 星座名(英名)
0415: * @return string 描画スクリプト
0416: */
0417: function drawPlanets($year, $month, $day, $zd) {
0418: global $Planets;
0419:
0420: //オブジェクト生成
0421: $pas = new pahooAstronomy();
0422:
0423: $id = HOROSCOPE; //CANVASのID
0424: $size = WIDTH1 * 0.7; //アイコンのサイズ
0425: $color = COLOR5; //アイコンのカラー
0426: $js = '';
0427: for ($i = 0; $i < 10; $i++) {
0428: $name = $Planets[$i][0];
0429: $rd = (RADIUS - WIDTH1 * 2) / 10 * $i + WIDTH1;
0430: //太陽
0431: if ($i == 0) {
0432: $l = $pas->longitude_sun($year, $month, $day, HOUR, 0, 0);
0433: //月
0434: } else if ($i == 1) {
0435: $l = $pas->longitude_moon($year, $month, $day, HOUR, 0, 0);
0436: //惑星
0437: } else {
0438: $items = $pas->zodiacEarth($name, $year, $month, $day, HOUR - $pas->TDIFF, 0, 0);
0439: $l = $items[0];
0440: }
0441: $js .= drawIcon($l, $rd, $name, $size, $color, $id);
0442: calcColor($i, $l, $zd);
0443: }
0444:
0445: //オブジェクト解放
0446: $pas = NULL;
0447:
0448: return $js;
0449: }
ホロスコープは平面なので、必要なのは地心黄経だけである。drawPlanets では、前述のメソッド zodiacEarth を使って惑星の地心黄経を、メソッド longitude_sun を使って太陽の黄経を、メソッド longitude_moon を使って月の黄経を求める。
準備:SVGアイコンを1つ描く
0375: /**
0376: * SVGアイコンを1つ描く
0377: * @param string $th 黄経(度)
0378: * @param string $rd 中心からの距離(ピクセル)
0379: * @param string $name アイコン名(主ファイル名)
0380: * @param string $size アイコンのサイズ(ピクセル)
0381: * @param string $color アイコンのカラー(RGB指定)
0382: * @param string $id CANVASのID
0383: * @return string 描画スクリプト
0384: */
0385: function drawIcon($th, $rd, $name, $size, $color, $id) {
0386: //描画座標
0387: $th = 180 - $th;
0388: $th = deg2rad($th);
0389: $x = RADIUS + $rd * cos($th) - $size / 2;
0390: $y = RADIUS + $rd * sin($th) - $size / 2;
0391:
0392: //SVGファイルの読み込み
0393: $fname = SVGPATH . $name . '.svg';
0394: $svg = file_get_contents($fname);
0395: $svg = preg_replace('/\#000000/ums', $color, $svg); //色指定
0396: $svg = 'data:image/svg+xml;base64,' . base64_encode($svg);
0397:
0398: //スクリプト生成
0399: $js = <<< EOD
0400: var img_{$name} = new Image();
0401: img_{$name}.src = '{$svg}';
0402: img_{$name}.onload = function() {
0403: var ctx = document.getElementById('{$id}').getContext('2d');
0404: ctx.drawImage(img_{$name}, {$x}, {$y}, {$size}, {$size});
0405: }
0406:
0407: EOD;
0408: return $js;
0409: }
SVGファイルを読み込み、デフォルトでは黒(#000000)で描画されている部分を指定カラーに置換する。
つづいて BASE64 エンコードを行い、JavaScriptの Image オブジェクトのソースとして展開する。

配置場所は地心黄経(度)$th を代入するだけなので、準惑星や彗星でも地心黄道座標さえ分かれば、なんでも配置できる。
準備:ラッキーカラー計算
0349: /**
0350: * ラッキーカラー計算
0351: * @param int $i 惑星番号
0352: * @param float $th 黄経(度)
0353: * @param string $zd 星座名(英名)
0354: * @return string 描画スクリプト
0355: */
0356: function calcColor($i, $th, $zd) {
0357: global $Zodiac, $Planets, $Pcolor;
0358:
0359: foreach ($Zodiac as $val) {
0360: if ($val[0] == $zd) {
0361: $dd = ($th - $val[5] - 15);
0362: if ($dd < (-180)) $dd += 360;
0363: $dd = (180 - abs($dd)) / 180;
0364: $Pcolor[0] += $dd;
0365: for ($j = 0; $j < 3; $j++) {
0366: $cc = hexdec(substr($Planets[$i][3], $j * 2, 2));
0367: $cc *= $dd;
0368: $Pcolor[$j + 1] += $cc;
0369: }
0370: break;
0371: }
0372: }
0373: }
ラッキーカラーの計算アルゴリズムは、$Planets に定義した惑星カラーを合成するものである。誕生日星座の中心座標と各惑星の座標の黄経差に応じて、離れているものほど色が暗くなるように合成している。
参考サイト
- PHPで二十四節気・七十二候一覧を作成:ぱふぅ家のホームページ
- PHPで月齢を計算:ぱふぅ家のホームページ
- jQueryで年月日セレクタを用意する:ぱふぅ家のホームページ
- PHPで日付入力:カレンダーから選択:ぱふぅ家のホームページ
- 天文年鑑 2019年(平成31年)版:誠文堂新光社
余談になるが、参考書籍に紹介している『天文計算入門』の初版は1978年(昭和53年)に発刊され、これを買って、関数電卓「FX-31」でハレー彗星の位置計算を行ったのが、私のプログラミングの事始めで、もう40年も前の話になる。
今回のプログラムのアルゴリズムは、当時のものを踏襲している。地心黄経さえ求められれば、準惑星や彗星もホロスコープ上に配置することができる。
(2022年4月24日)カラーコード計算修正,PHP8対応,リファラ・チェック改良