トップPC地図システム > PC地図システムの基本設計

PC地図システムの基本設計

はじめに

最初のプログラムは4,5日で作成できた。国土地理院地図はダウンロードベースなので、 いとも簡単であり、2、3日で最終形に近いものが書けた。

レンダリングについては、現時点は、陸地ポリゴンだけであるが、先に進む前に、 ここで十分に時間をかけて、方針を決めたい。

実行時間の計測

OSMバイナリファイルの読み込み時間と処理時間

現時点では、陸地ポリゴンだけであるが、シングルスレッドでの読み込み時間と処理時間は次にようになった。

最初の時間はファイル読み込みだけの時間、最後の時間は読み込み時間と処理時間を合わせた合計時間である。

何らかの処理後にはガーベージコレクションなどが働くのであろう。実行時間が大きく変動する。

ReadAllBytes 26.1588ms  c:/map/data/lands_split1/1/0.dat   37,505KB     75.3065ms
ReadAllBytes  6.2891ms  c:/map/data/lands_split5/28/12.dat  6,418KB     12.8882ms
ReadAllBytes  1.2325ms  c:/map/data/lands_low1/1/0.dat      1,309KB      2.8835ms
ReadAllBytes  2.0543ms  c:/map/data/lands_low1/0/0.dat      1,907KB  7.6608ms
ReadAllBytes 10.9436ms  c:/map/data/lands_split5/27/12.dat 15,171KB     31.6195ms
ReadAllBytes 40.4929ms  c:/map/data/lands_split5/27/13.dat  3,351KB     43.8489ms
ReadAllBytes 12.4499ms  c:/map/data/lands_split5/29/10.dat    481KB     13.3242ms
ReadAllBytes  5.7754ms  c:/map/data/lands_split5/30/10.dat    363KB      6.5944ms
ReadAllBytes 14.1663ms  c:/map/data/lands_split5/27/11.dat    735KB     15.1881ms
ReadAllBytes  1.8946ms  c:/map/data/lands_low1/1/1.dat        673KB      5.6647ms
ReadAllBytes  0.9672ms  c:/map/data/lands_low1/0/1.dat        845KB      2.4662ms

処理としては、byte配列をint配列に変換しているだけであるが、時間がかかるようだ。 Java で作ったバイナリファイルはビッグエンディアンであり、一方、C#はリトルエンディアンであるから、 変換は避けられない。

 int[] ia = new int[ba.Length/4];
 for (int n = 0; n < ba.Length; n += 4) {
     ia[n/4] = (ba[n]<<24) + (ba[n+1]<<16) + (ba[n+2]<<8) + ba[n+3];
 }

OSMバイナリファイルの読み込みは頻繁に起きるわけではないので、 ここでの時間はそれほど重要ではない。

陸地ポリゴンの空間検索時間およびレンダリング時間

getOSMs の行は最初の時間が空間検索時間、次の時間がレンダリング時間である。 ファイル読み込み直後の空間検索時間は大きいが、平均的には 1ms未満である。 一方、レンダリング時間(陸地ポリゴン塗りつぶし時間)は予想したより大きい。 平均的に 10ms前後となる。

陸地ポリゴンについては、事前に、完全に陸地かどうかを判別しておくことができ、 完全に陸地の場合には、空間検索もポリゴンの塗りつぶしも要らず、タイル全体の FillRectangle でよいので、はるかに高速に処理できる。

問題はこの先、森林や水域ポリゴンの塗りつぶしが必要となり、そこに時間がかかりそうなことである。

