OSM地図レンダリング用のOSMバイナリレコードファイルは Map4 に、uid、timestamp、user を追加する。タイル分割では rec_id も追加する。
Encoderの出力フォーマット: 文字コードは UTF-8。 length, osm_id, uid_user, time, lon, lat, {key, val}* ----- Node length, osm_id, uid_user, time, num_nds, {lon, lat}*, {key, val}* ----- Way length, osm_id, uid_user, time, num_members, {type, ref, role}*, {key, val}* ----- Relation
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.42GB、relation 37.0MB、計3.57GBとなった。
まずは Map4 を踏襲して、次のようにしている。
head, {lon,lat}, tags_length, {key,val}* ... point head, bbox, num_nds, {lon,lat}*, tags_length, {key,val}* ... line/polygon head, bbox, num_polys, {num_nds, {lon,lat}*}*, tags_length, {key,val}* ... multipolygon head: 第0,1bit(0x03) 0: point、 1: line、 2: polygon、 3: multipolygon 下位3バイト レコード長(headを含む)
しかし、OSMバイナリレコードファイル形式は Map4の一つ前に戻すことも考えている。マルチポリゴンの場合、 ポリゴン毎のノード数を前に置き、その後に、座標値列データを連続して置く。
この方がプログラムが分かりやすくなる。
現在は osm_id は特殊な (key,val) の一つとしているが、osm_id を独立項目にすることも検討している。 シンプルな建物やマイナーな道路などでは osm_id は省けるようにしたいため、head か bbox の次がよいだろう。
head, {lon,lat}, tags_length, {key,val}* ... point head, bbox, num_nds, {lon,lat}*, tags_length, {key,val}* ... line/polygon head, bbox, num_polys, {num_nds}*, {lon,lat}*, tags_length, {key,val}* ... multipolygon head: 第0,1bit(0x03) 0: point、 1: line、 2: polygon、 3: multipolygon 下位3バイト レコード長(headを含む)
Map4では予めサイズの異なるバッファプールを確保して、最適なサイズを割り当てるようにした。 ガーベージコレクションは減るが、適切なサイズとバッファ数を求めるのが難しい。 常時、使用メモリが大きくなるのも、パフォーマンス上好ましくないと思われる。 よって、以前のように、動的確保、解放方式に戻す。
Map4と同じであり、当面、大きな変更はしない。
統計では uid、(user、) を知りたいことがある。 Android機に読込むファイルには要らないかもしれないが、あってもさほど邪魔にはならない。 osm_id、timestampは含めたい。2038年問題を考えると、timestampは 8バイトが望ましいが、 地図システムでは高精度はいらない。時:分または日付だけでもよい。よって、4バイトで十分である。
osm_id は、node に対しては4バイトでは足りない。way、relationは4バイトでもよいが、 4バイトの節約は大した利益を生まないので、一律8バイトとする方がいいだろう。
uid(4)、timestamp(4)、osm_id(8)を追加すれば、ファイルサイズは 10数%増える。 ファイル読み込み時間自体はその分増えるが、パフォーマンス全体の増え方はそれより小さいであろう。
日本地図のマッパーは変換表を使えば 2 バイトで表せるだろう。 数件のレコードにしか現れない uid は省略してもいい。timestampは日付だけであれば2バイトで表せる。 osm_idも8バイトはpointレコードのみとすれば、レコード当たり8バイト強の増加ですむ。 しかし、約8バイト節約の代償として、プログラムが少し複雑になる。 経験上、プログラムを複雑にするのは得策ではない。素直に16バイト追加した方がよい。
Map4はガーベージコレクションを気にして、複雑にしすぎた。一からプログラムを作り直そう。
Map4では座標値列データエリアを再利用している。これが、少々複雑で、プログラムがパッと見ただけでは分からない。 float[] Renderer#points、int Renderer#ixPoints、int OSM#offPnts などが関連している。 OSMバイナリレコードごとではなく、複数レコードで一本化しているのかも知れない。 効率を考え、空間検索で抽出された全レコード分を points 配列に置いているのであろう。
必要サイズが分からないため、倍々で増やしている。最終的には余分なメモリが確保される無駄がある。 倍々ではなく、例えば、1.5倍とすれば、この無駄は減るが、再割り当て回数が増える。
よって、座標値データエリアは float[] OSM#points に置くことにする。
色々シンプル化しているが、まず、バス路線(細い青線)だけ描画された。 使用メモリは 150~250MB である。
ログディレクトリがなかった場合、生成するようにした。
陸地ポリゴンが正常に描画されることを確認した。 ただし、このまま先に進むのではなく、OSMのデータを見直したい。
OSMの配列メンバーの再利用はやめる。動的に確保して、レンダリングが終わったら解放する。
readAll /storage/36C5-1401/Map5/dat/lands-high6/56/25.dat 1219218