- started to move Matrices to MapViewPosition as these can be shared with

MapRenderer(TileLoader) and GLRenderer.
- using inverse projection to determine visible tiles and mapping screen-coordinates to model
- making MapPosition not final, reuse instance to get Position in Map-/GLRender

added: ScanBox scanline fill used for calculating visible tiles

rename:
- ShortPool -> VertexPool
- tile.isActive -> isLocked
This commit is contained in:
Hannes Janetzek
2012-09-26 17:02:03 +02:00
parent 8ec405cf5c
commit c5e3be9d2b
26 changed files with 1281 additions and 865 deletions

View File

@@ -17,7 +17,6 @@ package org.oscim.view;
import java.io.FileNotFoundException;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.theme.InternalRenderTheme;
import android.app.Activity;

View File

@@ -0,0 +1,97 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* 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.oscim.view;
import org.oscim.core.GeoPoint;
import org.oscim.core.MercatorProjection;
import android.opengl.Matrix;
/**
* A MapPosition Container.
*/
public class MapPosition {
public double lon;
public double lat;
public byte zoomLevel;
public float scale;
public float angle;
public double x;
public double y;
public float[] rotation;
public MapPosition() {
this.zoomLevel = (byte) 1;
this.scale = 1;
this.lat = 0;
this.lon = 0;
this.angle = 0;
this.x = MercatorProjection.longitudeToPixelX(this.lon, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
}
public void init() {
rotation = new float[16];
Matrix.setIdentityM(rotation, 0);
}
/**
* @param geoPoint
* the map position.
* @param zoomLevel
* the zoom level.
* @param scale
* ...
*/
public MapPosition(GeoPoint geoPoint, byte zoomLevel, float scale) {
// this.geoPoint = geoPoint;
this.zoomLevel = zoomLevel;
this.scale = scale;
this.lat = geoPoint.getLatitude();
this.lon = geoPoint.getLongitude();
this.angle = 0;
this.x = MercatorProjection.longitudeToPixelX(this.lon, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
}
public MapPosition(double latitude, double longitude, byte zoomLevel, float scale,
float angle) {
this.zoomLevel = zoomLevel;
this.scale = scale;
this.lat = latitude;
this.lon = longitude;
this.angle = angle;
this.x = MercatorProjection.longitudeToPixelX(longitude, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(latitude, zoomLevel);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MapPosition [geoPoint=");
builder.append("lat");
builder.append(this.lat);
builder.append("lon");
builder.append(this.lon);
builder.append(", zoomLevel=");
builder.append(this.zoomLevel);
builder.append("]");
return builder.toString();
}
}

View File

@@ -17,7 +17,6 @@ package org.oscim.view;
import java.util.HashMap;
import java.util.Map;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import android.graphics.Bitmap;

View File

@@ -23,7 +23,6 @@ import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.database.IMapDatabase;
import org.oscim.database.MapDatabaseFactory;
@@ -56,9 +55,9 @@ public class MapView extends FrameLayout {
final static String TAG = "MapView";
public final static boolean debugFrameTime = false;
public final static boolean testRegionZoom = false;
private final boolean mDebugDatabase = false;
public static final boolean debugFrameTime = false;
public static final boolean testRegionZoom = false;
private static final boolean debugDatabase = false;
RegionLookup mRegionLookup;
@@ -146,7 +145,7 @@ public class MapView extends FrameLayout {
for (int i = 0; i < mNumMapWorkers; i++) {
IMapDatabase mapDatabase;
if (mDebugDatabase) {
if (debugDatabase) {
// mapDatabase = MapDatabaseFactory
// .createMapDatabase(MapDatabases.TEST_READER);
mapDatabase = MapDatabaseFactory
@@ -188,7 +187,7 @@ public class MapView extends FrameLayout {
mMapZoomControls = new MapZoomControls(mapActivity, this);
mMapZoomControls.setShowMapZoomControls(true);
// enableRotation = true;
enableRotation = true;
for (MapWorker worker : mMapWorkers)
worker.start();
@@ -353,7 +352,7 @@ public class MapView extends FrameLayout {
*/
public void setMapDatabase(MapDatabases mapDatabaseType) {
if (mDebugDatabase)
if (debugDatabase)
return;
TileGenerator tileGenerator;
@@ -470,6 +469,9 @@ public class MapView extends FrameLayout {
Log.d(TAG, "onSizeChanged" + width + " " + height);
super.onSizeChanged(width, height, oldWidth, oldHeight);
if (width != 0 && height != 0)
mMapViewPosition.setViewport(width, height);
mapWorkersProceed();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2010, 2011, 2012 mapsforge.org, 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
@@ -15,36 +15,36 @@
package org.oscim.view;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.utils.FastMath;
import android.opengl.Matrix;
import android.util.FloatMath;
import android.util.Log;
/**
* A MapPosition stores the latitude and longitude coordinate of a MapView
* together with its zoom level.
*/
public class MapViewPosition {
private static final String TAG = "MapViewPosition";
// private static final String TAG = "MapViewPosition";
public final static int MAX_ZOOMLEVEL = 16;
public final static int MAX_ZOOMLEVEL = 17;
private final static float MAX_SCALE = 2.0f;
private final static float MIN_SCALE = 1.0f;
private final static float MAX_ANGLE = 20;
private final MapView mMapView;
private double mLatitude;
private double mLongitude;
private byte mZoomLevel;
// 1.0 - 2.0 scale per level
private float mScale;
private float mRotation;
public float mTilt;
// 2^mZoomLevel * mScale;
private float mMapScale;
// private final static float MAP_SIZE = 1000000;
// private final static float MAP_SIZE2 = 1000000 >> 1;
private float mRotation;
public float mTilt;
MapViewPosition(MapView mapView) {
mMapView = mapView;
@@ -58,20 +58,158 @@ public class MapViewPosition {
mMapScale = 1;
}
// private static double latitudeToMapView(double latitude) {
// double sinLatitude = Math.sin(latitude * (Math.PI / 180));
// return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 *
// Math.PI))
// * MAP_SIZE;
// }
//
// public static double longitudeToMapView(double longitude) {
// return (longitude + 180) / 360 * MAP_SIZE;
// }
//
// private static double pixelXToLongitude(double pixelX, byte zoomLevel) {
// return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5);
// }
private float[] mProjMatrix = new float[16];
private float[] mProjMatrixI = new float[16];
private float[] mUnprojMatrix = new float[16];
private float[] mRotateMatrix = new float[16];
private float[] mTmpMatrix = new float[16];
private int mHeight, mWidth;
void setViewport(int width, int height) {
Matrix.frustumM(mProjMatrix, 0, -0.5f * width, 0.5f * width,
-0.5f * height, 0.5f * height, 1, 2);
Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
Matrix.invertM(mUnprojMatrix, 0, mProjMatrix, 0);
Matrix.setIdentityM(mRotateMatrix, 0);
mHeight = height;
mWidth = width;
}
public synchronized boolean getMapPosition(final MapPosition mapPosition,
final float[] coords) {
// if (!isValid())
// return false;
// if (mapPosition.lat == mLatitude
// && mapPosition.lon == mLongitude
// && mapPosition.zoomLevel == mZoomLevel
// && mapPosition.scale == mScale
// && mapPosition.angle == mRotation)
// return false;
mapPosition.lat = mLatitude;
mapPosition.lon = mLongitude;
mapPosition.angle = mRotation;
mapPosition.zoomLevel = mZoomLevel;
mapPosition.scale = mScale;
byte z = mZoomLevel;
mapPosition.x = MercatorProjection.longitudeToPixelX(mLongitude, z);
mapPosition.y = MercatorProjection.latitudeToPixelY(mLatitude, z);
if (mapPosition.rotation != null) {
// updateMatrix();
System.arraycopy(mRotateMatrix, 0, mapPosition.rotation, 0, 16);
}
if (coords == null)
return true;
// if (mapPosition.rotation == null)
// updateMatrix();
// not so sure about this, but works...
float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4;
unproject(-1, 1, tilt, coords, 0); // top-left
unproject(1, 1, tilt, coords, 2); // top-right
unproject(1, -1, -tilt, coords, 4); // bottom-right
unproject(-1, -1, -tilt, coords, 6); // bottom-left
return true;
}
private float[] mv = { 0, 0, 0, 1 };
private float[] mBBoxCoords = new float[8];
private void unproject(float x, float y, float z, float[] coords, int position) {
mv[0] = x;
mv[1] = y;
mv[2] = z - 1;
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
if (mv[3] != 0) {
float w = 1 / mv[3];
float xx = mv[0] * w;
float yy = mv[1] * w;
coords[position] = xx;
coords[position + 1] = yy;
}
// else what?
}
private void updateMatrix() {
Matrix.setRotateM(mRotateMatrix, 0, mRotation, 0, 0, 1);
// tilt map
float tilt = mTilt;
Matrix.setRotateM(mTmpMatrix, 0, -tilt / (mHeight / 2), 1, 0, 0);
// apply first rotation, then tilt
Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0);
// get unproject matrix:
// (transpose of rotation is its inverse)
Matrix.transposeM(mTmpMatrix, 0, mRotateMatrix, 0);
// (AB)^-1 = B^-1*A^-1
Matrix.multiplyMM(mUnprojMatrix, 0, mTmpMatrix, 0, mProjMatrixI, 0);
}
/**
* sets viewBox to visible bounding box, (left,top,right,bottom)
*
* @param viewBox
* ...
*/
public synchronized void getViewBox(final float[] viewBox) {
updateMatrix();
float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4;
unproject(-1, 1, tilt, mBBoxCoords, 0); // top-left
unproject(1, 1, tilt, mBBoxCoords, 2); // top-right
unproject(1, -1, -tilt, mBBoxCoords, 4); // bottom-right
unproject(-1, -1, -tilt, mBBoxCoords, 6); // bottom-left
byte z = mZoomLevel;
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, z);
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, z);
double dx = pixelX - mBBoxCoords[0] / mScale;
double dy = pixelY - mBBoxCoords[1] / mScale;
double lon = MercatorProjection.pixelXToLongitude(dx, z);
double lat = MercatorProjection.pixelYToLatitude(dy, z);
Log.d(">>>", "bl:" + lon + " " + lat);
dx = pixelX - mBBoxCoords[2] / mScale;
dy = pixelY - mBBoxCoords[3] / mScale;
lon = MercatorProjection.pixelXToLongitude(dx, z);
lat = MercatorProjection.pixelYToLatitude(dy, z);
Log.d("...", "br:" + lon + " " + lat);
dx = pixelX - mBBoxCoords[4] / mScale;
dy = pixelY - mBBoxCoords[5] / mScale;
lon = MercatorProjection.pixelXToLongitude(dx, z);
lat = MercatorProjection.pixelYToLatitude(dy, z);
Log.d("...", "tl:" + lon + " " + lat);
dx = pixelX - mBBoxCoords[6] / mScale;
dy = pixelY - mBBoxCoords[7] / mScale;
lon = MercatorProjection.pixelXToLongitude(dx, z);
lat = MercatorProjection.pixelYToLatitude(dy, z);
Log.d("...", "tr:" + lon + " " + lat);
}
/**
* @return the current center point of the MapView.
@@ -168,6 +306,15 @@ public class MapViewPosition {
return new GeoPoint(latitude, longitude);
}
// public static double pixelXToLongitude(double pixelX, byte zoomLevel) {
// return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5);
// }
//
// public static double pixelYToLatitude(double pixelY, byte zoomLevel) {
// double y = 0.5 - (pixelY / ((long) Tile.TILE_SIZE << zoomLevel));
// return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
// }
/**
* Moves this MapViewPosition by the given amount of pixels.
*
@@ -187,14 +334,13 @@ public class MapViewPosition {
double rad = Math.toRadians(mRotation);
double x = dx * Math.cos(rad) + dy * -Math.sin(rad);
double y = dx * Math.sin(rad) + dy * Math.cos(rad);
dx = x;
dy = y;
}
dx = pixelX - dx;
dy = pixelY - dy;
dx = pixelX - x;
dy = pixelY - y;
}
else {
dx = pixelX - dx;
dy = pixelY - dy;
}
mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
mLatitude = MercatorProjection.limitLatitude(mLatitude);
@@ -202,6 +348,8 @@ public class MapViewPosition {
mLongitude = MercatorProjection.wrapLongitude(mLongitude);
// mLongitude = MercatorProjection.limitLongitude(mLongitude);
// getViewBox(null);
}
public synchronized void rotateMap(float angle, float cx, float cy) {
@@ -209,14 +357,17 @@ public class MapViewPosition {
// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation -
// angle));
mRotation -= angle;
updateMatrix();
}
public void setRotation(float f) {
mRotation = f;
updateMatrix();
}
public void setTilt(float f) {
mTilt = f;
updateMatrix();
}
synchronized void setMapCenter(GeoPoint geoPoint) {
@@ -251,38 +402,41 @@ public class MapViewPosition {
* ...
* @param pivotY
* ...
* @return true if scale was changed
*/
public synchronized void scaleMap(float scale, float pivotX, float pivotY) {
if (pivotY != 0 || pivotY != 0)
moveMap(pivotX * (1.0f - scale),
pivotY * (1.0f - scale));
public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
float newScale = mMapScale * scale;
int z = FastMath.log2((int) newScale);
if (z <= 0 || (z >= MAX_ZOOMLEVEL && mScale >= 8))
return;
return false;
if (z > MAX_ZOOMLEVEL) {
// z16 shows everything, just increase scaling
if (mScale * scale > 8)
return;
return false;
mScale *= scale;
mMapScale = newScale;
return;
} else {
mZoomLevel = (byte) z;
mScale = newScale / (1 << z);
mMapScale = newScale;
}
mZoomLevel = (byte) z;
mScale = newScale / (1 << z);
mMapScale = newScale;
if (pivotY != 0 || pivotY != 0)
moveMap(pivotX * (1.0f - scale),
pivotY * (1.0f - scale));
return true;
}
public boolean tilt(float moveX) {
float tilt = mTilt + moveX;
if (tilt > 25)
tilt = 25;
if (tilt > MAX_ANGLE)
tilt = MAX_ANGLE;
else if (tilt < 0)
tilt = 0;
if (mTilt == tilt)

View File

@@ -123,8 +123,8 @@ public class MapZoomControls {
mShowMapZoomControls = true;
mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX;
mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN;
if (!MapView.testRegionZoom)
mZoomControls.setVisibility(View.GONE);
// if (!MapView.testRegionZoom)
mZoomControls.setVisibility(View.GONE);
mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY;
mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(this));
@@ -203,12 +203,14 @@ public class MapZoomControls {
}
/**
* Sets the gravity for the placing of the zoom controls. Supported values are {@link Gravity#TOP},
* {@link Gravity#CENTER_VERTICAL}, {@link Gravity#BOTTOM}, {@link Gravity#LEFT}, {@link Gravity#CENTER_HORIZONTAL}
* and {@link Gravity#RIGHT}.
* Sets the gravity for the placing of the zoom controls. Supported values
* are {@link Gravity#TOP}, {@link Gravity#CENTER_VERTICAL},
* {@link Gravity#BOTTOM}, {@link Gravity#LEFT},
* {@link Gravity#CENTER_HORIZONTAL} and {@link Gravity#RIGHT}.
*
* @param zoomControlsGravity
* a combination of {@link Gravity} constants describing the desired placement.
* a combination of {@link Gravity} constants describing the
* desired placement.
*/
public void setZoomControlsGravity(int zoomControlsGravity) {
if (mZoomControlsGravity != zoomControlsGravity) {
@@ -220,14 +222,16 @@ public class MapZoomControls {
/**
* Sets the maximum zoom level of the map.
* <p>
* The maximum possible zoom level of the MapView depends also on the current {@link TileGenerator}. For example,
* downloading map tiles may only be possible up to a certain zoom level. Setting a higher maximum zoom level has no
* effect in this case.
* The maximum possible zoom level of the MapView depends also on the
* current {@link TileGenerator}. For example, downloading map tiles may
* only be possible up to a certain zoom level. Setting a higher maximum
* zoom level has no effect in this case.
*
* @param zoomLevelMax
* the maximum zoom level.
* @throws IllegalArgumentException
* if the maximum zoom level is smaller than the current minimum zoom level.
* if the maximum zoom level is smaller than the current minimum
* zoom level.
*/
public void setZoomLevelMax(byte zoomLevelMax) {
if (zoomLevelMax < mZoomLevelMin) {
@@ -242,7 +246,8 @@ public class MapZoomControls {
* @param zoomLevelMin
* the minimum zoom level.
* @throws IllegalArgumentException
* if the minimum zoom level is larger than the current maximum zoom level.
* if the minimum zoom level is larger than the current maximum
* zoom level.
*/
public void setZoomLevelMin(byte zoomLevelMin) {
if (zoomLevelMin > mZoomLevelMax) {

View File

@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Properties;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import android.os.AsyncTask;

View File

@@ -32,20 +32,24 @@ import android.widget.Scroller;
* Implementation for multi-touch capable devices. TODO write a AnimationTimer
* instead of using CountDownTimer
*/
public class TouchHandler {
public class TouchHandler
extends SimpleOnGestureListener
implements ScaleGestureDetector.OnScaleGestureListener {
private static final float SCALE_DURATION = 450;
private static final int INVALID_POINTER_ID = -1;
/* package */final MapView mMapView;
/* package */final MapViewPosition mMapPosition;
/* package */final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
/* package */boolean mBeginScale;
/* package */float mSumScale;
private final MapView mMapView;
private final MapViewPosition mMapPosition;
private final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
private boolean mBeginScale;
private float mSumScale;
private final float mMapMoveDelta;
private boolean mMoveStart;
private boolean mBeginRotate;
/* package */float mPosX;
/* package */float mPosY;
private float mPosX;
private float mPosY;
private double mAngle;
private int mActivePointerId;
@@ -65,9 +69,47 @@ public class TouchHandler {
mMapPosition = mapView.getMapPosition();
mMapMoveDelta = viewConfiguration.getScaledTouchSlop();
mActivePointerId = INVALID_POINTER_ID;
mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleListener());
mGestureDetector = new GestureDetector(context, new MapGestureDetector());
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mGestureDetector = new GestureDetector(context, this);
mScroller = new Scroller(mMapView.getContext(),
new android.view.animation.LinearInterpolator());
}
/**
* @param event
* ...
* @return ...
*/
public boolean handleMotionEvent(MotionEvent event) {
// workaround for a bug in the ScaleGestureDetector, see Android issue
// #12976
// if (event.getAction() != MotionEvent.ACTION_MOVE
// || event.getPointerCount() > 1) {
mScaleGestureDetector.onTouchEvent(event);
// }
if (!mScaling)
mGestureDetector.onTouchEvent(event);
int action = getAction(event);
boolean ret = false;
if (action == MotionEvent.ACTION_DOWN) {
ret = onActionDown(event);
} else if (action == MotionEvent.ACTION_MOVE) {
ret = onActionMove(event);
} else if (action == MotionEvent.ACTION_UP) {
ret = onActionUp(event);
} else if (action == MotionEvent.ACTION_CANCEL) {
ret = onActionCancel();
} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
return onActionPointerDown(event);
} else if (action == MotionEvent.ACTION_POINTER_UP) {
ret = onActionPointerUp(event);
}
return ret;
}
private static int getAction(MotionEvent motionEvent) {
@@ -131,48 +173,46 @@ public class TouchHandler {
return true;
}
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);
if (!mMapView.enableRotation || multi < 1)
return true;
double dx = x1 - x2;
double dy = y1 - y2;
double x1 = event.getX(0);
double x2 = event.getX(1);
double y1 = event.getY(0);
double y2 = event.getY(1);
double rad = Math.atan2(dy, dx);
double r = rad - mAngle;
double dx = x1 - x2;
double dy = y1 - y2;
if (!mBeginRotate && Math.abs(dy) < 80) {
if (mMapPosition.tilt(moveY / 4)) {
mMapView.redrawMap();
return true;
}
}
if (!mBeginRotate && !mBeginScale) {
if (r > 0.02 || r < -0.02)
mBeginRotate = true;
} else if (mBeginRotate) {
double rsin = Math.sin(r);
double rcos = Math.cos(r);
// focus point relative to center
double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
float x = (float) (cx * rcos + cy * -rsin - cx);
float y = (float) (cx * rsin + cy * rcos - cy);
mMapPosition.rotateMap((float) Math.toDegrees(rad - mAngle), x, y);
mAngle = rad;
mMapView.redrawMap();
}
double rad = Math.atan2(dy, dx);
double r = rad - mAngle;
if (!mBeginRotate && Math.abs(dy) < 80) {
if (mMapPosition.tilt(moveY / 4)) {
mMapView.redrawMap();
return true;
}
}
if (!mBeginRotate && !mBeginScale) {
if (r > 0.02 || r < -0.02)
mBeginRotate = true;
} else if (mBeginRotate) {
double rsin = Math.sin(r);
double rcos = Math.cos(r);
// focus point relative to center
double cx = (mMapView.getWidth() >> 1) - (x1 + x2) / 2;
double cy = (mMapView.getHeight() >> 1) - (y1 + y2) / 2;
float x = (float) (cx * rcos + cy * -rsin - cx);
float y = (float) (cx * rsin + cy * rcos - cy);
mMapPosition.rotateMap((float) Math.toDegrees(rad - mAngle), x, y);
mAngle = rad;
mMapView.redrawMap();
}
return true;
}
@@ -225,285 +265,240 @@ public class TouchHandler {
return true;
}
/**
* @param event
* ...
* @return ...
*/
public boolean handleMotionEvent(MotionEvent event) {
/******************* SimpleOnGestureListener *******************/
// workaround for a bug in the ScaleGestureDetector, see Android issue
// #12976
// if (event.getAction() != MotionEvent.ACTION_MOVE
// || event.getPointerCount() > 1) {
mScaleGestureDetector.onTouchEvent(event);
// }
private Scroller mScroller;
private float mScrollX, mScrollY;
private boolean fling = false;
if (!mScaling)
mGestureDetector.onTouchEvent(event);
int action = getAction(event);
boolean ret = false;
if (action == MotionEvent.ACTION_DOWN) {
ret = onActionDown(event);
} else if (action == MotionEvent.ACTION_MOVE) {
ret = onActionMove(event);
} else if (action == MotionEvent.ACTION_UP) {
ret = onActionUp(event);
} else if (action == MotionEvent.ACTION_CANCEL) {
ret = onActionCancel();
} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
return onActionPointerDown(event);
} else if (action == MotionEvent.ACTION_POINTER_UP) {
ret = onActionPointerUp(event);
}
return ret;
}
class MapGestureDetector extends SimpleOnGestureListener {
private Scroller mScroller;
private float mScrollX, mScrollY, mPrevScale;
private CountDownTimer mTimer = null;
private boolean fling = false;
public MapGestureDetector() {
mScroller = new Scroller(mMapView.getContext(),
new android.view.animation.LinearInterpolator());
}
@Override
public boolean onDown(MotionEvent e) {
if (fling) {
mScroller.forceFinished(true);
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
fling = false;
}
// Log.d("mapsforge", "onDown");
return true;
}
boolean scroll() {
if (mScroller.isFinished()) {
return false;
}
mScroller.computeScrollOffset();
float moveX = mScroller.getCurrX() - mScrollX;
float moveY = mScroller.getCurrY() - mScrollY;
if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) {
mMapPosition.moveMap(moveX, moveY);
mMapView.redrawMap();
mScrollX = mScroller.getCurrX();
mScrollY = mScroller.getCurrY();
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
int w = Tile.TILE_SIZE * 20;
int h = Tile.TILE_SIZE * 20;
mScrollX = 0;
mScrollY = 0;
@Override
public boolean onDown(MotionEvent e) {
if (fling) {
mScroller.forceFinished(true);
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
fling = false;
}
// Log.d("mapsforge", "onDown");
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
-w, w, -h, h);
return true;
}
// animate for two seconds
mTimer = new CountDownTimer(1500, 50) {
boolean scroll() {
if (mScroller.isFinished()) {
return false;
}
mScroller.computeScrollOffset();
float moveX = mScroller.getCurrX() - mScrollX;
float moveY = mScroller.getCurrY() - mScrollY;
if (moveX >= 1 || moveY >= 1 || moveX <= -1 || moveY <= -1) {
mMapPosition.moveMap(moveX, moveY);
mMapView.redrawMap();
mScrollX = mScroller.getCurrX();
mScrollY = mScroller.getCurrY();
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
int w = Tile.TILE_SIZE * 20;
int h = Tile.TILE_SIZE * 20;
mScrollX = 0;
mScrollY = 0;
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
-w, w, -h, h);
// animate for two seconds
mTimer = new CountDownTimer(1500, 50) {
@Override
public void onTick(long tick) {
scroll();
}
@Override
public void onFinish() {
// do nothing
}
}.start();
fling = true;
return true;
}
@Override
public void onLongPress(MotionEvent e) {
if (MapView.testRegionZoom) {
Log.d("mapsforge", "long press");
mMapView.mRegionLookup.updateRegion(-1, null);
}
}
boolean scale2(long tick) {
fling = true;
if (mPrevScale >= 1)
return false;
float adv = (SCALE_DURATION - tick) / SCALE_DURATION;
adv = mInterpolator.getInterpolation(adv);
float scale = adv - mPrevScale;
mPrevScale += scale;
scale += 1;
adv += 1;
if (scale > 1) {
mMapPosition.scaleMap(scale, mScrollX / adv, mScrollY / adv);
mMapView.redrawMap();
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (MapView.testRegionZoom) {
Log.d("mapsforge", "double tap");
mMapView.mRegionLookup.updateRegion(1,
mMapPosition.getOffsetPoint(mPosX, mPosY));
} else {
mScrollX = (e.getX(0) - (mMapView.getWidth() >> 1)) * 2f;
mScrollY = (e.getY(0) - (mMapView.getHeight() >> 1)) * 2f;
mPrevScale = 0;
mTimer = new CountDownTimer((int) SCALE_DURATION, 30) {
@Override
public void onTick(long tick) {
scroll();
scale2(tick);
}
@Override
public void onFinish() {
// do nothing
scale(0);
}
}.start();
fling = true;
return true;
}
@Override
public void onLongPress(MotionEvent e) {
if (MapView.testRegionZoom) {
Log.d("mapsforge", "long press");
mMapView.mRegionLookup.updateRegion(-1, null);
}
}
private final float mScaleDuration = 300;
boolean scale(long tick) {
fling = true;
if (mPrevScale >= 1)
return false;
float adv = (mScaleDuration - tick) / mScaleDuration;
adv = mInterpolator.getInterpolation(adv);
float scale = adv - mPrevScale;
mPrevScale += scale;
scale += 1;
adv += 1;
if (scale > 1) {
mMapPosition.scaleMap(scale, mScrollX / adv, mScrollY / adv);
mMapView.redrawMap();
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (MapView.testRegionZoom) {
Log.d("mapsforge", "double tap");
mMapView.mRegionLookup.updateRegion(1,
mMapPosition.getOffsetPoint(mPosX, mPosY));
} else {
mScrollX = (e.getX(0) - (mMapView.getWidth() >> 1)) * 2f;
mScrollY = (e.getY(0) - (mMapView.getHeight() >> 1)) * 2f;
mPrevScale = 0;
mTimer = new CountDownTimer((int) mScaleDuration, 30) {
@Override
public void onTick(long tick) {
scale(tick);
}
@Override
public void onFinish() {
scale(0);
}
}.start();
}
return true;
}
return true;
}
class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener {
private float mCenterX;
private float mCenterY;
private float mFocusX;
private float mFocusY;
private long mTimeStart;
private long mTimeEnd;
/******************* ScaleListener *******************/
@Override
public boolean onScale(ScaleGestureDetector gd) {
private float mCenterX;
private float mCenterY;
private float mFocusX;
private float mFocusY;
private long mTimeStart;
private long mTimeEnd;
float scale = gd.getScaleFactor();
mFocusX = gd.getFocusX() - mCenterX;
mFocusY = gd.getFocusY() - mCenterY;
@Override
public boolean onScale(ScaleGestureDetector gd) {
mSumScale *= scale;
float scale = gd.getScaleFactor();
mFocusX = gd.getFocusX() - mCenterX;
mFocusY = gd.getFocusY() - mCenterY;
mTimeEnd = SystemClock.elapsedRealtime();
mSumScale *= scale;
if (!mBeginScale) {
if (mTimeEnd - mTimeStart > 150 || mSumScale > 1.1 || mSumScale < 0.9) {
mBeginScale = true;
scale = mSumScale;
mTimeEnd = SystemClock.elapsedRealtime();
if (!mBeginScale) {
if (mTimeEnd - mTimeStart > 150 || mSumScale > 1.1 || mSumScale < 0.9) {
mBeginScale = true;
scale = mSumScale;
}
else
return true;
}
if (mMapPosition.scaleMap(scale, mFocusX, mFocusY))
mMapView.redrawMap();
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector gd) {
mTimeEnd = mTimeStart = SystemClock.elapsedRealtime();
mSumScale = 1;
mBeginScale = false;
mCenterX = mMapView.getWidth() >> 1;
mCenterY = mMapView.getHeight() >> 1;
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector gd) {
// Log.d("ScaleListener", "Sum " + mSumScale + " " + (mTimeEnd -
// mTimeStart));
if (mTimer == null && mTimeEnd - mTimeStart < 150
&& (mSumScale < 0.99 || mSumScale > 1.01)) {
mPrevScale = 0;
mZooutOut = mSumScale < 0.99;
mTimer = new CountDownTimer((int) SCALE_DURATION, 15) {
@Override
public void onTick(long tick) {
scale(tick);
}
else
return true;
}
mMapPosition.scaleMap(scale, mFocusX, mFocusY);
mMapView.redrawMap();
@Override
public void onFinish() {
scale(0);
return true;
}
}.start();
}
mBeginScale = false;
}
private float mPrevScale;
private CountDownTimer mTimer;
boolean mZooutOut;
boolean scale(long tick) {
if (mPrevScale >= 1) {
mTimer = null;
return false;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector gd) {
mTimeEnd = mTimeStart = SystemClock.elapsedRealtime();
mSumScale = 1;
mBeginScale = false;
mCenterX = mMapView.getWidth() >> 1;
mCenterY = mMapView.getHeight() >> 1;
float adv = (SCALE_DURATION - tick) / SCALE_DURATION;
adv = mInterpolator.getInterpolation(adv);
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
return true;
float scale = adv - mPrevScale;
mPrevScale += scale;
if (mZooutOut) {
mMapPosition.scaleMap(1 - scale, 0, 0);
} else {
mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY);
}
@Override
public void onScaleEnd(ScaleGestureDetector gd) {
// Log.d("ScaleListener", "Sum " + mSumScale + " " + (mTimeEnd -
// mTimeStart));
mMapView.redrawMap();
if (mTimer == null && mTimeEnd - mTimeStart < 150
&& (mSumScale < 0.99 || mSumScale > 1.01)) {
if (tick == 0)
mTimer = null;
mPrevScale = 0;
mZooutOut = mSumScale < 0.99;
mTimer = new CountDownTimer((int) mScaleDuration, 15) {
@Override
public void onTick(long tick) {
scale(tick);
}
@Override
public void onFinish() {
scale(0);
}
}.start();
}
mBeginScale = false;
}
private float mPrevScale;
private CountDownTimer mTimer;
boolean mZooutOut;
private final float mScaleDuration = 450;
boolean scale(long tick) {
if (mPrevScale >= 1) {
mTimer = null;
return false;
}
float adv = (mScaleDuration - tick) / mScaleDuration;
adv = mInterpolator.getInterpolation(adv);
float scale = adv - mPrevScale;
mPrevScale += scale;
if (mZooutOut) {
mMapPosition.scaleMap(1 - scale, 0, 0);
} else {
mMapPosition.scaleMap(1 + scale, mFocusX, mFocusY);
}
mMapView.redrawMap();
if (tick == 0)
mTimer = null;
return true;
}
return true;
}
}

View File

@@ -15,12 +15,12 @@
package org.oscim.view.generator;
import org.oscim.utils.PausableThread;
import org.oscim.view.renderer.TileGenerator;
import org.oscim.view.renderer.MapRenderer;
import org.oscim.view.renderer.TileGenerator;
/**
* A MapWorker uses a {@link IMapGenerator} to generate map tiles. It runs in a separate thread to avoid blocking the UI
* thread.
* A MapWorker uses a {@link TileGenerator} to generate map tiles. It runs in a
* separate thread to avoid blocking the UI thread.
*/
public class MapWorker extends PausableThread {
private final String THREAD_NAME;
@@ -28,11 +28,11 @@ public class MapWorker extends PausableThread {
private final TileGenerator mMapGenerator;
private final MapRenderer mMapRenderer;
// private final int mPrio;
/**
* @param id
* thread id
* @param jobQueue
* ...
* @param tileGenerator
* ...
* @param mapRenderer
@@ -46,7 +46,6 @@ public class MapWorker extends PausableThread {
mMapRenderer = mapRenderer;
THREAD_NAME = "MapWorker" + id;
// mPrio = Math.max(Thread.MIN_PRIORITY + id, Thread.NORM_PRIORITY - 1);
}
public TileGenerator getMapGenerator() {
@@ -85,7 +84,6 @@ public class MapWorker extends PausableThread {
@Override
protected int getThreadPriority() {
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 3;
// return mPrio;
}
@Override

View File

@@ -32,11 +32,13 @@ import java.util.concurrent.locks.ReentrantLock;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapPosition;
import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition;
import org.oscim.view.renderer.MapRenderer.TilesData;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
@@ -59,6 +61,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
static int CACHE_TILES = CACHE_TILES_MAX;
private final MapView mMapView;
private final MapViewPosition mMapViewPosition;
private static final MapPosition mMapPosition = new MapPosition();
private static ArrayList<VertexBufferObject> mVBOs;
private static int mWidth, mHeight;
@@ -71,12 +77,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static int mBufferMemoryUsage;
private static float[] mMVPMatrix = new float[16];
private static float[] mRotateMatrix = new float[16];
private static float[] mTmpMatrix = new float[16];
private static float[] mTmp2Matrix = new float[16];
private static float[] mProjMatrix = new float[16];
private static float[] mProjMatrixI = new float[16];
private static float[] mTileCoords = new float[8];
// mNextTiles is set by TileLoader and swapped with
// mDrawTiles in onDrawFrame in GL thread.
@@ -86,8 +88,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// changed. used in onDrawFrame to flip mNextTiles/mDrawTiles
private static boolean mUpdateTiles;
private static MapPosition mCurPosition;
private float[] mClearColor = null;
// number of tiles drawn in one frame
@@ -98,17 +98,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// lock to synchronize Main- and GL-Thread
static ReentrantLock tilelock = new ReentrantLock();
// used for passing tiles to be rendered from TileLoader(Main-Thread) to
// GLThread
static class TilesData {
int cnt = 0;
final MapTile[] tiles;
TilesData(int numTiles) {
tiles = new MapTile[numTiles];
}
}
/**
* @param mapView
* the MapView
@@ -117,34 +106,27 @@ public class GLRenderer implements GLSurfaceView.Renderer {
Log.d(TAG, "init MapRenderer");
mMapView = mapView;
mMapViewPosition = mapView.getMapViewPosition();
// mMapPosition = new MapPosition();
mMapPosition.init();
Matrix.setIdentityM(mMVPMatrix, 0);
mUpdateTiles = false;
}
/**
* called by TileLoader when only position changed
*
* @param mapPosition
* current MapPosition
*/
static void updatePosition(MapPosition mapPosition) {
mCurPosition = mapPosition;
}
/**
* called by TileLoader when list of active tiles changed
*
* @param mapPosition
* current MapPosition
* @param tiles
* active tiles
* @return mNextTiles (the previously active tiles)
*/
static TilesData updateTiles(MapPosition mapPosition, TilesData tiles) {
static TilesData updateTiles(TilesData tiles) {
GLRenderer.tilelock.lock();
mCurPosition = mapPosition;
// mCurPosition = mapPosition;
// unlock previously active tiles
for (int i = 0; i < mNextTiles.cnt; i++) {
@@ -178,13 +160,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// lock tiles (and their proxies) to not be removed from cache
for (int i = 0; i < mNextTiles.cnt; i++) {
MapTile t = mNextTiles.tiles[i];
if (!t.isActive)
if (!t.isLocked)
t.lock();
}
for (int j = 0; j < mDrawTiles.cnt; j++) {
MapTile t = mDrawTiles.tiles[j];
if (!t.isActive)
if (!t.isLocked)
t.lock();
}
@@ -386,8 +368,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
CACHE_TILES -= 50;
}
private static boolean isVisible(MapPosition mapPosition, MapTile tile) {
private static boolean isVisible(MapTile tile) {
float dx, dy, scale, div = 1;
MapPosition mapPosition = mMapPosition;
int diff = mapPosition.zoomLevel - tile.zoomLevel;
if (diff < 0)
@@ -407,7 +390,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// this kindof works for typical screen aspect
if (mRotate) {
int ssize = mWidth > mHeight ? mWidth : mHeight;
ssize += Tile.TILE_SIZE;
if (sy > ssize / 2 || sx > ssize / 2
|| sx + size * scale < -ssize / 2
|| sy + size * scale < -ssize / 2) {
@@ -429,10 +412,12 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static boolean mRotate = false;
private static void setMatrix(float[] matrix, MapPosition mapPosition, MapTile tile,
private static void setMatrix(float[] matrix, MapTile tile,
float div, boolean project) {
float x, y, scale;
MapPosition mapPosition = mMapPosition;
scale = mapPosition.scale / (div * COORD_MULTIPLIER);
x = (float) (tile.pixelX - mapPosition.x * div);
y = (float) (tile.pixelY - mapPosition.y * div);
@@ -443,48 +428,30 @@ public class GLRenderer implements GLSurfaceView.Renderer {
Matrix.scaleM(matrix, 0, scale, scale, 1);
// translate relative to map center
Matrix.translateM(matrix, 0,
x * COORD_MULTIPLIER,
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER,
-1); // put on near plane
Matrix.translateM(matrix, 0, x * COORD_MULTIPLIER,
-(y + Tile.TILE_SIZE) * COORD_MULTIPLIER, 0);
if (mRotate)
Matrix.multiplyMM(matrix, 0, mRotateMatrix, 0, matrix, 0);
Matrix.multiplyMM(matrix, 0, mapPosition.rotation, 0, matrix, 0);
if (project)
Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, matrix, 0);
}
// private float[] mv = new float[4];
// private float[] mu = { 1, 1, -1, 1 };
//
// private float[] mUnprojMatrix = new float[16];
//
// private void unproject(MapPosition pos, float x, float y) {
// mu[0] = x;
// mu[1] = y;
// mu[2] = -1;
//
// // add tilt
// Matrix.multiplyMV(mv, 0, mTmpMatrix, 0, mu, 0);
// // Log.d(TAG, ">> " + mv[0] + " " + mv[1] + " " + mv[2]);
//
// Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
// float size = Tile.TILE_SIZE * pos.scale;
// if (mv[3] != 0) {
// float w = 1 / mv[3];
// float xx = Math.round(((mv[0] * w) / size) * 100) / 100f;
// float yy = Math.round(((mv[1] * w) / size) * 100) / 100f;
// Log.d(TAG, " " + xx + " " + yy);
// }
// }
private static float scaleDiv(MapTile t) {
float div = 1;
int diff = mMapPosition.zoomLevel - t.zoomLevel;
if (diff < 0)
div = (1 << -diff);
else if (diff > 0)
div = (1.0f / (1 << diff));
return div;
}
@Override
public void onDrawFrame(GL10 glUnused) {
long start = 0;
MapPosition mapPosition;
if (MapView.debugFrameTime)
start = SystemClock.uptimeMillis();
@@ -498,66 +465,55 @@ public class GLRenderer implements GLSurfaceView.Renderer {
| GLES20.GL_STENCIL_BUFFER_BIT);
// get position and current tiles to draw
GLRenderer.tilelock.lock();
mapPosition = mCurPosition;
// mapPosition = mCurPosition;
if (mUpdateTiles) {
GLRenderer.tilelock.lock();
TilesData tmp = mDrawTiles;
mDrawTiles = mNextTiles;
mNextTiles = tmp;
mUpdateTiles = false;
GLRenderer.tilelock.unlock();
}
GLRenderer.tilelock.unlock();
if (mDrawTiles == null)
if (mDrawTiles == null || mDrawTiles.cnt == 0)
return;
// if (mRotate != (mMapView.enableRotation || mMapView.enableCompass)) {
// Matrix.setIdentityM(mMVPMatrix, 0);
// mRotate = mMapView.enableRotation || mMapView.enableCompass;
// }
// MapPosition mapPosition =
// mMapView.getMapViewPosition().getMapPosition();
mRotate = mMapView.enableRotation || mMapView.enableCompass;
MapPosition mapPosition = mMapPosition;
boolean changed = mMapViewPosition.getMapPosition(mapPosition, mTileCoords);
if (mRotate) {
// rotate map
Matrix.setRotateM(mRotateMatrix, 0, mapPosition.angle, 0, 0, 1);
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
// tilt map
// mMapView.getMapViewPosition().mTilt;
if (changed) {
for (int i = 0; i < tileCnt; i++)
tiles[i].isVisible = false;
float angle = mMapView.getMapViewPosition().mTilt / (mHeight / 2);
Matrix.setRotateM(mTmpMatrix, 0, -angle, 1, 0, 0);
// get relative zoom-level, tiles could not have been updated after
// zoom-level changed.
float div = scaleDiv(tiles[0]);
// move camera center back to map center
Matrix.translateM(mTmpMatrix, 0,
0, (float) Math.tan(Math.toRadians(angle)), 0);
mRotate = mMapView.enableRotation || mMapView.enableCompass;
// apply first rotation, then tilt
Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0);
float s = Tile.TILE_SIZE;
float scale = mapPosition.scale / div;
float px = (float) (mapPosition.x * div);
float py = (float) (mapPosition.y * div);
// // get unproject matrix
// Matrix.setIdentityM(mTmp2Matrix, 0);
// float s = mapPosition.scale;
// Matrix.translateM(mTmp2Matrix, 0,
// (float) (mapPosition.x * s),
// (float) (mapPosition.y * s), 0);
//
// Matrix.multiplyMM(mTmp2Matrix, 0, mRotateMatrix, 0, mTmp2Matrix,
// 0);
//
// // Matrix.invertM(mTmpMatrix, 0, mTmp2Matrix, 0);
// // (AB)^-1 = B^-1*A^-1
// Matrix.multiplyMM(mUnprojMatrix, 0, mTmp2Matrix, 0, mProjMatrixI,
// 0);
//
// // set tilt of screen coords
// Matrix.setRotateM(mTmpMatrix, 0, -15, 1, 0, 0);
//
// // unproject(mapPosition, 0, 0);
// unproject(mapPosition, -1, -1); // top-left
// unproject(mapPosition, 1, -1); // top-right
// unproject(mapPosition, -1, 1); // bottom-left
// unproject(mapPosition, 1, 1); // bottom-right
mTileCoords[0] = (px + mTileCoords[0] / scale) / s;
mTileCoords[1] = (py - mTileCoords[1] / scale) / s;
mTileCoords[2] = (px + mTileCoords[2] / scale) / s;
mTileCoords[3] = (py - mTileCoords[3] / scale) / s;
mTileCoords[4] = (px + mTileCoords[4] / scale) / s;
mTileCoords[5] = (py - mTileCoords[5] / scale) / s;
mTileCoords[6] = (px + mTileCoords[6] / scale) / s;
mTileCoords[7] = (py - mTileCoords[7] / scale) / s;
byte z = tiles[0].zoomLevel;
ScanBox.scan(mTileCoords, mDrawTiles, 1 << z);
}
if (mUpdateColor && mClearColor != null) {
@@ -566,9 +522,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mUpdateColor = false;
}
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
uploadCnt = 0;
int updateTextures = 0;
@@ -576,7 +529,9 @@ public class GLRenderer implements GLSurfaceView.Renderer {
for (int i = 0; i < tileCnt; i++) {
MapTile tile = tiles[i];
if (!isVisible(mapPosition, tile))
// if (!isVisible(mapPosition, tile))
// continue;
if (!tile.isVisible)
continue;
if (tile.texture == null && TextRenderer.drawToTexture(tile))
@@ -616,14 +571,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
for (int i = 0; i < tileCnt; i++) {
if (tiles[i].isVisible && tiles[i].isReady)
drawTile(mapPosition, tiles[i]);
drawTile(tiles[i]);
}
// proxies are clipped to the region where nothing was drawn to depth
// buffer. TODO draw all parent before grandparent
for (int i = 0; i < tileCnt; i++) {
if (tiles[i].isVisible && !tiles[i].isReady)
drawProxyTile(mapPosition, tiles[i]);
drawProxyTile(tiles[i]);
}
// GlUtils.checkGlError("end draw");
@@ -647,19 +602,32 @@ public class GLRenderer implements GLSurfaceView.Renderer {
else
TextRenderer.beginDraw(s, mProjMatrix);
// s = (float) 1.0 / COORD_MULTIPLIER;
// TextRenderer.beginDraw(s, mProjMatrix);
for (int i = 0; i < tileCnt; i++) {
if (!tiles[i].isVisible || tiles[i].texture == null)
continue;
setMatrix(mMVPMatrix, mapPosition, tiles[i], 1, false);
setMatrix(mMVPMatrix, tiles[i], 1, false);
TextRenderer.drawTile(tiles[i], mMVPMatrix);
}
TextRenderer.endDraw();
// TODO call overlay renderer
// TODO call overlay renderer here
// s = 0.5f;
// mTileCoords[0] = -s;
// mTileCoords[1] = s;
// mTileCoords[2] = s;
// mTileCoords[3] = s;
// mTileCoords[4] = -s;
// mTileCoords[5] = -s;
// mTileCoords[6] = s;
// mTileCoords[7] = -s;
//
// Matrix.setIdentityM(mMVPMatrix, 0);
// // Matrix.scaleM(mMVPMatrix, 0, 0.99f, 0.99f, 1);
// // Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
// // Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
// PolygonRenderer.debugDraw(mMVPMatrix, mTileCoords);
if (MapView.debugFrameTime) {
GLES20.glFinish();
@@ -670,27 +638,26 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// used to not draw a tile twice per frame...
private static byte mDrawSerial = 0;
private static void drawTile(MapPosition mapPosition, MapTile tile) {
private static void drawTile(MapTile tile) {
// draw parents only once
if (tile.lastDraw == mDrawSerial)
return;
float div = 1;
int diff = mapPosition.zoomLevel - tile.zoomLevel;
if (diff < 0)
div = (1 << -diff);
else if (diff > 0)
div = (1.0f / (1 << diff));
float div = scaleDiv(tile);
// float div = 1;
// int diff = mapPosition.zoomLevel - tile.zoomLevel;
// if (diff < 0)
// div = (1 << -diff);
// else if (diff > 0)
// div = (1.0f / (1 << diff));
tile.lastDraw = mDrawSerial;
int z = mapPosition.zoomLevel;
float s = mapPosition.scale;
int z = mMapPosition.zoomLevel;
float s = mMapPosition.scale;
float[] mvp = mMVPMatrix;
setMatrix(mvp, mapPosition, tile, div, true);
setMatrix(mvp, tile, div, true);
GLES20.glPolygonOffset(0, mDrawCount++);
@@ -734,7 +701,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
}
// TODO could use tile.proxies here
private static boolean drawProxyChild(MapPosition mapPosition, MapTile tile) {
private static boolean drawProxyChild(MapTile tile) {
int drawn = 0;
for (int i = 0; i < 4; i++) {
if (tile.rel.child[i] == null)
@@ -744,13 +711,13 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (c == null)
continue;
if (!isVisible(mapPosition, c)) {
if (!isVisible(c)) {
drawn++;
continue;
}
if (c.isReady) {
drawTile(mapPosition, c);
drawTile(c);
drawn++;
}
}
@@ -758,17 +725,17 @@ public class GLRenderer implements GLSurfaceView.Renderer {
}
// TODO could use tile.proxies here
private static void drawProxyTile(MapPosition mapPosition, MapTile tile) {
int diff = mapPosition.zoomLevel - tile.zoomLevel;
private static void drawProxyTile(MapTile tile) {
int diff = mMapPosition.zoomLevel - tile.zoomLevel;
boolean drawn = false;
if (mapPosition.scale > 1.5f || diff < 0) {
if (mMapPosition.scale > 1.5f || diff < 0) {
// prefer drawing children
if (!drawProxyChild(mapPosition, tile)) {
if (!drawProxyChild(tile)) {
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
MapTile t = tile.rel.parent.tile;
if (t.isReady) {
drawTile(mapPosition, t);
drawTile(t);
drawn = true;
}
}
@@ -776,7 +743,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (!drawn && (tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
MapTile t = tile.rel.parent.parent.tile;
if (t.isReady)
drawTile(mapPosition, t);
drawTile(t);
}
}
@@ -785,14 +752,14 @@ public class GLRenderer implements GLSurfaceView.Renderer {
MapTile t = tile.rel.parent.tile;
if (t != null && t.isReady) {
drawTile(mapPosition, t);
drawTile(t);
} else if (!drawProxyChild(mapPosition, tile)) {
} else if (!drawProxyChild(tile)) {
if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
t = tile.rel.parent.parent.tile;
if (t.isReady)
drawTile(mapPosition, t);
drawTile(t);
}
}
}
@@ -814,14 +781,18 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// Matrix.orthoM(mProjMatrix, 0, -0.5f / mAspect, 0.5f / mAspect, -0.5f,
// 0.5f, -1, 1);
float s = 0.5f;
Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
-s * height, s * height, 1, 2);
Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
Matrix.frustumM(mProjMatrix, 0,
-0.5f * width,
0.5f * width,
-0.5f * height,
0.5f * height, 1, 2);
// Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
// use this to scale only the view to see which tiles are rendered
// s = 1.0f;
// Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
// -s * height, s * height, 1, 2);
// Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
// set to zero: we modify the z value with polygon-offset for clipping
mProjMatrix[10] = 0;
@@ -869,6 +840,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView.redrawMap();
}
// FIXME this is a bit too spaghetti
void clearTiles(int numTiles) {
mDrawTiles = new TilesData(numTiles);
mNextTiles = new TilesData(numTiles);

View File

@@ -40,8 +40,8 @@ class LineLayer {
boolean isOutline;
int layer;
ShortItem pool;
protected ShortItem curItem;
VertexPoolItem pool;
protected VertexPoolItem curItem;
// number of vertices this layer holds
int verticesCnt;
@@ -85,10 +85,10 @@ class LineLayer {
squared = true;
if (pool == null) {
pool = curItem = ShortPool.get();
pool = curItem = VertexPool.get();
}
ShortItem si = curItem;
VertexPoolItem si = curItem;
short v[] = si.vertices;
int opos = si.used;
@@ -137,8 +137,8 @@ class LineLayer {
ux = -vy;
uy = vx;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -151,8 +151,8 @@ class LineLayer {
boolean outside = (x < tmin || x > tmax || y < tmin || y > tmax);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -170,8 +170,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -181,8 +181,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -195,8 +195,8 @@ class LineLayer {
v[opos++] = (short) (2 | ddx & DIR_MASK);
v[opos++] = (short) (2 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -210,8 +210,8 @@ class LineLayer {
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -248,8 +248,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -259,8 +259,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -334,8 +334,8 @@ class LineLayer {
ddx = (int) (ux * DIR_SCALE);
ddy = (int) (uy * DIR_SCALE);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -345,8 +345,8 @@ class LineLayer {
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -375,8 +375,8 @@ class LineLayer {
outside = (x < tmin || x > tmax || y < tmin || y > tmax);
if (opos == ShortItem.SIZE) {
si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si.next = VertexPool.get();
si = si.next;
opos = 0;
v = si.vertices;
@@ -394,8 +394,8 @@ class LineLayer {
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -405,8 +405,8 @@ class LineLayer {
v[opos++] = (short) (2 | -ddx & DIR_MASK);
v[opos++] = (short) (1 | -ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -422,8 +422,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -439,8 +439,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -470,8 +470,8 @@ class LineLayer {
v[opos++] = (short) (0 | ddx & DIR_MASK);
v[opos++] = (short) (1 | ddy & DIR_MASK);
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}
@@ -487,8 +487,8 @@ class LineLayer {
v[opos++] = dx;
v[opos++] = dy;
if (opos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (opos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
opos = 0;
}

View File

@@ -183,18 +183,18 @@ class LineRenderer {
static void compileLayerData(LineLayer layers, ShortBuffer sbuf) {
int pos = 0;
ShortItem last = null, items = null;
VertexPoolItem last = null, items = null;
for (LineLayer l = layers; l != null; l = l.next) {
if (l.isOutline)
continue;
for (ShortItem item = l.pool; item != null; item = item.next) {
for (VertexPoolItem item = l.pool; item != null; item = item.next) {
if (item.next == null) {
sbuf.put(item.vertices, 0, item.used);
} else {
// item.used = ShortItem.SIZE;
// item.used = VertexPoolItem.SIZE;
sbuf.put(item.vertices);
}
@@ -213,7 +213,7 @@ class LineRenderer {
l.curItem = null;
}
ShortPool.add(items);
VertexPool.add(items);
}
// @SuppressLint("UseValueOf")
@@ -310,7 +310,7 @@ class LineRenderer {
static void clear(LineLayer layer) {
for (LineLayer l = layer; l != null; l = l.next) {
if (l.pool != null) {
ShortPool.add(l.pool);
VertexPool.add(l.pool);
l.pool = null;
l.curItem = null;
}

View File

@@ -8,7 +8,7 @@
* 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/>.
*/
@@ -17,21 +17,21 @@ package org.oscim.view.renderer;
import java.util.ArrayList;
import java.util.Collections;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile;
import org.oscim.database.MapInfo;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlConfigChooser;
import org.oscim.view.MapPosition;
import org.oscim.view.MapView;
import org.oscim.view.generator.JobTile;
import org.oscim.view.renderer.GLRenderer.TilesData;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.FloatMath;
import android.util.Log;
// FIXME to many 'Renderer', this one needs a better name.. TileLoader?
public class MapRenderer extends GLSurfaceView {
private final static String TAG = "MapRenderer";
private GLRenderer mRenderer;
@@ -45,7 +45,7 @@ public class MapRenderer extends GLSurfaceView {
// 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;
@@ -59,9 +59,20 @@ public class MapRenderer extends GLSurfaceView {
// private static MapPosition mCurPosition, mDrawPosition;
private static int mWidth = 0, mHeight = 0;
// used for passing tiles to be rendered from TileLoader(Main-Thread) to
// GLThread
static final class TilesData {
int cnt = 0;
final MapTile[] tiles;
TilesData(int numTiles) {
tiles = new MapTile[numTiles];
}
}
private static TilesData mCurrentTiles;
// map zoom-level to available zoom-levels in MapDatabase
// maps zoom-level to available zoom-levels in MapDatabase
// e.g. 16->16, 15->16, 14->13, 13->13, 12->13,....
private static int[] mZoomLevels;
@@ -85,7 +96,7 @@ public class MapRenderer extends GLSurfaceView {
mTiles = new ArrayList<MapTile>();
mTilesLoaded = new ArrayList<MapTile>(30);
ShortPool.init();
VertexPool.init();
QuadTree.init();
mInitial = true;
@@ -97,13 +108,10 @@ public class MapRenderer extends GLSurfaceView {
* loading by TileGenerator class
*
* @param clear
* ...
* whether to clear and reload all tiles
*/
public synchronized void updateMap(boolean clear) {
boolean changedPos = false;
boolean changedZoom = false;
if (mMapView == null)
return;
@@ -155,24 +163,20 @@ public class MapRenderer extends GLSurfaceView {
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) {
} else if (tileX != mTileX || tileY != mTileY) {
if (mPrevScale - scale > 0 && scale > 1.2)
zdir = 1;
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;
}
@@ -180,30 +184,19 @@ public class MapRenderer extends GLSurfaceView {
mTileY = tileY;
mPrevZoom = zoomLevel;
GLRenderer.updatePosition(mapPosition);
// GLRenderer.updatePosition(mapPosition);
if (!MapView.debugFrameTime)
requestRender();
if (changedZoom || changedPos) {
// need to update visible list first when zoom level changes
// as scaling is relative to the tiles of current zoom-level
if (changedPos) {
mPrevScale = scale;
updateVisibleList(mapPosition, zdir);
if (!MapView.debugFrameTime)
requestRender();
}
// else {
// // pass new position to glThread
// GLRenderer.updatePosition(mapPosition);
// }
// if (!MapView.debugFrameTime)
// requestRender();
// if (changedPos)
// updateVisibleList(mapPosition, zdir);
if (changedPos || changedZoom) {
int remove = mTiles.size() - GLRenderer.CACHE_TILES;
if (remove > 50)
limitCache(mapPosition, remove);
@@ -256,15 +249,15 @@ public class MapRenderer extends GLSurfaceView {
// check MapDatabase zoom-level-mapping
if (mZoomLevels[zoomLevel] == 0) {
mCurrentTiles.cnt = 0;
mCurrentTiles = GLRenderer.updateTiles(mapPosition, mCurrentTiles);
mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
return;
}
if (mZoomLevels[zoomLevel] > zoomLevel) {
fetchChildren = true;
fetchProxy = true;
}
else if (mZoomLevels[zoomLevel] < zoomLevel) {
} else if (mZoomLevels[zoomLevel] < zoomLevel) {
fetchParent = true;
fetchProxy = true;
}
@@ -285,12 +278,12 @@ public class MapRenderer extends GLSurfaceView {
mTiles.add(tile);
}
mCurrentTiles.tiles[tiles++] = tile;
if (!fetchProxy && !(tile.isLoading || tile.newData || tile.isReady)) {
if (!fetchProxy && !tile.isActive()) {
mJobList.add(tile);
}
mCurrentTiles.tiles[tiles++] = tile;
if (fetchChildren) {
byte z = (byte) (zoomLevel + 1);
for (int i = 0; i < 4; i++) {
@@ -306,7 +299,7 @@ public class MapRenderer extends GLSurfaceView {
mTiles.add(c);
}
if (!(c.isLoading || c.newData || c.isReady)) {
if (!c.isActive()) {
mJobList.add(c);
}
}
@@ -314,18 +307,18 @@ public class MapRenderer extends GLSurfaceView {
if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
// prefetch parent
MapTile parent = tile.rel.parent.tile;
MapTile p = tile.rel.parent.tile;
if (parent == null) {
parent = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
if (p == null) {
p = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
QuadTree.add(parent);
mTiles.add(parent);
}
QuadTree.add(p);
mTiles.add(p);
mJobList.add(p);
if (!(parent.isLoading || parent.isReady || parent.newData)) {
if (!mJobList.contains(parent))
mJobList.add(parent);
} else if (!p.isActive()) {
if (!mJobList.contains(p))
mJobList.add(p);
}
}
}
@@ -333,7 +326,7 @@ public class MapRenderer extends GLSurfaceView {
// pass new tile list to glThread
mCurrentTiles.cnt = tiles;
mCurrentTiles = GLRenderer.updateTiles(mapPosition, mCurrentTiles);
mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
// note: this sets isLoading == true for all job tiles
if (mJobList.size() > 0) {
@@ -366,8 +359,7 @@ public class MapRenderer extends GLSurfaceView {
QuadTree.remove(t);
}
private static void updateTileDistances(ArrayList<?> tiles,
MapPosition mapPosition) {
private static void updateTileDistances(ArrayList<?> tiles, MapPosition mapPosition) {
int h = (Tile.TILE_SIZE >> 1);
byte zoom = mapPosition.zoomLevel;
long x = (long) mapPosition.x;
@@ -422,18 +414,17 @@ public class MapRenderer extends GLSurfaceView {
// remove orphaned tiles
for (int i = 0; i < size;) {
MapTile cur = mTiles.get(i);
MapTile t = mTiles.get(i);
// make sure tile cannot be used by GL or MapWorker Thread
if (!cur.isLocked() && !cur.isLoading && !cur.newData && !cur.isReady) {
clearTile(cur);
if (t.isLocked() || t.isActive()) {
i++;
} else {
// Log.d(TAG, "remove empty tile" + cur);
clearTile(t);
mTiles.remove(i);
removes--;
size--;
// Log.d(TAG, "remove empty tile" + cur);
continue;
}
i++;
}
// Log.d(TAG, "remove tiles: " + removes + " " + size);
@@ -451,7 +442,7 @@ public class MapRenderer extends GLSurfaceView {
synchronized (t) {
if (t.isLocked()) {
// dont remove tile used by renderthread
Log.d(TAG, "X not removing " + t + " " + t.isActive + " "
Log.d(TAG, "X not removing " + t + " " + t.isLocked + " "
+ t.distance);
mTiles.add(t);
@@ -478,7 +469,7 @@ public class MapRenderer extends GLSurfaceView {
synchronized (mTilesLoaded) {
// remove uploaded tiles
// remove tiles uploaded to vbo
for (int i = 0; i < size;) {
MapTile t = mTilesLoaded.get(i);
// rel == null means tile is already removed by limitCache
@@ -535,8 +526,7 @@ public class MapRenderer extends GLSurfaceView {
if (!tile.isLoading) {
// no one should be able to use this tile now, mapgenerator passed
// it,
// glthread does nothing until newdata is set.
// it, glthread does nothing until newdata is set.
Log.d(TAG, "passTile: canceled " + tile);
synchronized (mTilesLoaded) {
mTilesLoaded.add(tile);

View File

@@ -41,7 +41,7 @@ class MapTile extends JobTile {
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
boolean isActive;
boolean isLocked;
/**
* tile has new data to upload to gl
@@ -74,13 +74,16 @@ class MapTile extends JobTile {
// counting the tiles that use this tile as proxy
byte refs;
boolean isActive() {
return isLoading || newData || isReady;
}
boolean isLocked() {
return isActive || refs > 0;
return isLocked || refs > 0;
}
void lock() {
isActive = true;
isLocked = true;
if (isReady || newData)
return;
@@ -110,7 +113,7 @@ class MapTile extends JobTile {
}
void unlock() {
isActive = false;
isLocked = false;
if (proxies == 0)
return;

View File

@@ -23,8 +23,8 @@ class PolygonLayer {
PolygonLayer next;
Area area;
ShortItem pool;
protected ShortItem curItem;
VertexPoolItem pool;
protected VertexPoolItem curItem;
int verticesCnt;
int offset;
@@ -33,14 +33,14 @@ class PolygonLayer {
PolygonLayer(int layer, Area area) {
this.layer = layer;
this.area = area;
curItem = ShortPool.get();
curItem = VertexPool.get();
pool = curItem;
}
void addPolygon(float[] points, short[] index) {
short center = (short) ((Tile.TILE_SIZE >> 1) * S);
ShortItem si = curItem;
VertexPoolItem si = curItem;
short[] v = si.vertices;
int outPos = si.used;
@@ -59,8 +59,8 @@ class PolygonLayer {
int inPos = pos;
if (outPos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (outPos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
outPos = 0;
}
@@ -69,8 +69,8 @@ class PolygonLayer {
v[outPos++] = center;
for (int j = 0; j < length; j += 2) {
if (outPos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (outPos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
outPos = 0;
}
@@ -78,8 +78,8 @@ class PolygonLayer {
v[outPos++] = (short) (points[inPos++] * S);
}
if (outPos == ShortItem.SIZE) {
si = si.next = ShortPool.get();
if (outPos == VertexPoolItem.SIZE) {
si = si.next = VertexPool.get();
v = si.vertices;
outPos = 0;
}

View File

@@ -35,6 +35,9 @@ import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.oscim.utils.GlUtils;
@@ -257,7 +260,7 @@ class PolygonRenderer {
if (mCount > 0)
fillPolygons(zoom, scale);
//
// maybe reset start when only few layers left in stencil buffer
// if (mCount > 5){
// mCount = 0;
// mStart = 0;
@@ -273,6 +276,35 @@ class PolygonRenderer {
return l;
}
private static float[] debugFillColor = { 0.3f, 0.0f, 0.0f, 0.3f };
private static ByteBuffer mDebugFill;
static void debugDraw(float[] matrix, float[] coords) {
mDebugFill = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder());
FloatBuffer buf = mDebugFill.asFloatBuffer();
buf.put(coords);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
mDebugFill.position(0);
glUseProgram(polygonProgram);
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
glVertexAttribPointer(hPolygonVertexPosition, 2, GLES20.GL_FLOAT,
false, 0, mDebugFill);
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
glUniform4fv(hPolygonColor, 1, debugFillColor, 0);
glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GlUtils.checkGlError("draw debug");
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
}
static void drawDepthClip() {
glColorMask(false, false, false, false);
GLES20.glDepthMask(true);
@@ -299,16 +331,16 @@ class PolygonRenderer {
static void compileLayerData(PolygonLayer layers, ShortBuffer sbuf) {
int pos = 4;
ShortItem last = null, items = null;
VertexPoolItem last = null, items = null;
for (PolygonLayer l = layers; l != null; l = l.next) {
for (ShortItem item = l.pool; item != null; item = item.next) {
for (VertexPoolItem item = l.pool; item != null; item = item.next) {
if (item.next == null) {
sbuf.put(item.vertices, 0, item.used);
} else {
// item.used = ShortItem.SIZE;
// item.used = VertexPoolItem.SIZE;
sbuf.put(item.vertices);
}
@@ -326,13 +358,13 @@ class PolygonRenderer {
l.pool = null;
}
ShortPool.add(items);
VertexPool.add(items);
}
static void clear(PolygonLayer layers) {
for (PolygonLayer l = layers; l != null; l = l.next) {
if (l.pool != null)
ShortPool.add(l.pool);
VertexPool.add(l.pool);
}
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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 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 License for more details.
*
* You should have received a copy of the GNU Lesser General License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ported from Polymaps: Layer.js */
package org.oscim.view.renderer;
import org.oscim.view.renderer.MapRenderer.TilesData;
import android.util.FloatMath;
public class ScanBox {
interface Callback {
void call(MapTile tile);
}
class SetVisible implements Callback {
@Override
public void call(MapTile tile) {
tile.isVisible = true;
}
}
static class Edge {
float x0, y0, x1, y1, dx, dy;
void set(float x0, float y0, float x1, float y1) {
if (y0 <= y1) {
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
this.dx = x1 - x0;
this.dy = y1 - y0;
} else {
this.x0 = x1;
this.y0 = y1;
this.x1 = x0;
this.y1 = y0;
this.dx = x0 - x1;
this.dy = y0 - y1;
}
}
}
static Edge ab = new Edge();
static Edge bc = new Edge();
static Edge ca = new Edge();
static void scanSpans(Edge e0, Edge e1, float ymin, float ymax) {
// sort edge by x-coordinate
if (e0.x0 == e1.x0 && e0.y0 == e1.y0) {
if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) {
Edge t = e0;
e0 = e1;
e1 = t;
}
} else {
if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) {
Edge t = e0;
e0 = e1;
e1 = t;
}
}
float m0 = e0.dx / e0.dy;
float m1 = e1.dx / e1.dy;
int d0 = e0.dx > 0 ? 1 : 0;// use y + 1 to compute x0
int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
float x0, x1;
int y = (int) Math.max(ymin, FloatMath.floor(e1.y0));
int bottom = (int) Math.min(ymax, FloatMath.ceil(e1.y1));
for (; y < bottom; y++) {
// float x0 = (m0 * Math.min(e0.dy, y + d0 - e0.y0) + e0.x0);
// float x1 = (m1 * Math.min(e1.dy, y + d1 - e1.y0) + e1.x0);
x0 = y + d0 - e0.y0;
if (e0.dy < x0)
x0 = e0.dy;
x0 = m0 * x0 + e0.x0;
if (x0 < 0)
x0 = 0;
else
x0 = FloatMath.ceil(x0);
x1 = y + d1 - e1.y0;
if (e1.dy < x1)
x1 = e1.dy;
x1 = m1 * x1 + e1.x0;
if (x1 < 0)
x1 = 0;
else
x1 = FloatMath.floor(x1);
setVisible(y, (int) x1, (int) x0);
// setVisible(y, (int) (x1 - 0.5f), (int) (x0 + 0.5f));
}
}
static void scanTriangle(float ymin, float ymax) {
if (ab.dy > bc.dy) {
Edge t = ab;
ab = bc;
bc = t;
}
if (ab.dy > ca.dy) {
Edge t = ab;
ab = ca;
ca = t;
}
if (bc.dy > ca.dy) {
Edge t = bc;
bc = ca;
ca = t;
}
if (ab.dy != 0)
scanSpans(ca, ab, ymin, ymax);
if (bc.dy != 0)
scanSpans(ca, bc, ymin, ymax);
}
public static void scan(float[] coords, TilesData tiles, int max) {
sTiles = tiles;
cntDoubles = 0;
ab.set(coords[0], coords[1], coords[2], coords[3]);
bc.set(coords[2], coords[3], coords[4], coords[5]);
ca.set(coords[4], coords[5], coords[0], coords[1]);
scanTriangle(0, max);
// Log.d("..", ">doubles " + cntDoubles);
ab.set(coords[4], coords[5], coords[6], coords[7]);
bc.set(coords[6], coords[7], coords[0], coords[1]);
ca.set(coords[0], coords[1], coords[4], coords[5]);
scanTriangle(0, max);
// Log.d("..", "<doubles " + cntDoubles);
}
private static TilesData sTiles;
private static int cntDoubles;
private static void setVisible(int y, int x1, int x2) {
MapTile[] tiles = sTiles.tiles;
for (int i = 0, n = sTiles.cnt; i < n; i++) {
if (tiles[i].tileY == y) {
if (tiles[i].tileX >= x1 && tiles[i].tileX < x2) {
// if (tiles[i].isVisible) {
// Log.d("..", ">>>" + y + " " + tiles[i].tileX);
// cntDoubles++;
// }
tiles[i].isVisible = true;
}
}
}
}
}

View File

@@ -192,7 +192,7 @@ public class TextRenderer {
if (tex.tile == null)
break;
if (!tex.tile.isActive)
if (!tex.tile.isLocked)
break;
tex = null;
@@ -412,7 +412,7 @@ public class TextRenderer {
for (int i = 0; i < mTextures.length; i++) {
tex = mTextures[i];
if (tex.tile == null || !tex.tile.isActive)
if (tex.tile == null || !tex.tile.isLocked)
continue;
mShortBuffer.put(tex.vertices, 0, tex.length);

View File

@@ -16,10 +16,10 @@ package org.oscim.view.renderer;
import android.util.Log;
public class ShortPool {
public class VertexPool {
private static final int POOL_LIMIT = 6000;
static private ShortItem pool = null;
static private VertexPoolItem pool = null;
static private int count = 0;
static private int countAll = 0;
@@ -29,14 +29,14 @@ public class ShortPool {
pool = null;
}
static synchronized ShortItem get() {
static synchronized VertexPoolItem get() {
if (pool == null && count > 0) {
Log.d("ShortPool", "XXX wrong count: " + count);
Log.d("VertexPool", "XXX wrong count: " + count);
}
if (pool == null) {
countAll++;
return new ShortItem();
return new VertexPoolItem();
}
count--;
@@ -44,14 +44,14 @@ public class ShortPool {
if (count < 0) {
int c = 0;
for (ShortItem tmp = pool; tmp != null; tmp = tmp.next)
for (VertexPoolItem tmp = pool; tmp != null; tmp = tmp.next)
c++;
Log.d("ShortPool", "XXX wrong count: " + count + " left" + c);
return new ShortItem();
Log.d("VertexPool", "XXX wrong count: " + count + " left" + c);
return new VertexPoolItem();
}
ShortItem it = pool;
VertexPoolItem it = pool;
pool = pool.next;
it.used = 0;
it.next = null;
@@ -61,7 +61,7 @@ public class ShortPool {
// private static float load = 1.0f;
// private static int loadCount = 0;
static synchronized void add(ShortItem items) {
static synchronized void add(VertexPoolItem items) {
if (items == null)
return;
@@ -71,11 +71,11 @@ public class ShortPool {
// limit pool items
if (countAll < POOL_LIMIT) {
ShortItem last = items;
VertexPoolItem last = items;
while (true) {
count++;
// load += (float) last.used / ShortItem.SIZE;
// load += (float) last.used / VertexPoolItem.SIZE;
// loadCount++;
if (last.next == null)
@@ -91,14 +91,14 @@ public class ShortPool {
} else {
// int cleared = 0;
ShortItem prev, tmp = items;
VertexPoolItem prev, tmp = items;
while (tmp != null) {
prev = tmp;
tmp = tmp.next;
countAll--;
// load += (float) prev.used / ShortItem.SIZE;
// load += (float) prev.used / VertexPoolItem.SIZE;
// loadCount++;
prev.next = null;

View File

@@ -14,12 +14,12 @@
*/
package org.oscim.view.renderer;
public class ShortItem {
public class VertexPoolItem {
final short[] vertices;
int used;
ShortItem next;
VertexPoolItem next;
ShortItem() {
VertexPoolItem() {
vertices = new short[SIZE];
used = 0;
}