2地点の緯度経度から(おおよその)距離を計算してみよう

公開日:2025-04-11

注意

本記事は情報提供を目的としており、本記事の内容は無保証、サポートの対象外です。
サポート窓口、問合せ窓口にご質問をいただいても対応いたしかねますのでご了承ください。

こんにちは、ゆーいちです。

4月は東京で大きな展示会があります。

この展示会には弊社もブースを出しており、大阪在住の私も説明員として参加する予定なのですが、この出張申請を出そうとして ふと疑問がよぎりました。

そういえば大阪から東京までの直線距離ってどれぐらいなのだろう……?

距離…… おおよその値ならカスタマインで計算できたりしないかな……?

という事で、試してみました。

緯度経度を得よう

まずそもそもの話として、「大阪から東京までの距離」は、「2つの地点の座標(平たく言うと緯度経度)間の距離」と言えます。

さて、地点の緯度経度についてはどうやれば得られるでしょうか?

実は、gusuku Customineなら簡単に緯度経度を取得する事ができます。

具体的には、やること「ユーザーの現在位置を取得する」で現在位置の緯度経度を取得する事もできますし、やること「住所から緯度経度を取得する」で住所から緯度経度を取得する事もできます。

※注:後者の「住所から緯度経度を取得する」はGoogle MapsのAPIキーが必要となり、すこし敷居が高くなってしまうので、この記事ではやること「ユーザーの現在位置を取得する」を元にカスタマイズを作成しています。

緯度経度を得るためのカスタマイズ例

具体的に、やること「ユーザーの現在位置を取得する」を使った緯度経度の取得例を説明します。

なお、出てくるフィールドタイプ全て、数値フィールドになるので、アプリの作成例については割愛します。

3つのアクションで現在位置の緯度経度をフィールドにセットします。

1)ボタンを配置

ここは単にボタンを配置しているだけです。やること「ボタンをフィールド名の右に配置する」と、条件「追加画面・編集画面を表示した時」を使っています。

2)緯度経度を取得

やること「ユーザーの現在位置を取得する」を使って、現在の緯度経度を取得します。この「やること」を動かし、アクションの結果から値(緯度と経度)を得ます。

3)緯度経度をフィールドにセット

やること「フィールド値をまとめてセットする」を使い、緯度と経度それぞれのフィールドに値を一度にセットしています。

※なぜ、こういうマッピングになるのかは、やること「ユーザーの現在位置を取得する」の「使い方」に説明があるので、併せて見てみてください。

上記の緯度・経度のフィールドと、カスタマイズを2セット用意すると、次のようなアプリになると思います。

これで、kintoneのアプリ上で2つの地点の緯度経度を取得し、値を保存できるようになりました。

緯度経度のペアから距離を計算するには?

まずは簡単に、緯度経度のペアから距離をどうやれば計算できるのか?を考えてみましょう。


地球を「真球(完璧な球)」と仮定した場合、2点の緯度・経度から距離を求める方法は、「球面上の2点間の最短距離(大円距離)」というものを使います。

その上で、「球の表面にある2点が、中心を通る円(大円)に沿ってどれくらい離れてるか?」を三角関数で計算し、それに地球の半径(約 6371 km)を掛けて距離を出す事で、計算することができます…… が、この方式は精度が少し甘くなります。なぜでしょうか?

そう、地球は自転しているからです。

地球は自転しているため、その回転によって生じる遠心力が働きます。

この時、遠心力は赤道付近で最も強く、極ではゼロになります。

この遠心力が赤道方向に膨らむように地球を引っ張るため、地球は赤道半径が極半径よりも大きくなります。

そのため、より正確な数値を算出したい場合はその影響を考慮した式を用いると、より正確な値を求める事ができます(とはいえ、どの方式でも多少の計算誤差は出るようです)。

三角関数がでてくるよねコレ

さて、上ではしれっと流してしまいましたが、三角関数がでてきました。ウッ頭が……!

ここで質問です。kintoneやカスタマインでは三角関数って取り扱えるんでしたっけ?

かんがえてみましょう……