c:\map>map
readWords: 16296618
ReadAllBytes 23.48ms
c:/map/data/lands_split1/1/0.dat 37,505KB 71.81ms
ReadAllBytes 4.42ms
c:/map/data/lands_split5/28/12.dat 6,418KB 10.75ms
ReadAllBytes 0.99ms
c:/map/data/lands_low1/1/0.dat 1,309KB 2.22ms
getOSMs 4/25306 records 0.44ms 7.17ms
getOSMs 4/25306 records 10.00ms 14.92ms
getOSMs 4/25306 records 0.74ms 9.07ms
getOSMs 46/25306 records 12.45ms 23.44ms
getOSMs 12/25306 records 1.76ms 44.52ms
getOSMs 4/25306 records 16.52ms 44.86ms
getOSMs 4/25306 records 0.50ms 47.40ms
getOSMs 22/25306 records 0.56ms 14.96ms
getOSMs 16/25306 records 0.47ms 11.94ms
getOSMs 198/25306 records 0.51ms 18.73ms
getOSMs 20/25306 records 0.55ms 19.36ms
getOSMs 111/25306 records 0.60ms 37.97ms
getOSMs 1501/25306 records 0.63ms 49.52ms
getOSMs 229/25306 records 0.60ms 53.03ms
getOSMs 5/25306 records 0.52ms 56.70ms
getOSMs 152/25306 records 10.09ms 68.92ms
getOSMs 2/8844 records 0.38ms 4.75ms
getOSMs 2/8844 records 0.33ms 5.53ms
getOSMs 50/8844 records 0.57ms 6.85ms
getOSMs 9/8844 records 0.18ms 6.31ms
getOSMs 8/8844 records 0.15ms 7.25ms
getOSMs 3/8844 records 0.20ms 9.50ms
getOSMs 4/8844 records 0.19ms 10.87ms
getOSMs 20/8844 records 0.34ms 12.38ms
getOSMs 2/8844 records 0.13ms 4.13ms
getOSMs 1/8844 records 0.15ms 5.09ms
getOSMs 5/8844 records 0.22ms 6.38ms
getOSMs 35/8844 records 0.18ms 6.21ms
getOSMs 1/8844 records 0.19ms 4.31ms
getOSMs 3/8844 records 0.18ms 5.61ms
getOSMs 8/8844 records 0.18ms 11.61ms
getOSMs 141/8844 records 0.31ms 12.54ms
getOSMs 1/8844 records 0.28ms 5.48ms
getOSMs 41/8844 records 0.32ms 7.32ms
getOSMs 21/8844 records 0.19ms 6.62ms
getOSMs 17/8844 records 0.19ms 7.40ms
getOSMs 44/8844 records 0.18ms 8.27ms
getOSMs 214/8844 records 0.24ms 14.70ms
getOSMs 64/8844 records 1.45ms 15.34ms
getOSMs 363/8844 records 4.39ms 11.50ms
getOSMs 11/8844 records 0.19ms 5.47ms
getOSMs 21/8844 records 0.19ms 2.02ms
getOSMs 1/8844 records 0.42ms 3.41ms
getOSMs 1/8844 records 0.17ms 2.94ms
getOSMs 1/8844 records 0.29ms 7.46ms
getOSMs 46/8844 records 0.18ms 5.90ms
getOSMs 17/8844 records 3.25ms 5.47ms
getOSMs 55/8844 records 0.15ms 9.85ms
getOSMs 674/8844 records 0.24ms 13.93ms
getOSMs 553/8844 records 0.21ms 18.56ms
getOSMs 73/8844 records 0.16ms 15.70ms
getOSMs 819/8844 records 0.22ms 26.13ms
getOSMs 39/8844 records 0.19ms 4.86ms
getOSMs 19/8844 records 0.23ms 4.12ms
getOSMs 1/8844 records 0.33ms 7.40ms
getOSMs 73/8844 records 0.23ms 4.43ms
ReadAllBytes 1.63ms
c:/map/data/lands_low1/1/1.dat 673KB 3.06ms
getOSMs 84/2523 records 3.07ms 1.31ms
ReadAllBytes 1.94ms
getOSMs 17/8844 records 3.17ms 5.40ms
getOSMs 440/8844 records 3.41ms 7.78ms
c:/map/data/lands_low1/0/1.dat 845KB 7.82ms
getOSMs 1006/2523 records 3.50ms 10.88ms
ReadAllBytes 3.57ms
getOSMs 297/2264 records 14.25ms 7.27ms
c:/map/data/lands_low1/0/0.dat 1,907KB 8.41ms
getOSMs 20/10106 records 23.06ms 6.43ms
getOSMs 120/8844 records 23.36ms 10.85ms
getOSMs 554/10106 records 23.07ms 11.98ms
getOSMs 2075/8844 records 7.27ms 24.84ms
getOSMs 173/8844 records 0.28ms 10.28ms
getOSMs 980/2523 records 0.10ms 14.21ms
getOSMs 118/8844 records 0.54ms 11.74ms
getOSMs 247/10106 records 0.35ms 5.54ms
getOSMs 275/10106 records 0.21ms 5.75ms
getOSMs 591/8844 records 0.30ms 18.32ms
getOSMs 254/8844 records 0.17ms 18.27ms
getOSMs 771/10106 records 0.24ms 23.99ms
getOSMs 1091/8844 records 0.33ms 29.31ms
getOSMs 1872/10106 records 0.33ms 36.55ms
getOSMs 156/8844 records 0.20ms 4.91ms
getOSMs 206/8844 records 0.24ms 5.40ms
getOSMs 1/8844 records 0.19ms 6.74ms
getOSMs 1/8844 records 0.13ms 4.41ms
getOSMs 2/8844 records 0.14ms 5.03ms
getOSMs 16/8844 records 0.18ms 5.63ms
getOSMs 100/8844 records 0.32ms 7.03ms
getOSMs 55/8844 records 0.18ms 10.89ms
getOSMs 158/8844 records 0.18ms 15.49ms
getOSMs 1/8844 records 0.16ms 4.62ms
getOSMs 13/8844 records 0.25ms 5.47ms
getOSMs 3/8844 records 0.17ms 6.54ms
getOSMs 170/8844 records 0.18ms 6.87ms
getOSMs 5/8844 records 0.18ms 7.93ms
getOSMs 108/8844 records 0.19ms 13.71ms
getOSMs 62/8844 records 0.28ms 15.10ms
getOSMs 36/8844 records 0.17ms 11.61ms
getOSMs 141/8844 records 5.39ms 10.68ms
getOSMs 22/8844 records 0.44ms 4.69ms
getOSMs 5/8844 records 0.15ms 7.61ms
getOSMs 35/8844 records 0.21ms 3.62ms
getOSMs 2/8844 records 0.32ms 5.81ms
getOSMs 2/8844 records 0.33ms 5.32ms
getOSMs 69/8844 records 0.26ms 10.05ms
getOSMs 65/8844 records 0.18ms 8.52ms
getOSMs 17/8844 records 0.19ms 10.74ms
getOSMs 1/8844 records 0.25ms 5.68ms
getOSMs 63/8844 records 0.18ms 9.10ms
getOSMs 2/8844 records 0.12ms 11.69ms
getOSMs 42/8844 records 0.18ms 14.04ms
getOSMs 1/8844 records 0.18ms 6.34ms
getOSMs 11/8844 records 0.19ms 2.87ms
getOSMs 57/8844 records 0.20ms 8.77ms
getOSMs 1/8844 records 0.24ms 5.45ms
getOSMs 50/8844 records 0.24ms 9.65ms
getOSMs 50/8844 records 0.27ms 8.13ms
getOSMs 18/8844 records 3.39ms 8.46ms
getOSMs 1/8844 records 0.13ms 6.63ms
getOSMs 44/8844 records 0.18ms 7.96ms
getOSMs 11/8844 records 0.13ms 10.27ms
getOSMs 363/8844 records 1.98ms 9.37ms
getOSMs 1/8844 records 0.16ms 11.87ms
getOSMs 41/8844 records 0.14ms 12.88ms
getOSMs 64/8844 records 0.21ms 14.01ms
getOSMs 214/8844 records 0.27ms 18.26ms

