トップ地図ユーティリティ > OSM Relation処理

OSM Relation処理

はじめに

OSM(OpenStreetMap)のオブジェクトは Node、Way、Relation から成る。機械的に下の形式で、バイナリファイル化できる。

一つのRelationは一般に複数のメンバー Node、Way、Relation からなる。 例えば、都道府県を表す Relation は巨大なものとなる。島嶼部や飛び地があるため、複数のポリゴンとなり、 また他県の飛び地を含んでいる場合、穴あきポリゴンとなる。

OSM地図では、一つのポリゴン(outer polygon)に複数(1を含めて)の穴ポリゴン(inner polygon)を含むものをマルチポリゴンと呼んでいる。 レンダリングでは一つのレコードには outer polygon は一つであり、 島嶼部や飛び地がある場合には複数のポリゴン/マルチポリゴンレコードに分かれる。

osm_id, num_tags, {key, val}*, lon, lat                           ----- Node   
osm_id, num_tags, {key, val}*, num_nodes, {lon, lat}*             ----- Way  
osm_id, num_tags, {key, val}*, num_members, {type, ref, role}*    ----- Relation      

最初のプログラム

レコードは Point、Line、Polygon、MultiPolygon の4種とする。

中庭や屋上プールのある建物などはマルチポリゴンレコードとする。

広域森林や湖などを表すRelationは Wayを繋ぎ合わせてマルチポリゴンレコードとする。

都道府県境界や市町村境界などはエリア塗りつぶしは行わないため、 ポリゴン/マルチポリゴンレコードは生成しない。 広域森林などと同様に、メモリ上ではWayをつなぎ合わせて、outer polygon を生成する。 outer polygonの境界線の内側に都道府県名や市区町村名を描画するために、 個々の Way(Line)レコードに relation ID を含める。Way の進行方向に向かって右側が polygon の内側に当たるときは ID は正の値として、そうでないときは負の値とする。

現在はポリゴン/マルチポリゴンレコードとしているが、上のように変更した方が 総ファイルサイズが大幅に小さくなり、レンダリングのパフォーマンスが向上する。

バス路線Relationの場合、バス停(Node)と路線(Way)がメンバーである。 Wayをつなぎ合わせたバス路線を表すようなLineレコードは作成しない。 バス停レコード(Node/Point)および道路レコード(Way/Line)に、路線Relation ID を含める。

路線番号や路線名などバス路線管理データ(Relationデータ)は Point、Line、Polygon、MultiPolygonレコードとは別ファイルとする。

いずれは全体の処理を考えるが、ここでは、Relation処理だけを考える。

最初に Relationファイルを読み込み、HashSet setNodes、HashSet setWays にメンバーとなっている Node と Way の ID を登録する。

その後、これらの Node、Way をメモリに読込む。

出力レコード形式

xmlファイルバイナリ化でのレコードはノード、ウエイ、リレーションであるが、 レンダリング上のレコードはポイント、ライン、ポリゴン/マルチポリゴンである。

現在のレコード形式はかなり複雑であるが、構造的には大幅にシンプルに変えたい。

{key, val} は、元々は OSMタグを表すが、それ以外のデータも拡張データとして含める。key は2バイトに統一するが、 val は可変長であり、val はなしのときもあれば2つ以上のときもある。key によって処理は異なる。

ファイルサイズが多少大きくなっても、処理が単純化されれば、パフォーマンスは向上することもある。

Relation処理によって生まれるレコードが最も複雑となるため、ここで、出力レコード形式について検討する。

ファイル形式とメモリ上の構造は異なっていてもよい。 しかし、メモリ使用量削減とパフォーマンス向上のため、現在は、メッシュ単位のファイルをそのままメモリ上にキャッシュしている。

レコード単位になるのは、空間検索で絞り込んだ結果に対してである。

キャッシュ段階でレコード単位とする案もある。処理時間がかかるものは予め算出して、レコードに含めるが、 戸建て住宅、住宅地内道路などのように、少ないノードで構成されるレコードの場合、境界ボックス、面積などは瞬時に算出できる。 この場合、レコードには含めず、キャッシュに読込んだ時点で算出してもよい。 その方が、ファイルサイズが小さくなり、ファイル読み込み時間が短縮されるため、総合的なパフォーマンスは向上するかも知れない。

