PHPでホロスコープを描く

(1/1)
西洋占星術では、ある日の太陽、月、惑星と黄道十二宮の位置関係を表すホロスコープという図を用いる。今回は、物理学と天文学を使ってホロスコープを描くPHPプログラムを作ってみることにする。

余談になるが、参考書籍に紹介している『天文計算入門』の初版は1978年(昭和53年)に発刊され、これを買って、関数電卓「FX-31」でハレー彗星の位置計算を行ったのが、私のプログラミングの事始めで、もう40年も前の話になる。
今回のプログラムのアルゴリズムは、当時のものを踏襲している。地心黄経さえ求められれば、準惑星や彗星もホロスコープ上に配置することができる。

(2025年6月1日)章動、光行差補正を追加.pahooAstronomyクラスを全面改訂.

目次

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

PHPでホロスコープを描く
「年月日」「誕生日の星座」を選択し「作成」ボタンをクリックすると、その日のホロスコープを描き、ラッキーカラーを表示する。
📅 の右側のテキストボックスをクリックすると、「PHPで日付入力:カレンダーから選択」で紹介したカレンダー入力を使った日付入力ができる。
このホロスコープは、左が春分点(黄経0度)で、反時計回りに黄道十二宮を配置している。

サンプル・プログラム

圧縮ファイルの内容
horoscope.phpサンプル・プログラム本体
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
pahooAstronomy.php天文計算クラス pahooAstronomy。
使い方は「PHPでホロスコープを描く」などを参照。include_path が通ったディレクトリに配置すること。
pahooCalendar.php暦計算クラス pahooCalendar。
暦計算クラスの使い方は「PHPで日出没・月出没・月齢・潮を計算」を参照。include_path が通ったディレクトリに配置すること。
/svg/*.svg黄道十二宮・惑星・月・太陽の記号(SVGファイル)。
horoscope.php 更新履歴
バージョン 更新日 内容
2.2.0 2025/06/01 章動、光行差補正を追加
2.1 2022/04/24 カラーコード計算修正,PHP8対応,リファラ・チェック改良
2.0 2019/06/02 ラッキーカラーを追加
1.0 2019/03/23 初版
pahooInputData.php 更新履歴
バージョン 更新日 内容
1.8.1 2025/03/15 validRegexPattern() -- debug
1.8.0 2024/11/12 validRegexPattern() 追加
1.7.0 2024/10/09 validURL() validEmail() 追加
1.6.0 2024/10/07 isButton() -- buttonタグに対応
1.5.0 2024/01/28 exitIfExceedVersion() 追加
pahooCalendar.php 更新履歴
バージョン 更新日 内容
4.5.1 2025/05/31 deg2ddmm(), deg2hhmm() 不具合修正
4.5.0 2024/03/17 ヒジュラ暦メソッドを追加
4.4.1 2024/03/17 getCabinetOfficeHolidayTable() -- bug-fix
4.4.0 2024/02/25 内閣府の祝日表を参照できるようにした
4.3.2 2023/02/11 getSolarTerm72() 表記改訂:水澤腹堅→水沢腹堅
pahooAstronomy.php 更新履歴
バージョン 更新日 内容
2.1.0 2025/06/01 euatorialCoordinate() を追加
2.0.0 2025/05/31 全面改訂, 天象を計算できるようにした.
1.0 2019/03/23 初版

サンプル・プログラムの流れ

プログラムの流れを単純化すると、
  1. 各惑星の日心黄道座標を計算する。
  2. 日心黄道座標から各惑星(太陽、月を含む)の地心黄道座標を計算する。
  3. ホロスコープを描く。
となる。

準備:定数

horoscope.php

  37: //ホロスコープID
  38: define('HOROSCOPE', 'horoscope');
  39: 
  40: //ホロスコープを計算する時刻(日本標準時)
  41: define('HOUR', 21);
  42: 
  43: //ホロスコープの表示サイズ(単位:ピクセル)
  44: define('RADIUS', 300);              //外側の円の半径
  45: define('WIDTH1', 50);               //星座を描く部分の幅
  46: 
  47: //ホロスコープの表示色
  48: define('COLOR1', '#FFDD88');        //星座配置部分の色
  49: define('COLOR2', '#FFFFCC');        //惑星配置部分の色
  50: define('COLOR3', '#FFBB00');        //境界線の色
  51: define('COLOR4', '#0000FF');        //星座アイコンの色
  52: define('COLOR5', '#0000CC');        //惑星アイコンの色
  53: 
  54: //ホロスコープの表示色
  55: define('SVGPATH', './svg/');        //SVGアイコン・ファイルのパス名
  56: 
  57: //誕生日の星座(初期値)
  58: define('DEF_ZODIAC', 'Aries');

ホロスコープのサイズ、描画色などは定数にしている。自由に変更できる。

準備:アイコン・ファイルなど

horoscope.php

 313: //黄道十二宮
 314: $Zodiac = array(
 315: //    英名              十二宮名    和名        記号    開始月日    開始黄経
 316: array('Aries',          '白羊宮', 'おひつじ座', 'U+2648', '0321',   0),
 317: array('Taurus',         '金牛宮', 'おうし座',   'U+2649', '0420',   30),
 318: array('Gemini',         '双児宮', 'ふたご座',   'U+264A', '0521',   60),
 319: array('Cancer',         '巨蟹宮', 'かに座',     'U+264B', '0622',   90),
 320: array('Leo',            '獅子宮', 'しし座',     'U+264C', '0723',   120),
 321: array('Virgo',          '処女宮', 'おとめ座',   'U+264D', '0823',   150),
 322: array('Libra',          '天秤宮', 'てんびん座', 'U+264E', '0923',   180),
 323: array('Scorpio',        '天蝎宮', 'さそり座',   'U+264F', '1024',   210),
 324: array('Sagittarius',    '人馬宮', 'いて座',     'U+2650', '1123',   240),
 325: array('Capricorn',      '磨羯宮', 'やぎ座',     'U+2651', '1222',   270),
 326: array('Aquarius',       '宝瓶宮', 'みずがめ座', 'U+2652', '0120',   300),
 327: array('Pisces',         '双魚宮', 'うお座',     'U+2653', '0219',   300)
 328: );

horoscope.php

 330: //惑星・太陽・月
 331: $Planets = array(
 332: //    英名          和名        記号        カラー
 333: array('Sun',        '太陽',     'U+2609',   'D68E31'),
 334: array('Moon',       '月',       'U+263D',   'DCDCDC'),
 335: array('Mercury',    '水星',     'U+263F',   'FFFF00'),
 336: array('Venus',      '金星',     'U+2640',   '00FF00'),
 337: array('Mars',       '火星',     'U+2642',   'FF0000'),
 338: array('Jupiter',    '木星',     'U+2643',   'F312D8'),
 339: array('Saturn',     '土星',     'U+2644',   '8B0000'),
 340: array('Uranus',     '天王星',   'U+2645',   '00FFFF'),
 341: array('Neptune',    '海王星',   'U+2646',   '00139F'),
 342: array('Pluto',      '冥王星',   'U+2647',   '000000'),
 343: array('Earth',      '地球',     'U+1F728',  '000000')
 344: );

ホロスコープ上に描く黄道十二宮や惑星の軌道は、UNICODE文字に定義されているが、実装されていないフォントがあるようなので、Wikimedia Commonsに収録されているSVGファイルを利用させてもらった。
これらのファイルを、定数 SVGPATH に格納しておく。

準備:pahooAstronomy クラス

pahooAstronomy.php

  11: require_once('pahooCalendar.php');
  12: 
  13: // pahooAstronomyクラス ======================================================
  14: class pahooAstronomy extends pahooCalendar {

天文計算を行うクラス pahooAstronomy は、クラス pahooCalendar を継承する。よって、クラスファイル "pahooAstronomy.php", "pahooCalendar.php" の2つを組み込み関数  require_once  を使って読めるディレクトリに配置する。

解説:惑星の平均軌道要素

平均軌道要素
1619年(元和5年)、ドイツの天文学者ヨハネス・ケプラーは、ティコ・ブラーエが行った惑星の位置の精密な観測を基礎にして、「ケプラーの法則」と呼ばれる3つの経験則を導き出す。
  1. 惑星は太陽を焦点とする楕円軌道を描く。
  2. 太陽から惑星に至る直線は、等時間に等面積を描く。
  3. 惑星の公転周期の二乗は、太陽からの平均距離の三乗に比例する。
ケプラーの法則を解くことで、指定した日時の惑星の軌道上の位置を求めることができる。実際に計算するためには、軌道に関わるパラメータ(平均軌道要素)が必要である。まず、太陽を中心とする黄道座標系 (こうどうざひょうけい) を考える。春分点を0度として、反時計回り(東回りに)円周の角度を割り当てる。これを黄経 (こうけい)  $ \lambda $と呼ぶ。一方、地球の公転軌道を基準面とし、北側をプラス、南側をマイナスとする角度を黄緯 (こうい)  $ \beta $と呼ぶ。
惑星によって軌道の傾き方が異なる。そこで、基準面からの傾きを軌道傾角 (きどうけいかく)  $ i $ と呼ぶ。
すべての惑星は、反時計回りに公転している。基準面の南側から北側へ横切る位置を昇交点黄経 (しょうこうてんこうけい)  $ \Omega $ と呼ぶ。
公転軌道上で最も太陽に近づくときの黄経を近日点黄経 (きんじつてんこうけい)  $ \omega $ と呼ぶ。
公転軌道(楕円)の長軸を半分にした長さを天文単位(au;地球と太陽の平均距離1とする)であらわしたものがきどうちょうはんけい (きどうちょうはんけい)  $ a $ だ。
公転軌道(楕円)のつぶれ具合を軌道離心率 (きどうりしんりつ)  $ e $ と呼び、焦点と楕円の中心の距離を $ c $ とすると、$ \displaystyle e = \frac{c}{a} $ であらわすことができる。楕円軌道は $ 0 < e < 1 $ であり、$ e = 1 $ になると放物線軌道、$ e > 0 $ は双曲線軌道、$ e = 0 $ は円軌道になる。
軌道上の位置(黄経)は平均黄経 (へいきんこうけい)  $ L $ と呼ぶ。

平均軌道要素は、国立天文台の暦Wiki に掲載されており、ここでは、「瞬時の平均春分点および黄道にもとづく座標系における平均軌道要素」を利用する。
ただし、冥王星は2006年(平成18年)に準惑星に降格された後は掲載されていないため、『天文年鑑』2002年(平成14年)版を参考にした。

pahooAstronomy.php

  18: // 平均軌道要素
  19: // 瞬時の平均春分点および黄道にもとづく座標系における平均軌道要素
  20: // (出典)国立天文台 https://eco.mtk.nao.ac.jp/koyomi/wiki/CABFB6D1B5B0C6BBCDD7C1C7.html
  21: var $PlanetOrbitalElements = array(
  22: 'Mercury' => array(
  23: 0.3870983098,   +0.0,               +0.0,               // a 軌道長半径
  24: 0.2056317526,   +0.00002040653,     -0.000000028349,    // e 軌道離心率
  25: 252.25090552,   +538106659.820037,  +1.0925943,         // L 平均黄経
  26: 77.45611904,    +5603.042645,       +1.0635716,         // ω 近日点黄経
  27: 7.00498625,     +6.557301,          -0.0651516,         // i 軌道傾角
  28: 48.33089304,    4270.001444,        +0.6314994,         // Ω 昇交点黄経
  29: '内惑星',
  30: ),
  31: 'Venus' => array(
  32: 0.7233298200,   +0.0,               +0.0,               // a 軌道長半径
  33: 0.0067719164,   -0.00004776521,     +0.000000098127,    // e 軌道離心率
  34: 181.97980085,   +210669166.631989,  +1.1165021,         // L 平均黄経
  35: 131.56370300,   +5047.747081,       -3.8742545,         // ω 近日点黄経
  36: 3.39466189,     +3.613261,          -0.0031523,         // i 軌道傾角
  37: 76.67992019,    +3243.757636,       +1.4622586,         // Ω 昇交点黄経
  38: '内惑星',
  39: ),
  40: 'Mars' => array(
  41: 1.5236793419,   +0.00000000003,     +0.0,               // a 軌道長半径
  42: 0.0934006477,   +0.00009048438,     -0.000000080641,    // e 軌道離心率
  43: 355.43299958,   +68910106.933069,   1.1178674,          // L 平均黄経
  44: 336.06023395,   +6627.484990,       +0.4851610,         // ω 近日点黄経
  45: 1.84972648,     -2.163885,          +0.0459350,         // i 軌道傾角
  46: 49.55809321,    +2779.268736,       +0.0560611,         // Ω 昇交点黄経
  47: '外惑星',
  48: ),
  49: 'Jupiter' => array(
  50: 5.2026032092,   +0.00000019132,     -0.000000000039,    // a 軌道長半径
  51: 0.0484979255,   +0.00016322542,     -0.000000471366,    // e 軌道離心率
  52: 34.35151874,    +10930689.989453,   +0.8038700,         // L 平均黄経
  53: 14.33120687,    +5805.486625,       +3.7095016,         // ω 近日点黄経
  54: 1.30326698,     -19.787442,         +0.0167744,         // i 軌道傾角
  55: 100.46440702,   +3675.518747,       +1.4513295,         // Ω 昇交点黄経
  56: '外惑星',
  57: ),
  58: 'Saturn' => array(
  59: 9.5549091915,   -0.00000213896,     +0.000000000444,    // a 軌道長半径
  60: 0.0555481426,   -0.00034664062,     -0.000000643639,    // e 軌道離心率
  61: 50.0774443,     +4404639.847038,    +1.8686817,         // L 平均黄経
  62: 93.05723748,    +7069.540745,       +3.0151155,         // ω 近日点黄経
  63: 2.48887878,     -13.450388,         -0.0546800,         // i 軌道傾角
  64: 113.66550252,   +3157.516875,       -0.4383321,         // Ω 昇交点黄経
  65: '外惑星',
  66: ),
  67: 'Uranus' => array(
  68: 19.2184460618,  -0.00000003716,     +0.000000000979,    // a 軌道長半径
  69: 0.0463812221,   -0.00002729293,     +0.000000078913,    // e 軌道離心率
  70: 314.05500511,   +1547510.601961,    +1.0940272,         // L 平均黄経
  71: 173.00529106,   +5350.964266,       +0.7706068,         // ω 近日点黄経
  72: 0.77319689,     +2.787845,          +0.1349529,         // i 軌道傾角
  73: 74.00595701,    +1876.059902,       +4.8221068,         // Ω 昇交点黄経
  74: '外惑星',
  75: ),
  76: 'Neptune' => array(
  77: 30.1103868694,  -0.00000016635,     +0.000000000686,    // a 軌道長半径
  78: 0.0094557470,   +0.00000603263,     +0.0,               // e 軌道離心率
  79: 304.34866548,   +791579.913277,     +1.1117536,         // L 平均黄経
  80: 48.12027554,    +5134.664445,       +1.3836149,         // ω 近日点黄経
  81: 1.76995259,     -33.509412,         -0.0254991,         // i 軌道傾角
  82: 131.78405702,   +3967.934159,       +0.9342773,         // Ω 昇交点黄経
  83: '外惑星',
  84: ),
  85: 'Pluto' => array(
  86: 39.48168677,    -0.00076912,        +0.0,               // a 軌道長半径
  87: 0.24880766,     +0.00006465,        +0.0,               // e 軌道離心率
  88: 238.92881,      (+145.2078 * 3600), -0.0,               // L 平均黄経
  89: 224.06676,      (-0.0363 * 3600),   +0.0,               // ω 近日点黄経
  90: 17.14175,       (+0.00042 * 3600),  +0.0,               // i 軌道傾角
  91: 110.30347,      (+0.0112 * 3600),   +0.0,               // Ω 昇交点黄経
  92: '外惑星',
  93: ),
  94: );

解説:惑星の日心黄道座標を求める

日心黄道座標
太陽を中心とする黄経 $ L $、黄緯 $ \beta $、太陽と惑星への距離(動径 $ r $ )の3つ組みで惑星の位置を表すことを日心黄道座標と呼ぶ。
平均軌道要素から日心黄道座標を求める計算式を示す。 $$ \displaystyle \begin{align*} M &= L-\omega \\ E &= M+e\ sin(E) \\ tan\frac{V}{2} &= (\frac{1+e}{1-e})^{0.5}\ tan(\frac{E}{2}) \\ U &= \omega+V-\Omega \\ r &= a\frac{(1-e^2)}{(1+e\ cos(V))} \\ l &= \Omega+tan^{-1}\ \frac{(cos(i)sin(U)}{cos(U)} && cos(U)<0 \text{のとき} l=l+180 \\ b &= sin^{-1}(sin(i)\ sin(U)) \end{align*} $$
$ M $ :平均近点角, $ E $ :真近点角, $ U $ :黄緯引数, $ r $ :動径, $ l $ :黄経, $ b $ :黄緯
真近点角 $ E $ を求める計算式はケプラーの運動方程式と呼ばれるが、解析的に解く方法がなく、アイザック・ニュートンが『プリンキピア』において近似的に求める方法(ニュートン法)を紹介しているので、それに倣うことにする。
  1. $ E_0=L $
  2. $ \displaystyle \Delta E = L - E_0 + E\ sin \left( \dfrac{E_0}{1 - E \ cos(E_0)} \right) $
  3. $ E = E_0 + \Delta E $
  4. $ E_0 = E $
2~4の計算を $ \Delta E $ が十分小さくなるまで繰り返す。今回のプログラムは、この近似式をそのまま実装し、メソッド__kepler とした。

pahooAstronomy.php

 130: /**
 131:  * ケプラー運動方程式の解法(漸化法)
 132:  * @param   double $l 平均近点離角
 133:  * @param   double $e 軌道離心率
 134:  * @return  double 離心近点離角
 135: */
 136: function __kepler($M, $e, $eps = 1e-8) {
 137:     // 初期値
 138:     $M = deg2rad($M);
 139:     $E = $M;  
 140: 
 141:     // ニュートン近似法
 142:     do {
 143:         $delta = ($E - $e * sin($E- $M) / (1.0 - $e * cos($E));
 144:         $E -$delta;
 145:     } while (abs($delta> $eps);
 146: 
 147:     return rad2deg($E);
 148: }

pahooAstronomy.php

 150: /**
 151:  * 惑星の日心黄道座標を求める.
 152:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 153:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
 154:  * @param   double $hour, $min, $sec 時分秒(ローカル時間)
 155:  * @return  array(黄経,黄緯,動径) (単位:度)/FALSE:惑星名の間違い
 156: */
 157: function zodiacSun($planet, $year, $month, $day, $hour, $min, $sec) {
 158:     // 惑星名のバリデーション
 159:     if (! isset($this->PlanetOrbitalElements[$planet]))     return FALSE;
 160: 
 161:     // 平均軌道要素
 162:     $tbl = $this->PlanetOrbitalElements[$planet];
 163: 
 164:     // ユリウス世紀
 165:     $jd = $this->Gregorian2JD($year, $month, $day, $hour, $min, $sec, $this->TDIFF);
 166:     $T = $this->julianCentury($jd);
 167: 
 168:     // 平均軌道要素
 169:     $a     = $tbl[0+ $tbl[1* $T + $tbl[2* $T * $T;
 170:     $e     = $this->__angle($tbl[3+ $tbl[4* $T + $tbl[5* $T * $T);
 171:     $L     = $this->__angle($tbl[6+ $tbl[7] / 3600.0 * $T + $tbl[8] / 3600.0 * $T * $T);
 172:     $omega = $this->__angle($tbl[9+ $tbl[10] / 3600.0 * $T + $tbl[11] / 3600.0 * $T * $T);
 173:     $i     = $this->__angle($tbl[12+ $tbl[13] / 3600.0 * $T + $tbl[14] / 3600.0 * $T * $T);
 174:     $OMEGA = $this->__angle($tbl[15+ $tbl[16] / 3600.0 * $T + $tbl[17] / 3600.0 * $T * $T);
 175: 
 176:     // 平均近点角
 177:     $M = $this->__angle($L - $omega);
 178:     // 離心近点角
 179:     $E = $this->__kepler($M, $e);
 180:     // 真近点離角
 181:     $V = $this->__angle(2 * rad2deg(atan(sqrt((1 + $e) / (1 - $e)) * tan(deg2rad($E / 2)))));   
 182: 
 183:     // 黄緯引数
 184:     $U = $this->__angle($omega + $V - $OMEGA);
 185:     // 動径
 186:     $r = $a * (1.0 - $e * $e) / (1.0 + $e * cos(deg2rad($V)));
 187:     $b = rad2deg(asin(sin(deg2rad($i)) * sin(deg2rad($U))));    //黄緯
 188:     $l = $this->__angle($OMEGA + rad2deg(atan(cos(deg2rad($i)) * sin(deg2rad($U)) / cos(deg2rad($U)))));
 189:     if (cos(deg2rad($U)) < 0)    $l +180.0;                        //黄経
 190:     $l = $this->__angle($l);
 191: 
 192:     return array($l, $b, $r);
 193: }

ある日時の日心黄道座標を求めるメソッドは zodiacSun である。

解説:惑星の地心座標を求める

地心黄道座標
ホロスコープは、地球から見た空(天球)における惑星の位置を描くものである。これを地心黄道座標と呼ぶ。
すでに求めた日心黄道座標地心黄道座標に変換することは、地動説を天動説に逆変換するようなものだが、数学的には日心黄道座標に「PHPで二十四節気・七十二候一覧を作成」で紹介した太陽の黄経、黄緯、動径(地球からの距離)をベクトル加算することで求められる。
では、日心黄道座標から地心黄道座標への変換式を見ておこう。 $$ \text{地心黄道直交座標} =\left\{ \begin{array}{l} X_e = \cos \beta \cdot \cos \lambda + r_{\text{sun}} \cdot \cos \lambda_{\text{sun}} \\ Y_e = \cos \beta \cdot \sin \lambda + r_{\text{sun}} \cdot \sin \lambda_{\text{sun}} \\ Z_e = \sin \beta \end{array} \right. $$ $$ \lambda_{\text{sun}}:\text{太陽黄経}, \quad r_{\text{sun}}:\text{太陽からの距離} $$

 

$$ \text{地心黄道座標} = \left\{ \begin{array}{l} r = \sqrt{X^2 + Y^2 + Z^2} \\ \beta = \arcsin \left( \dfrac{Z}{r} \right) \\ \lambda = \arctan2(Y, X) \end{array} \right. $$

 

$$ \arctan2(y, x) = \begin{cases} \tan^{-1} \left( \dfrac{y}{x} \right) & \text{if } x > 0 \\ \tan^{-1} \left( \dfrac{y}{x} \right) + \pi & \text{if } x < 0,\ y \geq 0 \\ \tan^{-1} \left( \dfrac{y}{x} \right) - \pi & \text{if } x < 0,\ y < 0 \\ +\dfrac{\pi}{2} & \text{if } x = 0,\ y > 0 \\ -\dfrac{\pi}{2} & \text{if } x = 0,\ y < 0 \\ \text{undefined} & \text{if } x = 0,\ y = 0 \end{cases} $$

pahooAstronomy.php

 195: /**
 196:  * 惑星の地心黄道座標を求める.
 197:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 198:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
 199:  * @param   double $hour, $min, $sec 時分秒(ローカル時間)
 200:  * @return  array(黄経,黄緯,動径) (単位:度)/FALSE:惑星名の間違い
 201: */
 202: function zodiacEarth($planet, $year, $month, $day, $hour, $min, $sec) {
 203:     // 惑星名のバリデーション
 204:     if (! isset($this->PlanetOrbitalElements[$planet]))     return FALSE;
 205: 
 206:     // 日心黄道座標
 207:     list($l, $b, $r) = $this->zodiacSun($planet, $year, $month, $day, $hour, $min, $sec);
 208:     // 太陽黄経
 209:     $ls = $this->longitude_sun($year, $month, $day, $hour, $min, $sec, $this->TDIFF);
 210:     // 太陽距離
 211:     $rs = $this->distance_sun($year, $month, $day, $hour, $min, $sec, $this->TDIFF);
 212: 
 213:     // 直交座標へ変換
 214:     $X = $r * cos(deg2rad($b)) * cos(deg2rad($l)) + $rs * cos(deg2rad($ls));
 215:     $Y = $r * cos(deg2rad($b)) * sin(deg2rad($l)) + $rs * sin(deg2rad($ls));
 216:     $Z = $r * sin(deg2rad($b));
 217: 
 218:     // 地心黄道座標変換
 219:     $r1 = sqrt(pow($X, 2+ pow($Y, 2+ pow($Z, 2));   // 動径
 220:     $b1 = rad2deg(asin($Z / $r1));                      // 黄緯
 221:     $l1 = rad2deg(atan($Y / $X));
 222:     if ($X < 0)      $l1 +180;
 223:     $l1 = $this->__angle($l1);                          // 黄経
 224: 
 225:     return array($l1, $b1, $r1);
 226: }

上記の計算式をもとに、ある日時の地心黄道座標を求めるメソッドが zodiacSun である。

解説:章動

地球の自転軸は、黄道に対してコマのようにゆっくり(約2万6千年周期で)円運動をしている。これを歳差 (さいさ) と呼ぶ。
歳差の運動に沿って、自転軸が小刻みに揺れることを章動 (しょうどう) と呼び、その主成分は18.6年周期である。
これらは、地心黄緯にはほどんど影響しないが、地心黄経に若干影響する。そこで、黄経の章動を求めるメソッド nutationInLongitude を用意した。

pahooAstronomy.php

 228: /**
 229:  * 黄経の章動を求める.
 230:  * @param   double $T ユリウス世紀
 231:  * @return  double 黄経の章動(単位:度)
 232: */
 233: function nutationInLongitude($T) {
 234:     // 太陽の平均黄経(L)
 235:     $L = deg2rad(fmod(280.4665 + 36000.7698 * $T, 360.0));
 236:     // 月の昇交点の平均黄経(Ω)
 237:     $Omega = deg2rad(fmod(125.04452 - 1934.136261 * $T, 360.0));
 238: 
 239:     // 章動(経度)の近似式 [単位: 秒角]
 240:     $deltaPsi = -17.20 * sin($Omega- 1.32 * sin(2 * $L);
 241:     $deltaPsi /= 3600.0;    // 秒角 → 度
 242: 
 243:     return $deltaPsi;       // Δψ [deg]
 244: }

解説:光行差

光の速さは秒速30万kmというとんでもないスピードだが、地球も秒速約30kmで公転している。このため、ほんのわずかではあるが、惑星から地球に届く光は斜めから飛んでくるように見えるため、本当の惑星の位置よりもわずかに前方方向にズレる光行差 (こうこうさ) が知られている。
こちらも地心黄緯にはほどんど影響しないが、地心黄経に若干影響する。そこで、黄経の章動を求めるメソッド aberrationCorrection を用意した。

pahooAstronomy.php

 246: /**
 247:  * 黄経の光行差補正を求める.
 248:  * @param   double $T ユリウス世紀
 249:  * @param   double $sun_long_deg ユリウス世紀
 250:  * @return  double 平均黄道傾斜(単位:度)
 251: */
 252: function aberrationCorrection($T, $sunLongDeg) {
 253:     // 地球軌道離心率と近日点黄経
 254:     $e = 0.016708634 - 0.000042037 * $T - 0.0000001267 * $T * $T;
 255:     $Pi = 102.93735 + 1.71946 * $T + 0.00046 * $T * $T;     // 日心近日点黄経
 256: 
 257:     // 光行差補正 Δλ = -20.4898 / r * cos(λ - Π)(度)
 258:     $sunLongRad = deg2rad($sunLongDeg);
 259:     $PiRad = deg2rad($Pi);
 260:     $deltaLambda = -20.4898 * cos($sunLongRad - $PiRad) / 3600.0;
 261: 
 262:     return $deltaLambda;
 263: }

解説:地心黄道座標の補正

pahooAstronomy.php

 278: /**
 279:  * 惑星の地心黄道座標を求める.
 280:  * 光行差と章動を補正した視黄経を計算する。
 281:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 282:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
 283:  * @param   double $hour, $min, $sec 時分秒(ローカル時間)
 284:  * @return  array(黄経,黄緯,動径) (単位:度)/FALSE:惑星名の間違い
 285: */
 286: function zodiacEarthAP($planet, $year, $month, $day, $hour, $min, $sec) {
 287:     // 惑星名のバリデーション
 288:     if (! isset($this->PlanetOrbitalElements[$planet]))     return FALSE;
 289: 
 290:     list($lngE, $latE, $radE) = $this->zodiacEarth($planet, $year, $month, $day, $hour, $min, $sec);
 291: 
 292:     // ユリウス世紀
 293:     $jd = $this->AD2JD($year, $month, $day, $hour, $min, $sec, $this->TDIFF);
 294:     $T  = $this->julianCentury($jd);
 295: 
 296:     $deltaPsi = $this->nutationInLongitude($T);
 297:     $aberration = $this->aberrationCorrection($T, $lngE);
 298: 
 299:     // 視黄経 = 幾何学黄経 + 光行差補正 + 章動補正
 300:     $lng2 = $lngE + $deltaPsi + $aberration;
 301:     $lngAP = fmod($lng2 + 360.0, 360.0);        // 正規化
 302: 
 303:     return array($lngAP, $latE, $radE);
 304: }

ユーザー定義メソッド zodiacEarthAP は、章動と光行差を補正した地心黄道座標を求めることができる。

準備:ホロスコープを描く

horoscope.php

 472: /**
 473:  * ホロスコープを描く
 474:  * @param   int    $year, $month, $day  グレゴリオ暦による年月日
 475:  * @param   string $zd 星座名(英名)
 476:  * @return  string HTML BODY
 477: */
 478: function drawHoroscope($year, $month, $day, $zd) {
 479:     $id = HOROSCOPE;
 480:     $radius = RADIUS;
 481:     $width1 = WIDTH1;
 482:     $color1 = COLOR1;
 483:     $color2 = COLOR2;
 484:     $color3 = COLOR3;
 485:     $js1 = drawZodiac();
 486:     $js2 = drawPlanets($year, $month, $day, $zd);
 487:     $js =<<< EOT
 488: <script>
 489: onload = function() {
 490:     initJsdate({$year}, {$month}, {$day});      //年月日セレクタ
 491: 
 492:     var canvas = document.getElementById('{$id}');
 493:     if ( ! canvas || ! canvas.getContext ) { return false; }
 494:     var ctx = canvas.getContext('2d');
 495:     var r = {$radius};
 496:     var cx = r;
 497:     var cy = r;
 498:     var x, y;
 499: 
 500:     ctx.strokeStyle ='{$color3}';
 501: 
 502:     ctx.fillStyle = '{$color1}';
 503:     ctx.beginPath();
 504:     ctx.arc(cx, cx, r, 0, Math.PI * 2, false);
 505:     ctx.stroke();
 506:     ctx.fill();
 507: 
 508:     ctx.fillStyle = '{$color2}';
 509:     ctx.beginPath();
 510:     ctx.arc(cx, cy, r - {$width1}, 0, Math.PI * 2, false);
 511:     ctx.stroke();
 512:     ctx.fill();
 513: 
 514:     //12分割
 515:     for (var i = 0; i < 12; i++) {
 516:         var th = Math.PI - Math.PI * 2 / 12 * i;
 517:         x = r + r * Math.cos(th);
 518:         y = r + r * Math.sin(th);
 519:         ctx.moveTo(cx, cy);
 520:         ctx.lineTo(x, y);
 521:         ctx.stroke();
 522:     }
 523:     //黄道十二宮
 524:     {$js1}
 525:     //惑星・太陽・月
 526:     {$js2}
 527: }
 528: </script>
 529: 
 530: EOT;
 531: 
 532:     return $js;
 533: }

ホロスコープはHTML5の CANVAS 機能を使って描くことにする。

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

続いて、ホロスコープの円盤を描き、黄道十二宮と惑星・太陽・月のアイコンを配置する。

準備:黄道十二宮と惑星・太陽・月

horoscope.php

 451: /**
 452:  * 黄道十二宮アイコンを配置
 453:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
 454:  * @return  string 描画スクリプト
 455: */
 456: function drawZodiac() {
 457:     global $Zodiac;
 458: 
 459:     $id = HOROSCOPE;                //CANVASのID
 460:     $rd = RADIUS - (WIDTH1 * 0.5);  //中心からの距離
 461:     $size = WIDTH1 * 0.7;           //アイコンのサイズ
 462:     $color = COLOR4;                //アイコンのカラー
 463:     $js = '';
 464:     for ($i = 0$i < 12$i++) {
 465:         $name = $Zodiac[$i][0];
 466:         $js .drawIcon($i * 30 + 15, $rd, $name, $size, $color, $id);
 467:     }
 468: 
 469:     return $js;
 470: }

horoscope.php

 411: /**
 412:  * 惑星アイコンを配置+ラッキーカラー計算
 413:  * @param   int    $year, $month, $day  グレゴリオ暦による年月日
 414:  * @param   string $zd 星座名(英名)
 415:  * @return  string 描画スクリプト
 416: */
 417: function drawPlanets($year, $month, $day, $zd) {
 418:     global $Planets;
 419: 
 420:     //オブジェクト生成
 421:     $pas = new pahooAstronomy();
 422: 
 423:     $id = HOROSCOPE;                //CANVASのID
 424:     $size = WIDTH1 * 0.7;           //アイコンのサイズ
 425:     $color = COLOR5;                //アイコンのカラー
 426:     $js = '';
 427:     for ($i = 0$i < 10$i++) {
 428:         $name = $Planets[$i][0];
 429:         $rd = (RADIUS - WIDTH1 * 2) / 10 * $i + WIDTH1;
 430:         //太陽
 431:         if ($i == 0) {
 432:             $l = $pas->longitude_sun($year, $month, $day, HOUR, 0, 0);
 433:         //月
 434:         } else if ($i == 1) {
 435:             $l = $pas->longitude_moon($year, $month, $day, HOUR, 0, 0);
 436:         //惑星
 437:         } else {
 438:             $items = $pas->zodiacEarthAP($name, $year, $month, $day, HOUR - $pas->TDIFF, 0, 0);
 439:             $l = $items[0];
 440:         }
 441:         $js .drawIcon($l, $rd, $name, $size, $color, $id);
 442:         calcColor($i, $l, $zd);
 443:     }
 444: 
 445:     //オブジェクト解放
 446:     $pas = NULL;
 447: 
 448:     return $js;
 449: }

黄道十二宮のアイコンを配置する位置を計算し、アイコンを配置するのはユーザー関数 drawZodiac である。同様に、惑星・太陽・月については、ユーザー関数 drawPlanets を用いる。
ホロスコープは平面なので、必要なのは地心黄経だけである。drawPlanets では、前述のメソッド zodiacEarth を使って惑星の地心黄経を、メソッド longitude_sun を使って太陽の黄経を、メソッド longitude_moon を使って月の黄経を求める。

準備:SVGアイコンを1つ描く

horoscope.php

 375: /**
 376:  * SVGアイコンを1つ描く
 377:  * @param   string $th    黄経(度)
 378:  * @param   string $rd    中心からの距離(ピクセル)
 379:  * @param   string $name  アイコン名(主ファイル名)
 380:  * @param   string $size  アイコンのサイズ(ピクセル)
 381:  * @param   string $color アイコンのカラー(RGB指定)
 382:  * @param   string $id    CANVASのID
 383:  * @return  string 描画スクリプト
 384: */
 385: function drawIcon($th, $rd, $name, $size, $color, $id) {
 386:     //描画座標
 387:     $th = 180 - $th;
 388:     $th = deg2rad($th);
 389:     $x = RADIUS + $rd * cos($th- $size / 2;
 390:     $y = RADIUS + $rd * sin($th- $size / 2;
 391: 
 392:     //SVGファイルの読み込み
 393:     $fname = SVGPATH . $name . '.svg';
 394:     $svg = file_get_contents($fname);
 395:     $svg = preg_replace('/\#000000/ums', $color, $svg);     //色指定
 396:     $svg = 'data:image/svg+xml;base64,' . base64_encode($svg);
 397: 
 398:     //スクリプト生成
 399:     $js = <<< EOD
 400:     var img_{$name} = new Image();
 401:     img_{$name}.src = '{$svg}';
 402:     img_{$name}.onload = function() {
 403:         var ctx = document.getElementById('{$id}').getContext('2d');
 404:         ctx.drawImage(img_{$name}, {$x}, {$y}, {$size}, {$size});
 405:     }
 406: 
 407: EOD;
 408:     return $js;
 409: }

冒頭で用意したアイコン(SVGファイル)を CANVAS 上に配置するのがユーザー関数 drawIcon である。
SVGファイルを読み込み、デフォルトでは黒(#000000)で描画されている部分を指定カラーに置換する。
つづいて BASE64 エンコードを行い、JavaScriptの Image オブジェクトのソースとして展開する。

配置場所は地心黄経(度)$th を代入するだけなので、準惑星や彗星でも地心黄道座標さえ分かれば、なんでも配置できる。

準備:ラッキーカラー計算

horoscope.php

 349: /**
 350:  * ラッキーカラー計算
 351:  * @param   int    $i  惑星番号
 352:  * @param   float  $th 黄経(度)
 353:  * @param   string $zd 星座名(英名)
 354:  * @return  string 描画スクリプト
 355: */
 356: function calcColor($i, $th, $zd) {
 357:     global $Zodiac, $Planets, $Pcolor;
 358: 
 359:     foreach ($Zodiac as $val) {
 360:         if ($val[0] == $zd) {
 361:             $dd = ($th - $val[5- 15);
 362:             if ($dd < (-180))    $dd +360;
 363:             $dd = (180 - abs($dd)) / 180;
 364:             $Pcolor[0+$dd;
 365:             for ($j = 0$j < 3$j++) {
 366:                 $cc = hexdec(substr($Planets[$i][3], $j * 2, 2));
 367:                 $cc *$dd;
 368:                 $Pcolor[$j + 1+$cc;
 369:             }
 370:             break;
 371:         }
 372:     }
 373: }

ユーザー関数 calcColor は、その日のラッキーカラーを計算する。
ラッキーカラーの計算アルゴリズムは、$Planets に定義した惑星カラーを合成するものである。誕生日星座の中心座標と各惑星の座標の黄経差に応じて、離れているものほど色が暗くなるように合成している。

参考サイト

参考書籍

表紙 新装改訂版 天文計算入門
著者 長谷川一郎
出版社 恒星社厚生閣
サイズ 単行本
発売日 1996年01月25日頃
価格 2,750円(税込)
ISBN 9784769908180
 
表紙 天体の位置計算
著者 長沢工
出版社 地人書館
サイズ 単行本
発売日 1985年09月
価格 2,970円(税込)
ISBN 9784805202258
 
(この項おわり)
header