add osmdroid overlays + bonuspack

This commit is contained in:
Hannes Janetzek
2012-10-27 13:35:51 +02:00
parent 65a6f91f3c
commit ab5962d56c
114 changed files with 9562 additions and 1636 deletions

View File

@@ -1,32 +0,0 @@
/*
* 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.oscim.view;
import android.os.Handler;
import android.os.Message;
public class DelayedTaskHandler extends Handler {
public final int MESSAGE_UPDATE_POSITION = 1;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_UPDATE_POSITION:
break;
}
}
}

View File

@@ -19,10 +19,12 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.oscim.core.BoundingBox;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.Tile;
@@ -34,6 +36,9 @@ import org.oscim.database.OpenResult;
import org.oscim.generator.JobQueue;
import org.oscim.generator.JobTile;
import org.oscim.generator.MapWorker;
import org.oscim.overlay.LabelingOverlay;
import org.oscim.overlay.Overlay;
import org.oscim.overlay.OverlayManager;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLView;
import org.oscim.renderer.TileGenerator;
@@ -43,29 +48,28 @@ import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.Theme;
import org.oscim.utils.AndroidUtils;
import org.xml.sax.SAXException;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
/**
* A MapView shows a map on the display of the device. It handles all user input
* and touch gestures to move and zoom the map.
*/
public class MapView extends FrameLayout {
public class MapView extends RelativeLayout {
final static String TAG = "MapView";
public static final boolean debugFrameTime = false;
public static final boolean testRegionZoom = false;
// public static final boolean staticLabeling = false;
private static final boolean debugDatabase = false;
RegionLookup mRegionLookup;
// RegionLookup mRegionLookup;
public boolean enableRotation = false;
public boolean enableCompass = false;
@@ -81,10 +85,15 @@ public class MapView extends FrameLayout {
private MapDatabases mMapDatabaseType;
private TileManager mTileManager;
private GLView mGLView;
private JobQueue mJobQueue;
private MapWorker mMapWorkers[];
private int mNumMapWorkers = 4;
private final OverlayManager mOverlayManager;
private final GLView mGLView;
private final JobQueue mJobQueue;
// TODO use 1 download and 1 generator thread instead
private final MapWorker mMapWorkers[];
private final int mNumMapWorkers = 4;
private DebugSettings debugSettings;
private String mRenderTheme;
private Map<String, String> mMapOptions;
@@ -124,8 +133,10 @@ public class MapView extends FrameLayout {
}
Log.d(TAG, "create MapView: " + mapDatabaseType.name());
// this.setDrawingCacheEnabled(true);
this.setWillNotDraw(true);
// TODO make this dpi dependent
// TODO set tilesize, make this dpi dependent
Tile.TILE_SIZE = 400;
MapActivity mapActivity = (MapActivity) context;
@@ -138,6 +149,8 @@ public class MapView extends FrameLayout {
mMapViewPosition = new MapViewPosition(this);
mOverlayManager = new OverlayManager();
mTouchEventHandler = new TouchHandler(mapActivity, this);
mCompass = new Compass(mapActivity, this);
@@ -145,6 +158,7 @@ public class MapView extends FrameLayout {
mJobQueue = new JobQueue();
mTileManager = TileManager.create(this);
mGLView = new GLView(context, this);
mMapWorkers = new MapWorker[mNumMapWorkers];
@@ -156,7 +170,7 @@ public class MapView extends FrameLayout {
// .createMapDatabase(MapDatabases.TEST_READER);
mapDatabase = MapDatabaseFactory
.createMapDatabase(MapDatabases.MAP_READER);
mNumMapWorkers = 1;
// mNumMapWorkers = 1;
} else {
mapDatabase = MapDatabaseFactory.createMapDatabase(mapDatabaseType);
}
@@ -187,8 +201,8 @@ public class MapView extends FrameLayout {
addView(mGLView, params);
if (testRegionZoom)
mRegionLookup = new RegionLookup(this);
// if (testRegionZoom)
// mRegionLookup = new RegionLookup(this);
mMapZoomControls = new MapZoomControls(mapActivity, this);
mMapZoomControls.setShowMapZoomControls(true);
@@ -197,6 +211,35 @@ public class MapView extends FrameLayout {
for (MapWorker worker : mMapWorkers)
worker.start();
mOverlayManager.add(new LabelingOverlay(this));
// mOverlayManager.add(new GenericOverlay(this, new OverlayGrid(this)));
// mOverlayManager.add(new GenericOverlay(this, new OverlayTest(this)));
// ArrayList<OverlayItem> pList = new ArrayList<OverlayItem>();
// pList.add(new OverlayItem("title", "description", new GeoPoint(53.067221, 8.78767)));
// Overlay overlay = new ItemizedIconOverlay<OverlayItem>(this, context, pList, null);
// mOverlayManager.add(overlay);
// ArrayList<OverlayItem> pList = new ArrayList<OverlayItem>();
// pList.add(new ExtendedOverlayItem("Bremen", "description",
// new GeoPoint(53.047221, 8.78767), context));
// pList.add(new ExtendedOverlayItem("New York", "description",
// new GeoPoint(40.4251, -74.021), context));
// pList.add(new ExtendedOverlayItem("Tokyo", "description",
// new GeoPoint(35.4122, 139.4130), context));
// Overlay overlay = new ItemizedOverlayWithBubble<OverlayItem>(this, context, pList, null);
// mOverlayManager.add(overlay);
// PathOverlay pathOverlay = new PathOverlay(this, Color.BLUE, context);
// pathOverlay.addGreatCircle(
// new GeoPoint(53.047221, 8.78767),
// new GeoPoint(40.4251, -74.021));
// // pathOverlay.addPoint(new GeoPoint(53.047221, 8.78767));
// // pathOverlay.addPoint(new GeoPoint(53.067221, 8.78767));
// mOverlayManager.add(pathOverlay);
mMapViewPosition.animateTo(new GeoPoint(53.067221, 8.78767));
}
public void render() {
@@ -259,6 +302,9 @@ public class MapView extends FrameLayout {
if (mPausing || this.getWidth() == 0 || this.getHeight() == 0)
return;
if (AndroidUtils.currentThreadIsUiThread())
mOverlayManager.onUpdate(mMapViewPosition.getMapPosition());
mTileManager.updateMap(false);
}
@@ -266,7 +312,8 @@ public class MapView extends FrameLayout {
if (mPausing || this.getWidth() == 0 || this.getHeight() == 0)
return;
mTileManager.updateMap(true);
if (AndroidUtils.currentThreadIsUiThread())
mTileManager.updateMap(true);
}
/**
@@ -291,7 +338,6 @@ public class MapView extends FrameLayout {
/**
* Sets the map file for this MapView.
*
* @param mapOptions
* ...
* @return true if the map file was set correctly, false otherwise.
@@ -356,7 +402,6 @@ public class MapView extends FrameLayout {
/**
* Sets the MapDatabase for this MapView.
*
* @param mapDatabaseType
* the new MapDatabase.
*/
@@ -396,7 +441,6 @@ public class MapView extends FrameLayout {
/**
* Sets the internal theme which is used for rendering the map.
*
* @param internalRenderTheme
* the internal rendering theme.
* @return ...
@@ -418,7 +462,6 @@ public class MapView extends FrameLayout {
/**
* Sets the theme file which is used for rendering the map.
*
* @param renderThemePath
* the path to the XML file which defines the rendering theme.
* @throws IllegalArgumentException
@@ -488,11 +531,11 @@ public class MapView extends FrameLayout {
mapWorkersProceed();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mMapZoomControls.onLayout(changed, left, top, right, bottom);
}
// @Override
// protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// // super.onLayout(changed, left, top, right, bottom);
// mMapZoomControls.onLayout(changed, left, top, right, bottom);
// }
void destroy() {
for (MapWorker mapWorker : mMapWorkers) {
@@ -577,7 +620,6 @@ public class MapView extends FrameLayout {
/**
* Sets the center and zoom level of this MapView and triggers a redraw.
*
* @param mapPosition
* the new map position of this MapView.
*/
@@ -591,7 +633,6 @@ public class MapView extends FrameLayout {
/**
* Sets the center of the MapView and triggers a redraw.
*
* @param geoPoint
* the new center point of the map.
*/
@@ -611,7 +652,6 @@ public class MapView extends FrameLayout {
/**
* add jobs and remember MapWorkers that stuff needs to be done
*
* @param jobs
* tile jobs
*/
@@ -648,6 +688,35 @@ public class MapView extends FrameLayout {
mapWorker.proceed();
}
/**
* You can add/remove/reorder your Overlays using the List of
* {@link Overlay}. The first (index 0) Overlay gets drawn first, the one
* with the highest as the last one.
* @return ...
*/
public List<Overlay> getOverlays() {
return this.getOverlayManager();
}
public OverlayManager getOverlayManager() {
return mOverlayManager;
}
public BoundingBox getBoundingBox() {
return mMapViewPosition.getViewBox();
}
// @Override
// protected void onLayout(boolean changed, int l, int t, int r, int b) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// protected void onMeasure()) {
// // TODO Auto-generated method stub
//
// }
// /**
// * Sets the visibility of the zoom controls.
// *

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org, 2012 Hannes Janetzek
* Copyright 2010, 2011, 2012 mapsforge.org
* 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
@@ -14,30 +15,35 @@
*/
package org.oscim.view;
import java.lang.ref.WeakReference;
import org.oscim.core.BoundingBox;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.utils.FastMath;
import android.graphics.Point;
import android.opengl.Matrix;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.FloatMath;
import android.util.Log;
/**
* A MapPosition stores the latitude and longitude coordinate of a MapView
* together with its zoom level.
* together with its zoom level, rotation and tilt
*/
// TODO use global coordinates that directly scale to pixel
public class MapViewPosition {
private static final String TAG = "MapViewPosition";
private static final String TAG = MapViewPosition.class.getSimpleName();
public final static int MAX_ZOOMLEVEL = 17;
public final static int MIN_ZOOMLEVEL = 2;
private final static float MAX_ANGLE = 35;
private final static float MAX_ANGLE = 40;
private final MapView mMapView;
@@ -51,6 +57,12 @@ public class MapViewPosition {
private float mRotation;
public float mTilt;
// private static final int REF_ZOOM = 20;
private double mPosX;
private double mPosY;
private AnimationHandler mHandler;
MapViewPosition(MapView mapView) {
mMapView = mapView;
mLatitude = Double.NaN;
@@ -60,6 +72,8 @@ public class MapViewPosition {
mRotation = 0.0f;
mTilt = 0;
mMapScale = 1;
mHandler = new AnimationHandler(this);
}
private float[] mProjMatrix = new float[16];
@@ -69,19 +83,12 @@ public class MapViewPosition {
private float[] mRotMatrix = new float[16];
private float[] mTmpMatrix = new float[16];
private int mHeight, mWidth;
private static int mHeight, mWidth;
public final static float VIEW_SCALE = 1f / 2;
public final static float VIEW_DISTANCE = 2;
public final static float VIEW_NEAR = VIEW_DISTANCE;
public final static float VIEW_FAR = VIEW_DISTANCE * 2;
public final static float DIST = 2;
// public final static float VIEW_SCALE = 1f / 2;
// public final static float VIEW_DISTANCE = 1;
// public final static float VIEW_NEAR = 1;
// public final static float VIEW_FAR = 2;
void setViewport(int width, int height) {
float sw = VIEW_SCALE;
float sh = VIEW_SCALE;
@@ -124,50 +131,211 @@ public class MapViewPosition {
mapPosition.scale = mScale;
mapPosition.zoomLevel = z;
mapPosition.x = MercatorProjection.longitudeToPixelX(mLongitude, z);
mapPosition.y = MercatorProjection.latitudeToPixelY(mLatitude, z);
mapPosition.x = mPosX;
mapPosition.y = mPosY;
if (mapPosition.viewMatrix != null)
System.arraycopy(mViewMatrix, 0, mapPosition.viewMatrix, 0, 16);
if (mapPosition.rotateMatrix != null)
System.arraycopy(mRotMatrix, 0, mapPosition.rotateMatrix, 0, 16);
if (coords == null)
return true;
// not so sure about this, but somehow works. weird z-values...
float tilt = FloatMath.sin((float) Math.toRadians(mTilt
// * 2.2f for dist = 1
* 1.4f // for dist = 2
// * 0.8f for dist = 4
* ((float) mHeight / mWidth)));
float tilt = getZ(1);
float d = 1f;
unproject(-d, d, tilt, coords, 0); // bottom-left
unproject(d, d, tilt, coords, 2); // bottom-right
unproject(d, -d, -tilt, coords, 4); // top-right
unproject(-d, -d, -tilt, coords, 6); // top-left
unproject(-1, 1, tilt, coords, 0); // bottom-left
unproject(1, 1, tilt, coords, 2); // bottom-right
unproject(1, -1, -tilt, coords, 4); // top-right
unproject(-1, -1, -tilt, coords, 6); // top-left
return true;
}
/** @return the current center point of the MapView. */
public synchronized GeoPoint getMapCenter() {
return new GeoPoint(mLatitude, mLongitude);
}
/**
* @return a MapPosition or null, if this map position is not valid.
* @see #isValid()
*/
public synchronized MapPosition getMapPosition() {
if (!isValid()) {
return null;
}
return new MapPosition(mLatitude, mLongitude, mZoomLevel, mScale, mRotation);
}
/** @return the current zoom level of the MapView. */
public synchronized byte getZoomLevel() {
return mZoomLevel;
}
/** @return the current scale of the MapView. */
public synchronized float getScale() {
return mScale;
}
/**
* ...
* @return BoundingBox containing view
*/
public synchronized BoundingBox getViewBox() {
float[] coords = mBBoxCoords;
float tilt = getZ(1);
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
byte z = mZoomLevel;
double dx, dy;
double minLat = 0, minLon = 0, maxLat = 0, maxLon = 0, lon, lat;
for (int i = 0; i < 8; i += 2) {
dx = mPosX - coords[i + 0] / mScale;
dy = mPosY - coords[i + 1] / mScale;
lon = MercatorProjection.pixelXToLongitude(dx, z);
lat = MercatorProjection.pixelYToLatitude(dy, z);
if (i == 0) {
minLon = maxLon = lon;
minLat = maxLat = lat;
} else {
if (lat > maxLat)
maxLat = lat;
else if (lat < minLat)
minLat = lat;
if (lon > maxLon)
maxLon = lon;
else if (lon < minLon)
minLon = lon;
}
}
return new BoundingBox(minLat, minLon, maxLat, maxLon);
}
private float[] mv = { 0, 0, 0, 1 };
// private float[] mu = { 0, 0, 0, 1 };
private float[] mu = { 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 - 2f;
// // mv[2] = 1f / (z - 2f);
// mv[3] = 1;
// Matrix.multiplyMV(mu, 0, mProjMatrix, 0, mv, 0);
/* get the depth-value of the map for the current tilt, approximately.
* needed to un-project a point on screen to the position on the map. not
* so sure about this, but at least somehow works. */
private float getZ(float y) {
return FloatMath.sin((float) Math.toRadians(mTilt))
// * 2.2f // for dist = 1
* 1.3f // for dist = 2
// * 0.8f // for dist = 4
* ((float) mHeight / mWidth) * y;
}
/**
* for x,y in screen coordinates get the point on the map in map-tile
* coordinates
* @param x ...
* @param y ...
* @param reuse ...
* @return ...
*/
public synchronized Point getScreenPointOnMap(float x, float y, Point reuse) {
Point out = reuse == null ? new Point() : reuse;
float mx = ((mWidth / 2) - x) / (mWidth / 2);
float my = ((mHeight / 2) - y) / (mHeight / 2);
unproject(-mx, my, getZ(my), mu, 0);
out.x = (int) (mPosX + mu[0] / mScale);
out.y = (int) (mPosY + mu[1] / mScale);
return out;
}
/**
* get the GeoPoint for x,y in screen coordinates
* @param x screen pixel x
* @param y screen pixel y
* @return the corresponding GeoPoint
*/
public synchronized GeoPoint fromScreenPixels(float x, float y) {
float mx = ((mWidth / 2) - x) / (mWidth / 2);
float my = ((mHeight / 2) - y) / (mHeight / 2);
unproject(-mx, my, getZ(my), mu, 0);
double dx = mPosX + mu[0] / mScale;
double dy = mPosY + mu[1] / mScale;
GeoPoint p = new GeoPoint(
MercatorProjection.pixelYToLatitude(dy, mZoomLevel),
MercatorProjection.pixelXToLongitude(dx, mZoomLevel));
// Log.d(">>>", "fromScreenPixels " + p);
return p;
}
/**
* get the screen pixel for a GeoPoint
* @param geoPoint ...
* @param reuse ...
* @return ...
*/
public synchronized Point project(GeoPoint geoPoint, Point reuse) {
Point out = reuse == null ? new Point() : reuse;
double x = MercatorProjection.longitudeToPixelX(geoPoint.getLongitude(),
mZoomLevel);
double y = MercatorProjection.latitudeToPixelY(geoPoint.getLatitude(),
mZoomLevel);
mv[0] = (float) (x - mPosX) * mScale;
mv[1] = (float) (y - mPosY) * mScale;
mv[2] = 0;
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mViewMatrix, 0, mv, 0);
Matrix.multiplyMV(mv, 0, mProjMatrix, 0, mv, 0);
out.x = (int) (mv[0] / mv[3] * mWidth / 2);
out.y = (int) (mv[1] / mv[3] * mHeight / 2);
// Log.d(">>>", "project: " + out.x + " " + out.y);
return out;
}
public synchronized void getMVP(float[] matrix) {
Matrix.multiplyMM(matrix, 0, mProjMatrix, 0, mViewMatrix, 0);
}
// public static Point project(float x, float y, float[] matrix, float[] tmpVec, Point reuse) {
// Point out = reuse == null ? new Point() : reuse;
//
// tmpVec[0] = x;
// tmpVec[1] = y;
// tmpVec[2] = 0;
// tmpVec[3] = 1;
//
// Matrix.multiplyMV(tmpVec, 0, matrix, 0, tmpVec, 0);
//
// out.x = (int) (tmpVec[0] / tmpVec[3] * mWidth / 2);
// out.y = (int) (tmpVec[1] / tmpVec[3] * mHeight / 2);
//
// return out;
// }
private void unproject(float x, float y, float z, float[] coords, int position) {
mv[0] = x;
mv[1] = y;
mv[2] = z - 1f;
// mv[2] = -mu[2] / mu[3];
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
@@ -175,17 +343,13 @@ public class MapViewPosition {
if (mv[3] != 0) {
coords[position] = mv[0] / mv[3];
coords[position + 1] = mv[1] / mv[3];
// Log.d(TAG, (z * 1.4f - 1) + " " + mu[2] / mu[3] + " - " + x + ":"
// + y + " - "
// + coords[position] + ":" + coords[position + 1] + " - " + mTilt);
} else {
// else what?
Log.d(TAG, "... what?");
Log.d(TAG, "uproject failed");
}
}
private void updateMatrix() {
Matrix.setRotateM(mRotMatrix, 0, mRotation, 0, 0, 1);
// - view matrix
// 1. scale to window coordinates
// 2. rotate
@@ -195,11 +359,13 @@ public class MapViewPosition {
// 4. translate to near-plane
// 5. apply projection
Matrix.setRotateM(mRotMatrix, 0, mRotation, 0, 0, 1);
// tilt map
float tilt = mTilt;
Matrix.setRotateM(mTmpMatrix, 0, tilt, 1, 0, 0);
// apply first viewMatrix, then tilt
// apply first rotation, then tilt
Matrix.multiplyMM(mRotMatrix, 0, mTmpMatrix, 0, mRotMatrix, 0);
// scale to window coordinates
@@ -231,91 +397,7 @@ public class MapViewPosition {
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.
*/
public synchronized GeoPoint getMapCenter() {
return new GeoPoint(mLatitude, mLongitude);
}
/**
* @return an immutable MapPosition or null, if this map position is not
* valid.
* @see #isValid()
*/
public synchronized MapPosition getMapPosition() {
if (!isValid()) {
return null;
}
// Log.d("MapViewPosition", "lat: " + mLatitude + " lon: " +
// mLongitude);
return new MapPosition(mLatitude, mLongitude, mZoomLevel, mScale, mRotation);
}
/**
* @return the current zoom level of the MapView.
*/
public synchronized byte getZoomLevel() {
return mZoomLevel;
}
/**
* @return the current scale of the MapView.
*/
public synchronized float getScale() {
return mScale;
}
/**
* @return true if this MapViewPosition is valid, false otherwise.
*/
/** @return true if this MapViewPosition is valid, false otherwise. */
public synchronized boolean isValid() {
if (Double.isNaN(mLatitude)) {
return false;
@@ -336,168 +418,43 @@ public class MapViewPosition {
return true;
}
/**
* Get GeoPoint for a pixel on screen
*
* @param x
* ...
* @param y
* ...
* @return the GeoPoint
*/
public GeoPoint getOffsetPoint(float x, float y) {
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
double dx = ((mMapView.getWidth() >> 1) - x) / mScale;
double dy = ((mMapView.getHeight() >> 1) - y) / mScale;
if (mMapView.enableRotation || mMapView.enableCompass) {
double rad = Math.toRadians(mRotation);
double xx = dx * Math.cos(rad) + dy * -Math.sin(rad);
double yy = dx * Math.sin(rad) + dy * Math.cos(rad);
dx = pixelX - xx;
dy = pixelY - yy;
} else {
dx = pixelX - dx;
dy = pixelY - dy;
}
double latitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
latitude = MercatorProjection.limitLatitude(latitude);
double longitude = MercatorProjection.pixelXToLongitude(dx, mZoomLevel);
longitude = MercatorProjection.limitLongitude(longitude);
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.
*
* @param mx
* the amount of pixels to move the map horizontally.
* @param my
* the amount of pixels to move the map vertically.
* @param mx the amount of pixels to move the map horizontally.
* @param my the amount of pixels to move the map vertically.
*/
public synchronized void moveMap(float mx, float my) {
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
double pixelY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
double dx = mx / mScale;
double dy = my / mScale;
if (mMapView.enableRotation || mMapView.enableCompass) {
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);
double rcos = Math.cos(rad);
double rsin = Math.sin(rad);
double x = dx * rcos + dy * rsin;
double y = dx * -rsin + dy * rcos;
dx = x;
dy = y;
}
dx = pixelX - dx;
dy = pixelY - dy;
dx = mPosX - dx;
dy = mPosY - dy;
mLatitude = MercatorProjection.pixelYToLatitude(dy, mZoomLevel);
mLatitude = MercatorProjection.limitLatitude(mLatitude);
mLongitude = MercatorProjection.pixelXToLongitude(dx, mZoomLevel);
mLongitude = MercatorProjection.wrapLongitude(mLongitude);
// mLongitude = MercatorProjection.limitLongitude(mLongitude);
// getViewBox(null);
updatePosition();
}
public synchronized void rotateMap(float angle, float cx, float cy) {
moveMap(cx, cy);
// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation -
// angle));
mRotation += angle;
updateMatrix();
}
public void setRotation(float f) {
mRotation = f;
updateMatrix();
}
public boolean tilt(float move) {
float tilt = mTilt + move;
if (tilt > MAX_ANGLE)
tilt = MAX_ANGLE;
else if (tilt < 0)
tilt = 0;
if (mTilt == tilt)
return false;
setTilt(tilt);
// mTilt = tilt;
// updateMatrix();
return true;
}
public void setTilt(float f) {
mTilt = f;
// float sw = VIEW_SCALE;
// float sh = VIEW_SCALE;
// sh += (mTilt / 250);
// Matrix.frustumM(mProjMatrix, 0, -sw * mWidth, sw * mWidth,
// sh * mHeight, -sh * mHeight, 1, 2);
//
// Matrix.translateM(mProjMatrix, 0, 0, 0, -VIEW_DISTANCE);
//
// Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
// Matrix.invertM(mUnprojMatrix, 0, mProjMatrix, 0);
updateMatrix();
}
synchronized void setMapCenter(GeoPoint geoPoint) {
mLatitude = MercatorProjection.limitLatitude(geoPoint.getLatitude());
mLongitude = MercatorProjection.limitLongitude(geoPoint.getLongitude());
}
synchronized void setMapCenter(MapPosition mapPosition) {
mLatitude = MercatorProjection.limitLatitude(mapPosition.lat);
mLongitude = MercatorProjection.limitLongitude(mapPosition.lon);
mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel);
mMapScale = 1 << mZoomLevel;
}
synchronized void setZoomLevel(byte zoomLevel) {
mZoomLevel = mMapView.limitZoomLevel(zoomLevel);
mMapScale = 1 << mZoomLevel;
}
synchronized void setScale(float scale) {
mScale = scale;
}
// synchronized void zoomBoundingBox(GeoPoint p1, GeoPoint p2) {
//
// }
/**
* @param scale
* ...
* @param pivotX
* ...
* @param pivotY
* ...
* -
* @param scale ...
* @param pivotX ...
* @param pivotY ...
* @return true if scale was changed
*/
public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
@@ -512,13 +469,15 @@ public class MapViewPosition {
if (z > MAX_ZOOMLEVEL) {
// z17 shows everything, just increase scaling
// need to fix this for ScanBox
if (mScale * scale > 2) // 8)
if (mScale * scale > 4)
return false;
mScale *= scale;
mMapScale = newScale;
} else {
mZoomLevel = (byte) z;
updatePosition();
mScale = newScale / (1 << z);
mMapScale = newScale;
}
@@ -530,4 +489,182 @@ public class MapViewPosition {
return true;
}
/**
* rotate map around pivot cx,cy
* @param angle ...
* @param cx ...
* @param cy ...
*/
public synchronized void rotateMap(float angle, float cx, float cy) {
moveMap(cx, cy);
mRotation += angle;
updateMatrix();
}
public synchronized void setRotation(float f) {
mRotation = f;
updateMatrix();
}
public synchronized boolean tilt(float move) {
float tilt = mTilt + move;
if (tilt > MAX_ANGLE)
tilt = MAX_ANGLE;
else if (tilt < 0)
tilt = 0;
if (mTilt == tilt)
return false;
setTilt(tilt);
return true;
}
public synchronized void setTilt(float f) {
mTilt = f;
updateMatrix();
}
private void setMapCenter(double latitude, double longitude) {
mLatitude = MercatorProjection.limitLatitude(latitude);
mLongitude = MercatorProjection.limitLongitude(longitude);
updatePosition();
}
synchronized void setMapCenter(GeoPoint geoPoint) {
setMapCenter(geoPoint.getLatitude(), geoPoint.getLongitude());
}
synchronized void setMapCenter(MapPosition mapPosition) {
mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel);
mMapScale = 1 << mZoomLevel;
setMapCenter(mapPosition.lat, mapPosition.lon);
}
synchronized void setZoomLevel(byte zoomLevel) {
mZoomLevel = mMapView.limitZoomLevel(zoomLevel);
mMapScale = 1 << mZoomLevel;
updatePosition();
}
synchronized void setScale(float scale) {
mScale = scale;
}
private void updatePosition() {
mPosX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
mPosY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
}
private double mStartX;
private double mStartY;
private double mEndX;
private double mEndY;
private float mDuration = 500;
private Point mTmpPoint;
public synchronized void animateTo(GeoPoint geoPoint) {
MercatorProjection.projectPoint(geoPoint, mZoomLevel, mTmpPoint);
mEndX = MercatorProjection.longitudeToPixelX(geoPoint.getLongitude(), mZoomLevel);
mEndY = MercatorProjection.latitudeToPixelY(geoPoint.getLatitude(), mZoomLevel);
mStartX = mPosX;
mStartY = mPosY;
mDuration = 300;
mHandler.start((int) mDuration);
}
synchronized void setMapPosition(double x, double y) {
mLatitude = MercatorProjection.pixelYToLatitude(y, mZoomLevel);
mLatitude = MercatorProjection.limitLatitude(mLatitude);
mLongitude = MercatorProjection.pixelXToLongitude(x, mZoomLevel);
mLongitude = MercatorProjection.wrapLongitude(mLongitude);
updatePosition();
}
void onTick(long millisLeft) {
double adv = millisLeft / mDuration;
double mx = (mStartX + (mEndX - mStartX) * (1.0 - adv));
double my = (mStartY + (mEndY - mStartY) * (1.0 - adv));
setMapPosition(mx, my);
mMapView.redrawMap();
}
void onFinish() {
setMapPosition(mEndX, mEndY);
mMapView.redrawMap();
}
static class AnimationHandler extends Handler {
private final WeakReference<MapViewPosition> mMapViewPosition;
private static final int MSG = 1;
long mMillisInFuture;
long mInterval = 16;
long mStopTimeInFuture;
AnimationHandler(MapViewPosition mapAnimator) {
mMapViewPosition = new WeakReference<MapViewPosition>(mapAnimator);
}
public synchronized final void start(int millis) {
mMillisInFuture = millis;
MapViewPosition animator = mMapViewPosition.get();
if (animator == null)
return;
if (mMillisInFuture <= 0) {
animator.onFinish();
return;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
removeMessages(MSG);
sendMessage(obtainMessage(MSG));
}
public final void cancel() {
removeMessages(MSG);
}
@Override
public void handleMessage(Message msg) {
MapViewPosition animator = mMapViewPosition.get();
if (animator == null)
return;
final long millisLeft = mStopTimeInFuture
- SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
animator.onFinish();
} else if (millisLeft < mInterval) {
// no tick, just delay until done
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
animator.onTick(millisLeft);
// take into account user's onTick taking time to
// execute
long delay = lastTickStart + mInterval
- SystemClock.elapsedRealtime();
// special case: user's onTick took more than interval
// to
// complete, skip to next interval
while (delay < 0)
delay += mInterval;
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
}

View File

@@ -1,19 +0,0 @@
/*
* 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.oscim.view;
public class OverlayManager {
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* 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

View File

@@ -1,5 +1,6 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* 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
@@ -12,55 +13,52 @@
* 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.Tile;
import org.oscim.overlay.OverlayManager;
import android.content.Context;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewConfiguration;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
/**
* Implementation for multi-touch capable devices.
*/
// TODO:
// - write a AnimationTimer instead of using CountDownTimers
// - fix recognition of tilt/rotate/scale state...
final class TouchHandler
extends SimpleOnGestureListener
implements ScaleGestureDetector.OnScaleGestureListener {
final class TouchHandler implements OnGestureListener, OnScaleGestureListener, OnDoubleTapListener {
private static final float SCALE_DURATION = 450;
private static final String TAG = TouchHandler.class.getSimpleName();
private static final float SCALE_DURATION = 500;
private static final float ROTATION_DELAY = 200; // ms
private static final int INVALID_POINTER_ID = -1;
private final MapView mMapView;
private final MapViewPosition mMapPosition;
private final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
private final OverlayManager mOverlayManager;
private final DecelerateInterpolator mInterpolator;
private final DecelerateInterpolator mLinearInterpolator;
private boolean mBeginScale;
private float mSumScale;
private final float mMapMoveDelta;
private boolean mMoveStart;
private boolean mBeginRotate;
private boolean mBeginTilt;
private boolean mLongPress;
// private long mLongPressTime;
private float mPosX;
// private float mPosX;
private float mPosY;
private double mAngle;
@@ -76,16 +74,20 @@ final class TouchHandler
* the MapView
*/
public TouchHandler(Context context, MapView mapView) {
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mMapView = mapView;
mMapPosition = mapView.getMapPosition();
mMapMoveDelta = viewConfiguration.getScaledTouchSlop();
mOverlayManager = mapView.getOverlayManager();
// ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
// mMapMoveDelta = viewConfiguration.getScaledTouchSlop();
mActivePointerId = INVALID_POINTER_ID;
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mGestureDetector = new GestureDetector(context, this);
mGestureDetector.setOnDoubleTapListener(this);
mScroller = new Scroller(mMapView.getContext(),
new android.view.animation.LinearInterpolator());
mInterpolator = new DecelerateInterpolator(1.5f);
mScroller = new Scroller(mMapView.getContext(), mInterpolator);
mLinearInterpolator = new DecelerateInterpolator(0.8f);//new android.view.animation.LinearInterpolator();
}
/**
@@ -95,16 +97,8 @@ final class TouchHandler
*/
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) {
mGestureDetector.onTouchEvent(event);
mScaleGestureDetector.onTouchEvent(event);
// }
if (!mScaling)
mGestureDetector.onTouchEvent(event);
int action = getAction(event);
boolean ret = false;
@@ -136,10 +130,10 @@ final class TouchHandler
}
private boolean onActionDown(MotionEvent event) {
mPosX = event.getX();
// mPosX = event.getX();
mPosY = event.getY();
mMoveStart = false;
// mMoveStart = false;
mBeginRotate = false;
mBeginTilt = false;
// save the ID of the pointer
@@ -154,43 +148,19 @@ final class TouchHandler
private boolean onActionMove(MotionEvent event) {
int id = event.findPointerIndex(mActivePointerId);
// calculate the distance between previous and current position
float moveX = event.getX(id) - mPosX;
float moveY = event.getY(id) - mPosY;
// save the position of the event
// Log.d("...", "mx " + moveX + " my " + moveY);
boolean scaling = mScaleGestureDetector.isInProgress();
if (!mScaling)
mScaling = scaling;
if (!scaling && !mMoveStart) {
if (Math.abs(moveX) > mMapMoveDelta || Math.abs(moveY) > mMapMoveDelta) {
// the map movement threshold has been reached
// longPressDetector.pressStop();
mMoveStart = true;
}
return true;
}
mPosX = event.getX(id);
mPosY = event.getY(id);
float py = event.getY(id);
float moveY = py - mPosY;
mPosY = py;
// double-tap + hold
if (mLongPress) {
mMapPosition.scaleMap(1 - moveY / 100, 0, 0);
mMapView.redrawMap();
return true;
}
if (multi == 0) {
mMapPosition.moveMap(moveX, moveY);
mMapView.redrawMap();
if (multi == 0)
return true;
}
if (event.getEventTime() - mMultiTouchDownTime < ROTATION_DELAY)
return true;
@@ -206,18 +176,22 @@ final class TouchHandler
double rad = Math.atan2(dy, dx);
double r = rad - mAngle;
if (!mBeginRotate) {
if (!mBeginRotate && !mBeginScale) {
/* our naive gesture detector for rotation and tilt.. */
if (Math.abs(rad) < 0.25 || Math.abs(rad) > Math.PI - 0.25) {
mBeginTilt = true;
if (mMapPosition.tilt(moveY / 4)) {
mMapView.redrawMap();
}
return true;
}
if (!mBeginScale && !mBeginTilt) {
if (!mBeginTilt) {
if (Math.abs(r) > 0.05) {
Log.d("...", "begin rotate");
// Log.d(TAG, "begin rotate");
mAngle = rad;
mBeginRotate = true;
}
}
@@ -246,7 +220,7 @@ final class TouchHandler
private long mMultiTouchDownTime;
private boolean onActionPointerDown(MotionEvent event) {
// longPressDetector.pressStop();
mMultiTouchDownTime = event.getEventTime();
multi++;
@@ -256,7 +230,7 @@ final class TouchHandler
double dy = event.getY(0) - event.getY(1);
mAngle = Math.atan2(dy, dx);
}
Log.d("...", "multi down " + multi);
// Log.d("...", "multi down " + multi);
return true;
}
@@ -274,14 +248,14 @@ final class TouchHandler
pointerIndex = 0;
}
// save the position of the event
mPosX = motionEvent.getX(pointerIndex);
// mPosX = motionEvent.getX(pointerIndex);
mPosY = motionEvent.getY(pointerIndex);
mActivePointerId = motionEvent.getPointerId(pointerIndex);
}
multi--;
mLongPress = false;
Log.d("...", "multi up " + multi);
// Log.d("...", "multi up " + multi);
return true;
}
@@ -294,38 +268,32 @@ final class TouchHandler
private boolean onActionUp(MotionEvent motionEvent) {
mActivePointerId = INVALID_POINTER_ID;
mScaling = false;
multi = 0;
// if (mLongPress && SystemClock.uptimeMillis() - mLongPressTime < 150)
// {
// mScrollX = (mPosX - (mMapView.getWidth() >> 1)) * 2f;
// mScrollY = (mPosY - (mMapView.getHeight() >> 1)) * 2f;
// mPrevScale = 0;
//
// mTimer = new CountDownTimer((int) SCALE_DURATION, 30) {
// @Override
// public void onTick(long tick) {
// scale2(tick);
// }
//
// @Override
// public void onFinish() {
// scale2(0);
// }
// }.start();
// }
mLongPress = false;
multi = 0;
return true;
}
/******************* SimpleOnGestureListener *******************/
/******************* GestureListener *******************/
private Scroller mScroller;
private float mScrollX, mScrollY;
private boolean fling = false;
@Override
public void onShowPress(MotionEvent e) {
Log.d(TAG, "show press");
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.d(TAG, "single tap up");
return mOverlayManager.onSingleTapUp(e, mMapView);
}
@Override
public boolean onDown(MotionEvent e) {
if (fling) {
@@ -338,6 +306,8 @@ final class TouchHandler
fling = false;
}
// Log.d(TAG, "tap");
return true;
}
@@ -359,9 +329,32 @@ final class TouchHandler
return true;
}
@Override
public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
final float distanceY) {
if (mOverlayManager.onScroll(e1, e2, distanceX, distanceY, mMapView)) {
return true;
}
if (mScaling)
return true;
if (multi == 0) {
mMapPosition.moveMap(-distanceX, -distanceY);
mMapView.redrawMap();
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (mScaling)
return true;
int w = Tile.TILE_SIZE * 20;
int h = Tile.TILE_SIZE * 20;
mScrollX = 0;
@@ -376,7 +369,7 @@ final class TouchHandler
-w, w, -h, h);
// animate for two seconds
mTimer = new CountDownTimer(1500, 50) {
mTimer = new CountDownTimer(1500, 16) {
@Override
public void onTick(long tick) {
scroll();
@@ -384,20 +377,26 @@ final class TouchHandler
@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);
if (mLongPress)
return;
if (mOverlayManager.onLongPress(e, mMapView)) {
return;
}
mLongPress = true;
// if (MapView.testRegionZoom) {
// Log.d("mapsforge", "long press");
// mMapView.mRegionLookup.updateRegion(-1, null);
// }
}
boolean scale2(long tick) {
@@ -422,36 +421,30 @@ final class TouchHandler
return true;
}
/******************* DoubleTapListener ****************/
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// Log.d(TAG, "single tap confirmed");
return mOverlayManager.onSingleTapConfirmed(e, mMapView);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (MapView.testRegionZoom) {
mMapView.mRegionLookup.updateRegion(1,
mMapPosition.getOffsetPoint(mPosX, mPosY));
} else {
mLongPress = true;
Log.d(TAG, "double tap");
// mLongPressTime = SystemClock.uptimeMillis();
// 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) {
// scale2(tick);
// }
//
// @Override
// public void onFinish() {
// scale(0);
// }
// }.start();
}
return true;
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
mLongPress = true;
Log.d(TAG, "double tap event");
// TODO Auto-generated method stub
return false;
}
/******************* ScaleListener *******************/
private float mCenterX;
private float mCenterY;
private float mFocusX;
@@ -475,7 +468,7 @@ final class TouchHandler
if (!mBeginScale) {
if (mSumScale > 1.1 || mSumScale < 0.9) {
Log.d("...", "begin scale " + mSumScale);
// Log.d("...", "begin scale " + mSumScale);
mBeginScale = true;
// scale = mSumScale;
}
@@ -489,9 +482,11 @@ final class TouchHandler
@Override
public boolean onScaleBegin(ScaleGestureDetector gd) {
mScaling = true;
mBeginScale = false;
mTimeEnd = mTimeStart = SystemClock.elapsedRealtime();
mSumScale = 1;
mBeginScale = false;
mCenterX = mMapView.getWidth() >> 1;
mCenterY = mMapView.getHeight() >> 1;
@@ -514,19 +509,21 @@ final class TouchHandler
mZooutOut = mSumScale < 0.99;
mTimer = new CountDownTimer((int) SCALE_DURATION, 15) {
mTimer = new CountDownTimer((int) SCALE_DURATION, 32) {
@Override
public void onTick(long tick) {
scale(tick);
scaleAnim(tick);
}
@Override
public void onFinish() {
scale(0);
scaleAnim(0);
}
}.start();
} else {
mScaling = false;
}
mBeginScale = false;
}
@@ -534,7 +531,7 @@ final class TouchHandler
private CountDownTimer mTimer;
boolean mZooutOut;
boolean scale(long tick) {
boolean scaleAnim(long tick) {
if (mPrevScale >= 1) {
mTimer = null;
@@ -542,7 +539,8 @@ final class TouchHandler
}
float adv = (SCALE_DURATION - tick) / SCALE_DURATION;
adv = mInterpolator.getInterpolation(adv);
// adv = mInterpolator.getInterpolation(adv);
adv = mLinearInterpolator.getInterpolation(adv);
float scale = adv - mPrevScale;
mPrevScale += scale;
@@ -560,120 +558,4 @@ final class TouchHandler
return true;
}
/*
* from CountDownTimer.java: Copyright (C) 2008 The Android Open Source
* Project Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
* law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
final static class Timer {
/**
* Millis since epoch when alarm should stop.
*/
private final long mMillisInFuture;
/**
* The interval in millis that the user receives callbacks
*/
final long mCountdownInterval;
long mStopTimeInFuture;
/**
* @param millisInFuture
* The number of millis in the future from the call to
* {@link #start()} until the countdown is done and
* {@link #onFinish()} is called.
* @param countDownInterval
* The interval along the way to receive
* {@link #onTick(long)} callbacks.
*/
public Timer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
/**
* Cancel the countdown.
*/
public final void cancel() {
mHandler.removeMessages(MSG);
}
/**
* Start the countdown.
*
* @return ...
*/
public synchronized final Timer start() {
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
/**
* Callback fired on regular interval.
*
* @param millisUntilFinished
* The amount of time until finished.
*/
public void onTick(long millisUntilFinished) {
}
/**
* Callback fired when the time is up.
*/
public void onFinish() {
}
private static final int MSG = 1;
// handles counting down
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (Timer.this) {
final long millisLeft = mStopTimeInFuture
- SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
onFinish();
} else if (millisLeft < mCountdownInterval) {
// no tick, just delay until done
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
// take into account user's onTick taking time to
// execute
long delay = lastTickStart + mCountdownInterval
- SystemClock.elapsedRealtime();
// special case: user's onTick took more than interval
// to
// complete, skip to next interval
while (delay < 0)
delay += mCountdownInterval;
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
}
}