LoginSignup
7
8

More than 5 years have passed since last update.

国土地理院の標高タイルをJavaScriptで適切に取得する

Last updated at Posted at 2018-11-27

追記
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 };
}

以上

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8