avoid zoom-level relative calculation

This commit is contained in:
Hannes Janetzek 2013-03-12 16:07:19 +01:00
parent c14d101aef
commit 5230aee091
10 changed files with 906 additions and 853 deletions

View File

@ -16,6 +16,7 @@
*/
package org.oscim.core;
import android.os.Parcel;
import android.os.Parcelable;
@ -74,6 +75,11 @@ public class GeoPoint implements Parcelable, Comparable<GeoPoint> {
this(latitudeE6 / CONVERSION_FACTOR, longitudeE6 / CONVERSION_FACTOR);
}
public void project(Point2D out) {
out.x = MercatorProjection.longitudeToX(this.longitudeE6 / CONVERSION_FACTOR);
out.y = MercatorProjection.latitudeToY(this.latitudeE6 / CONVERSION_FACTOR);
}
@Override
public int compareTo(GeoPoint geoPoint) {
if (this.longitudeE6 > geoPoint.longitudeE6) {

View File

@ -27,6 +27,7 @@ public class MapPosition {
public float angle;
public float tilt;
// map center in tile coordinates of current zoom-level
public double x;
public double y;
@ -40,21 +41,6 @@ public class MapPosition {
this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
}
// public Point geopointToMap(GeoPoint in, Point reuse) {
// Point out = reuse == null ? new Point() : reuse;
// out.x = (int) (MercatorProjection.longitudeToPixelX(in.getLongitude(), zoomLevel) - x);
// out.y = (int) (MercatorProjection.latitudeToPixelY(in.getLatitude(), zoomLevel) - y);
//
// return out;
// }
// public void geopointToMap(GeoPoint in, float[] out, int pos) {
// out[pos * 2 + 0] =
// (float) (MercatorProjection.longitudeToPixelX(in.getLongitude(), zoomLevel) - x);
// out[pos * 2 + 1] =
// (float) (MercatorProjection.latitudeToPixelY(in.getLatitude(), zoomLevel) - y);
// }
/**
* @param geoPoint
* the map position.

View File

@ -15,7 +15,6 @@
*/
package org.oscim.core;
import android.graphics.Point;
/**
* An implementation of the spherical Mercator projection.
@ -197,6 +196,13 @@ public final class MercatorProjection {
return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5);
}
public static double toLongitude(double pixelX) {
return 360 * (pixelX - 0.5);
}
public static double toLongitude(double pixelX, double scale) {
return 360 * ((pixelX / scale) - 0.5);
}
/**
* Converts a pixel X coordinate to the tile X number.
*
@ -226,6 +232,15 @@ public final class MercatorProjection {
return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
}
public static double toLatitude(double pixelY) {
double y = 0.5 - pixelY;
return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
}
public static double toLatitude(double pixelY, double scale) {
double y = 0.5 - pixelY / scale;
return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
}
/**
* Converts a pixel Y coordinate to the tile Y number.
*
@ -272,12 +287,14 @@ public final class MercatorProjection {
throw new IllegalStateException();
}
public static Point projectPoint(GeoPoint geopoint, byte z, Point reuse) {
Point out = reuse == null ? new Point() : reuse;
// public static Point projectPoint(GeoPoint geopoint, byte z, Point reuse) {
// Point out = reuse == null ? new Point() : reuse;
//
// out.x = (int) MercatorProjection.longitudeToPixelX(geopoint.getLongitude(), z);
// out.y = (int) MercatorProjection.latitudeToPixelY(geopoint.getLatitude(), z);
//
// return out;
// }
out.x = (int) MercatorProjection.longitudeToPixelX(geopoint.getLongitude(), z);
out.y = (int) MercatorProjection.latitudeToPixelY(geopoint.getLatitude(), z);
return out;
}
}

View File

@ -18,7 +18,6 @@ package org.oscim.overlay;
import java.util.List;
import org.oscim.app.R;
import org.oscim.core.MercatorProjection;
import org.oscim.view.MapView;
import org.oscim.view.MapViewPosition;
@ -34,7 +33,6 @@ public class ItemizedIconOverlay<Item extends OverlayItem> extends ItemizedOverl
protected final List<Item> mItemList;
protected OnItemGestureListener<Item> mOnItemGestureListener;
private int mDrawnItemsLimit = Integer.MAX_VALUE;
private final Point mTouchScreenPoint = new Point();
private final Point mItemPoint = new Point();
@ -181,32 +179,29 @@ public class ItemizedIconOverlay<Item extends OverlayItem> extends ItemizedOverl
* ..
* @return true if event is handled false otherwise
*/
private boolean activateSelectedItems(final MotionEvent event,
final ActiveItem task) {
final int eventX = (int) event.getX();
final int eventY = (int) event.getY();
private boolean activateSelectedItems(MotionEvent event, ActiveItem task) {
int eventX = (int) event.getX() - mMapView.getWidth()/2;
int eventY = (int) event.getY() - mMapView.getHeight()/2;
MapViewPosition mapViewPosition = mMapView.getMapViewPosition();
byte z = mapViewPosition.getMapPosition().zoomLevel;
mapViewPosition.getScreenPointOnMap(eventX, eventY, mTouchScreenPoint);
int nearest = -1;
double dist = Double.MAX_VALUE;
// TODO use intermediate projection and bounding box test
for (int i = 0; i < this.mItemList.size(); ++i) {
final Item item = getItem(i);
for (int i = 0; i < this.mItemList.size(); i++) {
Item item = getItem(i);
// final Drawable marker = (item.getMarker(0) == null) ? this.mDefaultMarker : item
// .getMarker(0);
MercatorProjection.projectPoint(item.getPoint(), z, mItemPoint);
float dx = mItemPoint.x - mTouchScreenPoint.x;
float dy = mItemPoint.y - mTouchScreenPoint.y;
double d = Math.sqrt(dx * dx + dy * dy);
mapViewPosition.project(item.getPoint(), mItemPoint);
if (d < 50) {
int dx = mItemPoint.x - eventX;
int dy = mItemPoint.y - eventY;
double d = dx * dx + dy * dy;
// squared dist: 50*50 pixel
if (d < 2500) {
if (d < dist) {
dist = d;
nearest = i;

View File

@ -180,12 +180,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapViewPosition = mapView.getMapViewPosition();
mMapPosition = new MapPosition();
//Matrix.setIdentityM(mMVPMatrix, 0);
mMatrices = new Matrices();
// add half pixel to tile clip/fill coordinates to avoid rounding issues
short min = -4;
short max = (short) ((Tile.TILE_SIZE << 3) + 4);
short min = 0;
short max = (short) ((Tile.TILE_SIZE * COORD_SCALE));
mFillCoords = new short[8];
mFillCoords[0] = min;
mFillCoords[1] = max;
@ -329,7 +327,40 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static Object tilelock = new Object();
static void draw() {
private static void updateTileVisibility() {
float[] coords = mTileCoords;
MapPosition pos = mMapPosition;
MapTile[] tiles = mDrawTiles.tiles;
// lock tiles while updating isVisible state
synchronized (GLRenderer.tilelock) {
for (int i = 0; i < mDrawTiles.cnt; i++)
tiles[i].isVisible = false;
// relative zoom-level, 'tiles' could not have been updated after
// zoom-level changed.
byte z = tiles[0].zoomLevel;
float div = FastMath.pow(z - pos.zoomLevel);
// transform screen coordinates to tile coordinates
float scale = pos.scale / div;
float px = (float) pos.x * div;
float py = (float) pos.y * div;
for (int i = 0; i < 8; i += 2) {
coords[i + 0] = (px + coords[i + 0] / scale) / Tile.TILE_SIZE;
coords[i + 1] = (py + coords[i + 1] / scale) / Tile.TILE_SIZE;
}
// count placeholder tiles
mHolderCount = 0;
// check visibile tiles
mScanBox.scan(coords, z);
}
}
private static void draw() {
long start = 0;
if (MapView.debugFrameTime)
@ -374,46 +405,25 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// get current MapPosition, set mTileCoords (mapping of screen to model
// coordinates)
MapPosition pos = mMapPosition;
float[] coords = mTileCoords;
boolean changed;
boolean positionChanged;
synchronized (mMapViewPosition) {
changed = mMapViewPosition.getMapPosition(pos);
mMapViewPosition.getMapViewProjection(coords);
mMapViewPosition.updateAnimation();
positionChanged = mMapViewPosition.getMapPosition(pos);
if (positionChanged)
mMapViewPosition.getMapViewProjection(mTileCoords);
mMapViewPosition.getMatrix(mMatrices.view, null, mMatrices.viewproj);
}
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
if (changed) {
// lock tiles while updating isVisible state
synchronized (GLRenderer.tilelock) {
for (int i = 0; i < tileCnt; i++)
tiles[i].isVisible = false;
// relative zoom-level, 'tiles' could not have been updated after
// zoom-level changed.
byte z = tiles[0].zoomLevel;
float div = FastMath.pow(z - pos.zoomLevel);
// transform screen coordinates to tile coordinates
float scale = pos.scale / div;
float px = (float) pos.x * div;
float py = (float) pos.y * div;
for (int i = 0; i < 8; i += 2) {
coords[i + 0] = (px + coords[i + 0] / scale) / Tile.TILE_SIZE;
coords[i + 1] = (py + coords[i + 1] / scale) / Tile.TILE_SIZE;
}
// count placeholder tiles
mHolderCount = 0;
// check visibile tiles
mScanBox.scan(coords, z);
}
}
if (positionChanged)
updateTileVisibility();
tileCnt += mHolderCount;
@ -466,7 +476,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
List<RenderOverlay> overlays = mMapView.getOverlayManager().getRenderLayers();
for (int i = 0, n = overlays.size(); i < n; i++)
overlays.get(i).update(mMapPosition, changed, tilesChanged);
overlays.get(i).update(mMapPosition, positionChanged, tilesChanged);
/* draw base layer */
BaseMap.draw(tiles, tileCnt, pos, mMatrices);

View File

@ -14,6 +14,8 @@
*/
package org.oscim.utils;
import org.oscim.core.Point2D;
import android.graphics.Point;
/**
@ -169,18 +171,13 @@ public final class GeometryUtils {
return Math.abs((P.x - A.x) * (B.y - A.y) - (P.y - A.y) * (B.x - A.x)) / normalLength;
}
public static final class Point2D {
public double x;
public double y;
}
// from libosmscout-render
public static byte calcLinesIntersect(
double ax1, double ay1,
double ax2, double ay2,
double bx1, double by1,
double bx2, double by2,
GeometryUtils.Point2D point)
Point2D point)
{
double ua_numr = (bx2 - bx1) * (ay1 - by1) - (by2 - by1) * (ax1 - bx1);
double ub_numr = (ax2 - ax1) * (ay1 - by1) - (ay2 - ay1) * (ax1 - bx1);

View File

@ -78,7 +78,7 @@ public class MapView extends RelativeLayout {
private final MapViewPosition mMapViewPosition;
private final MapPosition mMapPosition;
private final MapZoomControls mMapZoomControls;
//private final MapZoomControls mMapZoomControls;
private final TouchHandler mTouchEventHandler;
private final Compass mCompass;
@ -86,7 +86,7 @@ public class MapView extends RelativeLayout {
private final TileManager mTileManager;
private final OverlayManager mOverlayManager;
private final GLView mGLView;
final GLView mGLView;
private final JobQueue mJobQueue;
// TODO use 1 download and 1 generator thread instead
@ -161,7 +161,6 @@ public class MapView extends RelativeLayout {
mTileManager = new TileManager(this);
mGLView = new GLView(context, this);
mMapWorkers = new MapWorker[mNumMapWorkers];
mDebugSettings = new DebugSettings();
@ -186,8 +185,8 @@ public class MapView extends RelativeLayout {
addView(mGLView, params);
mMapZoomControls = new MapZoomControls(mapActivity, this);
mMapZoomControls.setShowMapZoomControls(true);
//mMapZoomControls = new MapZoomControls(mapActivity, this);
//mMapZoomControls.setShowMapZoomControls(true);
mRotationEnabled = true;
//mOverlayManager.add(new GenericOverlay(this, new GridOverlay(this)));
@ -277,8 +276,6 @@ public class MapView extends RelativeLayout {
return mRotationEnabled;
}
/**
* Calculates all necessary tiles and adds jobs accordingly.
*
@ -303,8 +300,6 @@ public class MapView extends RelativeLayout {
boolean changed = mMapViewPosition.getMapPosition(mMapPosition);
//Log.d(TAG, "redraw " + changed + " " + forceRedraw);
// required when not changed?
if (AndroidUtils.currentThreadIsUiThread())
mOverlayManager.onUpdate(mMapPosition, changed);
@ -505,7 +500,6 @@ public class MapView extends RelativeLayout {
return false;
}
void destroy() {
for (MapWorker mapWorker : mMapWorkers) {
mapWorker.pause();
@ -580,14 +574,6 @@ public class MapView extends RelativeLayout {
return true;
}
// byte limitZoomLevel(byte zoom) {
// if (mMapZoomControls == null)
// return zoom;
//
// return (byte) Math.max(Math.min(zoom, getMaximumPossibleZoomLevel()),
// mMapZoomControls.getZoomLevelMin());
// }
/**
* Sets the center and zoom level of this MapView and triggers a redraw.
*
@ -598,6 +584,7 @@ public class MapView extends RelativeLayout {
Log.d(TAG, "setMapCenter "
+ " lat: " + mapPosition.lat
+ " lon: " + mapPosition.lon);
mMapViewPosition.setMapCenter(mapPosition);
redrawMap(true);
}
@ -609,10 +596,9 @@ public class MapView extends RelativeLayout {
* the new center point of the map.
*/
public void setCenter(GeoPoint geoPoint) {
MapPosition mapPosition = new MapPosition(geoPoint,
mMapViewPosition.getZoomLevel(), 1);
setMapCenter(mapPosition);
mMapViewPosition.setMapCenter(geoPoint);
redrawMap(true);
}
/**
@ -687,27 +673,4 @@ public class MapView extends RelativeLayout {
public GeoPoint getCenter() {
return new GeoPoint(mMapPosition.lat, mMapPosition.lon);
}
// /**
// * Sets the visibility of the zoom controls.
// *
// * @param showZoomControls
// * true if the zoom controls should be visible, false otherwise.
// */
// public void setBuiltInZoomControls(boolean showZoomControls) {
// mMapZoomControls.setShowMapZoomControls(showZoomControls);
//
// }
// /**
// * Sets the text scale for the map rendering. Has no effect in downloading
// mode.
// *
// * @param textScale
// * the new text scale for the map rendering.
// */
// public void setTextScale(float textScale) {
// mJobParameters = new JobParameters(mJobParameters.theme, textScale);
// clearAndRedrawMapView();
// }
}

View File

@ -21,9 +21,9 @@ import org.oscim.core.BoundingBox;
import org.oscim.core.GeoPoint;
import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Point2D;
import org.oscim.core.Tile;
import org.oscim.utils.FastMath;
import org.oscim.utils.GeometryUtils.Point2D;
import org.oscim.utils.GlUtils;
import android.graphics.Point;
@ -32,6 +32,7 @@ import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Scroller;
/**
* A MapPosition stores the latitude and longitude coordinate of a MapView
@ -39,11 +40,13 @@ import android.util.Log;
*/
public class MapViewPosition {
//private static final String TAG = MapViewPosition.class.getName();
private static final String TAG = MapViewPosition.class.getName();
public final static int MAX_ZOOMLEVEL = 17;
public final static int MIN_ZOOMLEVEL = 2;
public final static int MAX_END_SCALE = 8;
public final static double MAX_SCALE = ((1 << MAX_ZOOMLEVEL) * MAX_END_SCALE);
public final static double MIN_SCALE = (1 << MIN_ZOOMLEVEL);
private final static float MAX_ANGLE = 65;
@ -51,31 +54,39 @@ public class MapViewPosition {
private double mLatitude;
private double mLongitude;
private byte mZoomLevel;
// 1.0 - 2.0 scale per level
private float mScale;
// 2^mZoomLevel * mScale;
private float mMapScale;
private double mMapScale;
// mMapScale * Tile.TILE_SIZE
// i.e. size of tile 0/0/0 at current scale in pixel
private double mTileScale;
private float mRotation;
public float mTilt;
// private static final int REF_ZOOM = 20;
private double mPosX;
private double mPosY;
// map center in tile coordinates of current zoom-level
//private double mPosX;
//private double mPosY;
// NB: mMapScale == 2^mZoomLevel * mScale;
private byte mZoomLevel;
// 1.0 - 2.0 scale per level
private float mScale;
private final AnimationHandler mHandler;
private final Scroller mScroller;
MapViewPosition(MapView mapView) {
mMapView = mapView;
mLatitude = Double.NaN;
mLongitude = Double.NaN;
mZoomLevel = -1;
mScale = 1;
mRotation = 0.0f;
mTilt = 0;
mMapScale = 1;
mHandler = new AnimationHandler(this);
mScroller = new Scroller(mapView.getContext());
}
private final float[] mProjMatrix = new float[16];
@ -88,8 +99,8 @@ public class MapViewPosition {
// temporary vars: only use in synchronized functions!
private final Point2D mMovePoint = new Point2D();
private final float[] mv = { 0, 0, 0, 1 };
private final float[] mu = { 0, 0, 0, 1 };
private final float[] mv = new float[4];
private final float[] mu = new float[4];
private final float[] mBBoxCoords = new float[8];
private float mHeight, mWidth;
@ -118,38 +129,46 @@ public class MapViewPosition {
updateMatrix();
}
public synchronized boolean getMapPosition(final MapPosition mapPosition) {
// if (!isValid())
// return false;
/**
* Get the current MapPosition
*
* @param pos MapPosition object to be updated
* @return true if current position is different from 'pos'.
*/
public synchronized boolean getMapPosition(MapPosition pos) {
if (mapPosition.lat == mLatitude
&& mapPosition.lon == mLongitude
&& mapPosition.zoomLevel == mZoomLevel
&& mapPosition.scale == mScale
&& mapPosition.angle == mRotation
&& mapPosition.tilt == mTilt)
updateTileScale();
if (pos.lat == mLatitude
&& pos.lon == mLongitude
&& pos.zoomLevel == mZoomLevel
&& pos.scale == mScale
&& pos.angle == mRotation
&& pos.tilt == mTilt)
return false;
byte z = mZoomLevel;
mapPosition.lat = mLatitude;
mapPosition.lon = mLongitude;
mapPosition.angle = mRotation;
mapPosition.tilt = mTilt;
mapPosition.scale = mScale;
mapPosition.zoomLevel = z;
pos.lat = mLatitude;
pos.lon = mLongitude;
pos.angle = mRotation;
pos.tilt = mTilt;
mapPosition.x = mPosX;
mapPosition.y = mPosY;
// for tiling
pos.scale = mScale;
pos.zoomLevel = z;
pos.x = mAbsX * (Tile.TILE_SIZE << mZoomLevel);
pos.y = mAbsY * (Tile.TILE_SIZE << mZoomLevel);
return true;
}
/**
* get a copy of current matrices
* Get a copy of current matrices
*
* @param view ...
* @param proj ...
* @param view view Matrix
* @param proj projection Matrix
* @param vp view and projection
*/
public synchronized void getMatrix(float[] view, float[] proj, float[] vp) {
@ -163,21 +182,33 @@ public class MapViewPosition {
System.arraycopy(mVPMatrix, 0, vp, 0, 16);
}
/**
* Get the inverse projection of the viewport, i.e. the
* coordinates with z==0 that will be projected exactly
* to screen corners by current view-projection-matrix.
*
* @param box float[8] will be set.
*/
public synchronized void getMapViewProjection(float[] box) {
float t = getZ(1);
float t2 = getZ(-1);
unproject(1, -1, t, box, 0); // top-right
unproject(-1, -1, t, box, 2); // top-left
unproject(-1, 1, t2, box, 4); // bottom-left
unproject(1, 1, t2, box, 6); // bottom-right
// top-right
unproject(1, -1, t, box, 0);
// top-left
unproject(-1, -1, t, box, 2);
// bottom-left
unproject(-1, 1, t2, box, 4);
// bottom-right
unproject(1, 1, t2, box, 6);
}
// get the z-value of the map-plane for a point on screen
/*
* Get Z-value of the map-plane for a point on screen -
* calculate the intersection of a ray from camera origin
* and the map plane
*/
private float getZ(float y) {
// calculate the intersection of a ray from
// camera origin and the map plane
// origin is moved by VIEW_DISTANCE
double cx = VIEW_DISTANCE;
// 'height' of the ray
@ -208,11 +239,9 @@ public class MapViewPosition {
Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
if (mv[3] != 0) {
coords[position + 0] = mv[0] / mv[3];
coords[position + 1] = mv[1] / mv[3];
}
}
/** @return the current center point of the MapView. */
public synchronized GeoPoint getMapCenter() {
@ -227,20 +256,11 @@ public class MapViewPosition {
if (!isValid()) {
return null;
}
updateTileScale();
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;
}
/**
* ...
*
@ -253,96 +273,106 @@ public class MapViewPosition {
float t = getZ(1);
float t2 = getZ(-1);
unproject(1, -1, t, coords, 0); // top-right
unproject(-1, -1, t, coords, 2); // top-left
unproject(-1, 1, t2, coords, 4); // bottom-left
unproject(1, 1, t2, coords, 6); // bottom-right
unproject(1, -1, t, coords, 0);
unproject(-1, -1, t, coords, 2);
unproject(-1, 1, t2, coords, 4);
unproject(1, 1, t2, coords, 6);
byte z = mZoomLevel;
double dx, dy;
double minLat = 0, minLon = 0, maxLat = 0, maxLon = 0, lon, lat;
double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double maxY = Double.MIN_VALUE;
for (int i = 0; i < 8; i += 2) {
dx = mRealX - coords[i + 0];
dy = mRealY - coords[i + 1];
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;
}
minX = Math.min(minX, dx);
maxX = Math.max(maxX, dx);
minY = Math.min(minY, dy);
maxY = Math.max(maxY, dy);
}
BoundingBox bbox = new BoundingBox(minLat, minLon, maxLat, maxLon);
minX = MercatorProjection.toLongitude(minX, mTileScale);
maxX = MercatorProjection.toLongitude(maxX, mTileScale);
minY = MercatorProjection.toLatitude(minY, mTileScale);
maxY = MercatorProjection.toLatitude(maxY, mTileScale);
Log.d(">>>", "getScreenBoundingBox " + bbox);
// yea, this is upside down..
BoundingBox bbox = new BoundingBox(maxY, minX, minY, maxX);
Log.d(TAG, "getScreenBoundingBox " + bbox);
return bbox;
}
/**
* for x,y in screen coordinates get the point on the map in map-tile
* coordinates
* For x, y in screen coordinates set Point to map-tile
* coordinates at returned scale.
*
* @param x ...
* @param y ...
* @param reuse ...
* @return ...
* @param x screen coordinate
* @param y screen coordinate
* @param out Point coords will be set
* @return current map scale
*/
public synchronized Point getScreenPointOnMap(float x, float y, Point reuse) {
Point out = reuse == null ? new Point() : reuse;
public synchronized float getScreenPointOnMap(float x, float y, Point2D out) {
float mx = ((mWidth / 2) - x) / (mWidth / 2);
float my = ((mHeight / 2) - y) / (mHeight / 2);
// scale to -1..1
float mx = 1 - (x / mWidth * 2);
float my = 1 - (y / mHeight * 2);
unproject(-mx, my, getZ(-my), mu, 0);
out.x = (int) (mPosX + mu[0] / mScale);
out.y = (int) (mPosY + mu[1] / mScale);
//Log.d(TAG, "getScreenPointOnMap " + reuse);
out.x = mRealX + mu[0];
out.y = mRealY + mu[1];
return out;
return (float) mMapScale;
}
/**
* get the GeoPoint for x,y in screen coordinates
* Get the GeoPoint for x,y in screen coordinates.
* (only used by MapEventsOverlay currently)
*
* @param x screen pixel x
* @param y screen pixel y
* @param x screen coordinate
* @param y screen coordinate
* @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);
// scale to -1..1
float mx = 1 - (x / mWidth * 2);
float my = 1 - (y / mHeight * 2);
unproject(-mx, my, getZ(-my), mu, 0);
double dx = mPosX + mu[0] / mScale;
double dy = mPosY + mu[1] / mScale;
double dx = mRealX + mu[0];
double dy = mRealY + mu[1];
dx /= mMapScale * Tile.TILE_SIZE;
dy /= mMapScale * Tile.TILE_SIZE;
if (dx > 1) {
while (dx > 1)
dx -= 1;
} else {
while (dx < 0)
dx += 1;
}
if (dy > 1)
dy = 1;
else if (dy < 0)
dy = 0;
GeoPoint p = new GeoPoint(
MercatorProjection.pixelYToLatitude(dy, mZoomLevel),
MercatorProjection.pixelXToLongitude(dx, mZoomLevel));
//Log.d(TAG, "fromScreenPixels " + p);
MercatorProjection.toLatitude(dy),
MercatorProjection.toLongitude(dx));
return p;
}
/**
* get the screen pixel for a GeoPoint
* Get the screen pixel for a GeoPoint
*
* @param geoPoint ...
* @param reuse ...
@ -351,40 +381,24 @@ public class MapViewPosition {
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);
double x = MercatorProjection.longitudeToX(geoPoint.getLongitude()) * mTileScale;
double y = MercatorProjection.latitudeToY(geoPoint.getLatitude()) * mTileScale;
mv[0] = (float) (x - mRealX);
mv[1] = (float) (y - mRealY);
mv[0] = (float) (x - mPosX) * mScale;
mv[1] = (float) (y - mPosY) * mScale;
mv[2] = 0;
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mVPMatrix, 0, mv, 0);
out.x = (int) (mv[0] / mv[3] * mWidth / 2);
out.y = (int) (mv[1] / mv[3] * mHeight / 2);
// positive direction is down and right;
out.x = (int) ((mv[0] / mv[3]) * (mWidth / 2));
out.y = (int) -((mv[1] / mv[3]) * (mHeight / 2));
return out;
}
// 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 updateMatrix() {
// --- view matrix
// 1. scale to window coordinates
@ -449,6 +463,10 @@ public class MapViewPosition {
return true;
}
//private double mMaxLat = MercatorProjection.latitudeToY(MercatorProjection.LATITUDE_MAX);
private double mAbsX;
private double mAbsY;
/**
* Moves this MapViewPosition by the given amount of pixels.
*
@ -456,75 +474,88 @@ public class MapViewPosition {
* @param my the amount of pixels to move the map vertically.
*/
public synchronized void moveMap(float mx, float my) {
Point2D p = getMove(mx, my);
// stop animation
mHandler.cancel();
mLatitude = MercatorProjection.pixelYToLatitude(mPosY - p.y, mZoomLevel);
mLatitude = MercatorProjection.limitLatitude(mLatitude);
Point2D p = applyRotation(mx, my);
mLongitude = MercatorProjection.pixelXToLongitude(mPosX - p.x, mZoomLevel);
mLongitude = MercatorProjection.wrapLongitude(mLongitude);
move(p.x, p.y);
}
private synchronized void move(double mx, double my) {
mAbsX = (mRealX - mx) / mTileScale;
mAbsY = (mRealY - my) / mTileScale;
// clamp latitude
mAbsY = FastMath.clamp(mAbsY, 0, 1);
// wrap longitude
while (mAbsX > 1)
mAbsX -= 1;
while (mAbsX < 0)
mAbsX += 1;
mLongitude = MercatorProjection.toLongitude(mAbsX);
mLatitude = MercatorProjection.toLatitude(mAbsY);
updatePosition();
}
private Point2D getMove(float mx, float my) {
double dx = mx / mScale;
double dy = my / mScale;
private Point2D applyRotation(float mx, float my) {
if (mMapView.mRotationEnabled || mMapView.mCompassEnabled) {
double rad = Math.toRadians(mRotation);
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;
float x = (float) (mx * rcos + my * rsin);
float y = (float) (mx * -rsin + my * rcos);
mx = x;
my = y;
}
mMovePoint.x = dx;
mMovePoint.y = dy;
mMovePoint.x = mx;
mMovePoint.y = my;
return mMovePoint;
}
private void updateTileScale() {
int z = FastMath.log2((int) mMapScale);
z = FastMath.clamp(z, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL);
mZoomLevel = (byte) z;
mScale = (float) (mMapScale / (1 << z));
//Log.d(TAG, "updateTileScale " + mZoomLevel + " " + mScale);
}
/**
* -
*
* @param scale ...
* @param scale map by this factor
* @param pivotX ...
* @param pivotY ...
* @return true if scale was changed
*/
public synchronized boolean scaleMap(float scale, float pivotX, float pivotY) {
// stop animation
mHandler.cancel();
// sanitize input
// just sanitize input
scale = FastMath.clamp(scale, 0.5f, 2);
float newScale = mMapScale * scale;
double newScale = mMapScale * scale;
int z = FastMath.log2((int) newScale);
newScale = FastMath.clamp(newScale, MIN_SCALE, MAX_SCALE);
if (z < MIN_ZOOMLEVEL || (z >= MAX_ZOOMLEVEL && mScale >= 8))
if (newScale == mMapScale)
return false;
if (z > MAX_ZOOMLEVEL) {
// z17 shows everything, just increase scaling
// need to fix this for ScanBox
if (mScale * scale > 4)
return false;
scale = (float) (newScale / mMapScale);
mScale *= scale;
mMapScale = newScale;
} else {
mZoomLevel = (byte) z;
updatePosition();
mScale = newScale / (1 << z);
mMapScale = newScale;
}
if (pivotX != 0 || pivotY != 0)
moveMap(pivotX * (1.0f - scale),
pivotY * (1.0f - scale));
else
updatePosition();
return true;
}
@ -532,14 +563,21 @@ public class MapViewPosition {
/**
* rotate map around pivot cx,cy
*
* @param angle ...
* @param radians ...
* @param cx ...
* @param cy ...
*/
public synchronized void rotateMap(float angle, float cx, float cy) {
moveMap(cx, cy);
public synchronized void rotateMap(double radians, float cx, float cy) {
mRotation += angle;
double rsin = Math.sin(radians);
double rcos = Math.cos(radians);
float x = (float) (cx * rcos + cy * -rsin - cx);
float y = (float) (cx * rsin + cy * rcos - cy);
moveMap(x, y);
mRotation += Math.toDegrees(radians);
updateMatrix();
}
@ -567,6 +605,9 @@ public class MapViewPosition {
private void setMapCenter(double latitude, double longitude) {
mLatitude = MercatorProjection.limitLatitude(latitude);
mLongitude = MercatorProjection.limitLongitude(longitude);
mAbsX = MercatorProjection.longitudeToX(mLongitude);
mAbsY = MercatorProjection.latitudeToY(mLatitude);
updatePosition();
}
@ -575,33 +616,42 @@ public class MapViewPosition {
}
synchronized void setMapCenter(MapPosition mapPosition) {
//mZoomLevel = mMapView.limitZoomLevel(mapPosition.zoomLevel);
setZoomLevelLimit(mapPosition.zoomLevel);
mMapScale = 1 << mZoomLevel;
//mMapScale = 1 << mZoomLevel;
setMapCenter(mapPosition.lat, mapPosition.lon);
}
synchronized void setZoomLevel(byte zoomLevel) {
//mZoomLevel = mMapView.limitZoomLevel(zoomLevel);
setZoomLevelLimit(zoomLevel);
mMapScale = 1 << mZoomLevel;
mScale = 1;
//mMapScale = 1 << mZoomLevel;
//mScale = 1;
updatePosition();
}
private void setZoomLevelLimit(byte zoomLevel) {
mZoomLevel = (byte)FastMath.clamp(zoomLevel, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL);
mMapScale = FastMath.clamp(1 << zoomLevel, MIN_SCALE, MAX_SCALE);
//mMapScale = 1 << zoomLevel;
//mZoomLevel = (byte) FastMath.clamp(zoomLevel, MIN_ZOOMLEVEL, MAX_ZOOMLEVEL);
}
private double mRealX;
private double mRealY;
private void updatePosition() {
mPosX = MercatorProjection.longitudeToPixelX(mLongitude, mZoomLevel);
mPosY = MercatorProjection.latitudeToPixelY(mLatitude, mZoomLevel);
mTileScale = mMapScale * Tile.TILE_SIZE;
mRealX = mAbsX * mTileScale;
mRealY = mAbsY * mTileScale;
}
private double mStartX;
private double mStartY;
private double mEndX;
private double mEndY;
private int mScrollX;
private int mScrollY;
private double mStartScale;
private double mEndScale;
private float mDuration = 500;
public synchronized void animateTo(BoundingBox bbox) {
@ -610,6 +660,7 @@ public class MapViewPosition {
double dy = MercatorProjection.latitudeToY(bbox.getMinLatitude())
- MercatorProjection.latitudeToY(bbox.getMaxLatitude());
double log4 = Math.log(4);
double zx = -log4 * Math.log(dx) + (mWidth / Tile.TILE_SIZE);
@ -617,80 +668,160 @@ public class MapViewPosition {
double z = Math.min(zx, zy);
setZoomLevelLimit((byte) Math.floor(z));
double newScale = Math.pow(2, z);
mScale = FastMath.clamp((float) (1 + (z - mZoomLevel)), 1, MAX_END_SCALE);
//double newScale = (1 << (int)Math.floor(z));
mMapScale = (1 << mZoomLevel) * mScale;
//Log.d(TAG, "zoom: " + bbox + " " + zx + " " + zy + " / " + mScale + " " + mZoomLevel);
setMapCenter(bbox.getCenterPoint());
newScale = FastMath.clamp(newScale, MIN_SCALE, (1 << 15));
float scale = (float) (newScale / mMapScale);
Log.d(TAG, "scale to " + bbox + " "+ z + " " + newScale + " " + mMapScale
+ " " + FastMath.log2((int) newScale) + " " + scale);
mEndScale = mMapScale * scale;
mStartScale = mMapScale;
//mMapScale = newScale;
//updatePosition();
//
// // reset rotation/tilt
// mTilt = 0;
// mRotation = 0;
// updateMatrix();
//
// GeoPoint geoPoint = bbox.getCenterPoint();
// mEndX = MercatorProjection.longitudeToPixelX(geoPoint.getLongitude(), mZoomLevel);
// mEndY = MercatorProjection.latitudeToPixelY(geoPoint.getLatitude(), mZoomLevel);
// mStartX = mPosX;
// mStartY = mPosY;
//
// mDuration = 300;
// mHandler.start((int) mDuration);
// ----- mScale = FastMath.clamp((float) (1 + (z - mZoomLevel)), 1, MAX_END_SCALE);
//mMapScale = (1 << mZoomLevel) * mScale;
//Log.d(TAG, "zoom: " + bbox + " " + zx + " " + zy + " / " + mScale + " " + mZoomLevel);
//updatePosition();
// reset rotation/tilt
mTilt = 0;
mRotation = 0;
updateMatrix();
GeoPoint geoPoint = bbox.getCenterPoint();
//mStartScale = mMapScale;
double mx = MercatorProjection.longitudeToX(geoPoint.getLongitude()) * mTileScale;
double my = MercatorProjection.latitudeToY(geoPoint.getLatitude()) * mTileScale;
mx = mRealX - mx;
my = mRealY - my;
mScrollX = 0;
mScrollY = 0;
mDuration = 500;
mScroller.startScroll(0, 0, (int) mx, (int) my, (int)mDuration);
mHandler.start((int) mDuration);
}
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;
//mEndX = MercatorProjection.longitudeToPixelX(geoPoint.getLongitude(), mZoomLevel);
//mEndY = MercatorProjection.latitudeToPixelY(geoPoint.getLatitude(), mZoomLevel);
//mStartX = mPosX;
//mStartY = mPosY;
mDuration = 300;
mHandler.start((int) mDuration);
}
public synchronized void animateFling(int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
mScrollX = 0;
mScrollY = 0;
mScroller.fling(0, 0, velocityX, velocityY, minX, maxX, minY, maxY);
//mMapView.mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mDuration = 300;
mHandler.start((int) mDuration);
}
public synchronized void animateZoom(float scale) {
mStartScale = mMapScale;
mEndScale = mMapScale * scale;
//mScroller.fling(0, 0, velocityX, velocityY, minX, maxX, minY, maxY);
//mMapView.mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mDuration = 300;
mHandler.start((int) mDuration);
}
//private float mScrollX, mScrollY;
public void updateAnimation() {
//scroll();
}
synchronized boolean scroll(double div) {
if (mScroller.isFinished()) {
return false;
}
int x = mScrollX; //mScroller.getCurrX();
int y = mScrollY; //mScroller.getCurrY();
mScroller.computeScrollOffset();
int mx = mScroller.getCurrX() - x;
int my = mScroller.getCurrY() - y;
mx *= div;
my *= div;
if (mx >= 1 || my >= 1 || mx <= -1 || my <= -1) {
moveMap(mx, my);
//mMapView.redrawMap(true);
mScrollX = mScroller.getCurrX();
mScrollY = mScroller.getCurrY();
}
return true;
}
public synchronized void animateTo(float dx, float dy, float duration) {
getMove(dx, dy);
applyRotation(dx, dy);
mEndX = mPosX - mMovePoint.x;
mEndY = mPosY - mMovePoint.y;
//mEndX = mRealX - mMovePoint.x;
//mEndY = mRealY - mMovePoint.y;
mStartX = mPosX;
mStartY = mPosY;
//mStartX = mRealX;
//mStartY = mRealY;
mDuration = duration;
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);
void onTick(long millisLeft) {
boolean changed = false;
double div = 1;
if (mStartScale != 0) {
double adv = millisLeft / mDuration;
mMapScale = (adv * mStartScale) + (mEndScale * (1.0 - adv));
div = mMapScale / mStartScale;
updatePosition();
changed = true;
}
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);
if (scroll(div))
changed = true;
if (changed)
mMapView.redrawMap(true);
}
void onFinish() {
setMapPosition(mEndX, mEndY);
//setMapPosition(mEndX, mEndY);
//mMapView.mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mMapView.redrawMap(true);
mStartScale = 0;
}
/**
* below is borrowed from CountDownTimer class:
* Copyright (C) 2008 The Android Open Source Project
*/
static class AnimationHandler extends Handler {
private final WeakReference<MapViewPosition> mMapViewPosition;
private static final int MSG = 1;

View File

@ -1,358 +1,358 @@
/*
* 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.generator.TileGenerator;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
import android.widget.ZoomControls;
/**
* A MapZoomControls instance displays buttons for zooming in and out in a map.
*/
public class MapZoomControls {
private static class ZoomControlsHideHandler extends Handler {
private final ZoomControls mZoomControls;
ZoomControlsHideHandler(ZoomControls zoomControls) {
super();
mZoomControls = zoomControls;
}
@Override
public void handleMessage(Message message) {
mZoomControls.hide();
}
}
private static class ZoomInClickListener implements View.OnClickListener {
private final MapZoomControls mMapZoomControls;
ZoomInClickListener(MapZoomControls mapZoomControls) {
mMapZoomControls = mapZoomControls;
}
@Override
public void onClick(View view) {
// if (MapView.testRegionZoom)
// mMapView.mRegionLookup.updateRegion(1, null);
// else
// MapZoomControls.this.zoom((byte) 1);
mMapZoomControls.zoom((byte) 1);
}
}
private static class ZoomOutClickListener implements View.OnClickListener {
private final MapZoomControls mMapZoomControls;
ZoomOutClickListener(MapZoomControls mapZoomControls) {
mMapZoomControls = mapZoomControls;
}
@Override
public void onClick(View view) {
// if (MapView.testRegionZoom)
// mMapView.mRegionLookup.updateRegion(-1, null);
// else
mMapZoomControls.zoom((byte) -1);
}
}
/**
* Default {@link Gravity} of the zoom controls.
*/
private static final int DEFAULT_ZOOM_CONTROLS_GRAVITY = Gravity.BOTTOM
| Gravity.RIGHT;
/**
* Default maximum zoom level.
*/
private static final byte DEFAULT_ZOOM_LEVEL_MAX = 18;
/**
* Default minimum zoom level.
*/
private static final byte DEFAULT_ZOOM_LEVEL_MIN = 1;
/**
* Message code for the handler to hide the zoom controls.
*/
private static final int MSG_ZOOM_CONTROLS_HIDE = 0;
/**
* Horizontal padding for the zoom controls.
*/
private static final int ZOOM_CONTROLS_HORIZONTAL_PADDING = 5;
/**
* Delay in milliseconds after which the zoom controls disappear.
*/
private static final long ZOOM_CONTROLS_TIMEOUT = ViewConfiguration
.getZoomControlsTimeout();
private boolean mGravityChanged;
private boolean mShowMapZoomControls;
private final ZoomControls mZoomControls;
private int mZoomControlsGravity;
private final Handler mZoomControlsHideHandler;
private byte mZoomLevelMax;
private byte mZoomLevelMin;
private final MapView mMapView;
MapZoomControls(Context context, final MapView mapView) {
mMapView = mapView;
mZoomControls = new ZoomControls(context);
mShowMapZoomControls = true;
mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX;
mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN;
// if (!MapView.testRegionZoom)
mZoomControls.setVisibility(View.GONE);
mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY;
mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(this));
mZoomControls.setOnZoomOutClickListener(new ZoomOutClickListener(this));
mZoomControlsHideHandler = new ZoomControlsHideHandler(mZoomControls);
int wrapContent = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
LayoutParams layoutParams = new LayoutParams(wrapContent, wrapContent);
mapView.addView(mZoomControls, layoutParams);
}
/**
* Zooms in or out by the given amount of zoom levels.
*
* @param zoomLevelDiff
* the difference to the current zoom level.
* @return true if the zoom level was changed, false otherwise.
*/
boolean zoom(byte zoomLevelDiff) {
MapViewPosition mapViewPosition = mMapView.getMapViewPosition();
int z = mapViewPosition.getZoomLevel() + zoomLevelDiff;
if (zoomLevelDiff > 0) {
// check if zoom in is possible
if (z > mZoomLevelMax) {
return false;
}
} else if (zoomLevelDiff < 0) {
// check if zoom out is possible
if (z < getZoomLevelMin()) {
return false;
}
}
mapViewPosition.setZoomLevel((byte) z);
mMapView.redrawMap(true);
return true;
}
/**
* @return the current gravity for the placing of the zoom controls.
* @see Gravity
*/
public int getZoomControlsGravity() {
return mZoomControlsGravity;
}
/**
* @return the maximum zoom level of the map.
*/
public byte getZoomLevelMax() {
return mZoomLevelMax;
}
/**
* @return the minimum zoom level of the map.
*/
public byte getZoomLevelMin() {
return mZoomLevelMin;
}
/**
* @return true if the zoom controls are visible, false otherwise.
*/
public boolean isShowMapZoomControls() {
return mShowMapZoomControls;
}
/**
* @param show
* true if the zoom controls should be visible, false otherwise.
*/
public void setShowMapZoomControls(boolean show) {
mShowMapZoomControls = show;
}
/**
* 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.
*/
public void setZoomControlsGravity(int zoomControlsGravity) {
if (mZoomControlsGravity != zoomControlsGravity) {
mZoomControlsGravity = zoomControlsGravity;
mGravityChanged = true;
}
}
/**
* 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.
*
* @param zoomLevelMax
* the maximum zoom level.
* @throws IllegalArgumentException
* if the maximum zoom level is smaller than the current minimum
* zoom level.
*/
public void setZoomLevelMax(byte zoomLevelMax) {
if (zoomLevelMax < mZoomLevelMin) {
throw new IllegalArgumentException();
}
mZoomLevelMax = zoomLevelMax;
}
/**
* Sets the minimum zoom level of the map.
*
* @param zoomLevelMin
* the minimum zoom level.
* @throws IllegalArgumentException
* if the minimum zoom level is larger than the current maximum
* zoom level.
*/
public void setZoomLevelMin(byte zoomLevelMin) {
if (zoomLevelMin > mZoomLevelMax) {
throw new IllegalArgumentException();
}
mZoomLevelMin = zoomLevelMin;
}
private int calculatePositionLeft(int left, int right, int zoomControlsWidth) {
int gravity = mZoomControlsGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
switch (gravity) {
case Gravity.LEFT:
return ZOOM_CONTROLS_HORIZONTAL_PADDING;
case Gravity.CENTER_HORIZONTAL:
return (right - left - zoomControlsWidth) / 2;
case Gravity.RIGHT:
return right - left - zoomControlsWidth
- ZOOM_CONTROLS_HORIZONTAL_PADDING;
}
throw new IllegalArgumentException("unknown horizontal gravity: " + gravity);
}
private int calculatePositionTop(int top, int bottom, int zoomControlsHeight) {
int gravity = mZoomControlsGravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (gravity) {
case Gravity.TOP:
return 0;
case Gravity.CENTER_VERTICAL:
return (bottom - top - zoomControlsHeight) / 2;
case Gravity.BOTTOM:
return bottom - top - zoomControlsHeight;
}
throw new IllegalArgumentException("unknown vertical gravity: " + gravity);
}
private void showZoomControls() {
mZoomControlsHideHandler.removeMessages(MSG_ZOOM_CONTROLS_HIDE);
if (mZoomControls.getVisibility() != View.VISIBLE) {
mZoomControls.show();
}
}
private void showZoomControlsWithTimeout() {
showZoomControls();
mZoomControlsHideHandler.sendEmptyMessageDelayed(MSG_ZOOM_CONTROLS_HIDE,
ZOOM_CONTROLS_TIMEOUT);
}
int getMeasuredHeight() {
return mZoomControls.getMeasuredHeight();
}
int getMeasuredWidth() {
return mZoomControls.getMeasuredWidth();
}
void measure(int widthMeasureSpec, int heightMeasureSpec) {
mZoomControls.measure(widthMeasureSpec, heightMeasureSpec);
}
void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (!changed && !mGravityChanged) {
return;
}
int zoomControlsWidth = mZoomControls.getMeasuredWidth();
int zoomControlsHeight = mZoomControls.getMeasuredHeight();
int positionLeft = calculatePositionLeft(left, right, zoomControlsWidth);
int positionTop = calculatePositionTop(top, bottom, zoomControlsHeight);
int positionRight = positionLeft + zoomControlsWidth;
int positionBottom = positionTop + zoomControlsHeight;
mZoomControls.layout(positionLeft, positionTop, positionRight, positionBottom);
mGravityChanged = false;
}
void onMapViewTouchEvent(int action) {
if (mShowMapZoomControls) {
switch (action) {
case MotionEvent.ACTION_DOWN:
showZoomControls();
break;
case MotionEvent.ACTION_CANCEL:
showZoomControlsWithTimeout();
break;
case MotionEvent.ACTION_UP:
showZoomControlsWithTimeout();
break;
}
}
}
void onZoomLevelChange(int zoomLevel) {
boolean zoomInEnabled = zoomLevel < mZoomLevelMax;
boolean zoomOutEnabled = zoomLevel > mZoomLevelMin;
mZoomControls.setIsZoomInEnabled(zoomInEnabled);
mZoomControls.setIsZoomOutEnabled(zoomOutEnabled);
}
}
///*
// * 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.generator.TileGenerator;
//
//import android.content.Context;
//import android.os.Handler;
//import android.os.Message;
//import android.view.Gravity;
//import android.view.MotionEvent;
//import android.view.View;
//import android.view.ViewConfiguration;
//import android.view.ViewGroup.LayoutParams;
//import android.widget.ZoomControls;
//
///**
// * A MapZoomControls instance displays buttons for zooming in and out in a map.
// */
//public class MapZoomControls {
// private static class ZoomControlsHideHandler extends Handler {
// private final ZoomControls mZoomControls;
//
// ZoomControlsHideHandler(ZoomControls zoomControls) {
// super();
// mZoomControls = zoomControls;
// }
//
// @Override
// public void handleMessage(Message message) {
// mZoomControls.hide();
// }
// }
//
// private static class ZoomInClickListener implements View.OnClickListener {
// private final MapZoomControls mMapZoomControls;
//
// ZoomInClickListener(MapZoomControls mapZoomControls) {
// mMapZoomControls = mapZoomControls;
// }
//
// @Override
// public void onClick(View view) {
// // if (MapView.testRegionZoom)
// // mMapView.mRegionLookup.updateRegion(1, null);
// // else
// // MapZoomControls.this.zoom((byte) 1);
// mMapZoomControls.zoom((byte) 1);
// }
// }
//
// private static class ZoomOutClickListener implements View.OnClickListener {
// private final MapZoomControls mMapZoomControls;
//
// ZoomOutClickListener(MapZoomControls mapZoomControls) {
// mMapZoomControls = mapZoomControls;
// }
//
// @Override
// public void onClick(View view) {
// // if (MapView.testRegionZoom)
// // mMapView.mRegionLookup.updateRegion(-1, null);
// // else
// mMapZoomControls.zoom((byte) -1);
// }
// }
//
// /**
// * Default {@link Gravity} of the zoom controls.
// */
// private static final int DEFAULT_ZOOM_CONTROLS_GRAVITY = Gravity.BOTTOM
// | Gravity.RIGHT;
//
// /**
// * Default maximum zoom level.
// */
// private static final byte DEFAULT_ZOOM_LEVEL_MAX = 18;
//
// /**
// * Default minimum zoom level.
// */
// private static final byte DEFAULT_ZOOM_LEVEL_MIN = 1;
//
// /**
// * Message code for the handler to hide the zoom controls.
// */
// private static final int MSG_ZOOM_CONTROLS_HIDE = 0;
//
// /**
// * Horizontal padding for the zoom controls.
// */
// private static final int ZOOM_CONTROLS_HORIZONTAL_PADDING = 5;
//
// /**
// * Delay in milliseconds after which the zoom controls disappear.
// */
// private static final long ZOOM_CONTROLS_TIMEOUT = ViewConfiguration
// .getZoomControlsTimeout();
//
// private boolean mGravityChanged;
// private boolean mShowMapZoomControls;
// private final ZoomControls mZoomControls;
// private int mZoomControlsGravity;
// private final Handler mZoomControlsHideHandler;
// private byte mZoomLevelMax;
// private byte mZoomLevelMin;
// private final MapView mMapView;
//
// MapZoomControls(Context context, final MapView mapView) {
// mMapView = mapView;
// mZoomControls = new ZoomControls(context);
// mShowMapZoomControls = true;
// mZoomLevelMax = DEFAULT_ZOOM_LEVEL_MAX;
// mZoomLevelMin = DEFAULT_ZOOM_LEVEL_MIN;
// // if (!MapView.testRegionZoom)
// mZoomControls.setVisibility(View.GONE);
// mZoomControlsGravity = DEFAULT_ZOOM_CONTROLS_GRAVITY;
//
// mZoomControls.setOnZoomInClickListener(new ZoomInClickListener(this));
// mZoomControls.setOnZoomOutClickListener(new ZoomOutClickListener(this));
// mZoomControlsHideHandler = new ZoomControlsHideHandler(mZoomControls);
//
// int wrapContent = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
// LayoutParams layoutParams = new LayoutParams(wrapContent, wrapContent);
// mapView.addView(mZoomControls, layoutParams);
// }
//
// /**
// * Zooms in or out by the given amount of zoom levels.
// *
// * @param zoomLevelDiff
// * the difference to the current zoom level.
// * @return true if the zoom level was changed, false otherwise.
// */
// boolean zoom(byte zoomLevelDiff) {
// MapViewPosition mapViewPosition = mMapView.getMapViewPosition();
// int z = mapViewPosition.getZoomLevel() + zoomLevelDiff;
// if (zoomLevelDiff > 0) {
// // check if zoom in is possible
// if (z > mZoomLevelMax) {
// return false;
// }
//
// } else if (zoomLevelDiff < 0) {
// // check if zoom out is possible
// if (z < getZoomLevelMin()) {
// return false;
// }
// }
//
// mapViewPosition.setZoomLevel((byte) z);
// mMapView.redrawMap(true);
//
// return true;
// }
//
// /**
// * @return the current gravity for the placing of the zoom controls.
// * @see Gravity
// */
// public int getZoomControlsGravity() {
// return mZoomControlsGravity;
// }
//
// /**
// * @return the maximum zoom level of the map.
// */
// public byte getZoomLevelMax() {
// return mZoomLevelMax;
// }
//
// /**
// * @return the minimum zoom level of the map.
// */
// public byte getZoomLevelMin() {
// return mZoomLevelMin;
// }
//
// /**
// * @return true if the zoom controls are visible, false otherwise.
// */
// public boolean isShowMapZoomControls() {
// return mShowMapZoomControls;
// }
//
// /**
// * @param show
// * true if the zoom controls should be visible, false otherwise.
// */
// public void setShowMapZoomControls(boolean show) {
// mShowMapZoomControls = show;
// }
//
// /**
// * 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.
// */
// public void setZoomControlsGravity(int zoomControlsGravity) {
// if (mZoomControlsGravity != zoomControlsGravity) {
// mZoomControlsGravity = zoomControlsGravity;
// mGravityChanged = true;
// }
// }
//
// /**
// * 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.
// *
// * @param zoomLevelMax
// * the maximum zoom level.
// * @throws IllegalArgumentException
// * if the maximum zoom level is smaller than the current minimum
// * zoom level.
// */
// public void setZoomLevelMax(byte zoomLevelMax) {
// if (zoomLevelMax < mZoomLevelMin) {
// throw new IllegalArgumentException();
// }
// mZoomLevelMax = zoomLevelMax;
// }
//
// /**
// * Sets the minimum zoom level of the map.
// *
// * @param zoomLevelMin
// * the minimum zoom level.
// * @throws IllegalArgumentException
// * if the minimum zoom level is larger than the current maximum
// * zoom level.
// */
// public void setZoomLevelMin(byte zoomLevelMin) {
// if (zoomLevelMin > mZoomLevelMax) {
// throw new IllegalArgumentException();
// }
// mZoomLevelMin = zoomLevelMin;
// }
//
// private int calculatePositionLeft(int left, int right, int zoomControlsWidth) {
// int gravity = mZoomControlsGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
// switch (gravity) {
// case Gravity.LEFT:
// return ZOOM_CONTROLS_HORIZONTAL_PADDING;
//
// case Gravity.CENTER_HORIZONTAL:
// return (right - left - zoomControlsWidth) / 2;
//
// case Gravity.RIGHT:
// return right - left - zoomControlsWidth
// - ZOOM_CONTROLS_HORIZONTAL_PADDING;
// }
//
// throw new IllegalArgumentException("unknown horizontal gravity: " + gravity);
// }
//
// private int calculatePositionTop(int top, int bottom, int zoomControlsHeight) {
// int gravity = mZoomControlsGravity & Gravity.VERTICAL_GRAVITY_MASK;
// switch (gravity) {
// case Gravity.TOP:
// return 0;
//
// case Gravity.CENTER_VERTICAL:
// return (bottom - top - zoomControlsHeight) / 2;
//
// case Gravity.BOTTOM:
// return bottom - top - zoomControlsHeight;
// }
//
// throw new IllegalArgumentException("unknown vertical gravity: " + gravity);
// }
//
// private void showZoomControls() {
// mZoomControlsHideHandler.removeMessages(MSG_ZOOM_CONTROLS_HIDE);
// if (mZoomControls.getVisibility() != View.VISIBLE) {
// mZoomControls.show();
// }
// }
//
// private void showZoomControlsWithTimeout() {
// showZoomControls();
// mZoomControlsHideHandler.sendEmptyMessageDelayed(MSG_ZOOM_CONTROLS_HIDE,
// ZOOM_CONTROLS_TIMEOUT);
// }
//
// int getMeasuredHeight() {
// return mZoomControls.getMeasuredHeight();
// }
//
// int getMeasuredWidth() {
// return mZoomControls.getMeasuredWidth();
// }
//
// void measure(int widthMeasureSpec, int heightMeasureSpec) {
// mZoomControls.measure(widthMeasureSpec, heightMeasureSpec);
// }
//
// void onLayout(boolean changed, int left, int top, int right, int bottom) {
// if (!changed && !mGravityChanged) {
// return;
// }
//
// int zoomControlsWidth = mZoomControls.getMeasuredWidth();
// int zoomControlsHeight = mZoomControls.getMeasuredHeight();
//
// int positionLeft = calculatePositionLeft(left, right, zoomControlsWidth);
// int positionTop = calculatePositionTop(top, bottom, zoomControlsHeight);
// int positionRight = positionLeft + zoomControlsWidth;
// int positionBottom = positionTop + zoomControlsHeight;
//
// mZoomControls.layout(positionLeft, positionTop, positionRight, positionBottom);
// mGravityChanged = false;
// }
//
// void onMapViewTouchEvent(int action) {
// if (mShowMapZoomControls) {
// switch (action) {
// case MotionEvent.ACTION_DOWN:
// showZoomControls();
// break;
// case MotionEvent.ACTION_CANCEL:
// showZoomControlsWithTimeout();
// break;
// case MotionEvent.ACTION_UP:
// showZoomControlsWithTimeout();
// break;
// }
// }
// }
//
// void onZoomLevelChange(int zoomLevel) {
// boolean zoomInEnabled = zoomLevel < mZoomLevelMax;
// boolean zoomOutEnabled = zoomLevel > mZoomLevelMin;
//
// mZoomControls.setIsZoomInEnabled(zoomInEnabled);
// mZoomControls.setIsZoomOutEnabled(zoomOutEnabled);
// }
//}

View File

@ -20,14 +20,11 @@ import org.oscim.core.Tile;
import org.oscim.overlay.OverlayManager;
import android.content.Context;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
/**
* @author Hannes Janetzek
@ -40,18 +37,19 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
private static final String TAG = TouchHandler.class.getName();
private static final boolean debug = false;
private final MapView mMapView;
private final MapViewPosition mMapPosition;
private final OverlayManager mOverlayManager;
private final DecelerateInterpolator mInterpolator;
private boolean mBeginScale;
private float mSumScale;
private float mSumRotate;
private boolean mBeginScale;
private boolean mBeginRotate;
private boolean mBeginTilt;
private boolean mLongPress;
private boolean mDoubleTap;
private float mPrevX;
private float mPrevY;
@ -60,16 +58,17 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
private float mPrevY2;
private double mAngle;
private double mPrevPinchWidth;
private float mFocusX;
private float mFocusY;
private final GestureDetector mGestureDetector;
private static final float SCALE_DURATION = 500;
protected static final int JUMP_THRESHOLD = 100;
protected static final double PINCH_ZOOM_THRESHOLD = 5;
protected static final double PINCH_ROTATE_THRESHOLD = 0.02;
protected static final float PINCH_TILT_THRESHOLD = 1f;
protected int mPrevPointerCount = 0;
protected double mPrevPinchWidth = -1;
/**
* @param context
@ -83,8 +82,6 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
mOverlayManager = mapView.getOverlayManager();
mGestureDetector = new GestureDetector(context, this);
mGestureDetector.setOnDoubleTapListener(this);
mInterpolator = new DecelerateInterpolator(2f);
mScroller = new Scroller(mMapView.getContext(), mInterpolator);
}
/**
@ -128,8 +125,7 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
}
private boolean onActionCancel() {
//mPointerId1 = INVALID_POINTER_ID;
mLongPress = true;
mDoubleTap = false;
return true;
}
@ -143,8 +139,14 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
float width = mMapView.getWidth();
float height = mMapView.getHeight();
// return if detect a new gesture, as indicated by a large jump
if (Math.abs(mx) > JUMP_THRESHOLD || Math.abs(my) > JUMP_THRESHOLD)
return true;
// double-tap + hold
if (mLongPress) {
if (mDoubleTap) {
if (debug)
Log.d(TAG, "tap scale: " + mx + " " + my);
mMapPosition.scaleMap(1 - my / (height / 5), 0, 0);
mMapView.redrawMap(true);
@ -239,12 +241,7 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
mSumRotate += da;
if (Math.abs(da) > 0.001) {
double rsin = Math.sin(r);
double rcos = Math.cos(r);
float x = (float) (mFocusX * rcos + mFocusY * -rsin - mFocusX);
float y = (float) (mFocusX * rsin + mFocusY * rcos - mFocusY);
mMapPosition.rotateMap((float) Math.toDegrees(da), x, y);
mMapPosition.rotateMap(da, mFocusX, mFocusY);
changed = true;
}
}
@ -265,60 +262,59 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
return true;
}
private int mMulti = 0;
private int mMulti;
private boolean mWasMulti;
private boolean onActionPointerDown(MotionEvent event) {
private void updateMulti(MotionEvent e) {
int cnt = e.getPointerCount();
mMulti++;
mWasMulti = true;
mSumScale = 1;
if (cnt == 2) {
mPrevX = e.getX(0);
mPrevY = e.getY(0);
if (mMulti == 1) {
mPrevX2 = event.getX(1);
mPrevY2 = event.getY(1);
mPrevX2 = e.getX(1);
mPrevY2 = e.getY(1);
double dx = mPrevX - mPrevX2;
double dy = mPrevY - mPrevY2;
mAngle = Math.atan2(dy, dx);
mPrevPinchWidth = Math.sqrt(dx * dx + dy * dy);
mSumScale = 1;
}
}
private boolean onActionPointerDown(MotionEvent e) {
mMulti++;
mWasMulti = true;
updateMulti(e);
return true;
}
private boolean onActionPointerUp(MotionEvent e) {
int cnt = e.getPointerCount();
if (cnt >= 2) {
mPrevX = e.getX(0);
mPrevY = e.getY(0);
mPrevX2 = e.getX(1);
mPrevY2 = e.getY(1);
double dx = mPrevX - mPrevX2;
double dy = mPrevY - mPrevY2;
mAngle = Math.atan2(dy, dx);
mPrevPinchWidth = Math.sqrt(dx * dx + dy * dy);
}
updateMulti(e);
mMulti--;
mLongPress = false;
return true;
}
private boolean onActionDown(MotionEvent e) {
mPrevX = e.getX();
mPrevY = e.getY();
private void printState(String action) {
Log.d(TAG, action
+ " " + mDoubleTap
+ " " + mBeginScale
+ " " + mBeginRotate
+ " " + mBeginTilt);
}
mBeginRotate = false;
mBeginTilt = false;
mBeginScale = false;
private boolean onActionDown(MotionEvent e) {
mPrevX = e.getX(0);
mPrevY = e.getY(0);
if (debug)
printState("onActionDown");
return true;
}
@ -330,19 +326,22 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
*/
private boolean onActionUp(MotionEvent event) {
mLongPress = false;
mMulti = 0;
mPrevPinchWidth = -1;
mPrevPointerCount = 0;
if (debug)
printState("onActionUp");
mBeginRotate = false;
mBeginTilt = false;
mBeginScale = false;
mDoubleTap = false;
return true;
}
/******************* GestureListener *******************/
private final Scroller mScroller;
private float mScrollX, mScrollY;
private boolean fling = false;
//private final Scroller mScroller;
//private float mScrollX, mScrollY;
// private boolean fling = false;
@Override
public void onShowPress(MotionEvent e) {
@ -356,37 +355,22 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
@Override
public boolean onDown(MotionEvent e) {
if (fling) {
mScroller.forceFinished(true);
if (debug)
printState("onDown");
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
fling = false;
}
// if (fling) {
// mScroller.forceFinished(true);
//
// if (mTimer != null) {
// mTimer.cancel();
// mTimer = null;
// }
// fling = false;
// }
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(true);
mScrollX = mScroller.getCurrX();
mScrollY = mScroller.getCurrY();
}
return true;
}
@Override
public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
final float distanceY) {
@ -396,6 +380,8 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
}
if (mMulti == 0) {
if (debug)
printState("onScroll " + distanceX + " " + distanceY);
mMapPosition.moveMap(-distanceX, -distanceY);
mMapView.redrawMap(true);
}
@ -412,13 +398,6 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
int w = Tile.TILE_SIZE * 6;
int h = Tile.TILE_SIZE * 6;
mScrollX = 0;
mScrollY = 0;
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
if (mMapView.enablePagedFling) {
@ -436,28 +415,16 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
mMapPosition.animateTo(vx * move, vy * move, 250);
} else {
float s = (300 / mMapView.dpi) / 2;
mScroller.fling(0, 0, Math.round(velocityX * s),
Math.round(velocityY * s),
-w, w, -h, h);
mTimer = new CountDownTimer(1000, 16) {
@Override
public void onTick(long tick) {
scroll();
}
@Override
public void onFinish() {
}
}.start();
fling = true;
mMapPosition.animateFling(Math.round(velocityX * s), Math.round(velocityY * s), -w, w, -h, h);
// fling = true;
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
if (mLongPress)
if (mDoubleTap)
return;
if (mOverlayManager.onLongPress(e)) {
@ -470,28 +437,6 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
// }
}
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 *= 0.75;
scale += 1;
adv += 1;
if (scale > 1) {
mMapPosition.scaleMap(scale, mScrollX / adv, mScrollY / adv);
mMapView.redrawMap(true);
}
return true;
}
/******************* DoubleTapListener ****************/
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
@ -503,7 +448,11 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
if (mOverlayManager.onDoubleTap(e))
return true;
mLongPress = true;
//mDoubleTap = true;
mMapPosition.animateZoom(2);
if (debug)
printState("onDoubleTap");
return true;
}
@ -514,13 +463,12 @@ final class TouchHandler implements OnGestureListener, OnDoubleTapListener {
}
// /******************* ScaleListener *******************/
private float mPrevScale;
private CountDownTimer mTimer;
boolean mZooutOut;
//private float mPrevScale;
//private CountDownTimer mTimer;
//boolean mZooutOut;
// private float mCenterX;
// private float mCenterY;
private float mFocusX;
private float mFocusY;
// private long mTimeStart;
// private long mTimeEnd;
//