Merge pull request #374 from jmakovicka/hillshade-resample-2
Hillshade resample 2
This commit is contained in:
commit
d47b95c19c
4 changed files with 164 additions and 47 deletions
|
@ -222,14 +222,14 @@ public class ResourceManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom){
|
public synchronized boolean tileExistOnFileSystem(String file, ITileSource map, int x, int y, int zoom, boolean exact){
|
||||||
if(!imagesOnFS.containsKey(file)){
|
if(!imagesOnFS.containsKey(file)){
|
||||||
boolean ex = false;
|
boolean ex = false;
|
||||||
if(map instanceof SQLiteTileSource){
|
if(map instanceof SQLiteTileSource){
|
||||||
if(((SQLiteTileSource) map).isLocked()){
|
if(((SQLiteTileSource) map).isLocked()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ex = ((SQLiteTileSource) map).exists(x, y, zoom);
|
ex = ((SQLiteTileSource) map).exists(x, y, zoom, exact);
|
||||||
} else {
|
} else {
|
||||||
if(file == null){
|
if(file == null){
|
||||||
file = calculateTileId(map, x, y, zoom);
|
file = calculateTileId(map, x, y, zoom);
|
||||||
|
@ -306,7 +306,7 @@ public class ResourceManager {
|
||||||
|
|
||||||
if (loadFromFs && cacheOfImages.get(tileId) == null && map != null) {
|
if (loadFromFs && cacheOfImages.get(tileId) == null && map != null) {
|
||||||
boolean locked = map instanceof SQLiteTileSource && ((SQLiteTileSource) map).isLocked();
|
boolean locked = map instanceof SQLiteTileSource && ((SQLiteTileSource) map).isLocked();
|
||||||
if(!loadFromInternetIfNeeded && !locked && !tileExistOnFileSystem(tileId, map, x, y, zoom)){
|
if(!loadFromInternetIfNeeded && !locked && !tileExistOnFileSystem(tileId, map, x, y, zoom, false)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null;
|
String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null;
|
||||||
|
@ -349,7 +349,12 @@ public class ResourceManager {
|
||||||
}
|
}
|
||||||
Bitmap bmp = null;
|
Bitmap bmp = null;
|
||||||
if (req.tileSource instanceof SQLiteTileSource) {
|
if (req.tileSource instanceof SQLiteTileSource) {
|
||||||
|
try {
|
||||||
bmp = ((SQLiteTileSource) req.tileSource).getImage(req.xTile, req.yTile, req.zoom);
|
bmp = ((SQLiteTileSource) req.tileSource).getImage(req.xTile, req.yTile, req.zoom);
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
log.error("Out of memory error", e); //$NON-NLS-1$
|
||||||
|
clearTiles();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
File en = new File(req.dirWithTiles, req.tileId);
|
File en = new File(req.dirWithTiles, req.tileId);
|
||||||
if (en.exists()) {
|
if (en.exists()) {
|
||||||
|
|
|
@ -19,7 +19,14 @@ import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteDiskIOException;
|
import android.database.sqlite.SQLiteDiskIOException;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Bitmap.Config;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Matrix.ScaleToFit;
|
||||||
|
|
||||||
|
|
||||||
public class SQLiteTileSource implements ITileSource {
|
public class SQLiteTileSource implements ITileSource {
|
||||||
|
|
||||||
|
@ -34,6 +41,11 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
private final File file;
|
private final File file;
|
||||||
private int minZoom = 1;
|
private int minZoom = 1;
|
||||||
private int maxZoom = 17;
|
private int maxZoom = 17;
|
||||||
|
private int baseZoom = 17; //Default base zoom
|
||||||
|
|
||||||
|
final int margin = 1;
|
||||||
|
final int tileSize = 256;
|
||||||
|
final int minScaledSize = 8;
|
||||||
|
|
||||||
public SQLiteTileSource(File f, List<TileSourceTemplate> toFindUrl){
|
public SQLiteTileSource(File f, List<TileSourceTemplate> toFindUrl){
|
||||||
this.file = f;
|
this.file = f;
|
||||||
|
@ -82,11 +94,13 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTileSize() {
|
public int getTileSize() {
|
||||||
return base != null ? base.getTileSize() : 256;
|
return base != null ? base.getTileSize() : tileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUrlToLoad(int x, int y, int zoom) {
|
public String getUrlToLoad(int x, int y, int zoom) {
|
||||||
|
if (zoom > baseZoom)
|
||||||
|
return null;
|
||||||
SQLiteDatabase db = getDatabase();
|
SQLiteDatabase db = getDatabase();
|
||||||
if(db == null || db.isReadOnly() || urlTemplate == null){
|
if(db == null || db.isReadOnly() || urlTemplate == null){
|
||||||
return null;
|
return null;
|
||||||
|
@ -138,8 +152,12 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
try {
|
try {
|
||||||
long z;
|
long z;
|
||||||
z = db.compileStatement("SELECT minzoom FROM info").simpleQueryForLong(); //$NON-NLS-1$
|
z = db.compileStatement("SELECT minzoom FROM info").simpleQueryForLong(); //$NON-NLS-1$
|
||||||
if (z < 17)
|
if (z < 17 && z >= 0)
|
||||||
maxZoom = 17 - (int)z;
|
baseZoom = 17 - (int)z; // sqlite base zoom, =11 for SRTM hillshade
|
||||||
|
maxZoom = 17; // Cheat to have tiles request even if zoom level not in sqlite
|
||||||
|
// decrease maxZoom if too much scaling would be required
|
||||||
|
while ((tileSize >> (maxZoom - baseZoom)) < minScaledSize)
|
||||||
|
maxZoom--;
|
||||||
z = db.compileStatement("SELECT maxzoom FROM info").simpleQueryForLong(); //$NON-NLS-1$
|
z = db.compileStatement("SELECT maxzoom FROM info").simpleQueryForLong(); //$NON-NLS-1$
|
||||||
if (z < 17)
|
if (z < 17)
|
||||||
minZoom = 17 - (int)z;
|
minZoom = 17 - (int)z;
|
||||||
|
@ -149,27 +167,13 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean exists(int zoom) {
|
public boolean exists(int x, int y, int zoom, boolean exact) {
|
||||||
SQLiteDatabase db = getDatabase();
|
|
||||||
if(db == null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Cursor cursor = db.rawQuery("SELECT 1 FROM tiles WHERE z = ? LIMIT 1", new String[] {(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
|
||||||
try {
|
|
||||||
boolean e = cursor.moveToFirst();
|
|
||||||
cursor.close();
|
|
||||||
return e;
|
|
||||||
} catch (SQLiteDiskIOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean exists(int x, int y, int zoom) {
|
|
||||||
SQLiteDatabase db = getDatabase();
|
SQLiteDatabase db = getDatabase();
|
||||||
if(db == null){
|
if(db == null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long time = System.currentTimeMillis();
|
long time = System.currentTimeMillis();
|
||||||
|
if (exact || zoom <= baseZoom) {
|
||||||
Cursor cursor = db.rawQuery("SELECT 1 FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
Cursor cursor = db.rawQuery("SELECT 1 FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||||
try {
|
try {
|
||||||
boolean e = cursor.moveToFirst();
|
boolean e = cursor.moveToFirst();
|
||||||
|
@ -181,6 +185,22 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
} catch (SQLiteDiskIOException e) {
|
} catch (SQLiteDiskIOException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
int n = zoom - baseZoom;
|
||||||
|
int base_xtile = x >> n;
|
||||||
|
int base_ytile = y >> n;
|
||||||
|
Cursor cursor = db.rawQuery("SELECT 1 FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {base_xtile+"", base_ytile+"",(17 - baseZoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||||
|
try {
|
||||||
|
boolean e = cursor.moveToFirst();
|
||||||
|
cursor.close();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Checking parent tile existance x = " + base_xtile + " y = " + base_ytile + " z = " + baseZoom + " for " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
} catch (SQLiteDiskIOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLocked() {
|
public boolean isLocked() {
|
||||||
|
@ -191,11 +211,63 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
return db.isDbLockedByOtherThreads();
|
return db.isDbLockedByOtherThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Bitmap getMetaTile(int x, int y, int zoom, int flags) {
|
||||||
|
// return a (tileSize+2*margin)^2 tile around a given tile
|
||||||
|
// based on its neighbor. This is needed to have a nice bilinear resampling
|
||||||
|
// on tile edges. Margin of 1 is enough for bilinear resampling.
|
||||||
|
|
||||||
|
SQLiteDatabase db = getDatabase();
|
||||||
|
if(db == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap stitchedImage = Bitmap.createBitmap(tileSize + 2 * margin, tileSize + 2 * margin, Config.ARGB_8888);
|
||||||
|
Canvas canvas = new Canvas(stitchedImage);
|
||||||
|
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
|
if ((flags & (0x400 >> (4 * (dy + 1) + (dx + 1)))) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
int xOff, yOff, w, h;
|
||||||
|
int dstx, dsty;
|
||||||
|
Cursor cursor = db.rawQuery(
|
||||||
|
"SELECT image FROM tiles WHERE x = ? AND y = ? AND z = ?",
|
||||||
|
new String[] {(x + dx) + "", (y + dy) + "", (17 - zoom) + ""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||||
|
byte[] blob = null;
|
||||||
|
if(cursor.moveToFirst()) {
|
||||||
|
blob = cursor.getBlob(0);
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
if (dx < 0) xOff = tileSize - margin; else xOff = 0;
|
||||||
|
if (dx == 0) w = tileSize; else w = margin;
|
||||||
|
if (dy < 0) yOff = tileSize - margin; else yOff = 0;
|
||||||
|
if (dy == 0) h = tileSize; else h = margin;
|
||||||
|
dstx = dx * tileSize + xOff + margin;
|
||||||
|
dsty = dy * tileSize + yOff + margin;
|
||||||
|
if(blob != null){
|
||||||
|
|
||||||
|
Bitmap Tile = BitmapFactory.decodeByteArray(blob, 0, blob.length);
|
||||||
|
blob = null;
|
||||||
|
Rect src = new Rect(xOff, yOff, xOff + w, yOff + h);
|
||||||
|
Rect dst = new Rect(dstx, dsty, dstx + w, dsty + h);
|
||||||
|
canvas.drawBitmap(Tile, src, dst, null);
|
||||||
|
Tile.recycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stitchedImage; // return a tileSize+2*margin size image
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public Bitmap getImage(int x, int y, int zoom) {
|
public Bitmap getImage(int x, int y, int zoom) {
|
||||||
SQLiteDatabase db = getDatabase();
|
SQLiteDatabase db = getDatabase();
|
||||||
if(db == null){
|
if(db == null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (zoom <= baseZoom) {
|
||||||
|
// return the normal tile if exists
|
||||||
Cursor cursor = db.rawQuery("SELECT image FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
Cursor cursor = db.rawQuery("SELECT image FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||||
byte[] blob = null;
|
byte[] blob = null;
|
||||||
if(cursor.moveToFirst()) {
|
if(cursor.moveToFirst()) {
|
||||||
|
@ -206,6 +278,46 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
return BitmapFactory.decodeByteArray(blob, 0, blob.length);
|
return BitmapFactory.decodeByteArray(blob, 0, blob.length);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
// return a resampled tile from its last parent
|
||||||
|
int n = zoom - baseZoom;
|
||||||
|
int base_xtile = x >> n;
|
||||||
|
int base_ytile = y >> n;
|
||||||
|
|
||||||
|
int scaledSize= tileSize >> n;
|
||||||
|
int offset_x= x - (base_xtile << n);
|
||||||
|
int offset_y= y - (base_ytile << n);
|
||||||
|
int flags = 0x020;
|
||||||
|
|
||||||
|
if (scaledSize < minScaledSize)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (offset_x == 0)
|
||||||
|
flags |= 0x444;
|
||||||
|
else if (offset_x == (1 << n) - 1)
|
||||||
|
flags |= 0x111;
|
||||||
|
if (offset_y == 0)
|
||||||
|
flags |= 0x700;
|
||||||
|
else if (offset_y == (1 << n) - 1)
|
||||||
|
flags |= 0x007;
|
||||||
|
|
||||||
|
Bitmap metaTile = getMetaTile(base_xtile, base_ytile, baseZoom, flags);
|
||||||
|
|
||||||
|
if(metaTile != null){
|
||||||
|
// in tile space:
|
||||||
|
int delta_px = scaledSize * offset_x;
|
||||||
|
int delta_py = scaledSize * offset_y;
|
||||||
|
|
||||||
|
RectF src = new RectF(0.5f, 0.5f,
|
||||||
|
scaledSize + 2 * margin - 0.5f, scaledSize + 2 * margin - 0.5f);
|
||||||
|
RectF dest = new RectF(0, 0, tileSize, tileSize);
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
m.setRectToRect(src, dest, Matrix.ScaleToFit.FILL);
|
||||||
|
return Bitmap.createBitmap(metaTile, delta_px, delta_py,
|
||||||
|
scaledSize + 2*margin-1, scaledSize + 2*margin-1, m, true);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITileSource getBase() {
|
public ITileSource getBase() {
|
||||||
|
@ -231,7 +343,7 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
if (db == null || db.isReadOnly()) {
|
if (db == null || db.isReadOnly()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (exists(x, y, zoom)) {
|
if (exists(x, y, zoom, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length());
|
ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length());
|
||||||
|
|
|
@ -167,7 +167,7 @@ public class DownloadTilesDialog {
|
||||||
for (int x = x1; x <= x2 && !cancel; x++) {
|
for (int x = x1; x <= x2 && !cancel; x++) {
|
||||||
for (int y = y1; y <= y2 && !cancel; y++) {
|
for (int y = y1; y <= y2 && !cancel; y++) {
|
||||||
String tileId = rm.calculateTileId(map, x, y, z);
|
String tileId = rm.calculateTileId(map, x, y, z);
|
||||||
if (rm.tileExistOnFileSystem(tileId, map, x, y, z)) {
|
if (rm.tileExistOnFileSystem(tileId, map, x, y, z, true)) {
|
||||||
progressDlg.setProgress(progressDlg.getProgress() + 1);
|
progressDlg.setProgress(progressDlg.getProgress() + 1);
|
||||||
} else {
|
} else {
|
||||||
rm.getTileImageForMapSync(tileId, map, x, y, z, true);
|
rm.getTileImageForMapSync(tileId, map, x, y, z, true);
|
||||||
|
|
|
@ -158,7 +158,7 @@ public class MapTileLayer extends BaseMapLayer {
|
||||||
float y1 = (top + j - tileY) * ftileSize + h;
|
float y1 = (top + j - tileY) * ftileSize + h;
|
||||||
String ordImgTile = mgr.calculateTileId(map, leftPlusI, topPlusJ, nzoom);
|
String ordImgTile = mgr.calculateTileId(map, leftPlusI, topPlusJ, nzoom);
|
||||||
// asking tile image async
|
// asking tile image async
|
||||||
boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile, map, leftPlusI, topPlusJ, nzoom);
|
boolean imgExist = mgr.tileExistOnFileSystem(ordImgTile, map, leftPlusI, topPlusJ, nzoom, false);
|
||||||
Bitmap bmp = null;
|
Bitmap bmp = null;
|
||||||
boolean originalBeLoaded = useInternet && nzoom <= maxLevel;
|
boolean originalBeLoaded = useInternet && nzoom <= maxLevel;
|
||||||
if (imgExist || originalBeLoaded) {
|
if (imgExist || originalBeLoaded) {
|
||||||
|
@ -178,11 +178,11 @@ public class MapTileLayer extends BaseMapLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!originalBeLoaded && !imgExist) {
|
if (!originalBeLoaded && !imgExist) {
|
||||||
if (mgr.tileExistOnFileSystem(imgTile2, map, leftPlusI / 2, topPlusJ / 2, nzoom - 1)
|
if (mgr.tileExistOnFileSystem(imgTile2, map, leftPlusI / 2, topPlusJ / 2, nzoom - 1, false)
|
||||||
|| (useInternet && nzoom - 1 <= maxLevel)) {
|
|| (useInternet && nzoom - 1 <= maxLevel)) {
|
||||||
bmp = mgr.getTileImageForMapAsync(imgTile2, map, leftPlusI / 2, topPlusJ / 2, nzoom - 1, useInternet);
|
bmp = mgr.getTileImageForMapAsync(imgTile2, map, leftPlusI / 2, topPlusJ / 2, nzoom - 1, useInternet);
|
||||||
div = 2;
|
div = 2;
|
||||||
} else if (mgr.tileExistOnFileSystem(imgTile4, map, leftPlusI / 4, topPlusJ / 4, nzoom - 2)
|
} else if (mgr.tileExistOnFileSystem(imgTile4, map, leftPlusI / 4, topPlusJ / 4, nzoom - 2, false)
|
||||||
|| (useInternet && nzoom - 2 <= maxLevel)) {
|
|| (useInternet && nzoom - 2 <= maxLevel)) {
|
||||||
bmp = mgr.getTileImageForMapAsync(imgTile4, map, leftPlusI / 4, topPlusJ / 4, nzoom - 2, useInternet);
|
bmp = mgr.getTileImageForMapAsync(imgTile4, map, leftPlusI / 4, topPlusJ / 4, nzoom - 2, useInternet);
|
||||||
div = 4;
|
div = 4;
|
||||||
|
|
Loading…
Reference in a new issue