はじめまして、こんにちは。
今年の4月から新卒入社したエンジニアの矢尾(@80momoka)です。
弊社が以前から運営している「#きぼうを見よう」に、
新たに「ARきぼう予報」という機能が追加されました。
#きぼうを見よう
https://lookup.kibo.space/
AR機能はスマートフォンでご覧ください。
#きぼうを見よう のサイトに、新機能「🆕ARきぼう予報」が追加されました🎉
— KIBO宇宙放送局 (@KIBO_SPACE) 2021年10月6日
スマホを空にかざすだけで、ISSの現在地や軌道予測がわかります✌️これからはもっとISSを探しやすくなりますよ!🛰️
今夜のISSは日本上空を通過予定。ぜひ、あなたの上空の予報を見てみてね!https://t.co/qVOXuh8k5T
このARきぼう予報の中で、方角と位置関係をわかりやすくするために、周囲の都道府県がどの方角にあるかを示す表記をいれています。(下画像、赤い枠内に〇〇方面と表記)
この都道府県名を表示する際に、ユーザーが今いる県は非表示にしています。そのために現在地から都道府県を割り出す必要があり、簡易的な逆ジオコーディングを独自実装したので、それについて書きたいと思います。
逆ジオコーディングとは
まずジオコーディングとは、住所などから座標(緯度経度)を取得する機能のことで、
逆ジオコーディングとは文字通り逆の、座標(緯度経度)から住所を取得する機能のことです。
ARきぼう予報ではISSの軌道予報を計算するために、既にユーザーの現在地の緯度経度を取得していたため、そのデータを使用して地名を取得しようとしました。
逆ジオコーディングのAPIを探しましたが、有料であったり利用制限があったりと、望ましいものが見つからなかったため作ることになりました。
取得の流れ
全国各地の住所とその緯度経度のデータから、現在地の緯度経度と一番近い距離のデータを探し出し、その住所を取得しています。
全国各地の住所と緯度経度のデータは、国土交通省が提供している位置参照情報を使用しました。
国土交通省 位置参照情報ダウンロード
https://nlftp.mlit.go.jp/cgi-bin/isj/dls/_choose_method.cgi
各データは以下のようになっています。
{
'都道府県コード': '01',
'都道府県名': '北海道',
'市区町村コード': ' 01101',
'市区町村名': '札幌市中央区',
'大字町丁目コード': ' 011010001001',
'大字町丁目名': '旭ケ丘一丁目',
'緯度': '43.042230',
'経度': '141.319722',
'原典資料コード': '0',
'大字・字・丁目区分コード': '3'
}
このデータが羅列されたCSVファイルのままだとサイズがとても大きく扱いにくいため、
まずはJavaScriptから扱いやすいようにjsonを作成することにしました。
JavaScriptで現在地の都道府県を割り出す仕組みとしては、以下のように考えました。
上の画像のように、緯度経度の値ごとに区切った座標検索データを作って、現在地の緯度経度が含まれている範囲のデータの中から一番距離の近いデータを探し出します。
円が重なっている所はデータが重複しますが、距離を計算するための緯度経度の値があればいいので、都道府県や市区町村などの住所のデータは別で分けて緯度経度のみのファイルにします。住所データは、緯度経度のデータと対になるidを付けて、id 1~100、101~200…とファイルを分けます。
ただ今回の実装では、都道府県のみ取得できればよく、そこまで厳密な市区町村情報までは不必要であったため、データの重複をなくし、下の画像のように経度ごとのみで分けました。
(左:経度ごとに分けるイメージ 右:分けて作成した緯度経度情報のみのjsonファイル)
今回は経度0.1度ずつに分けてjsonファイルにまとめました。
件数の少ない経度127.5度以下や145度以上、128度以上129度未満(沖縄県の東側〜鹿児島県大島郡付近)はそれぞれまとめて一つのファイルにしています。
データを割り出す際は、現在地の経度と一致するjsonファイル(127.5度台であれば1275.json)を指定し、その中から現在地の緯度経度と一番距離が近いデータを探し出して割り出します。
しかしこのままだと、例えば下図のように赤●が現在地で★が一番近い市区町村だとしても、黄●の市区町村を取得してしまいます。精度を上げるために、赤●を含むデータとその左右のデータも含めた中から、一番近い距離のデータを探します。
今回の機能では、都道府県名のみ割り出せたらよく厳密な市区町村情報までは不必要であるため、現在地の経度を含む範囲のファイル内のみで割り出しています。
また、今後もし精度が求められる機能が追加されることがあった時に、データを使いやすいように緯度経度と住所に分けたままにしています。
(左:緯度経度のみのファイル 右:住所のみのファイル)
周囲の都道府県を選出・表示
まず各都道府県の県庁所在地の緯度経度と県名、ARに表示する名前をリストにしたものを用意します。
static list = [
{'lat':43.06417, 'lng':141.34694, 'name':'北海道', 'label':'北海道方面'},
{'lat':40.82444, 'lng':140.74, 'name':'青森県', 'label':'青森方面'},
…
このリストの中から、現在地の緯度経度と距離が近い順に取得します。
ユーザーがいる場所の県名は非表示にしたかったので、逆ジオコーディングで取得した県名とリストのデータ内の県名を照らし合わせて、合致しているものは省きます。
また今回は近隣の県のみ表示したかったので、ある程度距離が離れている県はこの時点で省きました。
県庁所在地がある方向を単純に2点の緯度経度から求めようとしたものの、地球は球体であるため簡単な計算ではズレが生じてしまいました。
現在地から各地点への正確な方角を求めるのは、geodesyというライブラリ内のコードを使用しました。
geodesy
https://www.npmjs.com/package/geodesy
Geodesy functions | Class: LatLonEllipsoidal_Vincenty finalBearingTo()
https://www.movable-type.co.uk/scripts/geodesy/docs/module-latlon-ellipsoidal-vincenty-LatLonEllipsoidal_Vincenty.html#finalBearingTo
Javascriptで2地点間の距離と方角を計算するライブラリ
https://thr3a.hatenablog.com/entry/20190502/1556772556
finalBearingTo()という関数にて取得した方角(0~360の値)をもとに、3D空間内に配置しています。
const len = 360;
const step = Math.PI * 2 / len;
const size = this.ar.dome.size;
const point = { 'lat':lat, 'lon':lng };
const angle = this.finalBearingTo(point);
// pos
let x = Math.sin(step * angle) * size;
let y = offsetY;
let z = Math.cos(step * angle) * size * -1;
youtu.beこのようにユーザーの周りに県名を表示することで、自分がどこ方面を向いているのかわかるようになり、ISSがいま日本のどこの上空を通過しているのか想像しやすくなっているのではないかと思います。
エンジニアを募集しています
私自身はまだエンジニア一年生ですが、バスキュールには凄いエンジニアの方がたくさんいらっしゃいます。
見たこともない新しいコンテンツを、企画から制作まで一緒に作っていけるのが非常に楽しいです。
また、かっちり決まった部署や働き方があるわけではないので、望めば様々なことに挑戦できる環境だと思います。
バスキュールの働き方に興味がありましたらぜひご応募ください。