地理情報の解析や研究において、標高情報は非常に重要です。この記事では、Javaを使用して日本の地理空間データから標高情報を取得する方法を解説します。
1. Mavenによるライブラリの設定
Javaプロジェクトで外部ライブラリを簡単に管理するために、Mavenを使用します。以下の依存関係をpom.xml
に追記することで、OkHttpライブラリをプロジェクトに追加できます。
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.1</version> <!-- 最新のバージョンに更新してください -->
</dependency>
2. 標高データの取得
ElevationFetcher
クラスを使用して、指定された緯度と経度に基づいて標高データを取得します。このクラスは、OkHttpライブラリを使用して、日本の地理空間データ提供サイトから標高データを取得します。
コードの詳細:
- getOnlyElevationメソッド: 指定された緯度と経度の標高データを取得します。
- fetchElevationメソッド: 緯度と経度をワールド座標に変換し、複数のDEMソースから標高データを取得します。
- getElevationメソッド: ワールド座標をピクセル座標に変換し、指定されたDEMソースから標高データを取得します。
以下は、ElevationFetcher
クラスの一部です:
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* ElevationFetcherクラスは、指定された緯度と経度の標高データを取得するためのクラスです。
* 日本の地理空間データ提供サイトから標高データを取得します。
*/
public class ElevationFetcher {
private static final int CONST_NO_DATA = -1;
private static final String BASE_URL = "https://cyberjapandata.gsi.go.jp/xyz/";
private static final OkHttpClient client = new OkHttpClient();
/**
* メインメソッド。東京の緯度と経度を使用して標高データを取得し、結果を出力します。
* @param args コマンドライン引数(未使用)
*/
public static void main(final String[] args) {
final var lon = 139.6917; // 東京の経度
final var lat = 35.6895; // 東京の緯度
try {
final var elevation = ElevationFetcher.getOnlyElevation(lat, lon);
System.out.println(elevation);
} catch (final IOException e) {
e.printStackTrace();
}
}
/**
* 指定された緯度と経度の標高データのみを取得します。
* @param lat 緯度
* @param lon 経度
* @return 標高データ
* @throws IOException データ取得中の例外
*/
public static BigDecimal getOnlyElevation(final double lat, final double lon) throws IOException {
try {
final var resultMap = ElevationFetcher.fetchElevation(lat, lon);
final var elevation = new BigDecimal(resultMap.get("elevation"));
return elevation;
} catch (final NumberFormatException e) {
final var elevation = new BigDecimal(CONST_NO_DATA);
return elevation;
}
}
/**
* 指定された緯度と経度の標高データを取得します。
* @param lat 緯度
* @param lon 経度
* @return 標高データを含むMap
* @throws IOException データ取得中の例外
*/
public static Map <String, String> fetchElevation(final double lat, final double lon) throws IOException {
final var lng_rad = Math.toRadians(lon);
final var lat_rad = Math.toRadians(lat);
final var R = 128 / Math.PI;
final var worldCoordX = R * (lng_rad + Math.PI);
final var worldCoordY = -1 * R / 2 * Math.log((1 + Math.sin(lat_rad)) / (1 - Math.sin(lat_rad))) + 128;
var elevation = ElevationFetcher.getElevation(worldCoordX, worldCoordY, 15, "dem5a", 1);
var hsrc = "5m(レーザ)";
if (elevation == ElevationFetcher.CONST_NO_DATA) {
elevation = ElevationFetcher.getElevation(worldCoordX, worldCoordY, 15, "dem5b", 1);
hsrc = "5m(写真測量)";
}
if (elevation == ElevationFetcher.CONST_NO_DATA) {
elevation = ElevationFetcher.getElevation(worldCoordX, worldCoordY, 14, "dem", 0);
hsrc = "10m";
}
final Map <String, String> resultMap = new HashMap <>();
if (elevation == ElevationFetcher.CONST_NO_DATA) {
resultMap.put("elevation", "-----");
} else {
resultMap.put("elevation", String.format("%.2f", elevation)); // 標高データをStringに変換
}
resultMap.put("hsrc", hsrc);
return resultMap;
}
/**
* 指定されたワールド座標、ズームレベル、DEMソースから標高データを取得します。
* @param worldCoordX ワールド座標X
* @param worldCoordY ワールド座標Y
* @param zoom ズームレベル
* @param demSource DEMソース
* @param dataRound 丸める小数点以下の桁数
* @return 標高データの値
* @throws IOException データ取得中の例外
*/
private static Double getElevation(final double worldCoordX, final double worldCoordY, final int zoom, final String demSource,
final int dataRound) throws IOException {
final var PixelX = worldCoordX * Math.pow(2, zoom);
final var TileX = (int) (PixelX / 256);
final var PixelY = worldCoordY * Math.pow(2, zoom);
final var TileY = (int) (PixelY / 256);
final var PixelXint = (int) PixelX;
final var px = PixelXint % 256;
final var PixelYint = (int) PixelY;
final var py = PixelYint % 256;
final var sFileName = ElevationFetcher.BASE_URL + String.format("%s/%d/%d/%d.txt", demSource, zoom, TileX, TileY);
final var request = new Request.Builder().url(sFileName).build();
try (var response = ElevationFetcher.client.newCall(request).execute()) {
if (!response.isSuccessful()) {
return (double) ElevationFetcher.CONST_NO_DATA;
}
final var responseBody = response.body();
if (responseBody == null) {
return (double) ElevationFetcher.CONST_NO_DATA;
}
final var lines = responseBody.string().split("\n");
if (lines.length <= py) {
return (double) ElevationFetcher.CONST_NO_DATA;
}
final var values = lines[py].split(",");
if (values.length <= px) {
return (double) ElevationFetcher.CONST_NO_DATA;
}
final var elevation = Double.parseDouble(values[px]);
return Math.round(elevation * Math.pow(10, dataRound)) / Math.pow(10, dataRound);
}
}
}
標高タイルの詳細仕様(国土地理院より)
標高タイルは、地図タイルと同一のタイル座標とピクセル座標を用いてデータを整備しています。
カンマ区切りのテキスト形式とPNG形式のファイルが提供されています。
標高タイルのデータ仕様では、256ピクセル×256ピクセルの地図タイルと関連づけられています。
テキスト形式の場合、1行にカンマ区切りで256個の標高値を表す数値データが格納されており、1枚の標高タイルは256行からなります。
PNG形式の場合、24ビットカラーのPNG形式で、一つのタイルの大きさは256ピクセル×256ピクセルです。
3. 結論
JavaとElevationFetcher
クラス、そしてMavenの設定を適切に使用することで、日本の地理空間データから正確な標高情報を効率的に取得することができます。この手法は、地理情報の解析や研究に非常に役立ちます。
※参考