- 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
|
<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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string-array name="preferences_map_generator_values">
|
<string-array name="preferences_map_generator_values">
|
||||||
<!-- <item>Mapfile</item> -->
|
<!-- <item>Mapfile</item> -->
|
||||||
<!-- <item>PostGIS</item>-->
|
<!-- <item>PostGIS</item>-->
|
||||||
<item>OpenScienceMap</item>
|
<item>OpenScienceMap</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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() {
|
||||||
//
|
//
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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) {
|
static void updatePosition(MapPosition mapPosition) {
|
||||||
Log.d(TAG, ">>> no map position");
|
// synchronized (MapRenderer.lock) {
|
||||||
return;
|
mCurPosition = mapPosition;
|
||||||
}
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
if (clear) {
|
static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
|
||||||
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;
|
|
||||||
|
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) {
|
static void addVBO(VertexBufferObject vbo) {
|
||||||
// need to update visible list first when zoom level changes
|
synchronized (mVBOs) {
|
||||||
// as scaling is relative to the tiles of current zoom-level
|
mVBOs.add(vbo);
|
||||||
updateVisibleList(mapPosition, 0);
|
|
||||||
} else {
|
|
||||||
// pass new position to glThread
|
|
||||||
synchronized (this) {
|
|
||||||
// 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 > 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,37 +218,46 @@ 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;
|
||||||
|
|
||||||
scale = (float) (2.0 * mDrawPosition.scale / (mHeight * div));
|
if (mRotate) {
|
||||||
x = (float) (tile.pixelX - mDrawPosition.x * div);
|
scale = (float) (1.0 * mDrawPosition.scale / (mHeight * div));
|
||||||
y = (float) (tile.pixelY - mDrawPosition.y * div);
|
x = (float) (tile.pixelX - mDrawPosition.x * div);
|
||||||
|
y = (float) (tile.pixelY - mDrawPosition.y * div);
|
||||||
|
|
||||||
mMVPMatrix[12] = x * scale * mAspect;
|
Matrix.setIdentityM(mMVPMatrix, 0);
|
||||||
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.scaleM(mMVPMatrix, 0, scale / COORD_MULTIPLIER,
|
||||||
//
|
scale / COORD_MULTIPLIER, 1);
|
||||||
// Matrix.scaleM(mMVPMatrix, 0, scale / COORD_MULTIPLIER,
|
|
||||||
// scale / COORD_MULTIPLIER, 1);
|
Matrix.translateM(mMVPMatrix, 0,
|
||||||
//
|
x * COORD_MULTIPLIER,
|
||||||
// Matrix.translateM(mMVPMatrix, 0, x * COORD_MULTIPLIER, -(y + Tile.TILE_SIZE)
|
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
|
||||||
// * COORD_MULTIPLIER, 0);
|
-1 + offset * 0.01f);
|
||||||
//
|
|
||||||
// Matrix.setRotateM(mRotateMatrix, 0, mDrawPosition.angle, 0, 0, 1);
|
Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
|
||||||
//
|
|
||||||
// Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
|
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 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;
|
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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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){"
|
||||||
+ " tex_c = tex_coord * div;"
|
+ " 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 = ""
|
final static String textFragmentShader = ""
|
||||||
+ "precision highp float;"
|
+ "precision highp float;"
|
||||||
+ "uniform sampler2D tex;"
|
+ "uniform sampler2D tex;"
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
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> {
|
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;
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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 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;
|
||||||
|
|||||||
@ -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
|
||||||
* ...
|
* ...
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
Loading…
x
Reference in New Issue
Block a user