位置情報を文字列へ変換するジオハッシュ関数

写真のジオタグなど位置情報から住所へ変換する逆ジオコーディングについては,WebサービスのAPIを利用する方法が考えられます。しかしながら,非公開アプリケーションとして用いる場合は,ライセンス料がネックとなることもあります。
そこで,逆ジオコーディングを自前で構築する方法はないものかと,情報収集を行ったところ,国土交通省が提供している「位置情報参照情報ダウンロードサービス」が使えそうだということが分かりました。また,位置情報を特定するには「ジオハッシュ」が有効だということも分かりました。
さらにいろいろ調べましたが,Web上にはまだ詳しい情報が少なくそのまま適用できそうなものも公開されていなかったため,自分でジオハッシュ関数を作成してみることにしました。

ジオハッシュとは

Geohash(ジオハッシュ)は、Gustavo Niemeyerがgeohash.orgというWebサービスを作成中に発明した経緯度に基づくジオコーディング方法の一つである。パブリックドメインになっている。階層的な空間データ構造であり、空間を分割していくことによって表現する。
ジオハッシュは、任意の精度で表現できる、文字列の末尾を削っていくと徐々に精度が落ちる、といった特徴がある。
そのため、近隣の2地点を表すコードは、似たような文字列から構成されることが多い。同時に、より多くの文字列が一致すれば、当該2点がより近いことを表す。

利用例としては,地点を特定したり,例えばデータベースなどに地点情報を格納したり,ジオタグへの適用も提案されているそうです。

出典:Wikipedia

アルゴリズム

Wikipediaのページではジオハッシュから緯度経度へ復号(デコード)する考え方が載っていますので,これを逆に読み取り,緯度経度からジオハッシュにエンコードする方法を考えてみます。まず,緯度については−90°〜0(南緯)と0〜+90°(北緯)の2つに分割した場合,対象位置情報の緯度がどちらに入るかで,2進数のビットを決めます。大区分(0〜90°=北緯)に入る場合は”1″,小区分(−90〜0°=南緯)に入る場合は”0″になります。例えば日本は北緯なので”1″になります。これを左側の1ビット目とします。
geohash2
次に,0~90°を再度2分割し,小区分(0〜45°),大区分(45°〜90°)のどちらに入るかを見ます。例えば東京の北緯はだいたい35°なので,小区分に入ります。したがって,左から2ビット目は”0″となります。さらに二分割すると,3ビット目は”1″になります。
geohash3geohash4
これを繰り返すことにより,東京(=都庁の位置)の緯度35.68952は,101100101100001000101000010111と変換されました。
経度についても大区分(0〜180°=東経),小区分(−180〜0°=西経)からスタートし,同様に2進数に変換すると,東京の経度139.69170は11100011010101100001100100010001となりました。
次にこれらから1つの2進数に変換しますが,左から順に奇数ビットに経度,偶数ビットに緯度を混ぜながら結合します。桁が不足するときは0で補います。上記の場合は,
経度:11100011010101100001100100010001
緯度:101100101100001000101000010111
結合:1110110100001110011100100010110000000110110000100001001101010010

この結合したものを5ビットずつに分割し,下表の文字列に変換します。(base32エンコード)

2進数 10進数 base32
00000 0 0
00001 1 1
00010 2 2
00011 3 3
00100 4 4
00101 5 5
00110 6 6
00111 7 7
01000 8 8
01001 9 9
01010 10 b
01011 11 c
01100 12 d
01101 13 e
01110 14 f
01111 15 g
10000 16 h
10001 17 j
10010 18 k
10011 19 m
10100 20 n
10101 21 p
10110 22 q
10111 23 r
11000 24 s
11001 25 t
11010 26 u
11011 27 v
11100 28 w
11101 29 x
11110 30 y
11111 31 z

先ほど結合した東京の位置情報の2進数を変換すると下表の様になりました。

11101 10100 00111 00111 00100 01011 00000 00110 11000 01000 01001 10101 0010
x n 7 7 4 c 0 6 s 8 9 p 切り捨て

コーディング

上記のようなアルゴリズムを確認しましたので,VBAで関数を作成してみます。
冗長な部分もあるかもしれませんが,可読性を優先しており,十分なスピードも得られています。
まずは,2進数への変換部分です。標準モジュールに以下のコードを作成します。

次に,ジオハッシュへ変換します。引数は10進数の緯度経度で,上の関数を呼び出して2進数に変換します。戻り値はジオハッシュの文字列となります。

これでジオハッシュ関数は完成です。
次のプロシージャでテストしてみます。

変換結果がイミディエイトウィンドウに表示されました。
geohash5

念のため,下記のサイトで確認してみると,同じ結果が得られています。

関連記事