サンプル・プログラムの実行例
図は2026年(令和8年)10月22日10時13分(日本時間)の例で、太陽が地平線の上にある。昼間でも星の位置を描くため、実際の空でこのように恒星が見えるわけではない。
目次
- サンプル・プログラムの実行例
- 使い方:日時と観測地点の入力
- 使い方:地図検索と標高取得
- 使い方:表示切替と画像保存
- サンプル・プログラムのダウンロード
- 準備:動作環境とファイル配置
- サンプル・プログラムの流れ
- 解説:入力の検証と日時の変換
- 解説:恒星の位置を求める
- 解説:星座線と名称のデータ
- 解説:太陽・月・惑星と月相
- 解説:Canvasへの投影と描画
- 解説:天の川の描画
- 解説:地図画面との連携
- 解説:画像ファイルへの保存
- 解説:JSON出力とエラー処理
- 外部データ生成ツールの使い方
- 解説:原本の取得とデータ変換
- 解説:生成記録とフォルダー・ZIP保存
- 外部データの出典とライセンス
- 計算条件と注意点
- 参考サイト
サンプル・プログラムのダウンロード
同梱の案内ファイル「!最初に読んでください.txt」も現状のZIPにはないため、ファイル配置は次節を参照していただきたい。
| skyMap.php | 星空マップ本体。PHPの計算処理とJavaScriptの画面処理 |
| skyMapDataBuilder.php | 外部データの取得・変換・保存ツール |
| SkyMap.md | 仕様書。設定値などは現行ソースも確認すること |
| skyMap-stars.json | HYG v4.1から抽出した6.5等までの8,920恒星 |
| skyMap-constellations.json | 88星座・695線分、主要恒星名109個、補助恒星 |
| skyMap-milkyway.json | 天の川の概略濃度データ |
| vsop87/ | 金星・地球・木星・土星・天王星・海王星のVSOP87D係数(JSON)と出典・ライセンス文書。pahooAstronomy.phpと同じフォルダー内に、vsop87フォルダーごと配置する。 |
| skyMap-HYG.txt skyMap-license.txt skyMap-constellations-source.txt skyMap-milkyway-source.txt skyMap-milkyway-license.txt | 各データの出典・加工内容・ライセンス |
| .pahooEnv | クラウドサービスを利用するためのアカウント情報などを記入する .env ファイル。 使い方は「各種クラウド連携サービス(WebAPI)の登録方法」を参照。include_path が通ったディレクトリに配置すること。 |
| pahooAstronomy.php | 天文計算クラス pahooAstronomy。 使い方は「PHPでホロスコープを描く」などを参照。include_path が通ったディレクトリに配置すること。 |
| pahooCalendar.php | 暦・潮位計算クラス pahooCalendar。 暦・潮位計算クラスの使い方は「PHPで二十四節気・七十二候一覧を作成」「PHPで月齢を計算」「PHPで日出没・月出没・月齢・潮を計算」「PHPで潮位を計算する」などを参照。include_path が通ったディレクトリに配置すること。 |
| pahooGeoCode.php | 住所・緯度・経度に関わるクラス pahooGeoCode。 使い方は「PHPで住所・ランドマークから最寄り駅を求める」「PHPで住所・ランドマークから緯度・経度を求める」などを参照。include_path が通ったディレクトリに配置すること。 |
| pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 1.0.0 | 2026/10/22 | 配布版 |
| 0.8.0 | 2026/10/21 | 関数・制御文の目的コメント,地図設定定数,上部入力パネルと行配置,国内10都市,座標3桁表示,画像右下の著作権表記 |
| 0.7.0 | 2026/10/21 | 別ウィンドウの地図・ランドマーク検索,既存pahooGeoCodeによる標高取得,国内5都市の座標・標高プリセット |
| 0.6.0 | 2026/10/12 | 全天・東西南北90度の半円星図切替,BMP/JPEG/PNG/WebP画像保存 |
| 0.5.0 | 2026/10/10 | 等級による恒星の大きさ・濃淡,B−V色指数の連続的な淡い色分け,凡例 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 1.0.0 | 2026/10/22 | 共通初期化に対応.引数・戻り値コメントを項目ごとに改行し,タグの区切りと行頭インデントをタブへ統一,バージョンアップ履歴を追加. |
| 0.1.0 | 2026/10/22 | 初版.9種類の外部データを原本ダウンロードから生成,選択・一括選択/解除,フォルダー/ZIP保存,出典・ライセンス・生成記録を同梱. |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 2.3.0 | 2026/10/21 | 天象を視黄経差・視赤経変化・真角距離から判定し,年月日を正規化 |
| 2.2.0 | 2026/10/21 | euatorialCoordinate()を追加 |
| 2.1.1 | 2025/11/29 | PHP8.5対応:double→float 対象コメント変更 |
| 2.1.0 | 2025/06/01 | euatorialCoordinate() を追加 |
| 2.0.0 | 2025/05/25 | 全面改訂, 天象を求められるようにした |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 4.7.0 | 2026/10/21 | __construct():時差0を正常値として扱うよう失敗判定を厳密比較へ変更 |
| 4.6.0 | 2025/10/07 | getMidAutumnMoon() 追加 |
| 4.5.1 | 2025/05/31 | deg2ddmm(), deg2hhmm() 不具合修正 |
| 4.5.0 | 2024/03/17 | ヒジュラ暦メソッドを追加 |
| 4.4.1 | 2024/03/17 | getCabinetOfficeHolidayTable() -- bug-fix |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 7.0.0 | 2026/10/18 | 汎用GeoJSON描画メソッドを追加(既存メソッドは変更なし) |
| 6.10.4 | 2026/09/26 | 外部APIに接続できない・応答がXMLでないときにWarningで停止しないようにした,searchPoint3 -- 前回のエラーを持ち越さないようにした |
| 6.10.3 | 2026/09/26 | 静岡県の表記,jsPolygon_Gmap/Leaflet の引数取り違え,searchPoint,getPointsGSI,makeYOLP_GeoSelectCategory,getLocalGovernmentCodeList,HeartRails系URLエンコード bug-fix |
| 6.10.2 | 2026/09/26 | unknown_certificate() -- サーバ証明書を検証するようにした |
| 6.10.1 | 2026/09/26 | drawGMap, drawLeaflet -- アイコン画像を取得できなくても停止しないようにした(getIconSize追加) |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 2.0.3 | 2026/09/26 | validEmail(), validNumber(), getValidNumber(), roundFloat(), pahooLoadEnv() bug-fix |
| 2.0.2 | 2026/09/26 | pahooLoadEnv() -- str_starts_with()を使わないようにした(PHP7対応) |
| 2.0.1 | 2025/08/11 | getParam() bug-fix |
| 2.0.0 | 2025/08/11 | pahooLoadEnv() 追加 |
| 1.9.0 | 2025/07/26 | getParam() 引数に$trim追加 |
使い方:日時と観測地点の入力
限界等級 は表示する恒星の暗さの上限で、数値を大きくすると暗い星まで描く。初期値は6.0等である。-1時間・+1時間 は日時の入力値を変更するボタンである。
標高は地表からの高さではなく海面を基準とした値である。建物の上で観測する場合は、地表の標高に建物上の観測位置の高さを加える。
| 項目 | 範囲・形式 | 初期値 |
|---|---|---|
| 緯度(latitude) | −90~90度。北緯が正、南緯が負 | 35.4658度 |
| 経度(longitude) | −180~180度。東経が正、西経が負 | 139.6223度 |
| 標高(height) | −500~9000m | 0m |
| 限界等級(magnitude) | 0~6.5等。画面では0.1刻み | 6.0等 |
| 観測日時(datetime) | 1900~2100年。YYYY-MM-DDTHH:MM | アクセス時の日本の日時 |
| タイムゾーン(timezone) | Asia/Tokyo、UTCなど、PHPが認識する識別子 | Asia/Tokyo |
使い方:地図検索と標高取得
メイン画面の 標高取得 でも標高を取得できる。取得できない場合は手入力する。地図から戻ったあと、日時などを確認して 星空を表示 を押す。
使い方:表示切替と画像保存
星座線、星座名、主要恒星名、太陽・月・惑星、天の川は個別に表示を切り替えられる。恒星を選ぶと名前・方位・高度・等級などを確認できる。星座名は通常最大20個とし、「すべて表示」でも名称が重なる場合は省略する。
太陽系の位置一覧は地平線の下にある天体も含み、月相の拡大図では月の満ち欠けと照らされる割合を確認できる。太陽・月・惑星の表示は恒星の限界等級とは独立している。
星図は BMP・JPEG・PNG・WebP で保存できる。全天画像は1600×2128ピクセル、方角別画像は1600×1488ピクセルで、日時・地点・凡例・出典も入る。ブラウザーが対応していない形式ではエラーを表示する。
準備:PHP の https対応
Windowsでは、"php.ini" の下記の行を有効化する。
extension=php_openssl.dllLinuxでは --with-openssl=/usr オプションを付けて再ビルドする。→OpenSSLインストール手順
また、クラウド連携や相手先サイトとの https通信では、なりすましを防ぐため、相手サーバのSSL/TLS証明書を検証している。
Windows版のPHPには、証明書の検証に使うCA証明書(ルート証明書の一覧)が同梱されていないため、そのままでは https によるデータ取得に失敗する。CA証明書ファイル(cacert.pem)を入手し、"php.ini" に次の2行を追加してから、PHP(Webサーバ)を再起動してほしい。パスは cacert.pem を置いた場所に合わせること。
curl.cainfo = "C:\php\extras\ssl\cacert.pem"Linuxでは、通常はOSのCA証明書が使われるので、この設定は要らない。
openssl.cafile = "C:\php\extras\ssl\cacert.pem"
これで準備は完了だ。
準備:pahooGeoCode クラス
pahooGeoCode.php
41: class pahooGeoCode {
42: public $items; // 検索結果格納用
43: public $error; // エラー・フラグ
44: public $errmsg; // エラー・メッセージ
45: public $hits; // 検索ヒット件数
46: public $webapi; // 直前に呼び出したWebAPI URL
47:
48: // 都道府県境界線データ
49: // SimpleMaps.com is a product of Pareto Software, LLC. © 2010-2025
50: // https://simplemaps.com/gis/country/jp
51: // ※各自の環境に合わせて設定すること
52: public $GeoJsonJP = __DIR__ . '/jp.json';
53:
54: // -- 以下のデータは .env ファイルに記述可能
55: // Google Cloud Platform APIキー
56: // https://cloud.google.com/maps-platform/
57: // ※Google Maps APIを利用しないのなら登録不要
58: public $GOOGLE_API_KEY_1 = ''; // HTTPリファラ用
59: public $GOOGLE_API_KEY_2 = ''; // IP制限用
60: public $GOOGLE_MAP_ID = ''; // GoogleMaps ID
61:
62: // Yahoo! JAPAN Webサービス アプリケーションID
63: // https://e.developer.yahoo.co.jp/register
64: // ※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
65: public $YAHOO_APPLICATION_ID = '';
66:
67: // OSM Nominatim Search API利用時に知らせるメールアドレス
68: // https://wiki.openstreetmap.org/wiki/JA:Nominatim#.E6.A4.9C.E7.B4.A2
69: // ※OSM Nominatim Search APIを利用しないのなら登録不要
70: public $NOMINATIM_EMAIL = '';
71:
72: // IP2Location.io APIキー
73: // https://www.ip2location.io/
74: // ※IP2Location.ioを利用しないのなら登録不要
75: public $IP2LOCATION_API_KEY = '';
地図や住所検索として Google を利用するのであれば Google Cloud Platform APIキー とマップID が必要で、その入手方法は「Google Cloud Platform - WebAPIの登録方法」を、Yahoo!JAPAN を利用するのであれば Yahoo! JAPAN Webサービス アプリケーションIDが必要で、その入手方法は「Yahoo!JAPAN デベロッパーネットワーク - WebAPIの登録方法」を、IP2Location.ioを利用するのであれば「PHPでIPアドレスやホスト名から住所を求める」を、それぞれ参照されたい。
住所検索などで外部のWebAPIに接続できないときや、応答がXMLでないときは、警告(Warning)を出さずに、エラーとして戻る。エラーの有無はメソッド iserror、内容はメソッド geterror で調べられる。メソッド searchPoint3 は、検索のたびにエラーの状態をリセットする。
PHPのクラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。
準備:pahooInputData 関数群
また、各種クラウドサービスに登録したときに取得するアカウント情報、アプリケーションパスワードなどを登録した .pahooEnv ファイルから読み込む関数 pahooLoadEnv を備えている。こちらについては、「各種クラウド連携サービス(WebAPI)の登録方法」をご覧いただきたい。
.pahooEnv には「名前=値」を1行に1つずつ書く。値は "..." や '...' で囲んでもよい(囲んだ引用符は取り除かれる)。# ではじまる行はコメントで、空行や「=」のない行は読み飛ばす。
準備:動作環境とファイル配置
skyMap.php と skyMapDataBuilder.php、3種類の skyMap-*.json、付属する出典・ライセンス文書を同じフォルダーへ配置する。共通PHPファイルは include_path が通る場所へ置く。
惑星係数は pahooAstronomy.php が自分自身のあるフォルダーの vsop87/ から読む。たとえば共通クラスを common/ に置くなら、生成した common/vsop87/ をそこへ配置する。JSONだけを本体の横へ移しても読み込めないので注意していただきたい。
地図機能は「PHPで地図で指定した場所の天気予報を求める」と同じ pahooGeoCode を利用する。.pahooEnv へのAPI情報の設定は「各種クラウド連携サービス(WebAPI)の登録方法」を参照すること。
skyMap.php
53: // 各種定数(START) ===========================================================
54:
55: // 恒星表ファイル
56: define('STAR_CATALOG', __DIR__ . '/skyMap-stars.json');
57: // 恒星表のリファレンス
58: define('HYG_REFERENCE', 'https://codeberg.org/astronexus/hyg');
59: // 88星座の星座線・星座名・主要恒星名・補助端点
60: define('CONSTELLATION_CATALOG', __DIR__ . '/skyMap-constellations.json');
61: // 天の川ファイル
62: define('MILKYWAY_CATALOG', __DIR__ . '/skyMap-milkyway.json');
63: // 入力可能な最小年・最大年
64: define('MIN_YEAR', 1900);
65: define('MAX_YEAR', 2100);
66:
67: // 地図描画サービスの選択
68: // 0:Google
69: // 2:地理院地図・OSM
70: define('MAPSERVICE', 0);
71:
72: // 住所検索サービスの選択
73: // 0:Google
74: // 1:Yahoo!JAPAN
75: // 11:HeartRails Geo API
76: // 12:OSM Nominatim Search API
77: // 13:国土地理院ジオコーディングAPI
78: define('GEOSERVICE', 2);
79:
80: // 逆ジオコーディングサービスの選択
81: // 0:Google
82: // 1:Yahoo!JAPAN
83: // 11:HeartRails Geo API
84: // 21:簡易ジオコーディングサービス
85: define('REVGEOSERVICE', 11);
86:
87: // マップの表示サイズ(単位:ピクセル)
88: define('MAP_WIDTH', 600);
89: define('MAP_HEIGHT', 400);
90: // マップID
91: define('MAPID', 'map_id');
92: // 初期値
93: define('DEF_LATITUDE', 35.4658); // 緯度
94: define('DEF_LONGITUDE', 139.6223); // 経度
95: define('DEF_TYPE', 'roadmap'); // マップタイプ
96: define('DEF_ZOOM', 13); // ズーム
97: define('DEF_CATEGORY', 'address'); // カテゴリ
98: define('DEF_DISTANCE', 250); // 距離
99:
100: // 検索キーの最小・最大文字長
101: define('QUERY_MIN_LEN', 3);
102: define('QUERY_MAX_LEN', 99);
103:
104: // 各種定数(END) =============================================================
準備:地図サービス(WebAPI)の選択
searchOutlet.php
62: // 地図描画サービスの選択
63: // 0:Google
64: // 2:地理院地図・OSM
65: define('MAPSERVICE', 2);
66:
67: // 住所検索サービスの選択
68: // 0:Google
69: // 1:Yahoo!JAPAN
70: // 11:HeartRails Geo API
71: // 12:OSM Nominatim Search API
72: // 13:国土地理院ジオコーディングAPI
73: define('GEOSERVICE', 11);
74:
75: // 逆ジオコーディングサービスの選択
76: // 0:Google
77: // 1:Yahoo!JAPAN
78: // 11:HeartRails Geo API
79: // 21:簡易ジオコーディングサービス
80: define('REVGEOSERVICE', 0);
住所検索サービスは、Google、Yahoo!JAPAN、HeartRails Geo API、OSM Nominatim Search API、国土地理院ジオコーディングAPI から選べる。あらかじめ、定数 GEOSERVICE に値を設定すること。
逆ジオコーディングサービスは、Google、Yahoo!JAPAN、HeartRails Geo API、簡易ジオコーディングサービスから選べる。あらかじめ、定数 REVGEOSERVICE に値を設定すること。
サンプル・プログラムの流れ
地図検索・標高取得は action で別処理へ振り分け、天体計算を実行せず応答する。表示レイヤーや方向の切替、画像保存はブラウザー側で行う。
解説:入力の検証と日時の変換
日時には DateTimeImmutable::createFromFormat() を使う。PHPは範囲を超えた日付を繰り上げることがあるため、変換後の文字列と元の入力を比較し、2月30日などの不正な日付や夏時間開始時の存在しない時刻を検出する。
検証後、選択した地域の日時 local とUTCへ変換した utc を保持する。以後の計算はUTCを基準に行い、画面には利用者が指定した地域の日時を表示する。
skyMap.php
473: /**
474: * 星図のGET入力を検証し,選択したタイムゾーンの日時とUTC日時を用意する.
475: * @param array $input latitude・longitude・height・datetime・timezone・magnitudeの入力
476: * @return array 数値化した座標・標高・限界等級とlocal・utcのDateTimeImmutableを含む配列
477: * @throws InvalidArgumentException 入力形式・範囲・日時が不正な場合
478: */
479: function readParameters($input) {
480: $defaults = array('latitude'=>(string)DEF_LATITUDE, 'longitude'=>(string)DEF_LONGITUDE,
481: 'datetime'=>(new DateTimeImmutable('now', new DateTimeZone('Asia/Tokyo')))->format('Y-m-d\TH:i'),
482: 'timezone'=>'Asia/Tokyo', 'magnitude'=>'6.0', 'height'=>'0');
483: $p = array();
484:
485: // 各入力項目に既定値または利用者が指定した値を設定する.
486: foreach ($defaults as $key=>$value) {
487: // 配列など文字列以外の入力を受け付けない.
488: if (isset($input[$key]) && ! is_string($input[$key])) throw new InvalidArgumentException('入力形式が不正です.');
489: $p[$key] = isset($input[$key]) ? $input[$key] : $value;
490: }
491:
492: // 座標・限界等級・標高をそれぞれの数値範囲で確認する.
493: foreach (array('latitude'=>array(-90,90), 'longitude'=>array(-180,180), 'magnitude'=>array(0,6.5), 'height'=>array(-500,9000)) as $key=>$range) {
494: // 数値に変換できない値や許容範囲外の値を拒否する.
495: if (! is_numeric($p[$key]) || ! is_finite((float)$p[$key]) || $p[$key] < $range[0] || $p[$key] > $range[1]) {
496: throw new InvalidArgumentException('緯度は−90~90,経度は−180~180,限界等級は0~6.5,標高は−500~9000mで指定してください.');
497: }
498: $p[$key] = (float)$p[$key];
499: }
500:
501: // PHPが認識できないタイムゾーンを拒否する.
502: if (! in_array($p['timezone'], DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC), TRUE)) {
503: throw new InvalidArgumentException('タイムゾーンが不正です.');
504: }
505: $tz = new DateTimeZone($p['timezone']);
506: $local = DateTimeImmutable::createFromFormat('!Y-m-d\TH:i', $p['datetime'], $tz);
507:
508: // 無効な日付・夏時間の欠落時刻・対象年代外の日付を拒否する.
509: if ($local === FALSE || $local->format('Y-m-d\TH:i') !== $p['datetime']
510: || (int)$local->format('Y') < MIN_YEAR || (int)$local->format('Y') > MAX_YEAR) {
511: throw new InvalidArgumentException('日時は1900~2100年の有効な年月日時分で指定してください(夏時間の欠落時刻も指定できません).');
512: }
513: $p['local'] = $local;
514: $p['utc'] = $local->setTimezone(new DateTimeZone('UTC'));
515:
516: return $p;
517: }
解説:恒星の位置を求める
starEquatorialOfDate() は恒星自身の移動である 固有運動 と、地球の自転軸の向きがゆっくり変わる 歳差 を反映する。固有運動は3次元のベクトルへ加える形にし、天の極付近で赤緯の余弦による割り算が不安定になるのを避けている。
dateToJulianDay() はUTCの日時を日数の連続値である ユリウス日 へ直し、localSiderealTime() は日時と観測地点の経度から 地方平均恒星時 を求める。恒星時は、地球の自転に対して星がどちらに見えるかを表す基準となる。
equatorialToHorizontal() では恒星時と赤経の差を使い、観測地点の緯度も加えて、東・北・天頂の3方向の成分を計算する。そこから北0度・東90度の 方位角 と地平線0度・天頂90度の 高度 を求める。
makeSkyData() は限界等級より暗い恒星と地平線の下の恒星を除き、描画する恒星の一覧を作る。
skyMap.php
427: /**
428: * 恒星の固有運動とIAU 1976歳差を反映し,J2000.0座標を観測日の平均分点へ変換.
429: * @param array $star 恒星表の行:[id,hip,raDeg,decDeg,mag,bv,pmRaCosDecMasYr,pmDecMasYr]
430: * @param float $jd 観測日時のユリウス日(対象1900~2100年)
431: * @return array [赤経,赤緯](度)
432: */
433: function starEquatorialOfDate($star, $jd) {
434: $years = ($jd - 2451545.0) / 365.25;
435: $a = deg2rad($star[2]);
436: $d = deg2rad($star[3]);
437: // pmRAはμ_α*cos(δ).極付近の除算を避け,接平面ベクトルで加える.
438: $k = deg2rad(1.0 / 3600000.0) * $years;
439: $x = cos($d) * cos($a) + $k * (-$star[6] * sin($a) - $star[7] * sin($d) * cos($a));
440: $y = cos($d) * sin($a) + $k * ( $star[6] * cos($a) - $star[7] * sin($d) * sin($a));
441: $z = sin($d) + $k * $star[7] * cos($d);
442: $a = atan2($y, $x);
443: $d = atan2($z, sqrt($x * $x + $y * $y));
444: $t = $years / 100.0;
445: $zeta = deg2rad((2306.2181 * $t + 0.30188 * $t*$t + 0.017998 * $t*$t*$t) / 3600.0);
446: $zz = deg2rad((2306.2181 * $t + 1.09468 * $t*$t + 0.018203 * $t*$t*$t) / 3600.0);
447: $theta = deg2rad((2004.3109 * $t - 0.42665 * $t*$t - 0.041833 * $t*$t*$t) / 3600.0);
448: $aa = cos($d) * sin($a + $zeta);
449: $bb = cos($theta) * cos($d) * cos($a + $zeta) - sin($theta) * sin($d);
450: $cc = sin($theta) * cos($d) * cos($a + $zeta) + cos($theta) * sin($d);
451: return array(normalizeAngle(rad2deg(atan2($aa, $bb) + $zz)), rad2deg(asin(max(-1.0, min(1.0, $cc)))));
452: }
skyMap.php
454: /**
455: * 赤道座標を大気差なしの地平座標へ変換する.
456: * @param float $ra 赤経(度)
457: * @param float $dec 赤緯(度)
458: * @param float $lst 地方平均恒星時(度)
459: * @param float $latitude 観測地の緯度(北緯+,度)
460: * @return array [方位角,高度](度).方位角は北0・東90
461: */
462: function equatorialToHorizontal($ra, $dec, $lst, $latitude) {
463: $h = deg2rad(normalizeAngle($lst - $ra));
464: $d = deg2rad($dec);
465: $p = deg2rad($latitude);
466: $east = -cos($d) * sin($h);
467: $north = cos($p) * sin($d) - sin($p) * cos($d) * cos($h);
468: $up = sin($p) * sin($d) + cos($p) * cos($d) * cos($h);
469: $azimuth = hypot($east, $north) < 1.0e-12 ? 0.0 : normalizeAngle(rad2deg(atan2($east, $north)));
470: return array($azimuth, rad2deg(atan2($up, hypot($east, $north))));
471: }
解説:星座線と名称のデータ
星座名の配置位置も観測日時・地点に合わせて変換する。星座線は恒星を結ぶ案内用の図形で、国際天文学連合(IAU)が定める星座の境界線そのものではない。へび座は頭と尾に名称を分けている。
skyMap.php
622: /**
623: * 恒星・星座・天体・天の川の観測日時と観測地点に対応した描画データを生成する.
624: * @param array $p readParametersで検証した観測パラメータ
625: * @return array 星図のメタデータ,恒星・星座・太陽系・月相・天の川を含むJSON応答用データ
626: */
627: function makeSkyData($p) {
628: // WindowsのACLではis_readable()の判定と実読込が異なる場合がある.実読込で確認する.
629: $source = @file_get_contents(STAR_CATALOG);
630: // 恒星表を読み込めない場合は計算を中止する.
631: if ($source === FALSE) throw new RuntimeException('Star catalog is not readable');
632: $catalog = json_decode($source, TRUE, 512, JSON_THROW_ON_ERROR);
633: $jd = dateToJulianDay($p['utc']);
634: $lst = localSiderealTime($jd, $p['longitude']);
635: $milkywaySource=@file_get_contents(MILKYWAY_CATALOG);
636:
637: // 天の川データを読み込めない場合は計算を中止する.
638: if($milkywaySource===FALSE)throw new RuntimeException('Milky Way data not readable');
639: $milkyway=json_decode($milkywaySource,TRUE,512,JSON_THROW_ON_ERROR);
640:
641: // J2000基底を観測日の赤道座標へ変換.逆写像には転置行列を使う.
642: $basis=array();
643: // J2000の三つの基底軸を観測日の平均分点へ変換する.
644: foreach(array(array(0,0),array(90,0),array(0,90)) as $axis){
645: list($a,$d)=starEquatorialOfDate(array(0,0,$axis[0],$axis[1],0,0,0,0),$jd);
646: $basis[]=array(cos(deg2rad($d))*cos(deg2rad($a)),cos(deg2rad($d))*sin(deg2rad($a)),sin(deg2rad($d)));
647: }
648: $milkyway['precessionBasis']=$basis;
649: $source = @file_get_contents(CONSTELLATION_CATALOG);
650:
651: // 星座データを読み込めない場合は計算を中止する.
652: if ($source === FALSE) throw new RuntimeException('Constellation catalog is not readable');
653: $figures = json_decode($source, TRUE, 512, JSON_THROW_ON_ERROR);
654: $names = $figures['starNames'];
655: // 星座線の端点は限界等級・地平線による恒星の絞り込みとは独立に計算する.
656: $needed = array();
657: // 各星座から星座線に必要な恒星番号を集める.
658: foreach ($figures['constellations'] as $c)
659: // 各線分の両端の番号を必要な恒星の集合へ追加する.
660: foreach ($c['lines'] as $line) {
661: $needed[$line[0]] = TRUE; $needed[$line[1]] = TRUE;
662: }
663: $vertices = array();
664:
665: // 恒星表と補助恒星を合わせて星座線の端点を計算する.
666: foreach (array_merge($catalog['stars'], $figures['supportStars']) as $s) {
667: // 星座線に使わない恒星は端点計算から除く.
668: if (! isset($needed[$s[1]])) continue;
669: list($ra, $dec) = starEquatorialOfDate($s, $jd);
670: list($az, $alt) = equatorialToHorizontal($ra, $dec, $lst, $p['latitude']);
671: $vertices[$s[1]] = array($az, $alt);
672: }
673: $constellations = array();
674:
675: // 各星座の線と名称の描画用データを作る.
676: foreach ($figures['constellations'] as $c) {
677: $labels = array();
678: // 複数の名称位置がある星座も位置ごとに変換する.
679: foreach ($c['labels'] as $label) {
680: list($ra, $dec) = starEquatorialOfDate(array(0,0,$label['raDeg'],$label['decDeg'],0,0,0,0), $jd);
681: list($az, $alt) = equatorialToHorizontal($ra, $dec, $lst, $p['latitude']);
682: $labels[] = array('name'=>$label['name'], 'azimuthDeg'=>$az, 'altitudeDeg'=>$alt);
683: }
684: $constellations[] = array('id'=>$c['id'], 'name'=>$c['name'], 'lines'=>$c['lines'], 'labels'=>$labels);
685: }
686: $stars = array();
687:
688: // 恒星表の各恒星を観測日の地平座標へ変換する.
689: foreach ($catalog['stars'] as $s) {
690: // 指定した限界等級より暗い恒星を表示対象から除く.
691: if ($s[4] > $p['magnitude']) continue;
692: list($ra, $dec) = starEquatorialOfDate($s, $jd);
693: list($az, $alt) = equatorialToHorizontal($ra, $dec, $lst, $p['latitude']);
694: // 地平線の下にある恒星を表示対象から除く.
695: if ($alt < 0.0) continue;
696: $stars[] = array('id'=>$s[0], 'hip'=>$s[1], 'azimuthDeg'=>round($az, 6),
697: 'altitudeDeg'=>round($alt, 6), 'magnitude'=>$s[4], 'bv'=>$s[5],
698: 'name'=>isset($names[$s[1]]) ? $names[$s[1]] : '');
699: }
700: $bodies=makeSolarSystemData($p,$lst);
701:
702: return array('version'=>VERSION, 'utc'=>$p['utc']->format('Y-m-d\TH:i:s\Z'),
703: 'local'=>$p['local']->format('Y-m-d H:i P'), 'timezone'=>$p['timezone'],
704: 'latitude'=>$p['latitude'], 'longitude'=>$p['longitude'], 'magnitude'=>$p['magnitude'],
705: 'julianDay'=>$jd, 'siderealDeg'=>$lst, 'catalogCount'=>count($catalog['stars']), 'stars'=>$stars,
706: 'constellations'=>$constellations, 'lineVertices'=>$vertices, 'height'=>$p['height'],
707: 'bodies'=>$bodies,'moonPhase'=>makeMoonPhase($bodies),'milkyWay'=>$milkyway);
708: }
解説:太陽・月・惑星と月相
太陽は longitude_sun() と distance_sun()、月は longitude_moon()・latitude_moon()・distance_moon()、惑星は zodiacEarth() を利用する。黄道座標を eclip2equat() で赤道座標へ変換し、観測地点から見た方位・高度を求める。
地球の中心から見た座標から、緯度・経度・標高に応じた観測点のベクトルを引き、視差 を補正する。これは特に地球に近い月で大切になる。
現行の共通クラスでは金星・木星・土星・天王星・海王星に VSOP87D の全係数を使用し、水星・火星には平均軌道要素による計算を使う。地球の係数も生成できるが、星図の通常処理で常に6天体分すべてを読むわけではない。画面の計算条件には金星について旧説明が残るため、現行クラスの処理に合わせて理解していただきたい。
makeMoonPhase() は観測点からの太陽と月の位置・距離を使い、月から太陽へ向かう方向と、月から観測者へ向かう方向の角度を求める。この角度の余弦から、月面の照らされて見える割合を計算する。
新月付近・上弦付近などの名称は太陽と月の黄経の差から決める。一方、明るい側の向きは3次元の照明方向として渡し、ブラウザーの makeMoonLayer() で月の球面を明暗に塗り分ける。星図上の月と拡大図でこの画像を使う。
skyMap.php
519: /**
520: * 既存クラスの計算結果を使い,太陽・月・7惑星の地平座標に観測地点の視差を補正.
521: * @param array $p 検証済み観測パラメータ(utc・latitude・longitude・height等)
522: * @param float $lst 地方平均恒星時(度)
523: * @return array 地平線下を含む9天体の位置・距離・名称等.大気差なし
524: */
525: function makeSolarSystemData($p, $lst) {
526: // 天文計算クラス:include_pathが通ったディレクトリに配置
527: require_once('pahooAstronomy.php');
528:
529: $astronomy = new pahooAstronomy('jp', 0.0);
530: // 天文計算クラスを初期化できなければ計算を中止する.
531: if ($astronomy->error) throw new RuntimeException('UTC astronomy initialization failed');
532: $args = array_map('intval', explode(' ', $p['utc']->format('Y n j G i s')));
533: $names = array('Sun'=>'太陽','Moon'=>'月','Mercury'=>'水星','Venus'=>'金星','Mars'=>'火星',
534: 'Jupiter'=>'木星','Saturn'=>'土星','Uranus'=>'天王星','Neptune'=>'海王星');
535: $bodies = array();
536:
537: // 太陽・月・各惑星を共通の観測条件で計算する.
538: foreach ($names as $id=>$name) {
539: // 太陽には既存の太陽位置と距離の計算を使用する.
540: if ($id === 'Sun') {
541: $longitude = $astronomy->longitude_sun(...$args); $latitude = 0.0;
542: $distance = $astronomy->distance_sun(...$args) * 149597870.7;
543: }
544: // 月には既存の月位置と地心距離の計算を使用する.
545: else if ($id === 'Moon') {
546: $longitude = $astronomy->longitude_moon(...$args);
547: $latitude = $astronomy->latitude_moon(...$args);
548: $distance = $astronomy->distance_moon(...$args) * 384400.0;
549: }
550: // 惑星には既存の惑星黄道座標と距離の計算を使用する.
551: else {
552: list($longitude, $latitude, $distance) = $astronomy->zodiacEarth($id, ...$args);
553: $distance *= 149597870.7;
554: }
555: list($ra, $dec) = $astronomy->eclip2equat($longitude, $latitude, ...$args);
556:
557: // 月では特に大きい地心視差を,観測地点の3次元ベクトルで補正する.
558: $u = atan(0.9966471893 * tan(deg2rad($p['latitude'])));
559: $rhoCos = 6378.137 * cos($u) + $p['height']/1000.0 * cos(deg2rad($p['latitude']));
560: $rhoSin = 6356.7523142 * sin($u) + $p['height']/1000.0 * sin(deg2rad($p['latitude']));
561: $x = $distance*cos(deg2rad($dec))*cos(deg2rad($ra)) - $rhoCos*cos(deg2rad($lst));
562: $y = $distance*cos(deg2rad($dec))*sin(deg2rad($ra)) - $rhoCos*sin(deg2rad($lst));
563: $z = $distance*sin(deg2rad($dec)) - $rhoSin;
564: $topRa = normalizeAngle(rad2deg(atan2($y,$x)));
565: $topDec = rad2deg(atan2($z,hypot($x,$y)));
566: list($az,$alt) = equatorialToHorizontal($topRa,$topDec,$lst,$p['latitude']);
567: $bodies[] = array('id'=>$id,'name'=>$name,'azimuthDeg'=>$az,'altitudeDeg'=>$alt,
568: 'aboveHorizon'=>$alt>=0.0,'geocentricRaDeg'=>$ra,'geocentricDecDeg'=>$dec,
569: 'topocentricRaDeg'=>$topRa,'topocentricDecDeg'=>$topDec,'topocentricDistanceKm'=>sqrt($x*$x+$y*$y+$z*$z),
570: 'distanceKm'=>$distance,'eclipticLongitudeDeg'=>$longitude,'eclipticLatitudeDeg'=>$latitude);
571: }
572: return $bodies;
573: }
skyMap.php
575: /**
576: * 観測地点からの太陽・月の位置と距離から,月の位相角・照明率・照明方向を求める.
577: * @param array $bodies makeSolarSystemDataの9天体の配列
578: * @return array name・phaseAngleDeg・illuminatedFraction(0~1)・elongationDeg・lightDirection(東,北,天頂)・aboveHorizon
579: */
580: function makeMoonPhase($bodies) {
581: $byId = array_column($bodies,NULL,'id');
582: $sun = $byId['Sun']; $moon = $byId['Moon'];
583: $vectors = array();
584:
585: // 太陽と月の地平座標を観測地点からの位置ベクトルへ変換する.
586: foreach (array('Sun'=>$sun,'Moon'=>$moon) as $id=>$b) {
587: $a=deg2rad($b['azimuthDeg']); $h=deg2rad($b['altitudeDeg']); $r=$b['topocentricDistanceKm'];
588: $vectors[$id]=array($r*cos($h)*sin($a),$r*cos($h)*cos($a),$r*sin($h));
589: }
590: $light = array(); $length=0.0;
591:
592: // 三つの軸ごとに月から太陽へのベクトルと長さを求める.
593: for($i=0;$i<3;$i++){ $light[$i]=$vectors['Sun'][$i]-$vectors['Moon'][$i]; $length+=$light[$i]*$light[$i]; }
594: $length=sqrt($length); $cosPhase=0.0;
595:
596: // 照明方向を正規化し,観測者方向との位相角の余弦を求める.
597: for($i=0;$i<3;$i++){ $light[$i]/=$length; $cosPhase-=$light[$i]*$vectors['Moon'][$i]/$moon['topocentricDistanceKm']; }
598: $cosPhase=max(-1.0,min(1.0,$cosPhase));
599: $angle=normalizeAngle($moon['eclipticLongitudeDeg']-$sun['eclipticLongitudeDeg']);
600:
601: // 黄経差が0度付近なら新月付近と案内する.
602: if($angle<10||$angle>=350)$name='新月付近';
603: // 上弦より前の黄経差なら満ちていく月と案内する.
604: else if($angle<80)$name='満ちていく月';
605: // 黄経差が90度付近なら上弦付近と案内する.
606: else if($angle<100)$name='上弦付近';
607: // 上弦から満月の間なら満月へ向かう月と案内する.
608: else if($angle<170)$name='満月へ向かう月';
609: // 黄経差が180度付近なら満月付近と案内する.
610: else if($angle<190)$name='満月付近';
611: // 満月から下弦の間なら欠けていく月と案内する.
612: else if($angle<260)$name='欠けていく月';
613: // 黄経差が270度付近なら下弦付近と案内する.
614: else if($angle<280)$name='下弦付近';
615: // 残りの黄経差では新月へ向かう月と案内する.
616: else $name='新月へ向かう月';
617: return array('name'=>$name,'phaseAngleDeg'=>rad2deg(acos($cosPhase)),
618: 'illuminatedFraction'=>(1.0+$cosPhase)/2.0,'elongationDeg'=>$angle,
619: 'lightDirection'=>$light,'aboveHorizon'=>$moon['aboveHorizon']);
620: }
解説:Canvasへの投影と描画
方角別表示では中心方位からの差を使い、左右45度の範囲を半円へ投影する。図外の天体を除き、星座線は地平線や表示範囲との交点を処理して、見える部分だけを描く。
drawSky() は背景、天の川、補助線、星座線、恒星、太陽系天体、ラベルなどを重ねる。恒星は明るいほど大きく濃くし、B−V色指数 に応じて青白色から淡い黄・橙色へ色分けする。色指数がない恒星には白を使う。
名称は文字の領域が重ならないように配置する。主要恒星名は明るさを優先して表示候補の約半数までに抑え、省略した名称は恒星の選択で確認できる。星座名は代表的なものを優先し、画面全体へ分散させる。
skyMap.php
987: function projectStar(azimuth, altitude) {
988: // 方角別表示では指定方向の左右45度を半円へ投影する.
989: if(viewMode!=='all'){
990: const h=altitude*Math.PI/180,delta=azimuthOffset(azimuth)*Math.PI/180;
991: return {x:center+radius*Math.sin(2*delta)*Math.cos(h),y:mapBase()-radius*Math.sin(h)};
992: }
993: const r = radius * (90 - altitude) / 90, a = azimuth * Math.PI / 180;
994: return {x:center-r*Math.sin(a), y:center-r*Math.cos(a)};
995: }
解説:天の川の描画
JavaScriptの makeMilkyWayLayer() は星図の各画素を inverseProject() で方位・高度へ戻し、観測日の赤道座標からJ2000.0へ逆変換する。その場所の天の川の濃度を補間して、透過画像として重ねる。これにより、日時・地点・表示方向に合わせて天の川の位置も変わる。
この濃淡は星空案内用の概略表現で、光害や月明かりによる見え方を再現するものではない。
解説:地図画面との連携
地図画面からは postMessage() で座標と標高を親画面へ渡す。受信側は送信元、開いたウィンドウ、要求ごとのトークンを確認する。これにより、関係のないページから送られた値をそのまま入力欄へ採用するのを避ける。
標高を取得できなければ NULL を返し、画面では標高を未入力にして手入力を案内する。以前の場所の標高や0mを成功値として流用しない。
skyMap.php
164: /**
165: * 標高を取得する.0mと取得失敗を区別する.
166: * @param float $latitude 緯度(世界測地系,度)
167: * @param float $longitude 経度(世界測地系,東経+,度)
168: * @return float|null 標高(m,−500~9000).取得できない場合はNULL
169: */
170: function getLocationAltitude($latitude, $longitude) {
171: // 住所・緯度・経度に関わるクラス:include_pathが通ったディレクトリに配置
172: require_once('pahooGeoCode.php');
173:
174: $pgc = new pahooGeoCode();
175: $previous = ini_set('default_socket_timeout', '8');
176: try {
177: // XMLを読めない環境では標高取得不能として返す.
178: if (! function_exists('simplexml_load_file')) return NULL;
179: $value = $pgc->getAltitude($latitude, $longitude);
180: return $value !== FALSE && is_numeric($value) && is_finite((float)$value) && $value >= -500 && $value <= 9000 ? (float)$value : NULL;
181: } finally {
182: // 一時的に変更した通信タイムアウトを元へ戻す.
183: if ($previous !== FALSE) ini_set('default_socket_timeout', $previous);
184: }
185: }
解説:画像ファイルへの保存
JPEG・PNG・WebPはCanvasの toBlob() を利用する。要求した形式と実際のMIME型を比較し、対応していない形式を別形式の拡張子で保存しないようにする。
BMPは encodeBmp() で24bit形式を組み立てる。CanvasのRGBAデータからBGRの順へ並べ替え、下の行から保存する。各行の長さを4バイトの倍数へそろえる余白も加える。
skyMap.php
1500: function encodeBmp(source){
1501: const w=source.width,h=source.height,stride=(w*3+3)&~3,buffer=new ArrayBuffer(54+stride*h),v=new DataView(buffer),bytes=new Uint8Array(buffer);
1502: v.setUint16(0,0x4d42,true);v.setUint32(2,buffer.byteLength,true);v.setUint32(10,54,true);v.setUint32(14,40,true);
1503: v.setInt32(18,w,true);v.setInt32(22,h,true);v.setUint16(26,1,true);v.setUint16(28,24,true);v.setUint32(34,stride*h,true);
1504: const rgba=source.getContext('2d').getImageData(0,0,w,h).data;
1505:
1506: // BMPの各走査行を画像の下側から格納する.
1507: for(let y=0;y<h;y++)
1508:
1509: // 各画素のRGBをBMP用のBGR順へ並べ替える.
1510: for(let x=0;x<w;x++){
1511: const s=(y*w+x)*4,d=54+(h-1-y)*stride+x*3;bytes[d]=rgba[s+2];bytes[d+1]=rgba[s+1];bytes[d+2]=rgba[s];
1512: }
1513:
1514: return new Blob([buffer],{type:'image/bmp'});
1515: }
解説:JSON出力とエラー処理
skyMap.php?latitude=35.681&longitude=139.767&height=3.4&datetime=2026-10-22T21%3A00&timezone=Asia%2FTokyo&magnitude=6.0&format=jsonJSONには stars、constellations、lineVertices、bodies、moonPhase、milkyWay などが入る。bodies は地平線下の天体も保持し、地平線上かどうかを aboveHorizon で表す。
不正な入力はHTTP 400、星図の計算やファイル読込に失敗した場合はHTTP 500で通知する。内部の例外内容はサーバーログへ記録し、画面には計算できない旨を表示する。標高取得失敗はHTTP 503と height=null などで通知する。
外部データ生成ツールの使い方
1つ以上の対象を選び、フォルダー保存またはZIP保存を指定して生成する。Chrome・EdgeのlocalhostまたはHTTPS環境では、最初に保存先を選び、その後サーバーが原本を取得・加工する。生成には数分かかることがある。
フォルダー保存は、選択した端末のフォルダーへ相対的な階層を保って書き出す。同名ファイルは置換されるため、既存データは事前にバックアップしていただきたい。対応する保存APIがない場合は、ZIPのダウンロードリンクから保存する。
このツールは利用者の端末へ生成物を保存するものであり、入力した任意のサーバーパスへ書き込む仕組みではない。生成データを星図サーバーへ置く作業は別途必要となる。
解説:原本の取得とデータ変換
builderConstellations() はStellarium Modernの線分をHIP番号で恒星表と対応付け、日本語の星座名・恒星名、名称の配置位置、補助恒星を付ける。星座だけを選択した場合も対応付けにHYGを取得するが、恒星表JSONは出力しない。
builderMilkyway() は天の川の輪郭をGDで塗り、領域の重なりを濃度として加算する。赤経の継ぎ目や輪郭内の穴を処理し、ガウス平滑化で境界をなめらかにして、8bit濃度を行順に並べたバイナリをbase64化する。
VSOP87Dは共通の原本を1回取得し、選択した天体の経度・緯度・距離の全係数を天体別JSONへ分ける。恒星表・星座で共用するHYGも1要求内では共通化する。毎回原本を取得するため、以前保存した原本ファイルには依存しない。
skyMapDataBuilder.php
116: /**
117: * HYG原本から描画用恒星表とHIP索引を作る.
118: * @param string $csv HYG v4.1 CSV本文
119: * @return array catalog(6.5等まで)・byHip(全恒星)の配列
120: * @throws RuntimeException CSV構造・件数が不正
121: */
122: function builderStars($csv) {
123: $fp = fopen('php://temp/maxmemory:5242880', 'w+'); fwrite($fp, $csv); rewind($fp);
124: $header = fgetcsv($fp, 0, ',', '"', ''); $stars = array(); $byHip = array();
125: // 変換に必要な列がそろっていることを確認する.
126: foreach (array('id','hip','ra','dec','mag','ci','pmra','pmdec') as $key) {
127: // CSVの仕様変更は黙って読み飛ばさず中断する.
128: if (!is_array($header) || !in_array($key, $header, true)) throw new RuntimeException('HYG列不足: '.$key);
129: }
130: // 恒星ごとに単位を変換し,HIP索引と明るい恒星の表を作る.
131: while (($row = fgetcsv($fp, 0, ',', '"', '')) !== false) {
132: // 欠落行は不正な原本として扱う.
133: if (count($row) !== count($header)) throw new RuntimeException('HYG CSV行の列数が不正です.');
134: $s = array_combine($header, $row);
135: // 太陽と等級未収録の天体を除く.
136: if ((int)$s['id'] === 0 || $s['mag'] === '') continue;
137: $v = array((int)$s['id'], (int)$s['hip'], (float)$s['ra']*15, (float)$s['dec'],
138: (float)$s['mag'], $s['ci']==='' ? null : (float)$s['ci'], (float)$s['pmra'], (float)$s['pmdec']);
139: // HIP番号を持つ恒星を星座線の端点参照に使う.
140: if ($v[1]) $byHip[$v[1]] = $v;
141: // 星空マップの最大限界等級までを出力する.
142: if ($v[4] <= 6.5) $stars[] = $v;
143: }
144: fclose($fp);
145: // 想定外の原本を検出するため,既知のv4.1件数を確認する.
146: if (count($stars) !== 8920) throw new RuntimeException('HYG v4.1の恒星数が想定と異なります: '.count($stars));
147: return array('catalog'=>array('source'=>'HYG v4.1 / David Nash (Astronexus)', 'license'=>'CC BY-SA 4.0',
148: 'epoch'=>2000.0, 'columns'=>array('id','hip','raDeg','decDeg','mag','bv','pmRaCosDecMasYr','pmDecMasYr'),
149: 'stars'=>$stars), 'byHip'=>$byHip);
150: }
解説:生成記録とフォルダー・ZIP保存
builderZip() はZIPのローカルヘッダー、各ファイル、中央ディレクトリー、終端レコードを pack() で作る。ファイル内容は無圧縮で、CRC-32とUTF-8のファイル名フラグを付ける。このため ZipArchive 拡張を必要としない。
ブラウザーはPOSTで生成を要求し、ファイル内容とZIPをbase64で受信する。フォルダー保存では受信した相対パスを確認してから必要な階層を作り、ZIP保存では showSaveFilePicker() で得た保存先へ書き込む。処理が途中で失敗した場合にも取り出せるよう、生成済みZIPへのリンクを残す。
コマンドラインから全対象を生成する場合は、次のように実行できる。星図本体や共通PHPクラスを生成するものではない。
php skyMapDataBuilder.php all skyMap-data.zip
skyMapDataBuilder.php
351: /**
352: * UTF-8ファイル名対応の無圧縮ZIPを作る(ZipArchive拡張不要).
353: * @param array $files 相対パスをキー,ファイル本文を値とする配列
354: * @return string ZIPバイナリ
355: */
356: function builderZip($files) {
357: $zip = ''; $central = ''; $count = 0; $date = (46<<9) | (1<<5) | 1;
358: // ファイル本体と中央ディレクトリーを順に構築する.
359: foreach ($files as $name=>$body) {
360: $offset = strlen($zip); $size = strlen($body); $crc = crc32($body); $n = strlen($name);
361: $zip .= pack('VvvvvvVVVvv', 0x04034b50, 20, 0x800, 0, 0, $date, $crc, $size, $size, $n, 0).$name.$body;
362: $central .= pack('VvvvvvvVVVvvvvvVV', 0x02014b50, 20, 20, 0x800, 0, 0, $date, $crc, $size, $size, $n, 0, 0, 0, 0, 0, $offset).$name;
363: $count++;
364: }
365: return $zip.$central.pack('VvvvvVVv', 0x06054b50, 0, 0, $count, $count, strlen($central), strlen($zip), 0);
366: }
外部データの出典とライセンス
VSOP87Dの配布元は、自身の作業をPublic Domainとする宣言と、元理論は自身の作業ではない旨を記している。この宣言を第三者の作業まで広げて解釈せず、付属する権利資料を確認する。生成データ一式をMIT Licenseへ変更する扱いにはしない。
保存画像にもデータの出典とライセンス表記を残す。地図サービスの帰属表示もそれぞれの条件に従う。
仕様書にある確認事項として、現行画面にはVSOP87Dの common/vsop87/LICENSE.txt への直接リンクと宣言の適用範囲の説明が不足している。本記事では出典を明示したが、配布物・画面側の権利表記の補完は別途必要である。
| データ | 出典・加工 | ライセンス等 |
|---|---|---|
| 恒星表 | HYG v4.1/David Nash(Astronexus)。等級抽出、列削減、単位変換 | CC BY-SA 4.0 |
| 星座線・名称 | Stellarium Modern/Stellarium team。HIP番号の対応、日本語名・配置位置・補助恒星を追加 | CC BY-SA 4.0。星座イラストは使用しない |
| 天の川 | D3 Celestial/Olaf Frohn、原輪郭Jose R. Vieira。濃度画像化・平滑化 | BSD 3-Clause |
| 惑星係数 | VSOP87D/Bureau des Longitudes、JSON配布Greg A. Miller。天体別に全項を抽出 | 配布元のLICENSE.txtとsource.txtを保持 |
計算条件と注意点
標高を含む観測点からの視差は補正するが、標高による地平線の低下は加算しない。山・建物による遮蔽も考慮しないため、高度が正の天体でも実際には見えない場合がある。
天体の記号は実際の見かけの直径や惑星の明るさを再現しない。月の表示には月面模様、秤動、月食の影を含まない。
また、光害・薄明・月明かり・雲の影響は再現しない。表示された恒星や天の川が、その場所・時刻に肉眼で見えるという意味ではない。星の方角や時刻による変化を学ぶ用途に活用していただきたい。
参考サイト
- PHPでホロスコープを描く:ぱふぅ家のホームページ
- PHPで惑星の位置を一覧表示する:ぱふぅ家のホームページ
- PHPで惑星の天象を一覧表示する:ぱふぅ家のホームページ
- PHPで地図で指定した場所の天気予報を求める:ぱふぅ家のホームページ
- 各種クラウド連携サービス(WebAPI)の登録方法:ぱふぅ家のホームページ
- DateTimeImmutable::createFromFormat:PHPマニュアル
- キャンバスAPI:MDN
- HYG Stellar database:David Nash(Astronexus)
- Stellarium Modern sky culture:Stellarium team
- D3 Celestial:Olaf Frohn
- D3 Celestial LICENSE
- VSOP87 Multi-Language:Greg A. Miller
- VSOP87 Multi-Language LICENSE.txt
- 表示-継承4.0国際(CC BY-SA 4.0):Creative Commons

地図から観測地点を選ぶ機能と、表示した星図を画像として保存する機能も用意した。さらに、恒星表などの原本を取得・加工する skyMapDataBuilder.php も紹介する。
本記事は skyMap.php と skyMapDataBuilder.php のバージョン1.0.0を対象とする。星空案内や学習のためのサンプルであり、計算の条件と限界は「計算条件と注意点」にまとめた。