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; // キャッシュサイズ=64ixEntry = (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; } } }