緯度・経度の位置情報から高度・標高を取得したい

スポンサーリンク
スポンサーリンク

標高を知りたい

先日行った権現岳への山行の際、ログ取りを行っていたものの、センサーが外れてしまっており気圧と温度のログが取れていなかった。いつもはこれから高度を算出し山行時の高度の変化をグラフ化していたができなくなってしまった。幸い位置情報については取れていたため、ここからなんとかできんだろかと思った。

スポンサーリンク

高度情報を提供しているAPI

まぁそういう情報提供しているAPIあるじゃろなーと軽い気持ちでググって出てきたものを見てみる。目的と外れるので詳細な比較とかはしてかない。

Google Maps JavaScript API

高度サービス  |  Maps JavaScript API  |  Google for Developers

登録必要、有料。高度データは何を基にしてるか分かんない。

Open-Elevation API

Open-Elevation API
open-elevation/docs/api.md at master · Jorl17/open-elevation
A free and open-source alternative to Google Elevation API. Host your own! - Jorl17/open-elevation

登録不要、無料。簡単に使える。GETで1024バイトまで、POSTは制限なし(!)。高度データはSRTMが基らしい。

天女山駐車場 1546.0m

Open-Meteo Elevation API

Elevation API | Open-Meteo.com
Get detailed elevation information for any set of coordinates using our digital elevation model. With impressive resolut...

スイスの気象関連の会社らしい。提供しているAPIの一つに高度がある。登録不要、無料。リミットはよく分かんない。これも簡単そう。Copernicus Digital Elevation ModelのGLO-90という全世界の90m四方解像度のデータを基にしているらしい。

天女山駐車場 1557.0m

Microsoft Bing Maps Elevations API

Elevations API - Bing Maps
The overview page for the Bing Maps Elevations API, used to get elevation information for a set of locations, polyline o...

登録必要、価格はよく分からん。基データもよく分からん。

HUAWEI Elevation API

Document

なんかあった。登録は必要そう。POSTのみ。

Opentopodata

Open Topo Data
Open DEM server.

色んなデータセットをまとめましたーって感じなんだろうか。無料のパブリックAPIは

  • Max 100 locations per request.
  • Max 1 call per second.
  • Max 1000 calls per day.

という制限がある。↓で試してみたが他との差がすごい。

天女山駐車場 671.7135620117188m

国土地理院 サーバサイドで経緯度から標高を求めるプログラム

地理院地図|サーバサイドで経緯度から標高を求めるプログラム

国土地理院の……APIといっていいと思うんですが。登録不要、無料で使える。制限は常識的な範囲での利用、とな。Yahooの標高APIとかでも使われてるデータから作られてるそう。データとしては実測値の最近点4点を平滑化したものだそう。

天女山駐車場 1533.4m

 

とまぁ色々見てきたけど結局国土地理院が無難かなー。あとは制限がかからないかがあれだけど。どれもこれも戻り値はJSONなのでやっぱJavascriptで書くのがいいんかな。ぶっちゃけあんまり好きじゃないんよね~。あとなんかCORSのエラーでそうー。

スポンサーリンク

プログラムからWebAPIとやりとり

何の言語でやろうかな?というところで、悩ましい。もうVBAでいいんじゃないか。

VBA

ためしに

Sub req()

Dim httpobj As XMLHTTP60
Set httpobj = New XMLHTTP60

httpobj.Open "GET", "https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=138.3979072&lat=35.9216733&outtype=JSON"
httpobj.send

Do While httpobj.readyState < 4
  DoEvents
Loop

Debug.Print httpobj.responseText

End Sub

結果

{"elevation":1533.4,"hsrc":"5m\uff08\u30ec\u30fc\u30b6\uff09"}

いいですね~。JSONのパーサを使いましょう。

GitHub - VBA-tools/VBA-JSON: JSON conversion and parsing for VBA
JSON conversion and parsing for VBA. Contribute to VBA-tools/VBA-JSON development by creating an account on GitHub.

そしたらこう

Sub req()

