PHPで惑星の天象を一覧表示する

(1/1)
天文学では、地球と各惑星が特定の位置(角度)にあるときを、合、衝、最大離角、東矩、西矩といった名前で呼ぶ。これらを天象と呼ぶ。
今回は、「PHPでホロスコープを描く」で、地球を基点にする惑星の位置(地心黄道座標)を計算するプログラムを利用し、ある年の惑星の天象を一覧表示するPHPプログラムを作ることにする。
2006年(平成18年)、冥王星は矮惑星に降格になったが、ここでは冥王星の天象も一覧に含める。

目次

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

PHPで惑星の天象一覧を表示する

サンプル・プログラム

圧縮ファイルの内容
planetPhenomena.phpサンプル・プログラム本体
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
pahooAstronomy.php天文計算クラス pahooAstronomy。
使い方は「PHPでホロスコープを描く」などを参照。include_path が通ったディレクトリに配置すること。
pahooCalendar.php暦計算クラス pahooCalendar。
暦計算クラスの使い方は「PHPで日出没・月出没・月齢・潮を計算」を参照。include_path が通ったディレクトリに配置すること。
planetPhenomena.php 更新履歴
バージョン 更新日 内容
1.0.0 2025/05/31 初版
pahooInputData.php 更新履歴
バージョン 更新日 内容
2.0.1 2025/08/11 getParam() bug-fix
2.0.0 2025/08/11 pahooLoadEnv() 追加
1.9.0 2025/07/26 getParam() 引数に$trim追加
1.8.1 2025/03/15 validRegexPattern() debug
1.8.0 2024/11/12 validRegexPattern() 追加
pahooCalendar.php 更新履歴
バージョン 更新日 内容
4.6.2 2026/07/25 sun_time, moon_time 白夜の戻り値をコメント
4.6.1 2025/11/23 next_fullmoon: bug-fix
4.6.0 2025/10/08 getMidAutumnMoon() 追加
4.5.1 2025/05/31 deg2ddmm(), deg2hhmm() 不具合修正
4.5.0 2024/03/17 ヒジュラ暦メソッドを追加
pahooAstronomy.php 更新履歴
バージョン 更新日 内容
2.1.1 2025/11/29 PHP8.5対応:double→float コメント記載変更
2.1.0 2025/06/01 euatorialCoordinate() を追加
2.0.0 2025/05/31 全面改訂, 天象を計算できるようにした.
1.0 2019/03/23 初版

準備:定数

planetPhenomena.php

  58: // 初期値(START) =============================================================
  59: 
  60: // 指定できる西暦年の範囲
  61: define('MIN_YEAR', 1901);
  62: define('MAX_YEAR', 2099);
  63: 
  64: // 表示言語(jp:日本語, en:英語, en3:英語略記)
  65: define('LANGUAGE', 'jp');
  66: 
  67: // 世界時からの時差(日本標準時)
  68: define('UTCDIFF', +9.0);
  69: 
  70: // Spinner - jQuery UI を使用するかどうか
  71: define('USESPINNER', TRUE);
  72: 
  73: // 数値増減クリックで即判定するかどうか(TRUE:即判定,FALE:判定ボタンを用意)
  74: define('ONCHANGE', FALSE);
  75: 
  76: // 表示幅(単位:ピクセル)
  77: define('WIDTH', 550);
  78: 
  79: // 初期値(END) ===============================================================

ここに用意した定数は自由に変更できる。

準備: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  を使って読めるディレクトリに配置する。

惑星の天象

惑星の天象
惑星の天象 (てんしょう) は、上図のようなものがある。内惑星と外惑星とで呼び名が違うことに留意されたい。ここで、地球から見たときの惑星と太陽の見かけの角距離のことを惑星の離角 (りかく) と呼ぶ。

