- refactor: moving parts of MapRenderer that run on main thread to new TileLoader class

- adding option for enable rotation.. still needs work
- renaming json db to test - it doesnt do json but still handy for testing
This commit is contained in:
Hannes Janetzek 2012-09-10 02:24:11 +02:00
parent 2d90a4dea4
commit 69fe74facc
24 changed files with 863 additions and 666 deletions

View File

@ -22,6 +22,10 @@
<item <item
android:id="@+id/menu_position_map_center" android:id="@+id/menu_position_map_center"
android:title="@string/menu_position_map_file_center"/> android:title="@string/menu_position_map_file_center"/>
<item
android:id="@+id/menu_rotation_enable"
android:title="@string/menu_rotation_enable"/>
</menu> </menu>
</item> </item>
<item <item

View File

@ -22,6 +22,10 @@
<item <item
android:id="@+id/menu_position_map_center" android:id="@+id/menu_position_map_center"
android:title="@string/menu_position_map_file_center"/> android:title="@string/menu_position_map_file_center"/>
<item
android:id="@+id/menu_rotation_enable"
android:title="@string/menu_rotation_enable"/>
</menu> </menu>
</item> </item>
<item <item

View File

@ -51,6 +51,7 @@
<string name="menu_info_about">About this software</string> <string name="menu_info_about">About this software</string>
<string name="menu_mapfile">Map file</string> <string name="menu_mapfile">Map file</string>
<string name="menu_position">Position</string> <string name="menu_position">Position</string>
<string name="menu_rotation_enable">Enable rotation</string>
<string name="menu_position_enter_coordinates">Enter coordinates</string> <string name="menu_position_enter_coordinates">Enter coordinates</string>
<string name="menu_position_last_known">Last known location</string> <string name="menu_position_last_known">Last known location</string>
<string name="menu_position_map_file_center">Map file center</string> <string name="menu_position_map_file_center">Map file center</string>

View File

@ -24,11 +24,11 @@ import javax.xml.parsers.ParserConfigurationException;
import org.mapsforge.android.mapgenerator.IMapGenerator; import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.JobQueue; import org.mapsforge.android.mapgenerator.JobQueue;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.android.mapgenerator.MapDatabaseFactory; import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
import org.mapsforge.android.mapgenerator.MapDatabases; import org.mapsforge.android.mapgenerator.MapDatabases;
import org.mapsforge.android.mapgenerator.MapRendererFactory; import org.mapsforge.android.mapgenerator.MapRendererFactory;
import org.mapsforge.android.mapgenerator.MapRenderers; import org.mapsforge.android.mapgenerator.MapRenderers;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.android.mapgenerator.MapWorker; import org.mapsforge.android.mapgenerator.MapWorker;
import org.mapsforge.android.mapgenerator.Theme; import org.mapsforge.android.mapgenerator.Theme;
import org.mapsforge.android.rendertheme.ExternalRenderTheme; import org.mapsforge.android.rendertheme.ExternalRenderTheme;
@ -78,6 +78,7 @@ public class MapView extends GLSurfaceView {
private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 16); private static final Byte DEFAULT_START_ZOOM_LEVEL = Byte.valueOf((byte) 16);
public final static boolean debugFrameTime = false; public final static boolean debugFrameTime = false;
public boolean enableRotation = false;
private final MapController mMapController; private final MapController mMapController;
private final MapViewPosition mMapViewPosition; private final MapViewPosition mMapViewPosition;
@ -160,7 +161,7 @@ public class MapView extends GLSurfaceView {
IMapDatabase mapDatabase; IMapDatabase mapDatabase;
if (mDebugDatabase) { if (mDebugDatabase) {
mapDatabase = MapDatabaseFactory mapDatabase = MapDatabaseFactory
.createMapDatabase(MapDatabases.JSON_READER); .createMapDatabase(MapDatabases.TEST_READER);
} else { } else {
mapDatabase = MapDatabaseFactory.createMapDatabase(mapDatabaseType); mapDatabase = MapDatabaseFactory.createMapDatabase(mapDatabaseType);
} }
@ -684,6 +685,10 @@ public class MapView extends GLSurfaceView {
mapWorker.proceed(); mapWorker.proceed();
} }
public void enableRotation(boolean enable) {
enableRotation = enable;
}
// public final int // public final int
// public Handler messageHandler = new Handler() { // public Handler messageHandler = new Handler() {
// //

View File

