- 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:
parent
2d90a4dea4
commit
69fe74facc
@ -22,6 +22,10 @@
|
||||
<item
|
||||
android:id="@+id/menu_position_map_center"
|
||||
android:title="@string/menu_position_map_file_center"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_rotation_enable"
|
||||
android:title="@string/menu_rotation_enable"/>
|
||||
</menu>
|
||||
</item>
|
||||
<item
|
||||
|
||||
@ -22,6 +22,10 @@
|
||||
<item
|
||||
android:id="@+id/menu_position_map_center"
|
||||
android:title="@string/menu_position_map_file_center"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_rotation_enable"
|
||||
android:title="@string/menu_rotation_enable"/>
|
||||
</menu>
|
||||
</item>
|
||||
<item
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<resources>
|
||||
<string-array name="preferences_map_generator_values">
|
||||
<!-- <item>Mapfile</item> -->
|
||||
<!-- <item>PostGIS</item>-->
|
||||
<!-- <item>PostGIS</item>-->
|
||||
<item>OpenScienceMap</item>
|
||||
</string-array>
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
<string name="menu_info_about">About this software</string>
|
||||
<string name="menu_mapfile">Map file</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_last_known">Last known location</string>
|
||||
<string name="menu_position_map_file_center">Map file center</string>
|
||||
|
||||
@ -24,11 +24,11 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.IMapGenerator;
|
||||
import org.mapsforge.android.mapgenerator.JobQueue;
|
||||
import org.mapsforge.android.mapgenerator.JobTile;
|
||||
import org.mapsforge.android.mapgenerator.MapDatabaseFactory;
|
||||
import org.mapsforge.android.mapgenerator.MapDatabases;
|
||||
import org.mapsforge.android.mapgenerator.MapRendererFactory;
|
||||
import org.mapsforge.android.mapgenerator.MapRenderers;
|
||||
import org.mapsforge.android.mapgenerator.JobTile;
|
||||
import org.mapsforge.android.mapgenerator.MapWorker;
|
||||
import org.mapsforge.android.mapgenerator.Theme;
|
||||
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);
|
||||
|
||||
public final static boolean debugFrameTime = false;
|
||||
public boolean enableRotation = false;
|
||||
|
||||
private final MapController mMapController;
|
||||
private final MapViewPosition mMapViewPosition;
|
||||
@ -160,7 +161,7 @@ public class MapView extends GLSurfaceView {
|
||||
IMapDatabase mapDatabase;
|
||||
if (mDebugDatabase) {
|
||||
mapDatabase = MapDatabaseFactory
|
||||
.createMapDatabase(MapDatabases.JSON_READER);
|
||||
.createMapDatabase(MapDatabases.TEST_READER);
|
||||
} else {
|
||||
mapDatabase = MapDatabaseFactory.createMapDatabase(mapDatabaseType);
|
||||
}
|
||||
@ -684,6 +685,10 @@ public class MapView extends GLSurfaceView {
|
||||
mapWorker.proceed();
|
||||
}
|
||||
|
||||
public void enableRotation(boolean enable) {
|
||||
enableRotation = enable;
|
||||
}
|
||||
|
||||
// public final int
|
||||
// public Handler messageHandler = new Handler() {
|
||||
//
|
||||
|
||||
@ -19,7 +19,6 @@ import org.mapsforge.core.MapPosition;
|
||||
import org.mapsforge.core.MercatorProjection;
|
||||
|
||||
import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
|
||||
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
|
||||
double dx, dy;
|
||||
|
||||
// float rad = (float) Math.toRadians(mRotation);
|
||||
// mx /= mScale;
|
||||
// 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;
|
||||
if (mMapView.enableRotation) {
|
||||
float rad = (float) Math.toRadians(mRotation);
|
||||
dx = mx / mScale;
|
||||
dy = my / mScale;
|
||||
|
||||
double dx = pixelX - mx / mScale;
|
||||
double dy = pixelY - my / mScale;
|
||||
double x = dx * FloatMath.cos(rad) + dy * -FloatMath.sin(rad);
|
||||
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.limitLatitude(mLatitude);
|
||||
|
||||
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.limitLongitude(mLongitude);
|
||||
}
|
||||
|
||||
public synchronized void rotateMap(float angle) {
|
||||
public synchronized void rotateMap(float angle, float cx, float cy) {
|
||||
moveMap(cx, cy);
|
||||
mRotation -= angle;
|
||||
Log.d("...", "angle:" + mRotation);
|
||||
// mRotation %= 360;
|
||||
}
|
||||
|
||||
synchronized void setMapCenter(GeoPoint geoPoint) {
|
||||
|
||||
@ -112,16 +112,33 @@ public class TouchHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (multi > 0) {
|
||||
// double dx = event.getX(0) - event.getX(1);
|
||||
// double dy = event.getY(0) - event.getY(1);
|
||||
// double rad = Math.atan2(dy, dx);
|
||||
// float angle = (float) Math.toDegrees(rad);
|
||||
// mMapPosition.rotateMap(angle - mAngle);
|
||||
// mAngle = angle;
|
||||
// mMapView.redrawTiles();
|
||||
// }
|
||||
if (mMapView.enableRotation) {
|
||||
if (multi > 0) {
|
||||
double x1 = event.getX(0);
|
||||
double x2 = event.getX(1);
|
||||
double y1 = event.getY(0);
|
||||
double y2 = event.getY(1);
|
||||
|
||||
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
|
||||
mPosX = event.getX(pointerIndex);
|
||||
mPosY = event.getY(pointerIndex);
|
||||
@ -182,7 +199,7 @@ public class TouchHandler {
|
||||
private boolean onActionUp(MotionEvent motionEvent) {
|
||||
mActivePointerId = INVALID_POINTER_ID;
|
||||
mScaling = false;
|
||||
|
||||
multi = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -400,7 +417,11 @@ public class TouchHandler {
|
||||
mCenterX = mMapView.getWidth() >> 1;
|
||||
mCenterY = mMapView.getHeight() >> 1;
|
||||
mScale = 1;
|
||||
// mMapPosition = mMapView.getMapPosition();
|
||||
|
||||
if (mTimer != null) {
|
||||
mTimer.cancel();
|
||||
mTimer = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -428,12 +428,11 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
mDebugDrawUnmatched = debugSettings.mDrawUnmatchted;
|
||||
|
||||
// fixed now....
|
||||
if (tile.newData || tile.isReady || tile.isCanceled) {
|
||||
if (tile.newData || tile.isReady) {
|
||||
Log.d(TAG, "XXX tile already loaded "
|
||||
+ tile + " "
|
||||
+ tile.newData + " "
|
||||
+ tile.isReady + " "
|
||||
+ tile.isCanceled);
|
||||
+ tile.isReady + " ");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,6 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
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.utils.GlUtils;
|
||||
import org.mapsforge.core.MapPosition;
|
||||
import org.mapsforge.core.MercatorProjection;
|
||||
import org.mapsforge.core.Tile;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
@ -57,45 +55,11 @@ import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
|
||||
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 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 {
|
||||
/**
|
||||
* used for passing tiles to be rendered from TileLoader(Main) to GLThread
|
||||
*/
|
||||
static class TilesData {
|
||||
int cnt = 0;
|
||||
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[] mRotateMatrix = new float[16];
|
||||
// private static float[] mProjMatrix = new float[16];
|
||||
private static float[] mRotateMatrix = new float[16];
|
||||
private static float[] mProjMatrix = new float[16];
|
||||
private static float[] mRotTMatrix = new float[16];
|
||||
|
||||
// newTiles is set in updateVisibleList and swapped
|
||||
// with curTiles on main thread. curTiles is swapped
|
||||
// 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
|
||||
// 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
|
||||
private static boolean mUpdateTiles;
|
||||
|
||||
private static boolean mInitial;
|
||||
|
||||
private float[] mClearColor = null;
|
||||
|
||||
// number of tiles drawn in one frame
|
||||
@ -130,6 +117,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
|
||||
private static boolean mUpdateColor = false;
|
||||
|
||||
static Object lock = new Object();
|
||||
|
||||
/**
|
||||
* @param mapView
|
||||
* the MapView
|
||||
@ -138,475 +127,52 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
Log.d(TAG, "init MapRenderer");
|
||||
|
||||
mMapView = mapView;
|
||||
|
||||
if (mInitial)
|
||||
return;
|
||||
|
||||
mJobList = new ArrayList<JobTile>();
|
||||
mTiles = new ArrayList<MapTile>();
|
||||
mTilesLoaded = new ArrayList<MapTile>(30);
|
||||
|
||||
Matrix.setIdentityM(mMVPMatrix, 0);
|
||||
|
||||
mInitial = true;
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public synchronized void redrawTiles(boolean clear) {
|
||||
boolean changedPos = false;
|
||||
boolean changedZoom = false;
|
||||
MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
|
||||
public void redrawTiles(boolean clear) {
|
||||
TileLoader.redrawTiles(clear);
|
||||
}
|
||||
|
||||
if (mapPosition == null) {
|
||||
Log.d(TAG, ">>> no map position");
|
||||
return;
|
||||
}
|
||||
static void updatePosition(MapPosition mapPosition) {
|
||||
// synchronized (MapRenderer.lock) {
|
||||
mCurPosition = mapPosition;
|
||||
// }
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
mInitial = true;
|
||||
synchronized (this) {
|
||||
static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
synchronized (this) {
|
||||
// do not change position while drawing
|
||||
mCurPosition = mapPosition;
|
||||
}
|
||||
static void addVBO(VertexBufferObject vbo) {
|
||||
synchronized (mVBOs) {
|
||||
mVBOs.add(vbo);
|
||||
}
|
||||
|
||||
if (!MapView.debugFrameTime)
|
||||
mMapView.requestRender();
|
||||
|
||||
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) {
|
||||
MapTile tile = (MapTile) jobTile;
|
||||
|
||||
if (tile.isCanceled) {
|
||||
if (!tile.isLoading) {
|
||||
// no one should be able to use this tile now, mapgenerator passed it,
|
||||
// glthread does nothing until newdata is set.
|
||||
Log.d(TAG, "passTile: canceled " + tile);
|
||||
tile.isLoading = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -644,9 +209,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
if (!MapView.debugFrameTime)
|
||||
mMapView.requestRender();
|
||||
|
||||
synchronized (mTilesLoaded) {
|
||||
mTilesLoaded.add(0, tile);
|
||||
}
|
||||
TileLoader.addTileLoaded(tile);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -655,37 +218,46 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
// ... asus has just 16 bit?!
|
||||
// private static final float depthStep = 0.00000011920928955078125f;
|
||||
|
||||
private static boolean mRotate = false;
|
||||
|
||||
private static void setMatrix(MapTile tile, float div, int offset) {
|
||||
float x, y, scale;
|
||||
|
||||
scale = (float) (2.0 * mDrawPosition.scale / (mHeight * div));
|
||||
x = (float) (tile.pixelX - mDrawPosition.x * div);
|
||||
y = (float) (tile.pixelY - mDrawPosition.y * div);
|
||||
if (mRotate) {
|
||||
scale = (float) (1.0 * mDrawPosition.scale / (mHeight * div));
|
||||
x = (float) (tile.pixelX - mDrawPosition.x * div);
|
||||
y = (float) (tile.pixelY - mDrawPosition.y * div);
|
||||
|
||||
mMVPMatrix[12] = x * scale * mAspect;
|
||||
mMVPMatrix[13] = -(y + Tile.TILE_SIZE) * scale;
|
||||
// increase the 'distance' with each tile drawn.
|
||||
mMVPMatrix[14] = -1 + offset * 0.01f; // depthStep; // 0.01f;
|
||||
mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER;
|
||||
mMVPMatrix[5] = scale / COORD_MULTIPLIER;
|
||||
Matrix.setIdentityM(mMVPMatrix, 0);
|
||||
|
||||
// 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);
|
||||
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));
|
||||
x = (float) (tile.pixelX - mDrawPosition.x * div);
|
||||
y = (float) (tile.pixelY - mDrawPosition.y * div);
|
||||
|
||||
mMVPMatrix[12] = x * scale * mAspect;
|
||||
mMVPMatrix[13] = -(y + Tile.TILE_SIZE) * scale;
|
||||
// increase the 'distance' with each tile drawn.
|
||||
mMVPMatrix[14] = -1 + offset * 0.01f; // depthStep; // 0.01f;
|
||||
mMVPMatrix[0] = scale * mAspect / COORD_MULTIPLIER;
|
||||
mMVPMatrix[5] = scale / COORD_MULTIPLIER;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean setTileScissor(MapTile tile, float div) {
|
||||
private static boolean isVisible(MapTile tile, float div) {
|
||||
double dx, dy, scale;
|
||||
|
||||
if (div == 0) {
|
||||
@ -773,8 +345,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
+ sbuf.limit() + " "
|
||||
+ sbuf.remaining() + " "
|
||||
+ PolygonLayers.sizeOf(tile.polygonLayers) + " "
|
||||
+ tile.isCanceled + " "
|
||||
+ tile.isLoading + " "
|
||||
+ tile.rel);
|
||||
|
||||
tile.lineOffset *= SHORT_BYTES;
|
||||
@ -790,7 +360,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
+ sbuf.limit() + " "
|
||||
+ sbuf.remaining() + " "
|
||||
+ LineLayers.sizeOf(tile.lineLayers)
|
||||
+ tile.isCanceled + " "
|
||||
+ tile.isLoading + " "
|
||||
+ tile.rel);
|
||||
|
||||
@ -864,6 +433,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
if (MapView.debugFrameTime)
|
||||
start = SystemClock.uptimeMillis();
|
||||
|
||||
mRotate = mMapView.enableRotation;
|
||||
|
||||
if (mUpdateColor && mClearColor != null) {
|
||||
glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]);
|
||||
mUpdateColor = false;
|
||||
@ -871,7 +442,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
|
||||
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
|
||||
// is masked out from the depth buffer as they share the same
|
||||
// memory region afaik
|
||||
@ -879,11 +450,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
| GLES20.GL_DEPTH_BUFFER_BIT
|
||||
| GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (mInitial)
|
||||
return;
|
||||
|
||||
// get position and current tiles to draw
|
||||
synchronized (this) {
|
||||
synchronized (MapRenderer.lock) {
|
||||
mDrawPosition = mCurPosition;
|
||||
|
||||
if (mUpdateTiles) {
|
||||
@ -904,7 +472,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile tile = tiles[i];
|
||||
|
||||
if (!setTileScissor(tile, 1))
|
||||
if (!isVisible(tile, 1))
|
||||
continue;
|
||||
|
||||
if (tile.texture == null && TextRenderer.drawToTexture(tile))
|
||||
@ -939,6 +507,11 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
if (updateTextures > 0)
|
||||
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);
|
||||
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
@ -970,10 +543,13 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
if (scale < 1)
|
||||
scale = 1;
|
||||
|
||||
// scale = (1.0f * mDrawPosition.scale / mHeight);
|
||||
// TextRenderer.beginDraw(scale);
|
||||
|
||||
if (z >= MapGenerator.STROKE_MAX_ZOOM_LEVEL)
|
||||
TextRenderer.beginDraw(FloatMath.sqrt(s) / scale);
|
||||
TextRenderer.beginDraw(FloatMath.sqrt(s) / scale, mRotTMatrix);
|
||||
else
|
||||
TextRenderer.beginDraw(s);
|
||||
TextRenderer.beginDraw(s, mRotTMatrix);
|
||||
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
if (!tiles[i].isVisible || tiles[i].texture == null)
|
||||
@ -1055,7 +631,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
if (c == null)
|
||||
continue;
|
||||
|
||||
if (!setTileScissor(c, 2)) {
|
||||
if (!isVisible(c, 2)) {
|
||||
drawn++;
|
||||
continue;
|
||||
}
|
||||
@ -1107,16 +683,13 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
|
||||
Log.d(TAG, "SurfaceChanged:" + width + " " + height);
|
||||
mTilesLoaded.clear();
|
||||
mTiles.clear();
|
||||
|
||||
ShortPool.init();
|
||||
QuadTree.init();
|
||||
// mTilesLoaded.clear();
|
||||
// mTiles.clear();
|
||||
// LineLayers.finish();
|
||||
|
||||
drawTiles = newTiles = curTiles = null;
|
||||
drawTiles = curTiles = null;
|
||||
mBufferMemoryUsage = 0;
|
||||
mInitial = true;
|
||||
// mInitial = true;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
@ -1127,22 +700,20 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
mHeight = height;
|
||||
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);
|
||||
|
||||
int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
|
||||
* (mHeight / (Tile.TILE_SIZE / 2) + 2);
|
||||
|
||||
TileLoader.init(mMapView, width, height, numTiles);
|
||||
|
||||
drawTiles = new TilesData(numTiles);
|
||||
newTiles = new TilesData(numTiles);
|
||||
curTiles = new TilesData(numTiles);
|
||||
|
||||
// Log.d(TAG, "using: " + numTiles + " + cache: " + CACHE_TILES);
|
||||
GlUtils.checkGlError("pre glGenBuffers");
|
||||
|
||||
// Set up vertex buffer objects
|
||||
int numVBO = (CACHE_TILES + numTiles);
|
||||
int numVBO = (CACHE_TILES + (numTiles * 2));
|
||||
int[] mVboIds = new int[numVBO];
|
||||
glGenBuffers(numVBO, mVboIds, 0);
|
||||
GlUtils.checkGlError("glGenBuffers");
|
||||
@ -1155,8 +726,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
// Set up textures
|
||||
TextRenderer.init(numTiles);
|
||||
|
||||
// glDisable(GL_DITHER);
|
||||
|
||||
if (mClearColor != null) {
|
||||
glClearColor(mClearColor[0], mClearColor[1],
|
||||
mClearColor[2], mClearColor[3]);
|
||||
@ -1199,10 +768,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
mFillCoords[6] = max;
|
||||
mFillCoords[7] = min;
|
||||
|
||||
// int i[] = new int[1];
|
||||
// GLES20.glGetIntegerv(GLES20.GL_, i, 0);
|
||||
// Log.d(TAG, " >>>> " + i[0]);
|
||||
|
||||
LineLayers.init();
|
||||
PolygonLayers.init();
|
||||
}
|
||||
|
||||
@ -19,25 +19,51 @@ import org.mapsforge.android.mapgenerator.JobTile;
|
||||
class MapTile extends JobTile {
|
||||
byte lastDraw = 0;
|
||||
|
||||
// VBO layout:
|
||||
// 16 bytes fill coordinates
|
||||
// n bytes polygon vertices
|
||||
// m bytes lines vertices
|
||||
/**
|
||||
* VBO layout:
|
||||
* - 16 bytes fill coordinates
|
||||
* - n bytes polygon vertices
|
||||
* - m bytes lines vertices
|
||||
*/
|
||||
VertexBufferObject vbo;
|
||||
|
||||
// polygonOffset in vbo is always 16 bytes,
|
||||
/**
|
||||
* polygonOffset in vbo is always 16 bytes,
|
||||
*/
|
||||
int lineOffset;
|
||||
|
||||
TextTexture texture;
|
||||
|
||||
// Tile data set by MapGenerator:
|
||||
/**
|
||||
* Tile data set by MapGenerator:
|
||||
*/
|
||||
LineLayer lineLayers;
|
||||
PolygonLayer polygonLayers;
|
||||
TextItem labels;
|
||||
|
||||
/**
|
||||
* tile has new data to upload to gl
|
||||
*/
|
||||
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;
|
||||
|
||||
MapTile(int tileX, int tileY, byte zoomLevel) {
|
||||
|
||||
@ -111,14 +111,39 @@ class Shaders {
|
||||
+ "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() {"
|
||||
+ " gl_Position = mvp * vec4(vertex.xy + (vertex.zw / scale), 0.0, 1.0);"
|
||||
+ " tex_c = tex_coord * div;"
|
||||
+ " 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 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 = ""
|
||||
+ "precision highp float;"
|
||||
+ "uniform sampler2D tex;"
|
||||
|
||||
@ -32,7 +32,9 @@ import android.util.Log;
|
||||
public class TextRenderer {
|
||||
private final static int TEXTURE_WIDTH = 512;
|
||||
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 VERTICES_PER_SPRITE = 4;
|
||||
@ -53,6 +55,7 @@ public class TextRenderer {
|
||||
|
||||
private static int mTextProgram;
|
||||
private static int hTextUVPMatrix;
|
||||
private static int hTextRotationMatrix;
|
||||
private static int hTextVertex;
|
||||
private static int hTextScale;
|
||||
private static int hTextTextureCoord;
|
||||
@ -99,6 +102,8 @@ public class TextRenderer {
|
||||
Shaders.textFragmentShader);
|
||||
|
||||
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
|
||||
hTextRotationMatrix = GLES20.glGetUniformLocation(mTextProgram, "rotation");
|
||||
|
||||
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
|
||||
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
|
||||
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
|
||||
@ -283,10 +288,10 @@ public class TextRenderer {
|
||||
float hh = height / 2.0f;
|
||||
|
||||
if (t.caption != null) {
|
||||
x1 = x3 = (short) (SCALE_FACTOR * (-hw));
|
||||
y1 = y3 = (short) (SCALE_FACTOR * (-hh));
|
||||
x2 = x4 = (short) (SCALE_FACTOR * (hw));
|
||||
y2 = y4 = (short) (SCALE_FACTOR * (hh));
|
||||
x1 = x3 = (short) (SCALE * (-hw));
|
||||
y1 = y3 = (short) (SCALE * (-hh));
|
||||
x2 = x4 = (short) (SCALE * (hw));
|
||||
y2 = y4 = (short) (SCALE * (hh));
|
||||
}
|
||||
else {
|
||||
float vx = t.x1 - t.x2;
|
||||
@ -298,26 +303,45 @@ public class TextRenderer {
|
||||
float ux = -vy;
|
||||
float uy = vx;
|
||||
|
||||
x1 = (short) (SCALE_FACTOR * (vx * hw + ux * hh));
|
||||
y1 = (short) (SCALE_FACTOR * (vy * hw + uy * hh));
|
||||
// int dx = (int) (vx * SCALE) & L2BIT_MASK;
|
||||
// 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));
|
||||
y3 = (short) (SCALE_FACTOR * (-vy * hw + uy * hh));
|
||||
|
||||
x4 = (short) (SCALE_FACTOR * (-vx * hw - ux * hh));
|
||||
y4 = (short) (SCALE_FACTOR * (-vy * hw - uy * hh));
|
||||
|
||||
x3 = (short) (SCALE_FACTOR * (vx * hw - ux * hh));
|
||||
y2 = (short) (SCALE_FACTOR * (vy * hw - uy * hh));
|
||||
x1 = (short) (SCALE * (vx * hw + ux * hh));
|
||||
y1 = (short) (SCALE * (vy * hw + uy * hh));
|
||||
x2 = (short) (SCALE * (-vx * hw + ux * hh));
|
||||
y3 = (short) (SCALE * (-vy * hw + uy * hh));
|
||||
x4 = (short) (SCALE * (-vx * hw - ux * hh));
|
||||
y4 = (short) (SCALE * (-vy * hw - uy * hh));
|
||||
x3 = (short) (SCALE * (vx * hw - ux * hh));
|
||||
y2 = (short) (SCALE * (vy * hw - uy * hh));
|
||||
|
||||
}
|
||||
short u1 = (short) (SCALE_FACTOR * x);
|
||||
short v1 = (short) (SCALE_FACTOR * y);
|
||||
short u2 = (short) (SCALE_FACTOR * (x + width));
|
||||
short v2 = (short) (SCALE_FACTOR * (y + height));
|
||||
short u1 = (short) (SCALE * x);
|
||||
short v1 = (short) (SCALE * y);
|
||||
short u2 = (short) (SCALE * (x + width));
|
||||
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
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
@ -366,7 +390,7 @@ public class TextRenderer {
|
||||
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
|
||||
mBitmapFormat, mBitmapType);
|
||||
|
||||
GLES20.glFlush();
|
||||
// GLES20.glFlush();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -397,13 +421,14 @@ public class TextRenderer {
|
||||
mShortBuffer);
|
||||
}
|
||||
|
||||
static void beginDraw(float scale) {
|
||||
static void beginDraw(float scale, float[] rotation) {
|
||||
GLES20.glUseProgram(mTextProgram);
|
||||
|
||||
GLES20.glEnableVertexAttribArray(hTextTextureCoord);
|
||||
GLES20.glEnableVertexAttribArray(hTextVertex);
|
||||
|
||||
GLES20.glUniform1f(hTextScale, scale);
|
||||
GLES20.glUniformMatrix4fv(hTextRotationMatrix, 1, false, rotation, 0);
|
||||
|
||||
if (debug) {
|
||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
||||
|
||||
530
src/org/mapsforge/android/glrenderer/TileLoader.java
Normal file
530
src/org/mapsforge/android/glrenderer/TileLoader.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -20,28 +20,20 @@ import org.mapsforge.core.Tile;
|
||||
*
|
||||
*/
|
||||
public class JobTile extends Tile implements Comparable<JobTile> {
|
||||
/**
|
||||
* tile is loaded and ready for drawing. (set and used by render thread after uploading data to gl).
|
||||
*/
|
||||
public boolean isReady;
|
||||
// public final static int LOADING = 1;
|
||||
// public final static int NEWDATA = 1 << 1;
|
||||
// public final static int READY = 1 << 2;
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* tile is in view region. (set and used by render thread)
|
||||
*/
|
||||
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.
|
||||
* distance from map center.
|
||||
*/
|
||||
public float distance;
|
||||
|
||||
@ -61,7 +53,8 @@ public class JobTile extends Tile implements Comparable<JobTile> {
|
||||
public int compareTo(JobTile o) {
|
||||
if (this.distance < o.distance) {
|
||||
return -1;
|
||||
} else if (this.distance > o.distance) {
|
||||
}
|
||||
if (this.distance > o.distance) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@ -61,8 +61,8 @@ public final class MapDatabaseFactory {
|
||||
switch (mapDatabase) {
|
||||
case MAP_READER:
|
||||
return new org.mapsforge.database.mapfile.MapDatabase();
|
||||
case JSON_READER:
|
||||
return new org.mapsforge.database.json.MapDatabase();
|
||||
case TEST_READER:
|
||||
return new org.mapsforge.database.test.MapDatabase();
|
||||
case POSTGIS_READER:
|
||||
return new org.mapsforge.database.postgis.MapDatabase();
|
||||
case PBMAP_READER:
|
||||
|
||||
@ -26,7 +26,7 @@ public enum MapDatabases {
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
JSON_READER,
|
||||
TEST_READER,
|
||||
|
||||
/**
|
||||
* ...
|
||||
|
||||
@ -91,7 +91,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
|
||||
private static float PI180 = (float) (Math.PI / 180) / 1000000.0f;
|
||||
private static float PIx4 = (float) Math.PI * 4;
|
||||
|
||||
private Tile mCurrentTile;
|
||||
private JobTile mCurrentTile;
|
||||
private static long mCurrentTileY;
|
||||
private static long mCurrentTileX;
|
||||
private static long mCurrentTileZoom;
|
||||
|
||||
@ -28,6 +28,8 @@ public class MapTile extends JobTile {
|
||||
// private long mLoadTime;
|
||||
private int mTextureID;
|
||||
|
||||
boolean isVisible;
|
||||
|
||||
/**
|
||||
* @param tileX
|
||||
* ...
|
||||
|
||||
@ -104,6 +104,10 @@ public class TileMap extends MapActivity {
|
||||
return true;
|
||||
|
||||
case R.id.menu_position:
|
||||
mMapView.enableRotation(true);
|
||||
return true;
|
||||
|
||||
case R.id.menu_rotation_enable:
|
||||
return true;
|
||||
|
||||
case R.id.menu_position_my_location_enable:
|
||||
|
||||
@ -49,8 +49,6 @@ public class Tile {
|
||||
*/
|
||||
public final long pixelY;
|
||||
|
||||
public volatile boolean isCanceled;
|
||||
|
||||
/**
|
||||
* @param tileX
|
||||
* the X number of the tile.
|
||||
|
||||
@ -16,7 +16,7 @@ package org.mapsforge.database;
|
||||
|
||||
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.
|
||||
* @return true if successful
|
||||
*/
|
||||
public abstract QueryResult executeQuery(Tile tile,
|
||||
public abstract QueryResult executeQuery(JobTile tile,
|
||||
IMapDatabaseCallback mapDatabaseCallback);
|
||||
|
||||
/**
|
||||
|
||||
@ -20,9 +20,9 @@ import java.io.RandomAccessFile;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.JobTile;
|
||||
import org.mapsforge.core.MercatorProjection;
|
||||
import org.mapsforge.core.Tag;
|
||||
import org.mapsforge.core.Tile;
|
||||
import org.mapsforge.database.FileOpenResult;
|
||||
import org.mapsforge.database.IMapDatabase;
|
||||
import org.mapsforge.database.IMapDatabaseCallback;
|
||||
@ -204,7 +204,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
* org.mapsforge.map.reader.MapDatabaseCallback)
|
||||
*/
|
||||
@Override
|
||||
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
if (sMapFileHeader == null)
|
||||
return QueryResult.FAILED;
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.protocol.RequestExpectContinue;
|
||||
import org.apache.http.protocol.RequestUserAgent;
|
||||
import org.mapsforge.android.mapgenerator.JobTile;
|
||||
import org.mapsforge.core.BoundingBox;
|
||||
import org.mapsforge.core.GeoPoint;
|
||||
import org.mapsforge.core.Tag;
|
||||
@ -106,7 +107,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
private IMapDatabaseCallback mMapGenerator;
|
||||
private float mScaleFactor;
|
||||
private Tile mTile;
|
||||
private JobTile mTile;
|
||||
private FileOutputStream mCacheFile;
|
||||
|
||||
private long mContentLenth;
|
||||
@ -129,7 +130,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
});
|
||||
|
||||
@Override
|
||||
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
QueryResult result = QueryResult.SUCCESS;
|
||||
mCacheFile = null;
|
||||
|
||||
@ -194,7 +195,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
entity.consumeContent();
|
||||
return QueryResult.FAILED;
|
||||
}
|
||||
if (mTile.isCanceled) {
|
||||
if (!mTile.isLoading) {
|
||||
Log.d(TAG, "1 loading canceled " + mTile);
|
||||
entity.consumeContent();
|
||||
|
||||
@ -249,7 +250,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
mRequest = null;
|
||||
|
||||
// FIXME remove this stuff
|
||||
if (mTile.isCanceled) {
|
||||
if (!mTile.isLoading) {
|
||||
Log.d(TAG, "loading canceled " + mTile);
|
||||
result = QueryResult.FAILED;
|
||||
}
|
||||
|
||||
@ -24,10 +24,10 @@ import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.JobTile;
|
||||
import org.mapsforge.core.BoundingBox;
|
||||
import org.mapsforge.core.GeoPoint;
|
||||
import org.mapsforge.core.Tag;
|
||||
import org.mapsforge.core.Tile;
|
||||
import org.mapsforge.core.WebMercator;
|
||||
import org.mapsforge.database.FileOpenResult;
|
||||
import org.mapsforge.database.IMapDatabase;
|
||||
@ -45,7 +45,7 @@ import android.util.Log;
|
||||
public class MapDatabase implements IMapDatabase {
|
||||
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;
|
||||
|
||||
@ -71,7 +71,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
private boolean connect() {
|
||||
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();
|
||||
dbOpts.setProperty("user", "osm");
|
||||
@ -102,7 +102,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
if (connection == null) {
|
||||
if (!connect())
|
||||
return QueryResult.FAILED;
|
||||
|
||||
@ -12,10 +12,11 @@
|
||||
* 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.database.json;
|
||||
package org.mapsforge.database.test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.JobTile;
|
||||
import org.mapsforge.core.BoundingBox;
|
||||
import org.mapsforge.core.MercatorProjection;
|
||||
import org.mapsforge.core.Tag;
|
||||
@ -51,7 +52,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
// private static double HALF_PI = Math.PI / 2;
|
||||
|
||||
@Override
|
||||
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
|
||||
long cx = tile.pixelX + (Tile.TILE_SIZE >> 1);
|
||||
long cy = tile.pixelY + (Tile.TILE_SIZE >> 1);
|
||||
Loading…
x
Reference in New Issue
Block a user