Dim httpobj As XMLHTTP60
Set httpobj = New XMLHTTP60

httpobj.Open "GET", "https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=138.3979072&lat=35.9216733&outtype=JSON"
httpobj.send

Do While httpobj.readyState < 4
DoEvents
Loop

Dim Json As Object
Set Json = JsonConverter.ParseJson(httpobj.responseText)

Debug.Print Json("elevation")

End Sub

結果

 1533.4

ふむー。あとはもうログの1行ごとに取得するようにすりゃいいね。私は常識村の常識的な常識人なので1秒のスリープを入れておこう。

Sub req()

Dim httpobj As XMLHTTP60
Set httpobj = New XMLHTTP60

For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row

  httpobj.Open "GET", "https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=" _
                       & Range("D" & i).Value & "&lat=" & Range("C" & i).Value & "&outtype=JSON"
  httpobj.send

  Do While httpobj.readyState < 4
    DoEvents
  Loop

  Dim Json As Object
  Set Json = JsonConverter.ParseJson(httpobj.responseText)

  Range("F" & i).Value = Json("elevation")

  Application.Wait Now() + TimeValue("00:00:01")

Next i

End Sub

こうの

こうなりました。意外ときれい。15000件とかだと15000/60/60で約4時間強……。センサーの接続はちゃんとチェックしようね。

Python

久しぶりにPython。単純に考えて、CSV読み込み→行ごとにAPIにアクセス→取得したデータを書き込み→CSVを出力って流れでできると思われる。

import csv
import time
import requests

l = []

with open("test.csv", "r") as f:
    reader = csv.reader(f)
    for row in reader:
        url = (
            "https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon="
            + row[3]
            + "&lat="
            + row[2]
            + "&outtype=JSON"
        )
        headers = {"User-Agent": "Mozilla/5.0"}

        res = requests.get(url=url, headers=headers)
        data = res.json()
        row.append(data["elevation"])
        l.append(row)

        time.sleep(1)

with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)
    for row in l:
        writer.writerow(row)

こう。で、追記済みのoutput.csvが出力される。いつもながらキレイに書けんなぁ。

ChatGPTとBardにレビューしてもらった

そういえば最近話題の対話型AIがレビューもできるって話なのでやってもらった。以下結果

ChatGPT

改善点と注意点:

    1. コードの機能は理解できましたが、エラー処理が不足しています。HTTPリクエストが失敗した場合やJSONデータの取得に問題がある場合に備えてエラーハンドリングを追加することが重要です。
    2. time.sleep(1)による1秒の待機は、サーバーへの負荷を軽減するためのものと思われますが、必要に応じて調整することができます。
    3. コード内の変数名やコメントは十分にわかりやすいですが、もし他の人がコードを読むことを考える場合、より詳細なコメントやドキュメンテーションを追加すると良いでしょう。
    4. Pythonのrequestsライブラリを使用してHTTPリクエストを送信していますが、エラー処理とリトライの実装も検討することをお勧めします。

これは基本的な概要ですが、コードは機能的に見えます。詳細な改善やカスタマイズはプロジェクトの要件に応じて行うことができます。

Bard

レビュー

このスクリプトは、わかりやすく、読みやすいコードで書かれています。また、APIの呼び出し頻度を制限するためにtime.sleep()を使用している点も適切です。

ただし、次の点に注意する必要があります。

  • CSVファイルの各行に標高を追加するときに、インデックスのエラーが発生する可能性があります。これを回避するには、次のようなコードを使用できます。
Python
try:
  row.append(data["elevation"])
except KeyError:
  pass
  • 出力CSVファイルを開くときに、newline=””を指定しています。これは、Windows環境でCSVファイルを書き込むときに、不要な改行文字が挿入されないようにするためです。ただし、MacやLinux環境でCSVファイルを書き込むときは、newline=””を指定しない方がよい場合があります。

上記の点に注意すれば、このスクリプトを安心して使用することができます。

 

すごい!

コメント

タイトルとURLをコピーしました