@ -19,7 +19,6 @@ import org.mapsforge.core.MapPosition;
import org.mapsforge.core.MercatorProjection; import org.mapsforge.core.MercatorProjection;
import android.util.FloatMath; import android.util.FloatMath;
import android.util.Log;
/** /**
* A MapPosition stores the latitude and longitude coordinate of a MapView together with its zoom level. * A MapPosition stores the latitude and longitude coordinate of a MapView together with its zoom level.
@ -112,41 +111,35 @@ public class MapViewPosition {
public synchronized void moveMap(float mx, float my) { public synchronized void moveMap(float mx, float my) {
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel); double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel); double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
double dx, dy;
// float rad = (float) Math.toRadians(mRotation); if (mMapView.enableRotation) {
// mx /= mScale; float rad = (float) Math.toRadians(mRotation);
// my /= mScale; dx = mx / mScale;
// dy = my / mScale;
// double x = mx * FloatMath.cos(rad) + my * -FloatMath.sin(rad);
// double y = mx * FloatMath.sin(rad) + my * FloatMath.cos(rad);
//
// double dx = pixelX - x;
// double dy = pixelY - y;
double dx = pixelX - mx / mScale; double x = dx * FloatMath.cos(rad) + dy * -FloatMath.sin(rad);
double dy = pixelY - my / mScale; double y = dx * FloatMath.sin(rad) + dy * FloatMath.cos(rad);
dx = pixelX - x;
dy = pixelY - y;
}
else {
dx = pixelX - mx / mScale;
dy = pixelY - my / mScale;
}
mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel); mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
mLatitude = MercatorProjection.limitLatitude(mLatitude); mLatitude = MercatorProjection.limitLatitude(mLatitude);
mLongitude = MercatorProjection.pixelXToLongitude(dx, mZoomLevel); mLongitude = MercatorProjection.pixelXToLongitude(dx, mZoomLevel);
//
// mLatitude = MercatorProjection.pixelYToLatitude(pixelY - moveVertical / mScale,
// mZoomLevel);
// mLatitude = MercatorProjection.limitLatitude(mLatitude);
//
// mLongitude = MercatorProjection.pixelXToLongitude(pixelX - moveHorizontal
// / mScale, mZoomLevel);
mLongitude = MercatorProjection.wrapLongitude(mLongitude); mLongitude = MercatorProjection.wrapLongitude(mLongitude);
// mLongitude = MercatorProjection.limitLongitude(mLongitude); // mLongitude = MercatorProjection.limitLongitude(mLongitude);
} }
public synchronized void rotateMap(float angle) { public synchronized void rotateMap(float angle, float cx, float cy) {
moveMap(cx, cy);
mRotation -= angle; mRotation -= angle;
Log.d("...", "angle:" + mRotation);
// mRotation %= 360;
} }
synchronized void setMapCenter(GeoPoint geoPoint) { synchronized void setMapCenter(GeoPoint geoPoint) {

View File

@ -112,16 +112,33 @@ public class TouchHandler {
return true; return true;
} }
// if (multi > 0) { if (mMapView.enableRotation) {
// double dx = event.getX(0) - event.getX(1); if (multi > 0) {
// double dy = event.getY(0) - event.getY(1); double x1 = event.getX(0);
// double rad = Math.atan2(dy, dx); double x2 = event.getX(1);
// float angle = (float) Math.toDegrees(rad); double y1 = event.getY(0);
// mMapPosition.rotateMap(angle - mAngle); double y2 = event.getY(1);
// mAngle = angle;
// mMapView.redrawTiles();
// }
double dx = x1 - x2;
double dy = y1 - y2;
double rad = Math.atan2(dy, dx);
float angle = (float) Math.toDegrees(rad);
// focus point relative to center
double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
double r = Math.toRadians(angle - mAngle);
double x = cx * Math.cos(r) + cy * -Math.sin(r) - cx;
double y = cx * Math.sin(r) + cy * Math.cos(r) - cy;
// Log.d("...", "move " + x + " " + y + " " + cx + " " + cy);
mMapPosition.rotateMap(angle - mAngle, (float) x, (float) y);
mAngle = angle;
mMapView.redrawTiles();
}
}
// save the position of the event // save the position of the event
mPosX = event.getX(pointerIndex); mPosX = event.getX(pointerIndex);
mPosY = event.getY(pointerIndex); mPosY = event.getY(pointerIndex);
@ -182,7 +199,7 @@ public class TouchHandler {
private boolean onActionUp(MotionEvent motionEvent) { private boolean onActionUp(MotionEvent motionEvent) {
mActivePointerId = INVALID_POINTER_ID; mActivePointerId = INVALID_POINTER_ID;
mScaling = false; mScaling = false;
multi = 0;
return true; return true;
} }
@ -400,7 +417,11 @@ public class TouchHandler {
mCenterX = mMapView.getWidth() >> 1; mCenterX = mMapView.getWidth() >> 1;
mCenterY = mMapView.getHeight() >> 1; mCenterY = mMapView.getHeight() >> 1;
mScale = 1; mScale = 1;
// mMapPosition = mMapView.getMapPosition();
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
return true; return true;
} }

View File

@ -428,12 +428,11 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mDebugDrawUnmatched = debugSettings.mDrawUnmatchted; mDebugDrawUnmatched = debugSettings.mDrawUnmatchted;
// fixed now.... // fixed now....
if (tile.newData || tile.isReady || tile.isCanceled) { if (tile.newData || tile.isReady) {
Log.d(TAG, "XXX tile already loaded " Log.d(TAG, "XXX tile already loaded "
+ tile + " " + tile + " "
+ tile.newData + " " + tile.newData + " "
+ tile.isReady + " " + tile.isReady + " ");
+ tile.isCanceled);
return false; return false;
} }

View File

@ -36,7 +36,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10;
@ -47,7 +46,6 @@ import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.android.rendertheme.RenderTheme; import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.utils.GlUtils; import org.mapsforge.android.utils.GlUtils;
import org.mapsforge.core.MapPosition; import org.mapsforge.core.MapPosition;
import org.mapsforge.core.MercatorProjection;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
import android.opengl.GLES20; import android.opengl.GLES20;
@ -57,45 +55,11 @@ import android.util.FloatMath;
import android.util.Log; import android.util.Log;
public class MapRenderer implements org.mapsforge.android.IMapRenderer { public class MapRenderer implements org.mapsforge.android.IMapRenderer {
private static final String TAG = "MapRenderer";
private static final int MB = 1024 * 1024; /**
private static final int SHORT_BYTES = 2; * used for passing tiles to be rendered from TileLoader(Main) to GLThread
static final float COORD_MULTIPLIER = 8.0f; */
static class TilesData {
private static final int MAX_TILES_IN_QUEUE = 40;
private static final int CACHE_TILES_MAX = 250;
private static final int LIMIT_BUFFERS = 16 * MB;
private static int CACHE_TILES = CACHE_TILES_MAX;
private final MapView mMapView;
private static ArrayList<JobTile> mJobList;
private static ArrayList<VertexBufferObject> mVBOs;
// all tiles currently referenced
private static ArrayList<MapTile> mTiles;
// tiles that have new data to upload, see passTile()
private static ArrayList<MapTile> mTilesLoaded;
private static int mWidth, mHeight;
private static float mAspect;
// current center tile, values used to check if position has
// changed for updating current tile list
private static long mTileX, mTileY;
private static float mPrevScale;
private static byte mPrevZoom;
private static int rotateBuffers = 2;
private static ShortBuffer shortBuffer[];
private static short[] mFillCoords;
// bytes currently loaded in VBOs
private static int mBufferMemoryUsage;
class TilesData {
int cnt = 0; int cnt = 0;
final MapTile[] tiles; final MapTile[] tiles;
@ -104,14 +68,39 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
} }
} }
private static final String TAG = "MapRenderer";
private static final int MB = 1024 * 1024;
private static final int SHORT_BYTES = 2;
static final float COORD_MULTIPLIER = 8.0f;
private static final int CACHE_TILES_MAX = 200;
private static final int LIMIT_BUFFERS = 16 * MB;
private static int CACHE_TILES = CACHE_TILES_MAX;
private final MapView mMapView;
private static ArrayList<VertexBufferObject> mVBOs;
private static int mWidth, mHeight;
private static float mAspect;
private static int rotateBuffers = 2;
private static ShortBuffer shortBuffer[];
private static short[] mFillCoords;
// bytes currently loaded in VBOs
private static int mBufferMemoryUsage;
private static float[] mMVPMatrix = new float[16]; private static float[] mMVPMatrix = new float[16];
// private static float[] mRotateMatrix = new float[16]; private static float[] mRotateMatrix = new float[16];
// private static float[] mProjMatrix = new float[16]; private static float[] mProjMatrix = new float[16];
private static float[] mRotTMatrix = new float[16];
// newTiles is set in updateVisibleList and swapped // newTiles is set in updateVisibleList and swapped
// with curTiles on main thread. curTiles is swapped // with curTiles on main thread. curTiles is swapped
// with drawTiles in onDrawFrame in GL thread. // with drawTiles in onDrawFrame in GL thread.
private static TilesData newTiles, curTiles, drawTiles; private static TilesData curTiles, drawTiles;
// draw position is updated from current position in onDrawFrame // draw position is updated from current position in onDrawFrame
// keeping the position and active tiles consistent while drawing // keeping the position and active tiles consistent while drawing
@ -121,8 +110,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
// changed. used in onDrawFrame to flip curTiles/drawTiles // changed. used in onDrawFrame to flip curTiles/drawTiles
private static boolean mUpdateTiles; private static boolean mUpdateTiles;
private static boolean mInitial;
private float[] mClearColor = null; private float[] mClearColor = null;
// number of tiles drawn in one frame // number of tiles drawn in one frame
@ -130,6 +117,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
private static boolean mUpdateColor = false; private static boolean mUpdateColor = false;
static Object lock = new Object();
/** /**
* @param mapView * @param mapView
* the MapView * the MapView
@ -138,475 +127,52 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
Log.d(TAG, "init MapRenderer"); Log.d(TAG, "init MapRenderer");
mMapView = mapView; mMapView = mapView;
if (mInitial)
return;
mJobList = new ArrayList<JobTile>();
mTiles = new ArrayList<MapTile>();
mTilesLoaded = new ArrayList<MapTile>(30);
Matrix.setIdentityM(mMVPMatrix, 0); Matrix.setIdentityM(mMVPMatrix, 0);
mInitial = true;
mUpdateTiles = false; mUpdateTiles = false;
QuadTree.init();
}
private static int updateTileDistances(ArrayList<?> tiles,
MapPosition mapPosition) {
int h = (Tile.TILE_SIZE >> 1);
byte zoom = mapPosition.zoomLevel;
long x = (long) mapPosition.x;
long y = (long) mapPosition.y;
int diff;
long dx, dy;
int cnt = 0;
// TODO this could need some fixing, and optimization
// to consider move/zoom direction
for (int i = 0, n = tiles.size(); i < n; i++) {
JobTile t = (JobTile) tiles.get(i);
diff = (t.zoomLevel - zoom);
if (t.isActive)
cnt++;
if (diff == 0) {
dx = (t.pixelX + h) - x;
dy = (t.pixelY + h) - y;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * 0.25f;
t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * 0.25f;
} else if (diff > 0) {
// tile zoom level is child of current
if (diff < 3) {
dx = ((t.pixelX + h) >> diff) - x;
dy = ((t.pixelY + h) >> diff) - y;
}
else {
dx = ((t.pixelX + h) >> (diff >> 1)) - x;
dy = ((t.pixelY + h) >> (diff >> 1)) - y;
}
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy));
t.distance = FloatMath.sqrt((dx * dx + dy * dy));
} else {
// tile zoom level is parent of current
dx = ((t.pixelX + h) << -diff) - x;
dy = ((t.pixelY + h) << -diff) - y;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * (-diff * 0.5f);
t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * (-diff * 0.5f);
}
}
return cnt;
}
private static boolean childIsActive(MapTile t) {
MapTile c = null;
for (int i = 0; i < 4; i++) {
if (t.rel.child[i] == null)
continue;
c = t.rel.child[i].tile;
if (c != null && c.isActive && !(c.isReady || c.newData))
return true;
}
return false;
}
// FIXME still the chance that one jumped two zoomlevels between
// cur and draw. should use reference counter instead
private static boolean tileInUse(MapTile t) {
byte z = mPrevZoom;
if (t.isActive) {
return true;
} else if (t.zoomLevel == z + 1) {
MapTile p = t.rel.parent.tile;
if (p != null && p.isActive && !(p.isReady || p.newData))
return true;
} else if (t.zoomLevel == z + 2) {
MapTile p = t.rel.parent.parent.tile;
if (p != null && p.isActive && !(p.isReady || p.newData))
return true;
} else if (t.zoomLevel == z - 1) {
if (childIsActive(t))
return true;
} else if (t.zoomLevel == z - 2) {
for (QuadTree c : t.rel.child) {
if (c == null)
continue;
if (c.tile != null && childIsActive(c.tile))
return true;
}
} else if (t.zoomLevel == z - 3) {
for (QuadTree c : t.rel.child) {
if (c == null)
continue;
for (QuadTree c2 : c.child) {
if (c2 == null)
continue;
if (c2.tile != null && childIsActive(c2.tile))
return true;
}
}
}
return false;
}
private static void limitCache(MapPosition mapPosition, int remove) {
int removes = remove;
int size = mTiles.size();
// remove orphaned tiles
for (int i = 0; i < size;) {
MapTile cur = mTiles.get(i);
// make sure tile cannot be used by GL or MapWorker Thread
if ((!cur.isActive) && (!cur.isLoading) && (!cur.newData)
&& (!cur.isReady) && (!tileInUse(cur))) {
clearTile(cur);
mTiles.remove(i);
removes--;
size--;
// Log.d(TAG, "remove empty tile" + cur);
continue;
}
i++;
}
if (removes <= 0)
return;
updateTileDistances(mTiles, mapPosition);
Log.d(TAG, "remove tiles: " + removes);
// boolean printAll = false;
for (int i = 1; i <= removes; i++) {
MapTile t = mTiles.get(0);
int pos = 0;
for (int j = 1; j < size; j++) {
MapTile t2 = mTiles.get(j);
if (t2.distance > t.distance) {
t = t2;
pos = j;
}
}
synchronized (t) {
if (t.isActive) {
// dont remove tile used by renderthread or mapgenerator
Log.d(TAG, "X not removing active " + t + " " + t.distance);
// if (printAll) {
// printAll = false;
// for (GLMapTile tt : mTiles)
// Log.d(TAG, ">>>" + tt + " " + tt.distance);
// }
} else if ((t.isReady || t.newData) && tileInUse(t)) {
// check if this tile could be used as proxy
// for not yet drawn active tile
Log.d(TAG, "X not removing proxy: " + t + " " + t.distance);
} else {
if (t.isLoading) {
Log.d(TAG, ">>> cancel loading " + t + " " + t.distance);
t.isCanceled = true;
}
mTiles.remove(pos);
clearTile(t);
size--;
}
}
}
}
private static void limitLoadQueue(int remove) {
int size = remove;
synchronized (mTilesLoaded) {
// remove uploaded tiles
for (int i = 0; i < size;) {
MapTile t = mTilesLoaded.get(i);
// rel == null means tile is already removed by limitCache
if (!t.newData || t.rel == null) {
mTilesLoaded.remove(i);
size--;
continue;
}
i++;
}
// clear loaded but not used tiles
if (size < MAX_TILES_IN_QUEUE)
return;
while (size-- > MAX_TILES_IN_QUEUE - 20) {
MapTile t = mTilesLoaded.get(size);
synchronized (t) {
if (t.rel == null) {
mTilesLoaded.remove(size);
continue;
}
if (tileInUse(t)) {
// Log.d(TAG, "keep unused tile data: " + t + " " + t.isActive);
continue;
}
mTilesLoaded.remove(size);
mTiles.remove(t);
// Log.d(TAG, "remove unused tile data: " + t);
clearTile(t);
}
}
}
}
private boolean updateVisibleList(MapPosition mapPosition, int zdir) {
double x = mapPosition.x;
double y = mapPosition.y;
byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale;
double add = 1.0f / scale;
int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
long pixelRight = (long) x + offsetX;
long pixelBottom = (long) y + offsetY;
long pixelLeft = (long) x - offsetX;
long pixelTop = (long) y - offsetY;
int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom, zoomLevel);
mJobList.clear();
mMapView.addJobs(null);
int tiles = 0;
if (newTiles == null)
return false;
int max = newTiles.tiles.length - 1;
for (int yy = tileTop; yy <= tileBottom; yy++) {
for (int xx = tileLeft; xx <= tileRight; xx++) {
if (tiles == max)
break;
MapTile tile = QuadTree.getTile(xx, yy, zoomLevel);
if (tile == null) {
tile = new MapTile(xx, yy, zoomLevel);
QuadTree.add(tile);
mTiles.add(tile);
}
newTiles.tiles[tiles++] = tile;
if (!(tile.isLoading || tile.newData || tile.isReady)) {
mJobList.add(tile);
}
if (zdir > 0 && zoomLevel > 0) {
// prefetch parent
MapTile parent = tile.rel.parent.tile;
if (parent == null) {
parent = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
QuadTree.add(parent);
mTiles.add(parent);
}
if (!(parent.isLoading || parent.isReady || parent.newData)) {
if (!mJobList.contains(parent))
mJobList.add(parent);
}
}
}
}
newTiles.cnt = tiles;
// pass new tile list to glThread
synchronized (this) {
for (int i = 0; i < curTiles.cnt; i++) {
boolean found = false;
for (int j = 0; j < drawTiles.cnt && !found; j++)
if (curTiles.tiles[i] == drawTiles.tiles[j])
found = true;
for (int j = 0; j < newTiles.cnt && !found; j++)
if (curTiles.tiles[i] == newTiles.tiles[j])
found = true;
if (!found)
curTiles.tiles[i].isActive = false;
}
for (int i = 0; i < tiles; i++)
newTiles.tiles[i].isActive = true;
TilesData tmp = curTiles;
curTiles = newTiles;
curTiles.cnt = tiles;
newTiles = tmp;
mCurPosition = mapPosition;
mUpdateTiles = true;
}
if (mJobList.size() > 0) {
updateTileDistances(mJobList, mapPosition);
Collections.sort(mJobList);
mMapView.addJobs(mJobList);
}
return true;
}
private static void clearTile(MapTile t) {
t.newData = false;
t.isLoading = false;
t.isReady = false;
LineLayers.clear(t.lineLayers);
PolygonLayers.clear(t.polygonLayers);
t.labels = null;
t.lineLayers = null;
t.polygonLayers = null;
if (t.vbo != null) {
synchronized (mVBOs) {
mVBOs.add(t.vbo);
}
t.vbo = null;
}
QuadTree.remove(t);
} }
/** /**
* called by MapView when position or map settings changes * called by MapView when position or map settings changes
*/ */
@Override @Override
public synchronized void redrawTiles(boolean clear) { public void redrawTiles(boolean clear) {
boolean changedPos = false; TileLoader.redrawTiles(clear);
boolean changedZoom = false;
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
if (mapPosition == null) {
Log.d(TAG, ">>> no map position");
return;
} }
if (clear) { static void updatePosition(MapPosition mapPosition) {
mInitial = true; // synchronized (MapRenderer.lock) {
synchronized (this) {
for (MapTile t : mTiles)
clearTile(t);
mTiles.clear();
mTilesLoaded.clear();
QuadTree.init();
curTiles.cnt = 0;
mBufferMemoryUsage = 0;
}
}
byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale;
long tileX = MercatorProjection.pixelXToTileX(mapPosition.x, zoomLevel)
* Tile.TILE_SIZE;
long tileY = MercatorProjection.pixelYToTileY(mapPosition.y, zoomLevel)
* Tile.TILE_SIZE;
int zdir = 0;
if (mInitial || mPrevZoom != zoomLevel) {
changedZoom = true;
mPrevScale = scale;
}
else if (tileX != mTileX || tileY != mTileY) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
mPrevScale = scale;
changedPos = true;
}
else if (mPrevScale - scale > 0.2 || mPrevScale - scale < -0.2) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
mPrevScale = scale;
changedPos = true;
}
if (mInitial) {
mCurPosition = mapPosition; mCurPosition = mapPosition;
mInitial = false; // }
} }
mTileX = tileX;
mTileY = tileY;
mPrevZoom = zoomLevel;
if (changedZoom) { static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
// need to update visible list first when zoom level changes synchronized (MapRenderer.lock) {
// as scaling is relative to the tiles of current zoom-level
updateVisibleList(mapPosition, 0);
} else {
// pass new position to glThread
synchronized (this) {
// do not change position while drawing
mCurPosition = mapPosition; mCurPosition = mapPosition;
for (int i = 0; i < curTiles.cnt; i++)
curTiles.tiles[i].isActive = false;
TilesData tmp = curTiles;
curTiles = tiles;
for (int i = 0; i < curTiles.cnt; i++)
curTiles.tiles[i].isActive = true;
for (int j = 0; j < drawTiles.cnt; j++)
drawTiles.tiles[j].isActive = true;
mUpdateTiles = true;
return tmp;
} }
} }
if (!MapView.debugFrameTime) static void addVBO(VertexBufferObject vbo) {
mMapView.requestRender(); synchronized (mVBOs) {
mVBOs.add(vbo);
if (changedPos)
updateVisibleList(mapPosition, zdir);
if (changedPos || changedZoom) {
int remove = mTiles.size() - CACHE_TILES;
if (remove > 10)
limitCache(mapPosition, remove);
} }
int size = mTilesLoaded.size();
if (size > MAX_TILES_IN_QUEUE)
limitLoadQueue(size);
} }
/** /**
@ -616,11 +182,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
public synchronized boolean passTile(JobTile jobTile) { public synchronized boolean passTile(JobTile jobTile) {
MapTile tile = (MapTile) jobTile; MapTile tile = (MapTile) jobTile;
if (tile.isCanceled) { if (!tile.isLoading) {
// no one should be able to use this tile now, mapgenerator passed it, // no one should be able to use this tile now, mapgenerator passed it,
// glthread does nothing until newdata is set. // glthread does nothing until newdata is set.
Log.d(TAG, "passTile: canceled " + tile); Log.d(TAG, "passTile: canceled " + tile);
tile.isLoading = false;
return true; return true;
} }
@ -644,9 +209,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (!MapView.debugFrameTime) if (!MapView.debugFrameTime)
mMapView.requestRender(); mMapView.requestRender();
synchronized (mTilesLoaded) { TileLoader.addTileLoaded(tile);
mTilesLoaded.add(0, tile);
}
return true; return true;
} }
@ -655,9 +218,31 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
// ... asus has just 16 bit?! // ... asus has just 16 bit?!
// private static final float depthStep = 0.00000011920928955078125f; // private static final float depthStep = 0.00000011920928955078125f;
private static boolean mRotate = false;
private static void setMatrix(MapTile tile, float div, int offset) { private static void setMatrix(MapTile tile, float div, int offset) {
float x, y, scale; float x, y, scale;
if (mRotate) {
scale = (float) (1.0 * mDrawPosition.scale / (mHeight * div));
x = (float) (tile.pixelX - mDrawPosition.x * div);
y = (float) (tile.pixelY - mDrawPosition.y * div);
Matrix.setIdentityM(mMVPMatrix, 0);
Matrix.scaleM(mMVPMatrix, 0, scale / COORD_MULTIPLIER,
scale / COORD_MULTIPLIER, 1);
Matrix.translateM(mMVPMatrix, 0,
x * COORD_MULTIPLIER,
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
-1 + offset * 0.01f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
}
else {
scale = (float) (2.0 * mDrawPosition.scale / (mHeight * div)); scale = (float) (2.0 * mDrawPosition.scale / (mHeight * div));
x = (float) (tile.pixelX - mDrawPosition.x * div); x = (float) (tile.pixelX - mDrawPosition.x * div);
y = (float) (tile.pixelY - mDrawPosition.y * div); y = (float) (tile.pixelY - mDrawPosition.y * div);
@ -668,24 +253,11 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
mMVPMatrix[14] = -1 + offset * 0.01f; // depthStep; // 0.01f; mMVPMatrix[14] = -1 + offset * 0.01f; // depthStep; // 0.01f;
mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER; mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER;
mMVPMatrix[5] = scale / COORD_MULTIPLIER; mMVPMatrix[5] = scale / COORD_MULTIPLIER;
}
// Matrix.setIdentityM(mMVPMatrix, 0);
//
// Matrix.scaleM(mMVPMatrix, 0, scale / COORD_MULTIPLIER,
// scale / COORD_MULTIPLIER, 1);
//
// Matrix.translateM(mMVPMatrix, 0, x * COORD_MULTIPLIER, -(y + Tile.TILE_SIZE)
// * COORD_MULTIPLIER, 0);
//
// Matrix.setRotateM(mRotateMatrix, 0, mDrawPosition.angle, 0, 0, 1);
//
// Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
//
// Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
} }
private static boolean setTileScissor(MapTile tile, float div) { private static boolean isVisible(MapTile tile, float div) {
double dx, dy, scale; double dx, dy, scale;
if (div == 0) { if (div == 0) {
@ -773,8 +345,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
+ sbuf.limit() + " " + sbuf.limit() + " "
+ sbuf.remaining() + " " + sbuf.remaining() + " "
+ PolygonLayers.sizeOf(tile.polygonLayers) + " " + PolygonLayers.sizeOf(tile.polygonLayers) + " "
+ tile.isCanceled + " "
+ tile.isLoading + " "
+ tile.rel); + tile.rel);
tile.lineOffset *= SHORT_BYTES; tile.lineOffset *= SHORT_BYTES;
@ -790,7 +360,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
+ sbuf.limit() + " " + sbuf.limit() + " "
+ sbuf.remaining() + " " + sbuf.remaining() + " "
+ LineLayers.sizeOf(tile.lineLayers) + LineLayers.sizeOf(tile.lineLayers)
+ tile.isCanceled + " "
+ tile.isLoading + " " + tile.isLoading + " "
+ tile.rel); + tile.rel);
@ -864,6 +433,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (MapView.debugFrameTime) if (MapView.debugFrameTime)
start = SystemClock.uptimeMillis(); start = SystemClock.uptimeMillis();
mRotate = mMapView.enableRotation;
if (mUpdateColor && mClearColor != null) { if (mUpdateColor && mClearColor != null) {
glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]); glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]);
mUpdateColor = false; mUpdateColor = false;
@ -871,7 +442,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
GLES20.glDepthMask(true); GLES20.glDepthMask(true);
// Note: i have the impression it is faster to also clear the // Note: having the impression it is faster to also clear the
// stencil buffer even when not needed. probaly otherwise it // stencil buffer even when not needed. probaly otherwise it
// is masked out from the depth buffer as they share the same // is masked out from the depth buffer as they share the same
// memory region afaik // memory region afaik
@ -879,11 +450,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
| GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT
| GLES20.GL_STENCIL_BUFFER_BIT); | GLES20.GL_STENCIL_BUFFER_BIT);
if (mInitial)
return;
// get position and current tiles to draw // get position and current tiles to draw
synchronized (this) { synchronized (MapRenderer.lock) {
mDrawPosition = mCurPosition; mDrawPosition = mCurPosition;
if (mUpdateTiles) { if (mUpdateTiles) {
@ -904,7 +472,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
MapTile tile = tiles[i]; MapTile tile = tiles[i];
if (!setTileScissor(tile, 1)) if (!isVisible(tile, 1))
continue; continue;
if (tile.texture == null && TextRenderer.drawToTexture(tile)) if (tile.texture == null && TextRenderer.drawToTexture(tile))
@ -939,6 +507,11 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (updateTextures > 0) if (updateTextures > 0)
TextRenderer.compileTextures(); TextRenderer.compileTextures();
if (mRotate) {
Matrix.setRotateM(mRotateMatrix, 0, mDrawPosition.angle, 0, 0, 1);
Matrix.transposeM(mRotTMatrix, 0, mRotateMatrix, 0);
}
GLES20.glEnable(GLES20.GL_DEPTH_TEST); GLES20.glEnable(GLES20.GL_DEPTH_TEST);
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
@ -970,10 +543,13 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (scale < 1) if (scale < 1)
scale = 1; scale = 1;
// scale = (1.0f * mDrawPosition.scale / mHeight);
// TextRenderer.beginDraw(scale);
if (z >= MapGenerator.STROKE_MAX_ZOOM_LEVEL) if (z >= MapGenerator.STROKE_MAX_ZOOM_LEVEL)
TextRenderer.beginDraw(FloatMath.sqrt(s) / scale); TextRenderer.beginDraw(FloatMath.sqrt(s) / scale, mRotTMatrix);
else else
TextRenderer.beginDraw(s); TextRenderer.beginDraw(s, mRotTMatrix);
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
if (!tiles[i].isVisible || tiles[i].texture == null) if (!tiles[i].isVisible || tiles[i].texture == null)
@ -1055,7 +631,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
if (c == null) if (c == null)
continue; continue;
if (!setTileScissor(c, 2)) { if (!isVisible(c, 2)) {
drawn++; drawn++;
continue; continue;
} }
@ -1107,16 +683,13 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
@Override @Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) { public void onSurfaceChanged(GL10 glUnused, int width, int height) {
Log.d(TAG, "SurfaceChanged:" + width + " " + height); Log.d(TAG, "SurfaceChanged:" + width + " " + height);
mTilesLoaded.clear(); // mTilesLoaded.clear();
mTiles.clear(); // mTiles.clear();
ShortPool.init();
QuadTree.init();
// LineLayers.finish(); // LineLayers.finish();
drawTiles = newTiles = curTiles = null; drawTiles = curTiles = null;
mBufferMemoryUsage = 0; mBufferMemoryUsage = 0;
mInitial = true; // mInitial = true;
if (width <= 0 || height <= 0) if (width <= 0 || height <= 0)
return; return;
@ -1127,22 +700,20 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
mHeight = height; mHeight = height;
mAspect = (float) height / width; mAspect = (float) height / width;
// Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f, 0.5f, -1, 1); Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f, 0.5f, -1, 1);
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2) int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
* (mHeight / (Tile.TILE_SIZE / 2) + 2); * (mHeight / (Tile.TILE_SIZE / 2) + 2);
TileLoader.init(mMapView, width, height, numTiles);
drawTiles = new TilesData(numTiles); drawTiles = new TilesData(numTiles);
newTiles = new TilesData(numTiles);
curTiles = new TilesData(numTiles); curTiles = new TilesData(numTiles);
// Log.d(TAG, "using: " + numTiles + " + cache: " + CACHE_TILES);
GlUtils.checkGlError("pre glGenBuffers");
// Set up vertex buffer objects // Set up vertex buffer objects
int numVBO = (CACHE_TILES + numTiles); int numVBO = (CACHE_TILES + (numTiles * 2));
int[] mVboIds = new int[numVBO]; int[] mVboIds = new int[numVBO];
glGenBuffers(numVBO, mVboIds, 0); glGenBuffers(numVBO, mVboIds, 0);
GlUtils.checkGlError("glGenBuffers"); GlUtils.checkGlError("glGenBuffers");
@ -1155,8 +726,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
// Set up textures // Set up textures
TextRenderer.init(numTiles); TextRenderer.init(numTiles);
// glDisable(GL_DITHER);
if (mClearColor != null) { if (mClearColor != null) {
glClearColor(mClearColor[0], mClearColor[1], glClearColor(mClearColor[0], mClearColor[1],
mClearColor[2], mClearColor[3]); mClearColor[2], mClearColor[3]);
@ -1199,10 +768,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
mFillCoords[6] = max; mFillCoords[6] = max;
mFillCoords[7] = min; mFillCoords[7] = min;
// int i[] = new int[1];
// GLES20.glGetIntegerv(GLES20.GL_, i, 0);
// Log.d(TAG, " >>>> " + i[0]);
LineLayers.init(); LineLayers.init();
PolygonLayers.init(); PolygonLayers.init();
} }

View File

@ -19,25 +19,51 @@ import org.mapsforge.android.mapgenerator.JobTile;
class MapTile extends JobTile { class MapTile extends JobTile {
byte lastDraw = 0; byte lastDraw = 0;
// VBO layout: /**
// 16 bytes fill coordinates * VBO layout:
// n bytes polygon vertices * - 16 bytes fill coordinates
// m bytes lines vertices * - n bytes polygon vertices
* - m bytes lines vertices
*/
VertexBufferObject vbo; VertexBufferObject vbo;
// polygonOffset in vbo is always 16 bytes, /**
* polygonOffset in vbo is always 16 bytes,
*/
int lineOffset; int lineOffset;
TextTexture texture; TextTexture texture;
// Tile data set by MapGenerator: /**
* Tile data set by MapGenerator:
*/
LineLayer lineLayers; LineLayer lineLayers;
PolygonLayer polygonLayers; PolygonLayer polygonLayers;
TextItem labels; TextItem labels;
/**
* tile has new data to upload to gl
*/
boolean newData; boolean newData;
// pointer to access relatives in TileTree /**
* tile is loaded and ready for drawing.
*/
boolean isReady;
/**
* tile is in view region.
*/
boolean isVisible;
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
boolean isActive;
/**
* pointer to access relatives in TileTree
*/
QuadTree rel; QuadTree rel;
MapTile(int tileX, int tileY, byte zoomLevel) { MapTile(int tileX, int tileY, byte zoomLevel) {

View File

@ -111,14 +111,39 @@ class Shaders {
+ "attribute vec4 vertex;" + "attribute vec4 vertex;"
+ "attribute vec2 tex_coord;" + "attribute vec2 tex_coord;"
+ "uniform mat4 mvp;" + "uniform mat4 mvp;"
+ "uniform mat4 rotation;"
+ "uniform float scale;" + "uniform float scale;"
+ "varying vec2 tex_c;" + "varying vec2 tex_c;"
+ "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);" + "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
+ "void main() {" + "void main() {"
+ " gl_Position = mvp * vec4(vertex.xy + (vertex.zw / scale), 0.0, 1.0);" + " if (mod(vertex.x, 2.0) == 0.0){"
+ " gl_Position = mvp * vec4(vertex.xy + vertex.zw / scale, 0.0, 1.0);"
+ " } else {"
+ " vec4 dir = rotation * vec4(vertex.zw / scale, 0.0, 1.0);"
+ " gl_Position = mvp * vec4(vertex.xy + dir.xy, 0.0, 1.0);"
+ " }"
+ " tex_c = tex_coord * div;" + " tex_c = tex_coord * div;"
+ "}"; + "}";
// final static String textVertexShader = ""
// + "precision highp float; "
// + "attribute vec4 vertex;"
// + "attribute vec2 tex_coord;"
// + "uniform mat4 mvp;"
// + "uniform mat4 rotation;"
// + "uniform float scale;"
// + "varying vec2 tex_c;"
// + "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
// + "void main() {"
// + " if (mod(vertex.x, 2.0) == 0.0){"
// + " gl_Position = mvp * vec4(vertex.xy + vertex.zw / scale, 0.0, 1.0);"
// + " } else {"
// + " vec4 dir = rotation * vec4(vertex.zw / scale, 0.0, 1.0);"
// + " gl_Position = mvp * vec4(vertex.xy + dir.xy, 0.0, 1.0);"
// + " }"
// + " tex_c = tex_coord * div;"
// + "}";
final static String textFragmentShader = "" final static String textFragmentShader = ""
+ "precision highp float;" + "precision highp float;"
+ "uniform sampler2D tex;" + "uniform sampler2D tex;"

View File

@ -32,7 +32,9 @@ import android.util.Log;
public class TextRenderer { public class TextRenderer {
private final static int TEXTURE_WIDTH = 512; private final static int TEXTURE_WIDTH = 512;
private final static int TEXTURE_HEIGHT = 256; private final static int TEXTURE_HEIGHT = 256;
private final static float SCALE_FACTOR = 8.0f; private final static float SCALE = 8.0f;
private final static int LBIT_MASK = 0xfffffffe;
private final static int L2BIT_MASK = 0xfffffffc;
final static int INDICES_PER_SPRITE = 6; final static int INDICES_PER_SPRITE = 6;
final static int VERTICES_PER_SPRITE = 4; final static int VERTICES_PER_SPRITE = 4;
@ -53,6 +55,7 @@ public class TextRenderer {
private static int mTextProgram; private static int mTextProgram;
private static int hTextUVPMatrix; private static int hTextUVPMatrix;
private static int hTextRotationMatrix;
private static int hTextVertex; private static int hTextVertex;
private static int hTextScale; private static int hTextScale;
private static int hTextTextureCoord; private static int hTextTextureCoord;
@ -99,6 +102,8 @@ public class TextRenderer {
Shaders.textFragmentShader); Shaders.textFragmentShader);
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp"); hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
hTextRotationMatrix = GLES20.glGetUniformLocation(mTextProgram, "rotation");
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex"); hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale"); hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord"); hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
@ -283,10 +288,10 @@ public class TextRenderer {
float hh = height / 2.0f; float hh = height / 2.0f;
if (t.caption != null) { if (t.caption != null) {
x1 = x3 = (short) (SCALE_FACTOR * (-hw)); x1 = x3 = (short) (SCALE * (-hw));
y1 = y3 = (short) (SCALE_FACTOR * (-hh)); y1 = y3 = (short) (SCALE * (-hh));
x2 = x4 = (short) (SCALE_FACTOR * (hw)); x2 = x4 = (short) (SCALE * (hw));
y2 = y4 = (short) (SCALE_FACTOR * (hh)); y2 = y4 = (short) (SCALE * (hh));
} }
else { else {
float vx = t.x1 - t.x2; float vx = t.x1 - t.x2;
@ -298,26 +303,45 @@ public class TextRenderer {
float ux = -vy; float ux = -vy;
float uy = vx; float uy = vx;
x1 = (short) (SCALE_FACTOR * (vx * hw + ux * hh)); // int dx = (int) (vx * SCALE) & L2BIT_MASK;
y1 = (short) (SCALE_FACTOR * (vy * hw + uy * hh)); // int dy = (int) (vy * SCALE) & L2BIT_MASK;
//
// x1 = (short) dx;
// y1 = (short) dy;
//
// x2 = (short) (dx | 1);
// y3 = (short) (dy | 1);
//
// x4 = (short) (dx | 3);
// y4 = (short) (dy | 3);
//
// x3 = (short) (dx | 2);
// y2 = (short) (dy | 2);
x2 = (short) (SCALE_FACTOR * (-vx * hw + ux * hh)); x1 = (short) (SCALE * (vx * hw + ux * hh));
y3 = (short) (SCALE_FACTOR * (-vy * hw + uy * hh)); y1 = (short) (SCALE * (vy * hw + uy * hh));
x2 = (short) (SCALE * (-vx * hw + ux * hh));
x4 = (short) (SCALE_FACTOR * (-vx * hw - ux * hh)); y3 = (short) (SCALE * (-vy * hw + uy * hh));
y4 = (short) (SCALE_FACTOR * (-vy * hw - uy * hh)); x4 = (short) (SCALE * (-vx * hw - ux * hh));
y4 = (short) (SCALE * (-vy * hw - uy * hh));
x3 = (short) (SCALE_FACTOR * (vx * hw - ux * hh)); x3 = (short) (SCALE * (vx * hw - ux * hh));
y2 = (short) (SCALE_FACTOR * (vy * hw - uy * hh)); y2 = (short) (SCALE * (vy * hw - uy * hh));
} }
short u1 = (short) (SCALE_FACTOR * x); short u1 = (short) (SCALE * x);
short v1 = (short) (SCALE_FACTOR * y); short v1 = (short) (SCALE * y);
short u2 = (short) (SCALE_FACTOR * (x + width)); short u2 = (short) (SCALE * (x + width));
short v2 = (short) (SCALE_FACTOR * (y + height)); short v2 = (short) (SCALE * (y + height));
// pack caption/way-text info in lowest bit
short tx;
if (t.caption == null)
tx = (short) ((int) (SCALE * t.x) & LBIT_MASK | 0);
else
tx = (short) ((int) (SCALE * t.x) & LBIT_MASK | 1);
short ty = (short) (SCALE * t.y);
short tx = (short) (SCALE_FACTOR * t.x);
short ty = (short) (SCALE_FACTOR * t.y);
// top-left // top-left
buf[pos++] = tx; buf[pos++] = tx;
buf[pos++] = ty; buf[pos++] = ty;
@ -366,7 +390,7 @@ public class TextRenderer {
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
mBitmapFormat, mBitmapType); mBitmapFormat, mBitmapType);
GLES20.glFlush(); // GLES20.glFlush();
return true; return true;
} }
@ -397,13 +421,14 @@ public class TextRenderer {
mShortBuffer); mShortBuffer);
} }
static void beginDraw(float scale) { static void beginDraw(float scale, float[] rotation) {
GLES20.glUseProgram(mTextProgram); GLES20.glUseProgram(mTextProgram);
GLES20.glEnableVertexAttribArray(hTextTextureCoord); GLES20.glEnableVertexAttribArray(hTextTextureCoord);
GLES20.glEnableVertexAttribArray(hTextVertex); GLES20.glEnableVertexAttribArray(hTextVertex);
GLES20.glUniform1f(hTextScale, scale); GLES20.glUniform1f(hTextScale, scale);
GLES20.glUniformMatrix4fv(hTextRotationMatrix, 1, false, rotation, 0);
if (debug) { if (debug) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

View File

@ -0,0 +1,530 @@
/*
* Copyright 2012 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.glrenderer;
import java.util.ArrayList;
import java.util.Collections;
import org.mapsforge.android.MapView;
import org.mapsforge.android.glrenderer.MapRenderer.TilesData;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.core.MapPosition;
import org.mapsforge.core.MercatorProjection;
import org.mapsforge.core.Tile;
import android.util.FloatMath;
import android.util.Log;
// for lack of a better name... maybe TileManager?
/**
* Update list of visible tiles and passes them to MapRenderer, when not available tiles are created and added to
* JobQueue (mapView.addJobs) for loading by MapGenerator class
*/
public class TileLoader {
private static final String TAG = "TileLoader";
private static final int MAX_TILES_IN_QUEUE = 40;
private static final int CACHE_TILES_MAX = 200;
// private static final int MB = 1024 * 1024;
// private static final int LIMIT_BUFFERS = 16 * MB;
private static int CACHE_TILES = CACHE_TILES_MAX;
private static MapView mMapView;
private static ArrayList<JobTile> mJobList;
// private static ArrayList<VertexBufferObject> mVBOs;
// all tiles currently referenced
private static ArrayList<MapTile> mTiles;
// private static ArrayList<MapTile> mTilesActive;
// tiles that have new data to upload, see passTile()
private static ArrayList<MapTile> mTilesLoaded;
// current center tile, values used to check if position has
// changed for updating current tile list
private static long mTileX, mTileY;
private static float mPrevScale;
private static byte mPrevZoom;
private static boolean mInitial;
// private static MapPosition mCurPosition, mDrawPosition;
private static int mWidth, mHeight;
private static TilesData newTiles; // , curTiles, drawTiles;
static void init(MapView mapView, int w, int h, int numTiles) {
mMapView = mapView;
ShortPool.init();
QuadTree.init();
mJobList = new ArrayList<JobTile>();
mTiles = new ArrayList<MapTile>();
mTilesLoaded = new ArrayList<MapTile>(30);
mInitial = true;
mWidth = w;
mHeight = h;
newTiles = new TilesData(numTiles);
}
static void redrawTiles(boolean clear) {
boolean changedPos = false;
boolean changedZoom = false;
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
if (mapPosition == null) {
Log.d(TAG, ">>> no map position");
return;
}
if (clear) {
mInitial = true;
synchronized (MapRenderer.lock) {
for (MapTile t : mTiles)
clearTile(t);
mTiles.clear();
mTilesLoaded.clear();
QuadTree.init();
// curTiles.cnt = 0;
// mBufferMemoryUsage = 0;
}
}
byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale;
long tileX = MercatorProjection.pixelXToTileX(mapPosition.x, zoomLevel)
* Tile.TILE_SIZE;
long tileY = MercatorProjection.pixelYToTileY(mapPosition.y, zoomLevel)
* Tile.TILE_SIZE;
int zdir = 0;
if (mInitial || mPrevZoom != zoomLevel) {
changedZoom = true;
mPrevScale = scale;
}
else if (tileX != mTileX || tileY != mTileY) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
mPrevScale = scale;
changedPos = true;
}
else if (mPrevScale - scale > 0.2 || mPrevScale - scale < -0.2) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
mPrevScale = scale;
changedPos = true;
}
if (mInitial) {
// mCurPosition = mapPosition;
mInitial = false;
}
mTileX = tileX;
mTileY = tileY;
mPrevZoom = zoomLevel;
if (changedZoom) {
// need to update visible list first when zoom level changes
// as scaling is relative to the tiles of current zoom-level
updateVisibleList(mapPosition, 0);
} else {
// pass new position to glThread
MapRenderer.updatePosition(mapPosition);
// synchronized () {
// // do not change position while drawing
// mCurPosition = mapPosition;
// }
}
if (!MapView.debugFrameTime)
mMapView.requestRender();
if (changedPos)
updateVisibleList(mapPosition, zdir);
if (changedPos || changedZoom) {
int remove = mTiles.size() - CACHE_TILES;
if (remove > 50)
limitCache(mapPosition, remove);
}
int size = mTilesLoaded.size();
if (size > MAX_TILES_IN_QUEUE)
limitLoadQueue(size);
}
private static boolean updateVisibleList(MapPosition mapPosition, int zdir) {
double x = mapPosition.x;
double y = mapPosition.y;
byte zoomLevel = mapPosition.zoomLevel;
float scale = mapPosition.scale;
double add = 1.0f / scale;
int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
long pixelRight = (long) x + offsetX;
long pixelBottom = (long) y + offsetY;
long pixelLeft = (long) x - offsetX;
long pixelTop = (long) y - offsetY;
int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom, zoomLevel);
mJobList.clear();
// set non processed tiles to isLoading == false
mMapView.addJobs(null);
int tiles = 0;
if (newTiles == null)
return false;
int max = newTiles.tiles.length - 1;
for (int yy = tileTop; yy <= tileBottom; yy++) {
for (int xx = tileLeft; xx <= tileRight; xx++) {
if (tiles == max)
break;
MapTile tile = QuadTree.getTile(xx, yy, zoomLevel);
if (tile == null) {
tile = new MapTile(xx, yy, zoomLevel);
QuadTree.add(tile);
mTiles.add(tile);
}
newTiles.tiles[tiles++] = tile;
if (!(tile.isLoading || tile.newData || tile.isReady)) {
mJobList.add(tile);
}
if (zdir > 0 && zoomLevel > 0) {
// prefetch parent
MapTile parent = tile.rel.parent.tile;
if (parent == null) {
parent = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
QuadTree.add(parent);
mTiles.add(parent);
}
if (!(parent.isLoading || parent.isReady || parent.newData)) {
if (!mJobList.contains(parent))
mJobList.add(parent);
}
}
}
}
// pass new tile list to glThread
newTiles.cnt = tiles;
newTiles = MapRenderer.updateTiles(mapPosition, newTiles);
// pass new tile list to glThread
// synchronized (MapRenderer.lock) {
//
// for (int i = 0; i < curTiles.cnt; i++)
// curTiles.tiles[i].isActive = false;
//
// for (int j = 0; j < drawTiles.cnt; j++)
// drawTiles.tiles[j].isActive = true;
//
// for (int i = 0; i < tiles; i++)
// newTiles.tiles[i].isActive = true;
//
// TilesData tmp = curTiles;
// curTiles = newTiles;
// curTiles.cnt = tiles;
// newTiles = tmp;
//
// mCurPosition = mapPosition;
//
// mUpdateTiles = true;
// }
if (mJobList.size() > 0) {
updateTileDistances(mJobList, mapPosition);
Collections.sort(mJobList);
mMapView.addJobs(mJobList);
}
return true;
}
private static void clearTile(MapTile t) {
t.newData = false;
t.isLoading = false;
t.isReady = false;
LineLayers.clear(t.lineLayers);
PolygonLayers.clear(t.polygonLayers);
t.labels = null;
t.lineLayers = null;
t.polygonLayers = null;
if (t.vbo != null) {
MapRenderer.addVBO(t.vbo);
t.vbo = null;
}
QuadTree.remove(t);
}
private static boolean childIsActive(MapTile t) {
MapTile c = null;
for (int i = 0; i < 4; i++) {
if (t.rel.child[i] == null)
continue;
c = t.rel.child[i].tile;
if (c != null && c.isActive && !(c.isReady || c.newData))
return true;
}
return false;
}
// FIXME still the chance that one jumped two zoomlevels between
// cur and draw. should use reference counter instead
private static boolean tileInUse(MapTile t) {
byte z = mPrevZoom;
if (t.isActive) {
return true;
} else if (t.zoomLevel == z + 1) {
MapTile p = t.rel.parent.tile;
if (p != null && p.isActive && !(p.isReady || p.newData))
return true;
} else if (t.zoomLevel == z + 2) {
MapTile p = t.rel.parent.parent.tile;
if (p != null && p.isActive && !(p.isReady || p.newData))
return true;
} else if (t.zoomLevel == z - 1) {
if (childIsActive(t))
return true;
} else if (t.zoomLevel == z - 2) {
for (QuadTree c : t.rel.child) {
if (c == null)
continue;
if (c.tile != null && childIsActive(c.tile))
return true;
}
} else if (t.zoomLevel == z - 3) {
for (QuadTree c : t.rel.child) {
if (c == null)
continue;
for (QuadTree c2 : c.child) {
if (c2 == null)
continue;
if (c2.tile != null && childIsActive(c2.tile))
return true;
}
}
}
return false;
}
private static void updateTileDistances(ArrayList<?> tiles,
MapPosition mapPosition) {
int h = (Tile.TILE_SIZE >> 1);
byte zoom = mapPosition.zoomLevel;
long x = (long) mapPosition.x;
long y = (long) mapPosition.y;
int diff;
long dx, dy;
// TODO this could need some fixing, and optimization
// to consider move/zoom direction
for (int i = 0, n = tiles.size(); i < n; i++) {
JobTile t = (JobTile) tiles.get(i);
diff = (t.zoomLevel - zoom);
if (diff == 0) {
dx = (t.pixelX + h) - x;
dy = (t.pixelY + h) - y;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * 0.25f;
t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * 0.25f;
} else if (diff > 0) {
// tile zoom level is child of current
if (diff < 3) {
dx = ((t.pixelX + h) >> diff) - x;
dy = ((t.pixelY + h) >> diff) - y;
}
else {
dx = ((t.pixelX + h) >> (diff >> 1)) - x;
dy = ((t.pixelY + h) >> (diff >> 1)) - y;
}
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy));
t.distance = FloatMath.sqrt((dx * dx + dy * dy));
} else {
// tile zoom level is parent of current
dx = ((t.pixelX + h) << -diff) - x;
dy = ((t.pixelY + h) << -diff) - y;
// t.distance = ((dx > 0 ? dx : -dx) + (dy > 0 ? dy : -dy)) * (-diff * 0.5f);
t.distance = FloatMath.sqrt((dx * dx + dy * dy)) * (-diff * 0.5f);
}
}
}
private static void limitCache(MapPosition mapPosition, int remove) {
int removes = remove;
int size = mTiles.size();
int tmp = size;
// remove orphaned tiles
for (int i = 0; i < size;) {
MapTile cur = mTiles.get(i);
// make sure tile cannot be used by GL or MapWorker Thread
if ((!cur.isActive) && (!cur.isLoading) && (!cur.newData)
&& (!cur.isReady) && (!tileInUse(cur))) {
clearTile(cur);
mTiles.remove(i);
removes--;
size--;
// Log.d(TAG, "remove empty tile" + cur);
continue;
}
i++;
}
Log.d(TAG, "remove tiles: " + removes + " " + size + " " + tmp);
if (removes <= 0)
return;
updateTileDistances(mTiles, mapPosition);
Collections.sort(mTiles);
// boolean printAll = false;
for (int i = 1; i <= removes; i++) {
MapTile t = mTiles.remove(size - i);
synchronized (t) {
if (t.isActive) {
// dont remove tile used by renderthread
Log.d(TAG, "X not removing active " + t + " " + t.distance);
// if (printAll) {
// printAll = false;
// for (GLMapTile tt : mTiles)
// Log.d(TAG, ">>>" + tt + " " + tt.distance);
// }
mTiles.add(t);
} else if ((t.isReady || t.newData) && tileInUse(t)) {
// check if this tile could be used as proxy
Log.d(TAG, "X not removing proxy: " + t + " " + t.distance);
mTiles.add(t);
} else {
if (t.isLoading) {
Log.d(TAG, "X cancel loading " + t + " " + t.distance);
t.isLoading = false;
}
clearTile(t);
}
}
}
}
private static void limitLoadQueue(int remove) {
int size = remove;
synchronized (mTilesLoaded) {
// remove uploaded tiles
for (int i = 0; i < size;) {
MapTile t = mTilesLoaded.get(i);
// rel == null means tile is already removed by limitCache
if (!t.newData || t.rel == null) {
mTilesLoaded.remove(i);
size--;
continue;
}
i++;
}
// clear loaded but not used tiles
if (size < MAX_TILES_IN_QUEUE)
return;
while (size-- > MAX_TILES_IN_QUEUE - 20) {
MapTile t = mTilesLoaded.get(size);
synchronized (t) {
if (t.rel == null) {
mTilesLoaded.remove(size);
continue;
}
if (tileInUse(t)) {
// Log.d(TAG, "keep unused tile data: " + t + " " + t.isActive);
continue;
}
mTilesLoaded.remove(size);
mTiles.remove(t);
// Log.d(TAG, "remove unused tile data: " + t);
clearTile(t);
}
}
}
}
static void addTileLoaded(MapTile tile) {
synchronized (mTilesLoaded) {
mTilesLoaded.add(0, tile);
}
}
}

