change max zoom-level to 24

- fix bug in ScanBox where tiles where not visible when map rotation had a steep angle
- refactor ScanBox, add transScale utility
This commit is contained in:
Hannes Janetzek 2013-04-18 18:13:11 +02:00
parent 8a808265a5
commit 24438c1e68
4 changed files with 71 additions and 42 deletions

View File

@ -310,24 +310,19 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// lock tiles while updating isVisible state // lock tiles while updating isVisible state
synchronized (GLRenderer.tilelock) { synchronized (GLRenderer.tilelock) {
int tileZoom = tiles[0].zoomLevel;
for (int i = 0; i < mDrawTiles.cnt; i++) for (int i = 0; i < mDrawTiles.cnt; i++)
tiles[i].isVisible = false; tiles[i].isVisible = false;
int z = tiles[0].zoomLevel; // scale and translate projection to tile coordinates
ScanBox.transScale(pos.x, pos.y, pos.scale, tileZoom, coords);
double curScale = Tile.SIZE * pos.scale;
double tileScale = Tile.SIZE * (pos.scale / (1 << z));
for (int i = 0; i < 8; i += 2) {
coords[i + 0] = (float) ((pos.x * curScale + coords[i + 0]) / tileScale);
coords[i + 1] = (float) ((pos.y * curScale + coords[i + 1]) / tileScale);
}
// count placeholder tiles // count placeholder tiles
mNumTileHolder = 0; mNumTileHolder = 0;
// check visibile tiles // check visibile tiles
mScanBox.scan(coords, z); mScanBox.scan(coords, tileZoom);
} }
} }

View File