内合 (ないごう) ‥‥内惑星が地球と太陽の間にある。惑星は太陽に近く、観測しにくい。離角0度。
外合 (がいごう) ‥‥内惑星が太陽の向こう側にある。惑星は太陽に近く、観測しにくい。離角0度。
東方最大離角 (とうほうさいだいりかく) ‥‥内惑星が太陽の東側にあり、日没後の西の空に見える最大の角距離のとき。
西方最大離角 (せいほうさいだいりかく) ‥‥内惑星が太陽の西側にあり、日の出前の東の空に見える最大の角距離のとき。

 (ごう) ‥‥外惑星が太陽の向こう側にある。惑星は太陽に近く、観測しにくい。離角0度。
 (しょう) ‥‥外惑星が地球と太陽の反対側にある。惑星は最も明るくなり、一晩中観測できる。離角180度。
東矩 (とうく) ‥‥外惑星が太陽の東側90度の位置にあるとき。惑星は日没後に南の空に見える。離角+90度。
西矩 (せいく) ‥‥
外惑星が太陽の西側90度の位置にあるとき。惑星は日の出前の東の空に見える。離角-90度。

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

pahooAstronomy.php

 306: /**
 307:  * 惑星の離角を求める.
 308:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 309:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
 310:  * @param   float $hour, $min, $sec 時分秒(地方時)
 311:  * @return  float 離角(正数:太陽の東側,負数:太陽の西側)
 312: */
 313: function elongation($planet, $year, $month, $day, $hour, $min, $sec) {
 314:     $lngS = $this->longitude_sun($year, $month, $day, $hour, $min, $sec, $this->TDIFF);
 315:     list($lngE, $latE, $radE) = $this->zodiacEarthAP($planet, $year, $month, $day, $hour, $min, $sec);
 316: 
 317:     // 離角を求める.
 318:     $el = fmod($lngE - $lngS + 180.0, 360.0);
 319:     if ($el < 0) {
 320:         $el +360.0;
 321:     }
 322: 
 323:     return $el - 180.0;
 324: }

惑星の日心黄道座標、地心黄道座標の求め方は「PHPでホロスコープを描く」をご覧いただきたい。
ここで求めた惑星の日心黄経を $ \lambda_s $、地心黄経を $ \lambda_e $ とすると、惑星の離角は
$$ E = \lambda_s - \lambda_e $$
で求めることができる。
これを実装したメソッドが elongation である。

解説:内惑星の天象を求める