kintoneの基本機能には今の所、三角関数を取り扱えるような機能はありません。

カスタマインの「やること」にも今の所、三角関数そのものの「やること」はありません。

ですが、カスタマインの「やること」には「JavaScript を実行する」があります!

ということで、JavaScriptで三角関数を使って距離計算を実現する事にします。

また今回は、測地線航海算法(Geodesic Sailing)のC言語での実装をJavaScriptに置き換えたものを採用しました。

参考にしたC言語実装:緯度経度から2地点間の距離を求める方法とその比較 #C – Qiita

4つのアクションで緯度経度のペアから2地点間の距離を計算します。

1)ボタンを配置

ここは単にボタンを配置しているだけです。やること「ボタンをフィールド名の右に配置する」を使っています。

2)レコードデータを退避

ここでは、やること「編集中のレコードデータを退避する」を使っています。条件は「ボタンを押した時」「複数フィールドのうちどれか1つ以上が空ならば(を反転させた「複数フィールドのすべてが空でないならば」)」を使っています。

※反転については、記事「追加条件は反転できます」を併せてご覧ください。

なぜ、やること「編集中のレコードデータを退避する」をここで使っているかというと、後述するJavaScriptの文中で、現在のレコードの値を簡単に取得して用いる為です。

ここでは、やること「JavaScript を実行する」を使っています。

JavaScriptのコードは次の通りです。

const EARTH_RAD = 6378.137; // km

const RX = 6378.137; // 回転楕円体の長半径(赤道半径)[km]
const RY = 6356.752; // 回転楕円体の短半径(極半径) [km]

function deg2rad(deg) {
  return deg * Math.PI / 180.0;
}

function cal_distance2(x1, y1, x2, y2) {
  const p1 = Math.atan(RY / RX * Math.tan(y1)); // 地点Aの化成緯度
  const p2 = Math.atan(RY / RX * Math.tan(y2)); // 地点Bの化成緯度
  const X = Math.acos(Math.sin(p1) * Math.sin(p2) + Math.cos(p1) * Math.cos(p2) * Math.cos(x1 - x2)); // 球面上の距離
  const F = (RX - RY) / RX; // 扁平率
  // 距離補正量
  const dr = F/8 * ((Math.sin(X)-X)*Math.pow((Math.sin(p1)+Math.sin(p2)), 2.0)/Math.pow(Math.cos(X/2), 2.0) - (Math.sin(X)+X)*Math.pow((Math.sin(p1)-Math.sin(p2)), 2.0)/Math.pow(Math.sin(X/2), 2.0));
  return RX * (X + dr); // 距離[km]
}

return cal_distance2(deg2rad(customine[8].経度1.value),deg2rad(customine[8].緯度1.value),deg2rad(customine[8].経度2.value),deg2rad(customine[8].緯度2.value));

なお、アクションの結果は「customine[【アクション番号】]」で取得することができ、やること「編集中のレコードデータを退避する」のアクションの結果は上記のソースコードの最後の行のように取り扱う事ができます。

先ほどのやること「JavaScript を実行する」のコード中でreturnした戻り値はアクションの結果として取得できるので、これをやること「フィールドに値をセットする」でセットすれば完成です。

実行してみた

今回は、gusuku Ashibinaa OSAKAgusuku Ashibinaa Tokyo の2地点間の距離を計算してみました。

※出てくる距離の単位はKmです。

これだけだと合っているのかどうかよくわからないのですが、国土地理院が 測量計算(距離と方位角の計算) というページを公開してくれているので、このページで検算をしてみます。

ほぼほぼ、合っていそうです(400Kmあって、1m以内の誤差なら「おおよそ」としては御の字でしょう)。

やること「JavaScript を実行する」は、チャットサポートを受ける事ができない「やること」ですが、JavaScriptのパワーを恩恵として受けられるので、ケースによっては非常に強力な処理が実現できる事があります。

ぜひ、機会があれば挑戦してみてください!

投稿者プロフィール

アバター画像
ゆーいち
ドキュメントを書いています。また、たまにISMSと向き合っています。