@ -15,8 +15,37 @@
package org.oscim.renderer; package org.oscim.renderer;
import org.oscim.core.Tile;
/**
* ScanBox is used to calculate tile coordinates that intersect
* the box (or trapezoid) which is usually the projection of
* screen bounds to the map at a given zoom-level.
*
* use:
* MapViewPosition.getMapViewProjection(coords)
* ScanBox.transScale(pos.x, pos.y, pos.scale, zoomLevel, coords)
* yourScanBox.scan(coords, zoomLevel);
*
* where zoomLevel is the zoom-level for which tile coordinates
* should be calculated.
* */
public abstract class ScanBox { public abstract class ScanBox {
public static void transScale(double x, double y, double scale, int zoom, float[] box){
scale *= Tile.SIZE;
//double curScale = Tile.SIZE * scale;
double div = scale / (1 << zoom);
x *= scale;
y *= scale;
for (int i = 0; i < 8; i += 2) {
box[i + 0] = (float) ((x + box[i + 0]) / div);
box[i + 1] = (float) ((y + box[i + 1]) / div);
}
}
/* /*
* ported from Polymaps: Layer.js * ported from Polymaps: Layer.js
*/ */
@ -44,7 +73,7 @@ public abstract class ScanBox {
private Edge ab = new Edge(); private Edge ab = new Edge();
private Edge bc = new Edge(); private Edge bc = new Edge();
private Edge ca = new Edge(); private Edge ca = new Edge();
private float minX, maxX; private int minX, maxX;
protected int mZoom; protected int mZoom;
@ -53,18 +82,27 @@ public abstract class ScanBox {
public void scan(float[] coords, int zoom) { public void scan(float[] coords, int zoom) {
mZoom = zoom; mZoom = zoom;
maxX = Float.MIN_VALUE;
minX = Float.MAX_VALUE; // clip result to min/max as steep angles
// cause overshooting in x direction.
float max = Float.MIN_VALUE;
float min = Float.MAX_VALUE;
for(int i = 0; i < 8; i += 2){ for(int i = 0; i < 8; i += 2){
float x = coords[i]; float x = coords[i];
if (x > maxX) if (x > max)
maxX = x; max = x;
if (x < minX) if (x < min)
minX = x; min = x;
} }
maxX = (float)Math.ceil(maxX);
minX = (float)Math.floor(minX); max = (float)Math.ceil(max);
min = (float)Math.floor(min);
if (min == max)
max++;
minX = (int) min;
maxX = (int) max;
// top-left -> top-right // top-left -> top-right
ab.set(coords[0], coords[1], coords[2], coords[3]); ab.set(coords[0], coords[1], coords[2], coords[3]);
@ -108,10 +146,10 @@ public abstract class ScanBox {
if (ca.dy == 0) if (ca.dy == 0)
return; return;
if (ab.dy > 0.1) if (ab.dy > 0.0)
scanSpans(ca, ab); scanSpans(ca, ab);
if (bc.dy > 0.1) if (bc.dy > 0.0)
scanSpans(ca, bc); scanSpans(ca, bc);
} }
@ -152,13 +190,13 @@ public abstract class ScanBox {
if (dy > e0.dy) if (dy > e0.dy)
dy = e0.dy; dy = e0.dy;
float x0 = (float)Math.ceil(e0.x0 + m0 * dy); int x0 = (int)Math.ceil(e0.x0 + m0 * dy);
dy = d1 + y - e1.y0; dy = d1 + y - e1.y0;
if (dy > e1.dy) if (dy > e1.dy)
dy = e1.dy; dy = e1.dy;
float x1 = (float)Math.floor(e1.x0 + m1 * dy); int x1 = (int)Math.floor(e1.x0 + m1 * dy);
if (x1 < minX) if (x1 < minX)
x1 = minX; x1 = minX;
@ -167,7 +205,7 @@ public abstract class ScanBox {
x0 = maxX; x0 = maxX;
if (x1 < x0) if (x1 < x0)
setVisible(y, (int) x1, (int) x0); setVisible(y, x1, x0);
} }
} }
} }

View File

@ -113,8 +113,8 @@ public class TileManager {
clearTile(mTiles[i]); clearTile(mTiles[i]);
} }
//else { //else {
// mInitialized is set when surface changed // mInitialized is set when surface changed
// and VBOs might be lost // and VBOs might be lost
// VertexPool.init(); // VertexPool.init();
//} //}
@ -162,26 +162,21 @@ public class TileManager {
// jobs come in. // jobs come in.
mMapView.addJobs(null); mMapView.addJobs(null);
// scale and translate projection to tile coordinates
// load some tiles more than currently visible (* 0.75) // load some tiles more than currently visible (* 0.75)
double scale = pos.scale * 0.9f; double scale = pos.scale * 0.9f;
double curScale = Tile.SIZE * scale;
int zoomLevel = FastMath.clamp(pos.zoomLevel, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL);
double tileScale = Tile.SIZE * (scale / (1 << zoomLevel)); int tileZoom = FastMath.clamp(pos.zoomLevel, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL);
float[] coords = mTileCoords; float[] coords = mTileCoords;
mMapViewPosition.getMapViewProjection(coords); mMapViewPosition.getMapViewProjection(coords);
for (int i = 0; i < 8; i += 2) { // scale and translate projection to tile coordinates
coords[i + 0] = (float) ((pos.x * curScale + coords[i + 0]) / tileScale); ScanBox.transScale(pos.x, pos.y, scale, tileZoom, coords);
coords[i + 1] = (float) ((pos.y * curScale + coords[i + 1]) / tileScale);
}
// scan visible tiles. callback function calls 'addTile' // scan visible tiles. callback function calls 'addTile'
// which sets mNewTiles // which sets mNewTiles
mNewTiles.cnt = 0; mNewTiles.cnt = 0;
mScanBox.scan(coords, zoomLevel); mScanBox.scan(coords, tileZoom);
MapTile[] newTiles = mNewTiles.tiles; MapTile[] newTiles = mNewTiles.tiles;
MapTile[] curTiles = mCurrentTiles.tiles; MapTile[] curTiles = mCurrentTiles.tiles;
@ -562,22 +557,22 @@ public class TileManager {
} }
private final ScanBox mScanBox = new ScanBox() { private final ScanBox mScanBox = new ScanBox() {
@Override @Override
public void setVisible(int y, int x1, int x2) { public void setVisible(int y, int x1, int x2) {
MapTile[] tiles = mNewTiles.tiles; MapTile[] tiles = mNewTiles.tiles;
int cnt = mNewTiles.cnt; int cnt = mNewTiles.cnt;
int max = tiles.length; int maxTiles = tiles.length;
int xmax = 1 << mZoom; int xmax = 1 << mZoom;
for (int x = x1; x < x2; x++) { for (int x = x1; x < x2; x++) {
MapTile tile = null; MapTile tile = null;
if (cnt == max) { if (cnt == maxTiles) {
Log.d(TAG, "reached maximum tiles " + max); Log.d(TAG, "reached maximum tiles " + maxTiles);
break; break;
} }
// NOTE to myself: do not modify x!
int xx = x; int xx = x;
if (x < 0 || x >= xmax) { if (x < 0 || x >= xmax) {

View File

@ -38,13 +38,14 @@ public class MapViewPosition {
private static final String TAG = MapViewPosition.class.getName(); private static final String TAG = MapViewPosition.class.getName();
// needs to fit for int: 2 * 20 * Tile.SIZE // needs to fit for int: 2 * 20 * Tile.SIZE
public final static int MAX_ZOOMLEVEL = 20; public final static int MAX_ZOOMLEVEL = 24;
public final static int MIN_ZOOMLEVEL = 2; public final static int MIN_ZOOMLEVEL = 2;
public final static double MAX_SCALE = (1 << MAX_ZOOMLEVEL); public final static double MAX_SCALE = (1 << MAX_ZOOMLEVEL);
public final static double MIN_SCALE = (1 << MIN_ZOOMLEVEL); public final static double MIN_SCALE = (1 << MIN_ZOOMLEVEL);
public final static int ABS_ZOOMLEVEL = 20; // TODO: remove. only used for animations
public final static int ABS_ZOOMLEVEL = 22;
private final static float MAX_ANGLE = 65; private final static float MAX_ANGLE = 65;