ただし、Java(C#でも同じ)のオブジェクトには管理上のデータがメモリを消費するため、注意がいる。

記事[1]によれば int[] intArray = new int[10]; は 56バイト、 List intList = new ArrayList(10); は 240バイトである。

この二つをメンバーとするクラスのインスタンスは 320バイトである。計算上、管理データは 24 バイトとなる。 配列にすれば、その分、使用メモリも増えるが、レコード単位で管理できる可能性があるので、まずは、実測したい。

num_kvs, {key, val}*, lon, lat                     ----- Point   
num_kvs, {key, val}*, num_nds, {lon, lat}*         ----- Line/Polygon  
num_kvs, {key, val}*, {num_nds}*, {lon, lat}*      ----- Multipolygon      

開発履歴

2024.2.11 森林の一部の描画が欠ける

低中ズームでの描画確認により、森林描画が各地で所々欠けることが分かった。 当初は面積による間引きの影響かと思ったが、そうではないようだ。 1月23日の結果はOSMデータそのもののエラーの可能性があるが、描画が欠けるのはそうではない。 桁違いに多くの個所で発生する。 Map3では描画されるため、バグはRelation処理か描画プログラムにある。

例えば三保市民の森(10323668)や新治市民の森(12460903)はすっぽり欠けている。

procRelationでチェックするとこれらのデータは出力されていないことが分かった。

prcRelationにケアレスミスがあった。この修正により広域森林が正常に描画されるようになった。

2024.1.23 Relation処理の中間記録

Relation処理の中間段階でのプログラムおよび実行結果を下に示す。

OSMデータにはエラーが含まれるため、この程度のエラーは許容範囲である。一部のリレーションは手作業で修正したので、 次にダウンロードしたときは治っているだろう。また、現在のデータは1年以上前のものであるから、 すでに、解決しているものもあれば、新しいエラーも生まれているであろう。

また、Way単独でレンダリングされるものもあるため、Relationでのレンダリングがなくても、 地図としては問題がないケースも多い。

Relation.java

c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class Parser -rel japan
mapNodes.size=131979
mapWays.size=822223
Error Outer 1#: 残=9 id=8546695
Error Outer 2#: 残=3 id=12463695 藤沢
Error Outer 3#: 残=4 id=12463696 藤沢
Error Outer 4#: 残=2 id=14191404
Error Outer 5#: 残=3 id=14469387
Error Outer 6#: 残=3 id=14482174
Error Outer 7#: 残=2 id=14723463
Error Outer 8#: 残=2 id=14765642
Error Outer 9#: 残=3 id=14869415
Error Inner 1#: 残=2 id=14869415
Error Inner 2#: 残=10 id=15101541
Error Outer 10#: 残=2 id=15414440
実行時間: 0.57分

2024.1.22 japan.osmのRelation処理でメンバーの Wayが見つからない

kanto.osmであれば、他地域のメンバーがなくても不思議はないが、japan.osm でも韓国などのデータを一部含むため、 特に Relation のメンバーに欠けるものがある。

一時はバグかと思ったが、ロシア、韓国と思われる。

c:\map>java -Dfile.encoding=UTF-8 -Xmx5g -classpath ./class Parser -rel japan
mapNodes.size=131979
mapWays.size=822223
#1 60189: 2 nodes, 4327 ways 不足、 boundary=true、name=Россия
#2 307756: 2 nodes, 101 ways 不足、 boundary=true、name=????
#3 1221185: 1 nodes, 597 ways 不足、 boundary=true、name=Дальневосточный федеральный окру г
#4 1778078: 1 nodes, 43 ways 不足、 boundary=true、name=Анивский городской округ
#5 1778083: 1 nodes, 3 ways 不足、 boundary=true、name=Невельский городской округ
#6 1778093: 1 nodes, 1 ways 不足、 boundary=true、name=Южно-Курильский городской округ
#7 2393403: 2 nodes, 70 ways 不足、 boundary=true、name=????
#8 2396450: 1 nodes, 30 ways 不足、 boundary=true、name=??
#9 3972378: 1 nodes, 20 ways 不足、 boundary=true、name=???
#10 4000722: 1 nodes, 27 ways 不足、 boundary=true、name=??
#11 4055199: 1 nodes, 15 ways 不足、 boundary=true、name=???
#12 7831149: 1 nodes, 10 ways 不足、 boundary=true、name=???
#13 7831215: 1 nodes, 11 ways 不足、 boundary=true、name=???
実行時間: 0.54分

リファレンス

[1] Javaにおけるインスタンスの使用メモリの計測
[2] Polygon クラスの使い方