FillPolygon時間の分析

    public void FillPolygon(Graphics g, Brush br, TileToRender tile, int offset, int length) {
        double fact = tile.fact;
        double xpx = tile.xpx;
        double ypx = tile.ypx;
        int INC = (slim ? 1 : 2);
        int end = offset + INC * length;

        var list = new List<PointF>();
        for (int ix = offset; ix < end; ) {
            float fx, fy;
            if (slim) {
                int xy = buf[ix++];
                fx = (float) ((x0 + (short)(xy>>16)) * fact - xpx);
                fy = (float) ((y0 + (short)(xy&0xffff)) * fact - ypx);
            } else {
                fx = (float) (buf[ix++] * fact - xpx);
                fy = (float) (buf[ix++] * fact - ypx);
            }
            list.Add(new PointF(fx, fy));
        }
        g.FillPolygon(br, list.ToArray());
    }

データセットの時間と描画時間を分けて実測した。ノード数の小さいポリゴンが無数にあるが、 データセット時間、描画時間とも微々たるものであるため省略した。

以下の実測結果で最初の数値はノード数、次がデータセット時間、最後が描画時間である。

データセット時間より描画時間の方が5~10倍大きい。 現在のプログラムはデータセット時間短縮のために多少分かりずらくなっている。 多少データセット時間が増えるとしても分かりやすくした方がいいであろう。

