目次
サンプル・プログラムの実行例
YOLPコンテンツジオコーダAPI(Yahoo!JAPAN)は、世界のキーワードから緯度・経度を求める機能が弱い。たとえば「サンティアゴ」でキーワード検索すると、Google Geocoding API チリの首都を第一候補として返すが、YOLPコンテンツジオコーダAPIはドミニカ共和国の県都しか返さない。
そこで、地図上のマーカーをドラッグし、計算ボタンを押すことで射程を再描画する機能を採り入れた。これは Googleマップ でも利用できる。
サンプル・プログラム
| ballistic.php | サンプル・プログラム本体 |
| .pahooEnv | クラウドサービスを利用するためのアカウント情報などを記入する .env ファイル。 使い方は「各種クラウド連携サービス(WebAPI)の登録方法」を参照。include_path が通ったディレクトリに配置すること。 |
| pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
| pahooGeoCode.php | 住所・緯度・経度に関わるクラス pahooGeoCode。 使い方は「PHPで住所・ランドマークから最寄り駅を求める」などを参照。include_path が通ったディレクトリに配置すること。 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 2.6.1 | 2025/09/19 | マーカードラッグ後に再描画で位置ズレを解消 |
| 2.6.0 | 2025/09/19 | jsDragMarker_Leaflet(), jsDrawLine_Leaflet() 追加 |
| 2.5.0 | 2025/08/31 | .pahooEnv導入 |
| 2.4.0 | 2025/07/20 | GoogleMapsAPIのAdvancedMarkerに対応 |
| 2.3 | 2021/03/28 | PHP8対応,リファラ・チェック改良 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 6.8.0 | 2025/08/10 | アクセスキーなどを ".pahooEnd" に分離 |
| 6.7.1 | 2025/07/26 | jsLine_Gmap() - bug-fix |
| 6.7.0 | 2025/07/20 | drawJSmap,drawGMap -- 引数 $markerLevel 追加 |
| 6.6.0 | 2025/07/19 | drawJSmap,drawGMap,drawLeaflet -- マップ中心マーカー表示引数を追加 |
| 6.5.0 | 2025/06/14 | GoogleMaps JavaScript APIの変更に対応 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 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() 追加 |
弾道方程式
末尾に、参考サイトや参考書籍を掲げた。ぜひご覧いただきたい。
発射点をa、着弾点をbとすると、地表面に沿った円弧acbを射程(range)と呼ぶ。acbの左側は地中に潜っていると考えてほしい。
射程を、地球中心から見た角度φを半射程角(semi-range angle)と呼ぶ。射程をS、地球の半径をR(6,378,136m)とすると、φは次の式によって求められる。
$$ \phi = \frac{S}{2R} $$
ミサイルの最終段のロケットモーターが燃え切ったときの速度比をvoとすると、次の式によって求められる。 $$ \displaystyle \begin{align} v_o &= \sqrt{\frac{-B+\sqrt{B^2-AC}}{A}} \\ A &= \sin^2\gamma \ (\cos^2\phi - \sin^2\gamma) \\ B &= \sin^2\gamma \ (1 - \cos^2\phi) \\ B &= \cos^2\phi - 1 \end{align} $$
$$ hm = a (1 - e) - R $$
軌道上の速度は変化する。地球中心に対する軌道上の角度をθ、地上の引力係数をμとすると、θにおける動径rと、動径上の速度vは、次の式によって求められる。 $$ \displaystyle \begin{align} \mu &= 3.986044\times10^{14}m^3s^{-2} \\ r &= \frac{a (1 - e^2)}{1 - e \cdot \cos \theta} \\ v &= \sqrt{\mu (\frac{2}{r} - \frac{1}{a}}) \end{align} $$
準備:PHP の https対応
Windowsでは、"php.ini" の下記の行を有効化する。
extension=php_openssl.dllLinuxでは --with-openssl=/usr オプションを付けて再ビルドする。→OpenSSLインストール手順
これで準備は完了だ。
準備:pahooInputData 関数群
また、各種クラウドサービスに登録したときに取得するアカウント情報、アプリケーションパスワードなどを登録した .pahooEnv ファイルから読み込む関数 pahooLoadEnv を備えている。こちらについては、「各種クラウド連携サービス(WebAPI)の登録方法」をご覧いただきたい。
準備:pahooGeoCode クラス
pahooGeoCode.php
40: class pahooGeoCode {
41: public $items; // 検索結果格納用
42: public $error; // エラー・フラグ
43: public $errmsg; // エラー・メッセージ
44: public $hits; // 検索ヒット件数
45: public $webapi; // 直前に呼び出したWebAPI URL
46:
47: // -- 以下のデータは .env ファイルに記述可能
48: // Google Cloud Platform APIキー
49: // https://cloud.google.com/maps-platform/
50: // ※Google Maps APIを利用しないのなら登録不要
51: public $GOOGLE_API_KEY_1 = ''; // HTTPリファラ用
52: public $GOOGLE_API_KEY_2 = ''; // IP制限用
53: public $GOOGLE_MAP_ID = ''; // GoogleMaps ID
54:
55: // Yahoo! JAPAN Webサービス アプリケーションID
56: // https://e.developer.yahoo.co.jp/register
57: // ※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
58: public $YAHOO_APPLICATION_ID = '';
59:
60: // OSM Nominatim Search API利用時に知らせるメールアドレス
61: // https://wiki.openstreetmap.org/wiki/JA:Nominatim#.E6.A4.9C.E7.B4.A2
62: // ※OSM Nominatim Search APIを利用しないのなら登録不要
63: public $NOMINATIM_EMAIL = '';
64:
65: // IP2Location.io APIキー
66: // https://www.ip2location.io/
67: // ※IP2Location.ioを利用しないのなら登録不要
68: 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アドレスやホスト名から住所を求める」を、それぞれ参照されたい。
PHPのクラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。
準備:地図サービスの選択
ballistic.php
53: // 地図描画サービスの選択
54: // 0:Google
55: // 2:地理院地図・OSM
56: define('MAPSERVICE', 2);
57:
58: // 住所検索サービスの選択
59: // 0:Google
60: // 1:Yahoo!JAPAN
61: // 11:HeartRails Geo API
62: // 12:OSM Nominatim Search API
63: define('GEOSERVICE', 1);
64:
65: // 逆ジオコーディングサービスの選択
66: // 0:Google
67: // 1:Yahoo!JAPAN
68: // 11:HeartRails Geo API
69: // 21:簡易ジオコーディングサービス
70: define('REVGEOSERVICE', 1);
住所検索サービスは、Google、Yahoo!JAPAN、HeartRails Geo API、OSM Nominatim Search API から選べる。あらかじめ、定数 GEOSERVICE に値を設定すること。
逆ジオコーディングサービスは、Google、Yahoo!JAPAN、HeartRails Geo API、簡易ジオコーディングサービスから選べる。あらかじめ、定数 REVGEOSERVICE に値を設定すること。
解説:初期値
ballistic.php
72: // マップの表示サイズ(単位:ピクセル)
73: define('MAP_WIDTH', 600);
74: define('MAP_HEIGHT', 400);
75: // マップID
76: define('MAPID', 'map_id');
77:
78: // 初期値
79: define('DEF_LONGITUDE0', 165.0); // 中心座標(経度)
80: define('DEF_LATITUDE0', 30.5); // (緯度)
81: define('DEF_TYPE', 'roadmap'); // マップタイプ
82: define('DEF_ZOOM', 3); // ズーム
83: define('DEF_CATEGORY', 'world'); // カテゴリ
84:
85: // 発射点
86: define('DEF_FROM', '東倉里ミサイル発射場'); // 地名
87: define('DEF_CAT_FROM', 'world'); // カテゴリ
88: define('DEF_LATITUDE1', 39.660075); // 緯度
89: define('DEF_LONGITUDE1', 124.705294); // 経度
90:
91: // 着弾点
92: define('DEF_TO', 'ホノルル'); // 地名
93: define('DEF_CAT_TO', 'world'); // カテゴリ
94: define('DEF_LATITUDE2', 21.308889); // 経度
95: define('DEF_LONGITUDE2', -157.826111); // 経度
96:
97: define('DEF_HM', 1500); // 弾道高(km)
初回起動時に表示する発射点は、北朝鮮の東倉里ミサイル発射場、着弾地点はハワイ・ホノルルとしてある。弾道高は1500kmである。
解説:マーカー設定など
解説:射程,弾道高から軌道要素を求める
ballistic.php
479: /**
480: * 射程,射角から軌道要素を求める
481: * @param double $dt 射程(メートル)
482: * @param double $aof 射角(度)
483: * @param array $elements 軌道要素を格納する配列
484: * @return なし
485: */
486: function getOrbitalElementSub($dt, $aof, &$elements) {
487: static $r = 6378136; // 地球半径(メートル)
488:
489: // ラジアン変換
490: $aof = deg2rad(90 - $aof);
491:
492: $sra = $dt / (2 * $r); // 半射程角
493:
494: $ax = pow(sin($aof), 2) * (pow(cos($sra), 2) - pow(sin($aof), 2));
495: $bx = pow(sin($aof), 2) * (1 - pow(cos($sra), 2));
496: $cx = pow(cos($sra), 2) - 1;
497:
498: $vo = sqrt((-$bx + sqrt(pow($bx, 2) - $ax * $cx)) / $ax); // 燃え切り速度比
499: $e = sqrt(1 - pow($vo, 2) * (2 - pow($vo, 2)) * pow(sin($aof), 2)); // 離心率
500: $a = $r / (2 - pow($vo, 2)); // 長径
501: $b = $a * sqrt(1 - pow($e, 2)); // 短径
502: $hmm = $a * (1 + $e) - $r; // 弾道高
503:
504: $elements['sra'] = $sra;
505: $elements['vo'] = $vo;
506: $elements['e'] = $e;
507: $elements['a'] = $a;
508: $elements['b'] = $b;
509: $elements['hmm'] = $hmm;
510: }
ballistic.php
512: /**
513: * 射程,弾道高から軌道要素を求める
514: * @param double $dt 射程(メートル)
515: * @param double $hmm 弾道高(メートル)
516: * @param array $elements 軌道要素を格納する配列
517: * @return なし
518: */
519: function getOrbitalElement($dt, $hmm, &$elements) {
520: $flag = TRUE;
521: $aof = 0.0; // 射角(度)
522:
523: // 誤差0.1度で射角を求める
524: while ($flag && ($aof < 90.0)) {
525: $aof += 1.0;
526: getOrbitalElementSub($dt, $aof, $elements);
527: if ($elements['hmm'] == $hmm) {
528: $flag = FALSE;
529: break;
530: } else if ($elements['hmm'] > $hmm) {
531: $aof -= 1.0;
532: while ($flag && ($aof < 90.0)) {
533: $aof += 0.1;
534: getOrbitalElementSub($dt, $aof, $elements);
535: if ($elements['hmm'] >= $hmm) {
536: $flag = FALSE;
537: break;
538: }
539: }
540: }
541: }
542: $elements['dt'] = $dt;
543: $elements['aof'] = $aof;
544: }
そこで本プログラムでは、射角の代わりに弾道高を入力して、軌道要素を求める関数 getOrbitalElement を用意した。
弾道高から射角を逆算することは難しいので、射角を0.1度ずつ増やし、ユーザー関数 getOrbitalElementSub を呼び出し、与えられた弾道高にほぼ近づいたら計算を打ち切るという方法で軌道要素を求めている。
計算回数を減らすため、初段は1度ずつ射角を増やし、近づいてきたら0.1度ずつ増やすようにしている。
解説:軌道要素から、飛翔経路長、速度を求める
ballistic.php
447: /**
448: * 軌道要素から、飛翔経路長、速度を求める
449: * @param array $elements 軌道要素
450: * @return なし
451: */
452: function getBallistic(&$elements) {
453: static $u = 3.98602e+14; // 地心引力係数
454: $n = 100; // 分割数
455:
456: $dw = $elements['sra'] / $n;
457: $ds = 0.0; // 飛翔経路長
458: $vs = 0.0;
459: $vmax = 0.0; // 最大速度
460: for ($i = 0; $i <= 100; $i++) {
461: $r = $elements['a'] * (1.0 - pow($elements['e'], 2)) / (1.0 - $elements['e'] * cos($dw * $i));
462: $v = sqrt($u * ((2.0 / $r) - (1.0 / $elements['a'])));
463: if ($v > $vmax) $vmax = $v;
464: $vs += $v;
465: if ($i == 0) $tmp1 = $r;
466: else $tmp2 = $r;
467: if ($i > 1) {
468: $dx = $tmp2 * sin($dw);
469: $dy = $tmp1 - $tmp2 * cos($dw);
470: $ds += sqrt(pow($dx, 2) + pow($dy, 2));
471: $tmp1 = $tmp2;
472: }
473: }
474: $elements['ds'] = $ds * 2;
475: $elements['vm'] = $vs / ($n + 1);
476: $elements['vmax'] = $vmax;
477: }
そこで、「弾道方程式」で紹介した動径を使って、動径角を100分割して、それを足していくことで飛翔経路長を近似している。
同時に速度を100回求め、平均速度と最高速度を計算している。
解説:軌道要素の計算
ballistic.php
847: // 軌道要素の計算
848: if (($hm > 0) && ($items['longitude1'] != '') && ($items['latitude1'] != '') && ($items['longitude2'] != '') && ($items['latitude2'] != '')) {
849: $dt = $pgc1->distance($items['longitude1'], $items['latitude1'], $items['longitude2'], $items['latitude2']);
850: $items['hmm'] = $hm * 1000;
851: getOrbitalElement($dt, $hm * 1000, $items);
852: getBallistic($items);
853: }
854:
855: // 地図描画サービス
856: switch (MAPSERVICE) {
857: // Google
858: case 0:
859: $call = jsDragMarker_Gmap($items2[$i]['latitude'], $items2[$i]['longitude']);
860: $call .= jsDrawLine_Gmap(1, $items1, 'rgb(255, 0, 0)', 1);
861: $call .= jsDrawLine_Gmap(2, $items2, 'rgb(0, 0, 0)', 1);
862: $zd = 1;
863: break;
864: // Yahoo!JAPAN
865: case 1:
866: $call = jsDragMarker_YOLPmap($items2[$i]['latitude'], $items2[$i]['longitude']);
867: $call .= jsDrawLine_YOLPmap(1, $items1, 'FF0000', 1);
868: $call .= jsDrawLine_YOLPmap(2, $items2, '000000', 1);
869: $zd = 0;
870: break;
871: // 地理院地図・OSM
872: case 2:
873: $call = jsDragMarker_Leaflet($items2[$i]['latitude'], $items2[$i]['longitude']);
874: $call .= jsDrawLine_Leaflet(1, $items1, 'FF0000', 1);
875: $call .= jsDrawLine_Leaflet(2, $items2, '000000', 1);
876: $zd = 0;
877: break;
878: default:
879: $call = '';
880: $zd = 0;
881: break;
882: }
883: $lat = $items2[$i]['latitude'];
884: $lng = $items2[$i]['longitude'];
885:
886: // エラー発生時
887: } else {
結語
参考サイト
- PHPで大圏航路を描く:ぱふぅ家のホームページ
- PHPで2地点間の直線距離を求める:ぱふぅ家のホームページ


そこで今回は、マップ上で発射地点と着弾地点を指定し、弾道の最高点の高さを入力するだけで、軌道要素と弾道を計算するPHPプログラムをつくってみることにする。
ユーザーインターフェースは、「PHPで大圏航路を描く」を流用した。
なお、作者の力不足から、コリオリの力、多段ロケットによる加速、弾頭の形状・材質、地球大気による減速など、物理的な諸条件は含めていない。大まかな検証をすることが目的だと考えていただきたい。
(2025年9月19日)マーカードラッグ後に再描画するとマーカーの位置が戻ってしまう不具合を解消.jsDragMarker_Leaflet(), jsDrawLine_Leaflet 追加.
(2025年8月31日).pahooEnv導入
(2025年7月20日)GoogleMaps JavaScript APIのAdvancedMarkerに対応
(2025年6月14日)GoogleMaps JavaScript APIの変更に対応した.