アルゴリズムとか地図システム基礎技術と重なるものもあるが、 地図アプリのベースとなる基本技術をここにまとめておく。
タイルの管理や検索を効率よく行うために、
タイルは一つの 8バイト整数で識別する。
地図ソース番号(src)、zoom、x、y は全て非負の整数である。src、zoom に1バイト、x、y に3バイト割り当てる。
地図ソースデータが不要なときは、このパートを 0 とする。
long key(Tile.Source src, int zoom, int x, int y) { return (((long)src.ordinal())<<56) + (((long)zoom)<<48) + (((long)x)<<24) + y; }
自作地図アプリでは世界XY平面座標は原点(左上)が (0, 0)、右下が (230, 230) である。
このことから、タイル(zoom, x, y)の原点(左上)の世界XY平面座標は (x*230-zoom, y*230-zoom) となる。
プログラムでは x*(1<<(30-zoom))、 y*(1<<(30-zoom)) である。
x / (1< タイル単位のレンダリングではタイル矩形と
レンダリング対象のレコード境界ボックス(矩形)が交差する範囲内でレンダリングが生じる。
このタイル矩形 rectTile とレコード矩形 rectRecord の交差範囲をレンダリング前に求めておくと、効率的にレンダリングが行える。
Android Java の場合は、次のようにすれば、交差矩形 rect を求められる。
交差する部分があれば fIntersect が true となり、rect にその交差矩形の値がセットされる。
交差範囲がなかった場合は fIntersect は false となり、rect の値は最初にセットした rectTile と同じ値のままである
(幅、高さが0になるわけではない)。
タイル(zoom, x, y)の矩形 rectTile は次のようにして得られる。
一方、OSMバイナリレコードの境界ボックスはレコードのデータから得られる。
左、上、右、下を x0, y0, x1, y1 とすれば
タイル単位のレンダリングでは、現在レンダリング中のタイルの左上を原点とする相対座標値を得る必要がある。
また、単位は画素単位にする必要がある。
タイルの左上座標は x*(1<<(30-zoom)), y*(1<<(30-zoom)) である。タイルの縦横サイズは (1<<(30-zoom)) である。
これを 256(画素) とすればよい。
したがって、left に対しては (left - x*(1<<(30-zoom))) * 256 / (1<<(30-zoom)) が求める相対座標値である。
right についても同様である。
top については (top - y*(1<<(30-zoom))) * 256 / (1<<(30-zoom)) が求める相対座標値である。
bottom についても同様である。
説明は長くなったが、最初から相対座標を使えば、プログラム的には以下に示すように簡単となる。
Rect rect = new Rect(rectTile);
boolean fIntersect = rect.intersect(rectRecord);
Rect rectTile = new Rect(x*(1<<(30-zoom)), y*(1<<(30-zoom), (x+1)*(1<<(30-zoom)), (y+1)*(1<<(30-zoom));
Rect rectRecord = new Rect(x0, y0, x1, y1);
最初から相対座標を使う場合
double fact = 1.0 / (1 << (22-zoom));
RectF rectRecord = new RectF( (float)(x0*fact - x*256), (float)(y0*fact - y*256),
(float)(x1*fact - x*256), (float)(y1*fact - y*256) );
RectF rect = new RectF(0, 0, 256, 256);
boolean fIntersect = rect.intersect(rectRecord);