pahooAstronomy.php

 365: /**
 366:  * 指定した年の内惑星の天象を求める.
 367:  * 内惑星:外合, 内合, 東方最大離角, 西方最大離角
 368:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 369:  * @param   int    $year   求めたい西暦年
 370:  * @param   array  $cals   暦を格納する配列
 371:  *                          [年][月][日] = 天象
 372:  * @return  int 格納した天象の数
 373: */
 374: function planetPhenomenaInner($planet, $year, &$cals) {
 375:     $cnt = 0;               // 格納した天象の数
 376:     $flag = 0;              // +:西方最大離角後,-:東方最大離角後
 377:     $flagTom = FALSE;       // 留フラグ
 378: 
 379:     // 指定年の前日(大晦日)から計算開始する.
 380:     $yy = $year - 1;
 381:     $mm = 12;
 382:     $dd = 31;
 383:     $e0 = $emin = $emax = $this->elongation($planet, $yy, $mm, $dd, 0, 0, 0);
 384:     $yy++;
 385:     $mm = 1;
 386:     do {
 387:         // 1ヶ月分のループ
 388:         $dayOfMonth = $this->getDaysInMonth($yy, $mm);
 389:         for ($dd = 1$dd <$dayOfMonth$dd++) {
 390:             $e = $this->elongation($planet, $yy, $mm, $dd, 0, 0, 0);
 391:             // 外合
 392:             if (($e0 <0.0&& ($e >0.0)) {
 393:                 for ($hh = -47$hh < 0$hh++) {
 394:                     $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 395:                     if (($e0 <0.0&& ($e >0.0)) {
 396:                         $cals[$yy][$mm][$dd + floor(($hh - 1) / 24)] = '外合';
 397:                         $cnt++;
 398:                         $e0 = $e;
 399:                         break;
 400:                     } else {
 401:                         $e0 = $e;
 402:                     }
 403:                 }
 404:             // 内合
 405:             } else if (($e0 >0.0&& ($e <0.0)) {
 406:                 for ($hh = -47$hh < 0$hh++) {
 407:                     $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 408:                     if (($e0 >0.0&& ($e <0.0)) {
 409:                         $cals[$yy][$mm][$dd + floor(($hh - 1) / 24)] = '内合';
 410:                         $cnt++;
 411:                         $e0 = $e;
 412:                         break;
 413:                     } else {
 414:                         $e0 = $e;
 415:                     }
 416:                 }
 417:             } else if ($flag == 0) {
 418:                 if ($e > $emax) {
 419:                     $flag = +1;
 420:                 } else {
 421:                     $flag = -1;
 422:                 }
 423:             // 東方最大離角
 424:             } else if ($flag > 0) {
 425:                 if ($e > $emax) {
 426:                     $emax = $e;
 427:                 } else {
 428:                     $emax = $this->elongation($planet, $yy, $mm, $dd, -48, 0, 0);
 429:                     for ($hh = -47$hh < 0$hh++) {
 430:                         $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 431:                         if ($e > $emax) {
 432:                             $emax = $e;
 433:                         } else {
 434:                             $cals[$yy][$mm][$dd + floor($hh / 24)] = '東方最大離角';
 435:                             $cnt++;
 436:                             $flag = -1;
 437:                             $emin = $emax;
 438:                             break;
 439:                         }
 440:                     }
 441:                 }
 442:             // 西方最大離角
 443:             } else if ($flag < 0) {
 444:                 if ($e < $emin) {
 445:                     $emin = $e;
 446:                 } else {
 447:                     $emin = $this->elongation($planet, $yy, $mm, $dd, -48, 0, 0);
 448:                     for ($hh = -47$hh < 0$hh++) {
 449:                         $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 450:                         if ($e < $emin) {
 451:                             $emin = $e;
 452:                         } else {
 453:                             $cals[$yy][$mm][$dd + floor($hh / 24)] = '西方最大離角';
 454:                             $cnt++;
 455:                             $flag = +1;
 456:                             $emax = $emin;
 457:                             break;
 458:                         }
 459:                     }
 460:                 }
 461:             }
 462:             $e0 = $e;
 463:         }
 464:         $mm++;
 465:     } while ($mm <12);
 466: 
 467:     return $cnt;
 468: }

ユーザー定義メソッド planetPhenomenaInner は、指定した内惑星の、指定した西暦年の内惑星の天象を計算し、配列に格納する。

前述のメソッド elongation を利用し、毎日の離角を計算する。
すべての惑星は反時計回りに公転しているので、0をまたいで離角の符合が負から正へ変わるタイミングが外合である。ポイントが見つかったら、2日(48時間)前から1時間毎にステップ幅を細かくして、その日時を求める。このようにポイントが見つかったらステップ幅を細かくする処理は、他の天象の時にも行っている。
逆に、0をまたいで離角の符合が正から負へ変わるタイミングが内合である。
また、毎日の離角の最大値を変数 $emax に代入しておき、その $emax の値を下回るポイントが東方最大離角である。
逆に、毎日の離角の最小値を変数 $emin に代入しておき、その $emin の値を上回るポイントが西方最大離角である。

天象が起きる時刻を表示しようと考えたが、惑星の軌道要素は近似式であるため、実際の天象と数時間~数日の誤差があり、一覧に表示することは断念した。同様の理由も、東方最大離角・西方最大離角の時の離角も誤差が大きいため、一覧には表示しない。

解説:外惑星の天象を求める

pahooAstronomy.php

 470: /**
 471:  * 指定した年の外惑星の天象を求める.
 472:  * 内惑星:衝, 合, 東矩, 西矩
 473:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 474:  * @param   int    $year   求めたい西暦年
 475:  * @param   array  $cals   暦を格納する配列
 476:  *                          [年][月][日] = 天象
 477:  * @return  int 格納した天象の数
 478: */
 479: function planetPhenomenaOuter($planet, $year, &$cals) {
 480:     $cnt = 0;               // 格納した天象の数
 481: 
 482:     // 指定年の前日(大晦日)から計算開始する.
 483:     $yy = $year - 1;
 484:     $mm = 12;
 485:     $dd = 31;
 486:     $e0 = $emin = $emax = $this->elongation($planet, $yy, $mm, $dd, 0, 0, 0);
 487:     $yy++;
 488:     $mm = 1;
 489:     do {
 490:         // 1ヶ月分のループ
 491:         $dayOfMonth = $this->getDaysInMonth($yy, $mm);
 492:         for ($dd = 1$dd <$dayOfMonth$dd++) {
 493:             $e = $this->elongation($planet, $yy, $mm, $dd, 0, 0, 0);
 494:             // 
 495:             if (($e0 <0.0&& ($e >0.0)) {
 496:                 for ($hh = -47$hh <0$hh++) {
 497:                     $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 498:                     if (($e0 <0.0&& ($e > 0.0)) {
 499:                         $cals[$yy][$mm][$dd + floor(($hh - 1) / 24)] = '衝';
 500:                         $cnt++;
 501:                         $e0 = $e;
 502:                         break;
 503:                     } else {
 504:                         $e0 = $e;
 505:                     }
 506:                 }
 507:             // 
 508:             } else if (($e0 >0.0&& ($e <0.0)) {
 509:                 for ($hh = -47$hh < 0$hh++) {
 510:                     $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 511:                     if (($e0 >0.0&& ($e <0.0)) {
 512:                         $cals[$yy][$mm][$dd + floor(($hh - 1) / 24)] = '合';
 513:                         $cnt++;
 514:                         $e0 = $e;
 515:                         break;
 516:                     } else {
 517:                         $e0 = $e;
 518:                     }
 519:                 }
 520:             // 東矩
 521:             } else if (($e0 >+90.0&& ($e <+90.0)) {
 522:                 for ($hh = -47$hh < 0$hh++) {
 523:                     $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 524:                     if (($e0 >+90.0&& ($e <+90.0)) {
 525:                         $cals[$yy][$mm][$dd + floor($hh / 24)] = '東矩';
 526:                         $cnt++;
 527:                         break;
 528:                     } else {
 529:                         $e0 = $e;
 530:                     }
 531:                 }
 532:             // 西矩
 533:             } else if (($e0 >-90.0&& ($e < -90.0)) {
 534:                 for ($hh = -47$hh < 0$hh++) {
 535:                     $e = $this->elongation($planet, $yy, $mm, $dd, $hh, 0, 0);
 536:                     if (($e0 >-90.0&& ($e <-90.0)) {
 537:                         $cals[$yy][$mm][$dd + floor($hh / 24)] = '西矩';
 538:                         $cnt++;
 539:                         break;
 540:                     } else {
 541:                         $e0 = $e;
 542:                     }
 543:                 }
 544:             }
 545:             $e0 = $e;
 546:         }
 547:         $mm++;
 548:     } while ($mm <12);
 549: 
 550:     return $cnt;
 551: }

ユーザー定義メソッド planetPhenomenaOuter は、指定した内惑星の、指定した西暦年の外惑星の天象を計算し、配列に格納する。

内惑星と同様、0をまたいで離角の符合が負から正へ変わるタイミングがである。
逆に、0をまたいで離角の符合が正から負へ変わるタイミングがである。
また、離角が90度になるタイミングが東矩、-90度になるタイミングが西矩である。

準備:惑星の天象を求める

pahooAstronomy.php

 553: /**
 554:  * 指定した年の惑星の天象を求める.
 555:  * 惑星の天象とは‥‥
 556:  *  内惑星:外合, 内合, 東方最大離角, 西方最大離角, 留
 557:  *  外惑星:衝, 東矩, 西矩, 合
 558:  * @param   string $planet 惑星名(Mercury, Venus, ... Pluto)
 559:  * @param   int    $year   求めたい西暦年
 560:  * @param   array  $cals   暦を格納する配列
 561:  *                          [年][月][日] = 天象
 562:  * @return  int 格納した天象の数
 563: */
 564: function planetPhenomena($planet, $year, &$cals) {
 565:     // 内惑星の天象を求める.
 566:     if ($this->PlanetOrbitalElements[$planet][18] == '内惑星') {
 567:         $cnt = $this->planetPhenomenaInner($planet, $year, $cals);
 568:     // 外惑星の天象を求める.
 569:     } else {
 570:         $cnt = $this->planetPhenomenaOuter($planet, $year, $cals);
 571:     }
 572:     return $cnt;
 573: }

ユーザー定義メソッド planetPhenomena は、前述の2つのメソッドを呼び出し、指定した惑星の、指定した西暦年の外惑星の天象を計算し、配列に格納する。

準備:天象を一覧表示する

planetPhenomena.php

 276: // 天象一覧を計算する.
 277: if ($errmsg == '') {
 278:     $items = array();       // 全惑星の天象を格納する配列
 279:     $planetsEN = array();
 280:     $planetsJP = array();
 281:     $pa->getPlanetsEN($planetsEN);
 282:     $pa->getPlanetsJP($planetsJP);
 283: 
 284:     // 全惑星の天象を配列 $items に代入する
 285:     foreach ($planetsEN as $key=>$planet) {
 286:         $cals = array();
 287:         $pa->planetPhenomena($planet, $year, $cals);
 288:         for ($mm = 1$mm <12$mm++) {
 289:             $dayOfMonth = $pa->getDaysInMonth($year, $mm);
 290:             for ($dd = 1$dd < $dayOfMonth$dd++) {
 291:                 if (isset($cals[$year][$mm][$dd])) {
 292:                     $yyyymmdd = sprintf('%04d-%02d-%02d', $year, $mm, $dd);
 293:                     $items[$yyyymmdd][$planetsJP[$key]] = $cals[$year][$mm][$dd];
 294:                 }
 295:             }
 296:         }
 297:     }
 298:     // 配列を日付順にソートする.
 299:     ksort($items);
 300: 
 301:     // 一覧表(HTML)を作成する.
 302:     $table =<<< EOT
 303: <table>
 304: <tr><th>年月日</th><th>惑星</th><th>天象</th></tr>
 305: 
 306: EOT;
 307:     foreach ($items as $yyyymmdd=>$item2) {
 308:         foreach ($item2 as $planet=>$phenomena) {
 309:             preg_match('/(\d{4})\-(\d{2})\-(\d{2})/', $yyyymmdd, $arr);
 310:             $ymd = sprintf('%04d年%02d月%02d日(%s)', $arr[1], $arr[2], $arr[3], $pa->getWeekString($arr[1], $arr[2], $arr[3]));
 311:             $table ."<tr><td>{$ymd}</td><td>{$planet}</td><td>{$phenomena}</td></tr>\n";
 312:         }
 313:     }
 314: }
 315: $table ."</table>\n";
 316: 
 317: // 表示用HTMLを生成する.
 318: $HtmlBody = makeCommonBody($year, $table, $errmsg);

メイン・プログラムでは、すべての惑星に対して planetPhenomena を実行し、その結果を多次元配列 $items に格納する。この配列の1次元目は年月日、2次元目は惑星の名前である。
多次元配列 $items を年月日(1次元目)でソートしたら、table タグを使った一覧表を作成する。

参考サイト

参考書籍

表紙 新装改訂版 天文計算入門
著者 長谷川一郎
出版社 恒星社厚生閣
サイズ 単行本
発売日 1996年01月25日頃
価格 2,750円(税込)
ISBN 9784769908180
 
表紙 天体の位置計算
著者 長沢 工
出版社 地人書館
サイズ 単行本
発売日 1981年01月01日頃
価格 2,970円(税込)
ISBN 9784805202258
パソコンなどの普及によって,今まで専門家のものとされていた「位置天文学」が,身近なものとなった.本書の構成・指示にしたがって,恒星や,太陽・月・惑星等の位置を自らの手で計算し,その基礎理論を理解することにより,自分のための「観測年表」を作ることも可能になる.
 
(この項おわり)
header