トップMy OpenStreetMap > 陸地タイル判定

陸地タイル判定

はじめに

内陸地図を見ることが多い者にとって、陸地は空気のようなもので、 そのレンダリングに時間がかかっているなど思いもよらないだろう。

ところがOSM(OpenStreetMap)では、陸地のレンダリング(描画)に意外と時間がかかる。 タイルのレンダリングではラインレコード(道路・鉄道など)やポリゴンレコード(陸地、森林、水域など)の 描画はレコードの境界ボックス(外接矩形)とタイル(矩形)の交差の有無で判別する。

陸地ポリゴンの分割がない場合、本州では、全てのタイルに対して、巨大な本州ポリゴンをレンダリングする ことになる。

陸地ポリゴンの分割によって、無駄はかなり軽減されるが、まだまだ大きい。 ハイズームでは道路、建物などの描画にかかる時間よりも大きくなることが珍しくない。

地図アプリMapでは、このような無駄時間を極力抑えるために、事前処理によって、個々のタイルが陸地か それとも海岸線を含むタイルかを判別しておき、描画時にこのデータを使う。 陸地タイルの場合、そのタイルを単に陸地の色で塗りつぶすだけでよいので、 陸地ポリゴンを描画するよりも何桁も高速である。陸地タイルかどうか分からないときだけ、 陸地ポリゴンを描画することになる。

陸地ポリゴンの分割

低ズームでは、ノードを間引いた陸地ポリゴンデータで陸地を描画するため、それほど時間がかからない。 陸地タイル判定を使うのは zoom 7, 8 以上となる。 zoom 10 程度までは、間引き無し、分割なしの陸地ポリゴンデータを使って、事前判定を行う。

zoom が大きくなるほど、事前処理も難しくなる。陸地ポリゴンが巨大で複雑であると、 判定に時間がかかりすぎるため、処理が打ち切られ、判定不能というタイルが増加する。 地図の描画エラーにはならないが、本当は陸地タイルであるのに、 その情報が得られない率が高まることになり、目的が達成できない。

したがって、ハイズームに対しては、分割した陸地ポリゴンを使うことにする。

その場合、陸地ポリゴンの分割について留意事項が生まれる。陸地ポリゴンの描画だけを考えると、 どこで分割してもいいが、陸地タイル判定に使う場合、タイル境界線を選ぶ必要がある。 そうしないと、内陸にあるのに、陸地タイルと判定できないタイルが生じる。 現在、既に、タイル境界線を陸地ポリゴン境界線としているので、問題はない。

もう一つの留意点はマージンである。陸地タイルかどうかの判定は Java の Polygon#contains(Rectangle)メソッドによっている。

引数は整数であるが、内部計算に浮動小数点演算がないとは限らない。 タイルの境界線と陸地ポリゴンの境界線が一致する場合、タイル矩形は陸地ポリゴンの内部と判定されるか? 演算上の誤差により、タイルが陸地ポリゴンのごくわずか外になることはないか?

一般には、分割で、描画にスジが現われるのを防ぐために、境界を少しオーバラップさせることがある。 陸地ポリゴンの分割でも、分割線のところで、1/10000 程度のマージンを持たせて、 境界をオーバラップさせておく方が安心である。

現在のプログラムではこのマージンがないため、新たに追加する。

陸地タイルの抽出

日本地図を対象に陸地タイル(海岸線データを含まない)抽出プログラムを作成した。 このプログラムではチェックのしやすさを考えてzoom単位のファイル出力となっている。

プログラムソースコード: LandTile.java

実用上は出力ファイルは一つの方が望ましい。

スマホでのデータ取り出しを簡単にして、メモリ使用量も小さくしたい。

特に、zoom 16 ではこの出力データをそのままメモリに読み込むのは得策ではない。 zoom 15であるタイルが陸地であれば、zoom 16 のその子供の4タイルも当然陸地であるから、 zoom 16 のデータはメモリに置かなくてもよい。

1タイルを 8バイトで表現したときのファイルは 12.4MB となった。

プログラムソースコード: LandTile.java

おわりに

空間検索およびタイル描画をリファインしたら、陸地判定をやめても十分に高速化された。

当面、このプログラムを残しておくが、この先もあってもなくても大差がないようならば取り払う。

リファレンス

[1] OSM陸地ポリゴンをOSMデータから構築する
[2] 陸地ポリゴン