パフォーマンスにこだわらず、プログラムを簡素にしたい。
リレーションのメンバーを並び替え、整った形にすることは必須である。 それをマルチポリゴンレコードなどとして出力することは簡単である。 しかし、レコードサイズが大きく、境界ボックスの領域が広大になることが多く、 ブロック分割が難しい。そこで、別の方法も検討したい。
Encoderの出力フォーマット: 文字コードは UTF-16。 length:4, osm_id:8, uid:4, time:4, lon, lat, {key, val}* ----- Node length:4, osm_id:8, uid:4, time:4, bbox:16, num_nds, {lon, lat}*, {key, val}* ----- Way length:4, osm_id:8, uid:4, time:4, num_members, {type, ref, role}*, {key, val}* ----- Relation bbox: minlon, minlat, maxlon, maxlat
lengthは自分を含むレコード長(単位:バイト)。
uid、userはペアでコード化する。現在(2024年10月)、japan.osm で、4万弱のため、2バイトでもよいが、 4バイトを割り当てる。
データ更新時刻 time は分単位として、4バイトを割り当てる。精度はもっと下げてもよいので、2バイト化も可能である。 しかし、レコードサイズの縮小に拘らない方がよい。
role は enum で定義し、レコード上は2バイトで表す。inner、outer などいくつかについては、 レンダリングに関係するが、レンダリングでは無視するものが殆どである。
【ソースデータ例】<node id='31253515' timestamp='2022-01-09T09:59:40Z' uid='7707735' user='zyxzyx' visible='true' version='5' changeset='115935292' lat='35.6536052' lon='139.7601994' />
japan のファイルサイズは node 136MB、way 3.99GB、relation 37.0MB、計4.13GBとなった。
当面、レンダリング対象外のrelationを除くと、relation は 28MBとなった。
maxId=2D922B13B, nodes=FF19CB7, ways=23BD110, rels=28F11(167697), 実行時間: 32.77分
relation member のノードは 153,588 nodes, 11.9 MB、ウェイは 677,412 ways, 217.8 MB であった。 ウェイレコードは平均で 300B を超える。
全体の5%程度であるから、ブロックファイルとの重複は問題でない。 同じようにzoom 8か9で分割すれば、入れ替え頻度はzoom 12分割のブロックファイルより小さくなるので、 osm_idによるメンバー取り出し平均時間は十分に小さいであろう。
レコードに組み立てた場合、行政境界などでは同じウエイが2回以上使われる。また、 境界ボックスは大きくなるため、zoom 12だけの分割はできず、zoom 7、8といった分割も必要となる。
現在は、バス路線や行政境界名の描画はブロックファイルの総サイズを抑えるために、工夫をしている。 このような工夫をやめ、プログラムをシンプルにすると、ブロックファイルの総サイズは更に何割か大きくなる。
つまり、relationレコードを事前に組み立て、色んな工夫をやめると、総サイズが大きくなりすぎる。 SDカードの容量は問題ないが、パソコンからスマホ/タブレットへのファイル転送時間が増大する。
しかし、プログラムの簡単化を一番重視すると、総サイズの増大を許容すべきかも知れない。
北海道、本州、四国、九州などは除外する。ファイルサイズの縮小は僅かである(37.0 -> 36.7MB)。
空間インデックスを使う代わりに、ブロック分割する。
{lon,lat}* は先頭は現状の絶対値、次からは前のノードとの差分値を2バイトペアで表す。 2バイトで表せないときは中間に必要なだけノードを挿入して、差分が2バイトで表せるようにする。
length:4, head:4, osm_id:8, uid:4, time:4, lon:4, lat:4, {key:2,val:2*}* -- point
length:4, ~同上~ time:4, bbox:16, num_nds:4, {lon4/2,lat4/2}*, {key:2,val:2*}* -- line/polygon
length:4, ~同上~ time:4, bbox:16, num_polys:2, {num_nds:4}*, {lon:4/2,lat:4/2}*, {key:2,val:2*}* -- multipolygon
bbox: minlon, minlat, maxlon, maxlat
num_ndsはごく一部のレコードで、2バイト幅を超えるものがあるので、4バイト幅とする。
{lon,lat}* は先頭が 4バイトペアで次からは前との差分を2バイトペアで表す。必要に応じて、ノード間に 1つ以上のノードを挿入して、差分が2バイトに収まるようにする。
relationについてはかなりの処理がいるが、 node と way については、単純にブロック分割するだけである。 しかし、polygon についてはいずれ中心位置の算出が必要になる。
まずは node と way を zoom 12 と zoom 8 で 分割してみる。
zoom 12 は 3.33GB、zoom 8 は 32MB となった。このときは zoom 12 に置く場合、重複が3以上となる場合に、zoom 8に置いた。
zoom 12 に置く場合、重複が起きるとき、zoom 8 に置くと zoom 12 は 2.92GB、zoom 8 は 252MB となった。zoom 8 では重複がありうる。zoom 8 での最大は 27.8MB となった。
head は上位4ビットを type、下位28ビットを rec_id とする。osm_id はレコードの識別には使えない。 マルチポリゴンの場合、同じ outer polygon が二つ以上の場合、outer polygon 毎のレコードとなるため、osm_id は同じとなる。
上記の node、way は relation のメンバーを含んでいる。ただし、relation では同じ way、node を繰り返し使用する。 例えば、バス路線relation では、同じバス停、同じ道を複数の路線が使う。 また、行政境界線は少なくとも、二つの行政が共通で使う。3回以上共用されることも珍しくない。
このため、単純に relation で lineレコードや polygon/multipolygon レコードを組み立てると、 総レコードサイズは大幅に増加する。また、polygon/multipolygon は way単独のものより、 はるかに大きくなることが多く、zoom 8のブロックをまたぐものが多くなり、この重複により、 総ファイルサイズが一層大きくなる。
バス路線や航路などはレンダリングでは、繋いで長いものにする必要はないが、 広域森林や大きな湖などは必ず大きな polygon/multipolygon にする必要がある。
バス路線は独立したレコードにするのではなく、道路レコードにバス路線IDを含めておくだけでもよい。 一般に point/lineレコードの場合は複数のrelationが共用する場合、この方をとれる。
行政境界の場合も、境界線と線の内側に行政名を描くだけの場合、同じように共用できる。 しかし、地図を区別に異なる色で塗りつぶす場合には、polygon/multipolygonにしなければならない。
まずは、広域森林、湖(relationによる水域)など、レンダリングでは polygon/multipolygon化が必須のものについて、 relation処理でpolygon/multipolygonレコードを作り、総ファイルサイズがどれくらい増加するかを調べたい。
まず、ハイズームだけを作成した。zoom 12 が 2.92GB、zoom 8 が 351MB となった。 この後、行政境界、バス路線などで増加するが、思ったよりは少なくて済みそうである。