c:\map>map
readWords: 16296618
ReadAllBytes 24.32ms
c:/map/data/lands_split1/1/0.dat 37,505KB 72.94ms
ReadAllBytes 4.39ms
c:/map/data/lands_split5/28/12.dat 6,418KB 11.57ms
ReadAllBytes 0.93ms
c:/map/data/lands_low1/1/0.dat 1,309KB 2.14ms
204 0.01ms 0.12ms
376 0.02ms 0.09ms
1021 0.05ms 0.13ms
376 0.01ms 0.09ms
231 0.02ms 0.06ms
1021 0.25ms 0.18ms
393 0.01ms 2.81ms
29911 1.67ms 8.45ms
29911 1.39ms 6.00ms
29911 0.63ms 9.44ms
29911 0.53ms 10.51ms
29911 0.62ms 5.90ms
110 0.01ms 0.04ms
29911 0.72ms 24.37ms
1021 0.15ms 3.42ms
29911 0.62ms 2.97ms
29911 0.92ms 3.61ms
1021 0.05ms 0.15ms
29911 0.46ms 2.70ms
29911 0.76ms 7.31ms
29911 0.49ms 2.15ms
29911 1.18ms 7.41ms
29911 0.87ms 8.44ms
1021 0.02ms 0.12ms
1021 0.02ms 0.17ms
204 0.00ms 0.06ms
29911 0.51ms 5.03ms
29911 0.54ms 5.56ms
393 0.01ms 0.11ms
29911 0.38ms 3.30ms
1021 0.01ms 1.70ms
29911 0.50ms 4.13ms
190 0.00ms 0.04ms
110 0.00ms 0.01ms
619 0.02ms 0.08ms
376 0.02ms 0.19ms
29911 0.77ms 4.91ms
29911 2.77ms 5.41ms
643 0.01ms 0.63ms
123 0.00ms 0.03ms
166 0.00ms 0.04ms
110 0.00ms 0.03ms
231 0.00ms 0.04ms
438 0.01ms 0.18ms
436 0.01ms 0.12ms
344 0.01ms 0.10ms
1021 0.02ms 0.09ms
125 0.00ms 0.04ms
643 0.01ms 0.09ms
29911 0.54ms 4.13ms
29911 0.67ms 4.50ms
29911 0.61ms 5.14ms
29911 0.51ms 2.95ms
29911 0.66ms 3.04ms
29911 0.48ms 3.76ms
1021 0.03ms 0.14ms
1021 0.02ms 0.17ms
1021 0.02ms 0.25ms
1021 0.02ms 0.10ms
29911 0.56ms 4.07ms
29911 0.72ms 2.96ms
1021 0.02ms 0.17ms
29911 0.53ms 5.69ms
29911 0.45ms 4.08ms
29911 0.93ms 3.44ms
29911 0.45ms 3.20ms
376 0.01ms 0.20ms
29911 0.47ms 3.32ms
231 0.00ms 0.13ms
1021 0.02ms 0.24ms
29911 0.59ms 3.26ms
1021 0.03ms 0.14ms
1021 0.02ms 0.92ms
1021 0.02ms 0.23ms
29911 1.19ms 2.21ms
1021 0.02ms 0.15ms
1021 0.02ms 0.26ms
1021 0.01ms 0.13ms
1021 0.02ms 0.19ms
29911 0.40ms 2.43ms
29911 0.37ms 3.75ms
29911 0.49ms 4.01ms
29911 0.79ms 4.38ms
29911 0.37ms 2.68ms
231 0.00ms 0.03ms
29911 0.60ms 3.61ms
1021 0.02ms 0.95ms
29911 0.56ms 2.95ms
405 0.01ms 0.06ms
1536 0.03ms 0.16ms
1125 0.02ms 0.13ms
1536 0.03ms 0.13ms
140 0.00ms 0.02ms
869 0.02ms 1.04ms
83711 4.65ms 8.17ms
56564 1.93ms 6.18ms
1125 0.02ms 1.59ms
8967 0.41ms 2.50ms
344 0.01ms 0.05ms
1536 0.03ms 0.70ms
148 0.00ms 0.03ms
886 0.01ms 0.08ms
865 0.01ms 0.12ms
865 0.02ms 1.11ms
2700 0.03ms 0.19ms
83711 3.17ms 8.67ms
6145 0.10ms 0.64ms
1911 0.03ms 0.21ms
1536 0.03ms 0.17ms
1125 0.02ms 0.11ms
1067 0.02ms 0.11ms
6145 0.11ms 2.00ms
1125 0.02ms 0.12ms
200 0.00ms 0.02ms
66736 2.72ms 6.69ms
1911 0.03ms 5.45ms
865 0.02ms 4.52ms
1536 0.03ms 0.36ms
1125 0.02ms 0.11ms
83711 2.55ms 12.63ms
66736 3.02ms 8.38ms
13937 0.35ms 3.20ms
6145 0.10ms 1.17ms
1911 0.03ms 0.56ms
8967 0.16ms 1.16ms
1536 0.03ms 0.45ms
1067 0.02ms 0.10ms
1125 0.02ms 0.17ms
869 0.02ms 0.12ms
886 0.02ms 0.08ms
66736 2.79ms 5.54ms
869 0.02ms 0.11ms
344 0.01ms 0.03ms
1536 0.02ms 0.11ms
6145 0.69ms 0.88ms
1536 0.84ms 0.22ms
1911 0.03ms 0.18ms
1125 0.02ms 0.10ms
886 0.01ms 0.11ms
865 0.01ms 0.09ms
6145 0.08ms 0.38ms
1536 0.83ms 0.12ms
6145 0.11ms 1.14ms
1125 0.02ms 0.16ms
6145 0.12ms 3.01ms
1536 0.03ms 0.13ms
1911 0.03ms 0.21ms
1911 0.03ms 0.23ms
865 0.01ms 0.62ms
1911 0.04ms 0.24ms
1536 0.03ms 0.19ms
1125 0.02ms 0.13ms
1536 0.02ms 0.14ms
1125 0.02ms 0.16ms
1536 0.02ms 0.15ms
66736 1.90ms 5.43ms
865 0.01ms 0.10ms
1125 0.02ms 0.09ms
1125 0.02ms 0.15ms
1125 0.02ms 0.09ms
66736 2.48ms 5.45ms
1536 0.02ms 0.30ms
865 0.02ms 0.23ms
1125 0.02ms 0.10ms
66736 2.46ms 4.68ms
66736 2.05ms 6.47ms
1536 0.03ms 0.69ms
1911 0.03ms 0.21ms
1125 0.03ms 0.27ms
1911 0.57ms 0.18ms
1911 0.04ms 2.19ms
1536 0.03ms 0.26ms
865 0.02ms 0.15ms
1536 0.03ms 0.13ms
1536 0.02ms 0.24ms
1536 0.02ms 0.09ms
1536 0.03ms 0.33ms
1125 0.02ms 0.30ms
1536 0.02ms 0.09ms
1125 0.02ms 0.33ms
865 0.02ms 0.22ms
1125 0.03ms 0.44ms
865 0.06ms 0.24ms
1125 0.03ms 0.26ms
1125 0.02ms 0.14ms
865 0.03ms 0.51ms
1125 0.02ms 0.47ms
886 0.02ms 0.71ms
1911 0.04ms 0.70ms
1536 0.03ms 0.31ms
1125 0.03ms 0.14ms
1911 0.03ms 0.66ms
1536 0.03ms 0.16ms
1125 0.02ms 0.11ms
1536 0.03ms 0.21ms
1125 0.02ms 1.54ms
865 0.02ms 0.05ms

OSMバイナリレコードについて

陸地ポリゴンにも osm_id(8バイト)、タグ(8バイト)、wayarea(4バイト)を持たせているが、 レンダリングでは要らない。

レコードの過半数は小さな建物であるが、タグは head の数ビットで代用できる。 osm_id も wayarea もレンダリングには使わない。

境界ボックスの左上座標はブロックの左上座標との相対アドレスとすれば、大抵は2バイトで表せるだろう。

Blockには、バイナリレコードをレコード単位で管理する管理テーブルを置いてはどうか。 ファイルには境界ボックスを持たず、ブロックを読み込んだ時、算出する。 管理テーブルは小さい建物などを管理するものと、その他を管理するものに分かれていてもよい。

境界ボックスは外接矩形であるが、外接円であれば、中心座標と半径で済む。 横長、縦長については外接矩形の方が精度は高い。また、判定は円より簡単である。