追記
Python版も書いた。
国土地理院の標高タイルをPythonで取得する - Qiita
1. 地理院タイルについて
1.1. 概要
タイル座標を指定して特定のURLにリクエストを投げると、地図画像や標高など様々な種類のタイルを取得することができる。URLはタイルの種類ごとに異なり、一覧は地理院タイル一覧で確認できる。
1.2. 標高タイル
名前の通り各地点の標高が記載されたタイルで、仕様は標高タイルの詳細仕様に記載されている。
それぞれのタイルは$256 \times 256$ピクセルで、テキスト形式とPNG形式が提供されているが、以下では簡単のためテキスト形式を扱う。
注意点
- 単に標高がコンマ区切りで記載されているだけだが、標高値が存在しない画素(海など)は「e」の文字が入っていることに注意。
-
地理院タイル一覧をみると、
DEM5A
,DEM5B
,DEM10B
,DEMGM
など複数種類の標高タイルが提供されている。それぞれ対応するズームレベルや測量方法・精度が異なるため、標高値についてを読んで適切なものを選択すること。 - 東方向がX、南方向がYになっており、ディスプレイの座標系と相性が良い
2. 実装
Fetch APIを利用して下記のようなfetchTile
関数を使うと扱いやすい。
- コンマ区切りのテキスト形式で取得したレスポンスを改行コードで行に分割
- 各行はさらにコンマで分割
- 標高の数値はFloatへ変換
- 「e」文字(海など)を標高0[m]に変換
などの前処理を行い、二次元配列としてタイルを取得できるようにしている。
function fetchTile(coord) {
return new Promise(resolve => {
fetch(`https://cyberjapandata.gsi.go.jp/xyz/dem/${coord.z}/${coord.x}/${coord.y}.txt`)
.then(response => response.text())
.then(text => text.split("\n"))
.then(rows => rows.slice(0, rows.length - 1)) // Last row: empty
.then(rows => rows.map(r => r.split(",").map(d => d === "e" ? 0 : parseFloat(d)))) // e: sea
.then(data => resolve(data))
.catch(error => {throw error});
});
}
この実装ではDEM10B
の標高タイル(対応するズームレベルが0-14ともっとも広い)を取得しているが、必要に応じてURLの部分を変更(あるいはfetchTileの引数で指定できるよう修正)すれば良い。
3. タイルの取得方法
3.1. fetchTile
関数の使い方
タイル座標を先述のfetchTile
関数に与え、以下のようにする。
const nabewariTile = {z: 13, x: 7262, y: 3232}; // 鍋割山のタイル座標
fetchTile(nabewariTile).then(d => {
// dを利用
});
3.2. タイル座標の調べ方
(1) 目視で確認
地図上でタイル座標を確認したければタイル座標確認ページが便利。
例えば鍋割山は
となっている。
(2) 緯度経度から計算
ある地点の緯度経度を指定して、その地点が属するタイル座標を知りたい場合、以下のような関数を用意する。
function getTileCoords(lat, lon, zoom) {
const xTile = parseInt(Math.floor((lon + 180) / 360 * (1 << zoom)));
const yTile = parseInt(Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * (1 << zoom)));
return { "z": zoom, "x": xTile, "y": yTile };
}
以上