View File

@ -20,28 +20,20 @@ import org.mapsforge.core.Tile;
* *
*/ */
public class JobTile extends Tile implements Comparable<JobTile> { public class JobTile extends Tile implements Comparable<JobTile> {
/** // public final static int LOADING = 1;
* tile is loaded and ready for drawing. (set and used by render thread after uploading data to gl). // public final static int NEWDATA = 1 << 1;
*/ // public final static int READY = 1 << 2;
public boolean isReady; // public final static int AVAILABLE = 1 << 1 | 1 << 2;
// public final static int CANCELED = 1 << 3;
// public int state;
/** /**
* tile is removed from JobQueue and loading in DatabaseRenderer. set by MapWorker. * tile is in JobQueue
*/ */
public boolean isLoading; public boolean isLoading;
/** /**
* tile is in view region. (set and used by render thread) * distance from map center.
*/
public boolean isVisible;
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
public boolean isActive;
/**
* distance from center, used in TileScheduler set by updateVisibleList.
*/ */
public float distance; public float distance;
@ -61,7 +53,8 @@ public class JobTile extends Tile implements Comparable<JobTile> {
public int compareTo(JobTile o) { public int compareTo(JobTile o) {
if (this.distance < o.distance) { if (this.distance < o.distance) {
return -1; return -1;
} else if (this.distance > o.distance) { }
if (this.distance > o.distance) {
return 1; return 1;
} }
return 0; return 0;

View File

@ -61,8 +61,8 @@ public final class MapDatabaseFactory {
switch (mapDatabase) { switch (mapDatabase) {
case MAP_READER: case MAP_READER:
return new org.mapsforge.database.mapfile.MapDatabase(); return new org.mapsforge.database.mapfile.MapDatabase();
case JSON_READER: case TEST_READER:
return new org.mapsforge.database.json.MapDatabase(); return new org.mapsforge.database.test.MapDatabase();
case POSTGIS_READER: case POSTGIS_READER:
return new org.mapsforge.database.postgis.MapDatabase(); return new org.mapsforge.database.postgis.MapDatabase();
case PBMAP_READER: case PBMAP_READER:

View File

@ -26,7 +26,7 @@ public enum MapDatabases {
/** /**
* ... * ...
*/ */
JSON_READER, TEST_READER,
/** /**
* ... * ...

View File

@ -91,7 +91,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
private static float PI180 = (float) (Math.PI / 180) / 1000000.0f; private static float PI180 = (float) (Math.PI / 180) / 1000000.0f;
private static float PIx4 = (float) Math.PI * 4; private static float PIx4 = (float) Math.PI * 4;
private Tile mCurrentTile; private JobTile mCurrentTile;
private static long mCurrentTileY; private static long mCurrentTileY;
private static long mCurrentTileX; private static long mCurrentTileX;
private static long mCurrentTileZoom; private static long mCurrentTileZoom;

View File

@ -28,6 +28,8 @@ public class MapTile extends JobTile {
// private long mLoadTime; // private long mLoadTime;
private int mTextureID; private int mTextureID;
boolean isVisible;
/** /**
* @param tileX * @param tileX
* ... * ...

View File

@ -104,6 +104,10 @@ public class TileMap extends MapActivity {
return true; return true;
case R.id.menu_position: case R.id.menu_position:
mMapView.enableRotation(true);
return true;
case R.id.menu_rotation_enable:
return true; return true;
case R.id.menu_position_my_location_enable: case R.id.menu_position_my_location_enable:

View File

@ -49,8 +49,6 @@ public class Tile {
*/ */
public final long pixelY; public final long pixelY;
public volatile boolean isCanceled;
/** /**
* @param tileX * @param tileX
* the X number of the tile. * the X number of the tile.

View File

@ -16,7 +16,7 @@ package org.mapsforge.database;
import java.io.File; import java.io.File;
import org.mapsforge.core.Tile; import org.mapsforge.android.mapgenerator.JobTile;
/** /**
* *
@ -38,7 +38,7 @@ public interface IMapDatabase {
* the callback which handles the extracted map elements. * the callback which handles the extracted map elements.
* @return true if successful * @return true if successful
*/ */
public abstract QueryResult executeQuery(Tile tile, public abstract QueryResult executeQuery(JobTile tile,
IMapDatabaseCallback mapDatabaseCallback); IMapDatabaseCallback mapDatabaseCallback);
/** /**

View File

@ -20,9 +20,9 @@ import java.io.RandomAccessFile;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.core.MercatorProjection; import org.mapsforge.core.MercatorProjection;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile;
import org.mapsforge.database.FileOpenResult; import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback; import org.mapsforge.database.IMapDatabaseCallback;
@ -204,7 +204,7 @@ public class MapDatabase implements IMapDatabase {
* org.mapsforge.map.reader.MapDatabaseCallback) * org.mapsforge.map.reader.MapDatabaseCallback)
*/ */
@Override @Override
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
if (sMapFileHeader == null) if (sMapFileHeader == null)
return QueryResult.FAILED; return QueryResult.FAILED;

View File

@ -53,6 +53,7 @@ import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.protocol.RequestExpectContinue; import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestUserAgent; import org.apache.http.protocol.RequestUserAgent;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.core.BoundingBox; import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint; import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
@ -106,7 +107,7 @@ public class MapDatabase implements IMapDatabase {
private IMapDatabaseCallback mMapGenerator; private IMapDatabaseCallback mMapGenerator;
private float mScaleFactor; private float mScaleFactor;
private Tile mTile; private JobTile mTile;
private FileOutputStream mCacheFile; private FileOutputStream mCacheFile;
private long mContentLenth; private long mContentLenth;
@ -129,7 +130,7 @@ public class MapDatabase implements IMapDatabase {
}); });
@Override @Override
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
QueryResult result = QueryResult.SUCCESS; QueryResult result = QueryResult.SUCCESS;
mCacheFile = null; mCacheFile = null;
@ -194,7 +195,7 @@ public class MapDatabase implements IMapDatabase {
entity.consumeContent(); entity.consumeContent();
return QueryResult.FAILED; return QueryResult.FAILED;
} }
if (mTile.isCanceled) { if (!mTile.isLoading) {
Log.d(TAG, "1 loading canceled " + mTile); Log.d(TAG, "1 loading canceled " + mTile);
entity.consumeContent(); entity.consumeContent();
@ -249,7 +250,7 @@ public class MapDatabase implements IMapDatabase {
mRequest = null; mRequest = null;
// FIXME remove this stuff // FIXME remove this stuff
if (mTile.isCanceled) { if (!mTile.isLoading) {
Log.d(TAG, "loading canceled " + mTile); Log.d(TAG, "loading canceled " + mTile);
result = QueryResult.FAILED; result = QueryResult.FAILED;
} }

View File

@ -24,10 +24,10 @@ import java.util.HashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.core.BoundingBox; import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint; import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile;
import org.mapsforge.core.WebMercator; import org.mapsforge.core.WebMercator;
import org.mapsforge.database.FileOpenResult; import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
@ -45,7 +45,7 @@ import android.util.Log;
public class MapDatabase implements IMapDatabase { public class MapDatabase implements IMapDatabase {
private final static String TAG = "MapDatabase"; private final static String TAG = "MapDatabase";
private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?,false)"; private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?)";
private final float mScale = 1; private final float mScale = 1;
@ -71,7 +71,7 @@ public class MapDatabase implements IMapDatabase {
private boolean connect() { private boolean connect() {
Connection conn = null; Connection conn = null;
String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis"; String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis-2.0";
Properties dbOpts = new Properties(); Properties dbOpts = new Properties();
dbOpts.setProperty("user", "osm"); dbOpts.setProperty("user", "osm");
@ -102,7 +102,7 @@ public class MapDatabase implements IMapDatabase {
} }
@Override @Override
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
if (connection == null) { if (connection == null) {
if (!connect()) if (!connect())
return QueryResult.FAILED; return QueryResult.FAILED;

View File

@ -12,10 +12,11 @@
* You should have received a copy of the GNU Lesser General Public License along with * You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.mapsforge.database.json; package org.mapsforge.database.test;
import java.io.File; import java.io.File;
import org.mapsforge.android.mapgenerator.JobTile;
import org.mapsforge.core.BoundingBox; import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.MercatorProjection; import org.mapsforge.core.MercatorProjection;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
@ -51,7 +52,7 @@ public class MapDatabase implements IMapDatabase {
// private static double HALF_PI = Math.PI / 2; // private static double HALF_PI = Math.PI / 2;
@Override @Override
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
long cx = tile.pixelX + (Tile.TILE_SIZE >> 1); long cx = tile.pixelX + (Tile.TILE_SIZE >> 1);
long cy = tile.pixelY + (Tile.TILE_SIZE >> 1); long cy = tile.pixelY + (Tile.TILE_SIZE >> 1);