diff --git a/src/org/oscim/core/GeoPoint.java b/src/org/oscim/core/GeoPoint.java index 0cdf2057..2efdb493 100644 --- a/src/org/oscim/core/GeoPoint.java +++ b/src/org/oscim/core/GeoPoint.java @@ -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 { 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) { diff --git a/src/org/oscim/core/MapPosition.java b/src/org/oscim/core/MapPosition.java index 59ece2e7..5e169135 100644 --- a/src/org/oscim/core/MapPosition.java +++ b/src/org/oscim/core/MapPosition.java @@ -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. diff --git a/src/org/oscim/core/MercatorProjection.java b/src/org/oscim/core/MercatorProjection.java index fdf6e185..0ed58cfb 100644 --- a/src/org/oscim/core/MercatorProjection.java +++ b/src/org/oscim/core/MercatorProjection.java @@ -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; - } } diff --git a/src/org/oscim/overlay/ItemizedIconOverlay.java b/src/org/oscim/overlay/ItemizedIconOverlay.java index cb01e994..77411033 100644 --- a/src/org/oscim/overlay/ItemizedIconOverlay.java +++ b/src/org/oscim/overlay/ItemizedIconOverlay.java @@ -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 extends ItemizedOverl protected final List mItemList; protected OnItemGestureListener 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 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; diff --git a/src/org/oscim/renderer/GLRenderer.java b/src/org/oscim/renderer/GLRenderer.java index dffd4592..7fa82400 100644 --- a/src/org/oscim/renderer/GLRenderer.java +++ b/src/org/oscim/renderer/GLRenderer.java @@ -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 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); diff --git a/src/org/oscim/utils/GeometryUtils.java b/src/org/oscim/utils/GeometryUtils.java index a1a63533..04294f77 100644 --- a/src/org/oscim/utils/GeometryUtils.java +++ b/src/org/oscim/utils/GeometryUtils.java @@ -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); diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java index 2d3d8070..80505a4a 100644 --- a/src/org/oscim/view/MapView.java +++ b/src/org/oscim/view/MapView.java @@ -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(); @@ -177,7 +176,7 @@ public class MapView extends RelativeLayout { if (!mMapViewPosition.isValid()) { Log.d(TAG, "set default start position"); - setMapCenter(new MapPosition(new GeoPoint(0,0), (byte) 2, 1)); + setMapCenter(new MapPosition(new GeoPoint(0, 0), (byte) 2, 1)); } LayoutParams params = new LayoutParams( @@ -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. * @@ -291,7 +288,7 @@ public class MapView extends RelativeLayout { if (forceRedraw) render(); - if (mClearMap){ + if (mClearMap) { mTileManager.init(mWidth, mHeight); mClearMap = false; @@ -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); @@ -314,7 +309,7 @@ public class MapView extends RelativeLayout { } } - private void clearMap(){ + private void clearMap() { // clear tile and overlay data before next draw mClearMap = true; } @@ -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(); - // } } diff --git a/src/org/oscim/view/MapViewPosition.java b/src/org/oscim/view/MapViewPosition.java index 3b5dce38..ef4d23cd 100644 --- a/src/org/oscim/view/MapViewPosition.java +++ b/src/org/oscim/view/MapViewPosition.java @@ -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,10 +239,8 @@ 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]; - } + coords[position + 0] = mv[0] / mv[3]; + coords[position + 1] = mv[1] / mv[3]; } /** @return the current center point of the MapView. */ @@ -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; - } + 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; + 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(); + + // ----- mScale = FastMath.clamp((float) (1 + (z - mZoomLevel)), 1, MAX_END_SCALE); + + //mMapScale = (1 << mZoomLevel) * mScale; //Log.d(TAG, "zoom: " + bbox + " " + zx + " " + zy + " / " + mScale + " " + mZoomLevel); - setMapCenter(bbox.getCenterPoint()); + //updatePosition(); - // 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); + // 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); - - 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(true); + 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; + } + + 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 mMapViewPosition; private static final int MSG = 1; diff --git a/src/org/oscim/view/MapZoomControls.java b/src/org/oscim/view/MapZoomControls.java index c8e7e606..d407b6fe 100644 --- a/src/org/oscim/view/MapZoomControls.java +++ b/src/org/oscim/view/MapZoomControls.java @@ -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 . - */ -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. - *

- * 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 . +// */ +//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. +// *

+// * 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); +// } +//} diff --git a/src/org/oscim/view/TouchHandler.java b/src/org/oscim/view/TouchHandler.java index e7274487..2c033062 100644 --- a/src/org/oscim/view/TouchHandler.java +++ b/src/org/oscim/view/TouchHandler.java @@ -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; //