LoginSignup
4
2

地理情報システムの作り方(位置情報ゲームも作れる!)

Last updated at Posted at 2023-12-15

今回は地理情報システムの作り方について簡単に解説します。
未来でもしSiv3Dがスマホアプリ開発に対応したら、この記事を応用して簡単に位置情報ゲームが作れるようになります。

地理情報システムとは

地理情報システム(GIS:Geographic Information System)は、地理的位置を手がかりに、位置に関する情報を持ったデータ(空間データ)を総合的に管理・加工し、視覚的に表示し、高度な分析や迅速な判断を可能にする技術である。

国土地理院から引用
https://www.gsi.go.jp/GIS/whatisgis.html

簡単に言えば、位置情報を持ったデータを視覚的に表示する技術です。
ポケモンGOなどの位置情報ゲームも立派な地理情報システムです。

実装

42行で実装します。

#include <Siv3D.hpp> // OpenSiv3D

void Main() {
	constexpr s3d::int32 tile_size = 256; // タイルの大きさ
	constexpr s3d::int32 tile_num_x = 5; // 横に表示する XYZ タイルの数
	constexpr s3d::int32 tile_num_y = 3; // 縦に表示する XYZ タイルの数
	constexpr s3d::int32 tile_index_x = 25; //	左上のタイルの横の開始番号
	constexpr s3d::int32 tile_index_y = 11; //	左上のタイルの縦の開始番号

	struct TextureAndPos {
		s3d::Texture texture;
		s3d::int32 x, y;
		void draw() const {
			texture.draw(x * tile_size, y * tile_size);
		}
	};
	s3d::Array<TextureAndPos> texture_list;

	s3d::String z_value = U"5";
	for (s3d::int32 iy = 0; iy < tile_num_y; ++iy) {
		const s3d::String y_value = s3d::ToString(tile_index_y + iy);
		for (s3d::int32 ix = 0; ix < tile_num_x; ++ix) {
			const s3d::String x_value = s3d::ToString(tile_index_x + ix);
			const s3d::String local_file_path = z_value + U"-" + x_value + U"-" + y_value + U".png";

			s3d::String new_path = U"https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png";
			new_path.replace(U"{x}", x_value);
			new_path.replace(U"{y}", y_value);
			new_path.replace(U"{z}", z_value);

			if (s3d::SimpleHTTP::Save(new_path, local_file_path).isOK()) {
				texture_list.emplace_back(s3d::Texture(local_file_path), ix, iy);
			}
		}
	}
	s3d::Window::Resize(tile_num_x * tile_size, tile_num_y * tile_size);
	while (System::Update()) {
		for (auto& texture : texture_list) {
			texture.draw(); // 地図を描画
		}
	}
}

ソースコードのLicenseは CC0 1.0 (パブリックドメイン)。
ご自由にお使いください。

実行結果

地図が表示されました。

出典:「国土地理院 - 地理院タイル」
地理院タイル一覧ページ(https://maps.gsi.go.jp/development/ichiran.html)

スクリーンショット 2023-12-10 22.19.35.png

「え?ただ画像を貼り付けているだけじゃないの?」 と思われるかもしれませんね。
では、試しに7-8行目の以下の値に書き換えてみましょう。

constexpr s3d::int32 tile_index_x = 15; //	左上のタイルの横の開始番号
constexpr s3d::int32 tile_index_y = 10; //	左上のタイルの縦の開始番号

そうするとヨーロッパの地図が表示されましたね。
この値をいじると地図の任意の位置を表示することができます。

スクリーンショット 2023-12-15 20.57.11.png

地図を変えてみる

26行目に書かれている URL から地図の断片的な画像を取得して表示しています。
次に別の URL に変えてみましょう。

s3d::String new_path = U"https://cyberjapandata.gsi.go.jp/xyz/gmld_ptc2/{z}/{x}/{y}.png";

そうすると、今度は「植生(樹木被覆率)」の地図が表示されました。

地球地図全球版 植生(樹木被覆率) 第2版 © 国土地理院・千葉大学・協働機関

スクリーンショット 2023-12-15 21.10.55.png

地理画像の表示の仕組み

「App」フォルダの中を見てみると断片化された地図が保存されています。
これは「XYZタイル」という形式です。

image.png

XYZタイルとは「メルカトル図法の緯度(北緯・南緯どちらも)約85.0511度以下の世界地図を2^Z分割した 256px * 256px の大きさのタイル画像」の集合体です。原点は西経180度、北緯約85.0511度の位置です。
今回はZ=5の大きさで生成しているので、経度 Xが2^Z分割、つまり32分割(数値は0~31)、yも32分割(数値は0~31)されたメルカトル図法の画像が表示されています。
この仕組みを使うと簡単に地図を取得して表示ができます。

詳しい説明は国土地理院のウェブサイトを見てください。
https://maps.gsi.go.jp/development/siyou.html

image.png

応用

この地図の仕組みを応用してOpenSiv3Dを用いて作ったソフトウェアがこちらです。

imoko.gif

このように移動や拡大・縮小、地名や人物を地図に描画することができます。

この XYZ タイル形式を用いた移動や拡大・縮小に対応した表示は以下の「XYZTiles.hpp」に実装されています。
https://github.com/AsPJT/PAX_SAPIENTICA/blob/develop/Library/PAX_MAHOROBA/XYZTiles.hpp
複雑なことをしているので詳細な説明を省きますが、画像だけでなく数値データの読み込みも対応しておりより自由度の高い仕組みになっています。難しいソースコードなので、中身をじっくり読むのはC++熟練者にだけおすすめしておきます。

🌏地理情報システム

PAXS.png

今回は地理情報システムの作り方の解説でした。
もし参考になりましたら、GitHubにスターを付けていただけると今後のSiv3Dで使える解説記事や便利なソースコードの公開のモチベーションにつながります⭐
最後までお読みいただきありがとうございました!

4
2
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
4
2