Google Map準拠地図では、zoom 0 では世界地図全体が 256x256画素の一つのタイル画像で表される。 zoom 1では縦横を二分して世界地図が計4枚のタイルで表される。
現在使用中のスマホは高精細なため、タイルのサイズを 768x768画素としている。 256画素かどうかは本質的な話ではない。zoom 0 の世界地図の原点(西北)が (0,0) で、 東南が (1, 1) と考えた方が分かりやすい。
Map4 はとりあえず Map3 を踏襲する。特に、スマホでの文字は、256x256画素のタイルを作成して、 それを 768x768画素に拡大するよりも、最初から、768x768画素のタイルを作成する方がきれいな文字となる。
その場合、タイルキャッシュに使われるメモリは9倍になる。 256x256画素では 256KBx64 = 16MB で済むが、768x768画素では 144MB となる。
現在はメモリが逼迫しているわけではないが、キャッシュに 144MB 使うのには抵抗がある。 ひとまずは、キャッシュサイズを 32 としておく。
キャッシュを階層化して、Bitmap は 24~32タイル、png/jpeg を 128~512タイルとすれば、 パフォーマンスは向上するであろう。
public class Tile {
enum Status { free, waiting, busy, ready }
enum Source { lands, japan, kanto, hot, gsi, ort }
final static String GSI = "https://cyberjapandata.gsi.go.jp/xyz/std/";
final static String ORT = "https://cyberjapandata.gsi.go.jp/xyz/ort/";
final static Tile[] cache = new Tile[64];
final static Tile[] cache = new Tile[32];
static int ixEntry = 0;
Status status;
Bitmap bmp; // PX x PX画素
Canvas canvas;
Source src; // 地図のソース
int zoom, x, y; // タイルアドレス
String url, dir, path;
long key;
public Tile() {
bmp = Bitmap.createBitmap(Map.PX, Map.PX, Bitmap.Config.ARGB_8888);
}
static void initialize() {
for (int i = 0; i < cache.length; i++) {
cache[i] = new Tile();
cache[i].status = Status.free;
}
}
void set(Source src, int zoom, int x, int y, long key) {
this.src = src;
this.zoom = zoom;
this.x = x;
this.y = y;
this.key = key; // ユニーク
this.dir = Map.DIR + "GSI/" + src.name() + "/" + zoom + "/" + x;
this.path = this.dir + "/" + y + ".jpg"; // download先
if (src == Source.japan || src == Source.kanto || src == Source.hot) {
this.url = null;
} else {
String zxy = zoom + "/" + x + "/" + y;
this.url = src == Source.gsi ? GSI + zxy + ".png" : null;
}
}
// サイクリックに使用
static void alloc(Source src, int zoom, int x, int y, long key) {
synchronized (cache) {
for (int n = 0; n < cache.length; n++) {
Tile tile = cache[ixEntry];
ixEntry = (ixEntry + 1) & 0x3f; // キャッシュサイズ=64
ixEntry = (ixEntry + 1) & 0x1f; // キャッシュサイズ=32
if (tile.status != Status.busy &&
(tile.status != Status.waiting || tile.zoom != zoom)) {
tile.set(src, zoom, x, y, key);
tile.status = Status.waiting;
break;
} else {
System.out.printf("allocできず: key=%X %s\n", key, src.name());
}
}
}
}
static Tile get(long key) {
synchronized(cache) {
for (Tile tile : cache) {
if (tile != null && tile.bmp != null && tile.key == key) {
return tile;
}
}
return null;
}
}
static Tile getRequest(Source src, int zoom) {
synchronized(cache) {
for (Tile tile : cache) {
if (tile != null && tile.status == Status.waiting) {
if (tile.src == src && tile.zoom == zoom) {
return tile;
}
tile.status = Status.free;
}
}
return null;
}
}
}