春告げ鳥

興味のあることをごちゃ混ぜで書いているので、.カテゴリー別に閲覧することをオススメします

GIS入門

この記事はkstm Advent Calendar 2016の3日目の記事です。

qiita.com

GIS系と呼ばれる分野があり、結構奥が深いと思ったのでその話をしたいと思います。
プログラマーGISに関わりのある仕事に就く割合はそんなに多くはないと思いますが、僕がバイトを始めてGISに関することを知るのに結構苦労して、分からずに何度も書き直した記憶があるのでこれから始めようと思う人に向けて記事を書きます。

地理情報システム(GIS)とは

GISとは、地理情報システム(Geographic Information Systems)の略称で、文字や数字、画像などを地図と結びつけて、コンピュータ上に再現し、位置や場所からさまざまな情報を統合したり、分析したり、分かりやすく地図表現したりすることができる仕組みであり、行政や市民生活やビジネスの現場で幅広く利用することが可能である。
http://www.gis.jacic.or.jp/gis/gakushu/whatisgis/whatisgis1.html

国土地理院などの機関が公的なデータとして行政区域や河川、道路などの情報を公開しています。 これらのデータを使って便利なアプリケーションなどを作ろうというのが目的です。

この記事では、ブラウザで地図を表示する時に必要な知識について焦点を当てて書きたいと思います。

地図タイル

ブラウザ上で地図を表示する時に重要なのが、地図タイルです。Google Mapなどを開いた時に、読み込みがある一定の正方形区切りに行われていることに気づく人もいるかもしれません。
実はほとんどの地図表示ライブラリでは、正方形の画像をつなぎ合わせて地球全体の地図を表示しています。(256x256ピクセルとか)それぞれ拡大率に応じて画像が用意されています。
サーバー側では地図画像は分割されていて、クライアントの動きに応じて表示に必要な画像だけをサーバーにリクエストしています。 どんなURLでリクエストを送るかとかもある程度基準があります。

地理院の地図タイルの場合は

https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png

地理院地図|地理院タイル一覧

地図タイルサーバは基本的に{z}/{x}/{y}の形式が多いです。
たまに{x}/{y}/{z}もあります。
zが倍率でxやyが地球を何分割かした時の左上(左下)からの番号です。

地図タイルにも分類があり、ラスタ画像とベクタ画像があります。

ラスタタイル

ラスタタイルは通常の画像形式(pngとか)でサーバは正方形区切りの画像を返します。
例えば北海道の一部を表示する地理院地図のラスタタイルを以下に示します。

http://cyberjapandata.gsi.go.jp/xyz/std/5/28/11.png

http://cyberjapandata.gsi.go.jp/xyz/std/5/28/11.png

ベクタタイル

ラスタタイルがあればベクタタイルもあります。
ある正方形の区切りの中のオブジェクト(点・線・図形)をサーバが返してブラウザ上で表示することができます。
主に使われるのはGeoJSONという形式で、地図表示ライブラリにはGeoJSONを勝手に解釈して表示してくれるものもあります。

GeoJSONは名前の通りGeometry(Geography)の情報を載せたJSONです。下に使用とサンプルを示します。

http://s.kitazaki.name/docs/geojson-spec-ja.html#g ...
↑こんな感じでオブジェクトを書いていきます。

ブラウザ上ではラスタタイルとほぼ同じように表示されます。 国土地理院がベクタタイルの提供実験を行っているのでリンクを貼っておきます。

http://gsi-cyberjapan.github.io/vector-tile-experiment/#16/35.7057/139.9575

ベクタタイルを用いるとブラウザ上でオブジェクトとして使うことが出来るため、対象をクリックして詳細を表示といったことをすることが出来ます。一方、ベクタタイルはブラウザ上でオブジェクトとして表示するためラスタタイルで表示するのに比べて重くなりがちです。特に表示するオブジェクトが多いとスムーズにスクロール出来なかったりします。そういった場合はポリゴンの頂点を元データより削減して圧縮表示をする場合があります。(Google Map等)

空間参照系

GIS系のデータを扱うときに度々必要になるのが、空間参照系の指定です。
地球全体をどんな回転楕円体として近似させるか決定するパラメータ、回転体を平面で表示するときの投影方法などをまとめた規格があり、空間参照系といいます。

空間参照系は地域ごとに異なったパラメータを用いたりもするので、組み合わせが沢山あります。

Spatial Reference List -- Spatial Reference

そこまで高い精度を用いる必要がない場合は地球全体の形に近似した楕円体のWGS84という空間参照系を使うことが多いです。実際にGPSの座標計算や多くの地図表示アプリ(Google Mapとか)ではWGS84を用いています。

二点間の距離を求める公式

地球を回転楕円体としてみなすため、二点間の距離も楕円体に沿った距離を計算する必要があります。
緯度経度から二点間の距離を計算するためのヒュベニの公式というものがあり、実際にその計算方法をJavaScriptのコードにしたものを下に示します。

distance between two points

GISデータをデータベースに格納

ベクタタイル等で使うポリゴンや位置情報はgeometry型という型が便利です。 点・線・図形などのオブジェクトや空間参照系など地理情報に関わるデータを一つのカラムにまとめて表現することが出来ます。 また、集約関数などもあり、図形同士の結合、分割や凸包とかを処理するための関数もあります。 MySQLでは標準でgeometry型が実装されていて、PostgreSQLではPostGISという拡張機能によって実装されています。
僕の場合はPostGISしか使ったことがないので断言はできませんが、リファレンス等を読むと機能的な差異はそこまでないと思います。

あとがき

バイトでは知らなくて書き直したことが結構あって(GeoJSONとか知らなくて独自フォーマットで実装したりした。 ちゃんと調べていれば良かったのになということが多々ありました。 地図を表示するのはGeoJSONとか地図タイルとか便利なものを知っていると結構簡単に作ることができて、最近のスマホではJavaScriptGPSの座標とかも取得できるので知っているだけで結構面白いものが作れます。 ちょっと作ってみたいものとしてはサイクリスト向けの位置情報共有サイトとかどうですかね。kstmは体育会系のサークルなのでラーメン食べるために自転車で山を越えることもあるそうですが、一緒に走っていた人が見えなくなった時に開くと位置情報で場所がわかるみたいな。道路情報や距離計算などを組み合わせてカーナビを作るということも夢ではないかもしれません。