some Animator improvements
- fixes annoying zoomTo jumping
This commit is contained in:
parent
5d07d45f86
commit
46878c81b7
@ -80,6 +80,21 @@ public class MapPosition {
|
||||
this.zoomLevel = other.zoomLevel;
|
||||
}
|
||||
|
||||
public void set(double x, double y, double scale, float rotation, float tilt) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.scale = scale;
|
||||
|
||||
while (rotation > 180)
|
||||
rotation -= 360;
|
||||
while (rotation < -180)
|
||||
rotation += 360;
|
||||
this.angle = rotation;
|
||||
|
||||
this.tilt = tilt;
|
||||
this.zoomLevel = FastMath.log2((int) scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return scale relative to zoom-level.
|
||||
*/
|
||||
|
@ -26,30 +26,28 @@ import org.oscim.core.MapPosition;
|
||||
import org.oscim.core.Point;
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.renderer.MapRenderer;
|
||||
|
||||
// TODO: rewrite
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Animator {
|
||||
static final Logger log = LoggerFactory.getLogger(Animator.class);
|
||||
|
||||
//static final Logger log = LoggerFactory.getLogger(MapAnimator.class);
|
||||
|
||||
public Animator(Map map, Viewport viewport) {
|
||||
mViewport = viewport;
|
||||
public Animator(Map map) {
|
||||
mMap = map;
|
||||
}
|
||||
|
||||
private final int ANIM_NONE = 0;
|
||||
private final int ANIM_MOVE = 1 << 0;
|
||||
private final int ANIM_SCALE = 1 << 1;
|
||||
private final int ANIM_FLING = 1 << 2;
|
||||
private final int ANIM_BBOX = 1 << 3;
|
||||
private final int ANIM_ROTATE = 1 << 4;
|
||||
private final int ANIM_TILT = 1 << 5;
|
||||
private final int ANIM_ROTATE = 1 << 2;
|
||||
private final int ANIM_TILT = 1 << 3;
|
||||
private final int ANIM_FLING = 1 << 4;
|
||||
|
||||
private final Map mMap;
|
||||
private final Viewport mViewport;
|
||||
|
||||
private final MapPosition mPos = new MapPosition();
|
||||
private final MapPosition mCurPos = new MapPosition();
|
||||
private final MapPosition mStartPos = new MapPosition();
|
||||
private final MapPosition mDeltaPos = new MapPosition();
|
||||
|
||||
@ -57,125 +55,97 @@ public class Animator {
|
||||
private final Point mPivot = new Point();
|
||||
private final Point mVelocity = new Point();
|
||||
|
||||
private double mScaleBy;
|
||||
|
||||
private float mDuration = 500;
|
||||
private long mAnimEnd = -1;
|
||||
|
||||
private int mState = ANIM_NONE;
|
||||
|
||||
public synchronized void animateTo(BoundingBox bbox) {
|
||||
public synchronized void animateTo(long duration, BoundingBox bbox) {
|
||||
mMap.getMapPosition(mStartPos);
|
||||
/* TODO for large distance first scale out, then in
|
||||
* calculate the maximum scale at which the bbox is completely visible */
|
||||
* calculate the maximum scale at which the BoundingBox
|
||||
* is completely visible */
|
||||
double dx = Math.abs(longitudeToX(bbox.getMaxLongitude())
|
||||
- longitudeToX(bbox.getMinLongitude()));
|
||||
|
||||
double dy = Math.abs(latitudeToY(bbox.getMinLatitude())
|
||||
- latitudeToY(bbox.getMaxLatitude()));
|
||||
|
||||
log.debug("anim bbox " + bbox);
|
||||
|
||||
double zx = mMap.getWidth() / (dx * Tile.SIZE);
|
||||
double zy = mMap.getHeight() / (dy * Tile.SIZE);
|
||||
double newScale = Math.min(zx, zy);
|
||||
|
||||
animateTo(500, bbox.getCenterPoint(), newScale, false);
|
||||
GeoPoint p = bbox.getCenterPoint();
|
||||
|
||||
mState = ANIM_MOVE | ANIM_SCALE | ANIM_BBOX;
|
||||
mDeltaPos.set(longitudeToX(p.getLongitude()) - mStartPos.x,
|
||||
latitudeToY(p.getLatitude()) - mStartPos.y,
|
||||
newScale - mStartPos.scale,
|
||||
-mStartPos.angle,
|
||||
-mStartPos.tilt);
|
||||
|
||||
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
|
||||
}
|
||||
|
||||
public synchronized void animateTo(long duration, GeoPoint geoPoint, double scale,
|
||||
boolean relative) {
|
||||
public synchronized void animateTo(BoundingBox bbox) {
|
||||
animateTo(1000, bbox);
|
||||
}
|
||||
|
||||
mViewport.getMapPosition(mPos);
|
||||
public synchronized void animateTo(long duration, GeoPoint geoPoint,
|
||||
double scale, boolean relative) {
|
||||
mMap.getMapPosition(mStartPos);
|
||||
|
||||
if (relative) {
|
||||
if (mAnimEnd > 0 && (mState & ANIM_SCALE) != 0)
|
||||
scale = mDeltaPos.scale * scale;
|
||||
else
|
||||
scale = mPos.scale * scale;
|
||||
}
|
||||
if (relative)
|
||||
scale = mStartPos.scale * scale;
|
||||
|
||||
scale = clamp(scale, Viewport.MIN_SCALE, Viewport.MAX_SCALE);
|
||||
mDeltaPos.scale = scale;
|
||||
|
||||
mScaleBy = scale - mPos.scale;
|
||||
mDeltaPos.set(longitudeToX(geoPoint.getLongitude()) - mStartPos.x,
|
||||
latitudeToY(geoPoint.getLatitude()) - mStartPos.y,
|
||||
scale - mStartPos.scale,
|
||||
0, 0);
|
||||
|
||||
mStartPos.scale = mPos.scale;
|
||||
mStartPos.angle = mPos.angle;
|
||||
animStart(duration, ANIM_MOVE | ANIM_SCALE);
|
||||
}
|
||||
|
||||
mStartPos.x = mPos.x;
|
||||
mStartPos.y = mPos.y;
|
||||
|
||||
mDeltaPos.x = longitudeToX(geoPoint.getLongitude());
|
||||
mDeltaPos.y = latitudeToY(geoPoint.getLatitude());
|
||||
|
||||
mDeltaPos.x -= mStartPos.x;
|
||||
mDeltaPos.y -= mStartPos.y;
|
||||
|
||||
mState = ANIM_MOVE | ANIM_SCALE;
|
||||
|
||||
animStart(duration);
|
||||
public synchronized void animateTo(GeoPoint p) {
|
||||
animateTo(500, p, 1, true);
|
||||
}
|
||||
|
||||
public synchronized void animateTo(long duration, MapPosition pos) {
|
||||
|
||||
mViewport.getMapPosition(mPos);
|
||||
mMap.getMapPosition(mStartPos);
|
||||
|
||||
pos.scale = clamp(pos.scale,
|
||||
Viewport.MIN_SCALE,
|
||||
Viewport.MAX_SCALE);
|
||||
mDeltaPos.scale = pos.scale;
|
||||
|
||||
mScaleBy = pos.scale - mPos.scale;
|
||||
mDeltaPos.set(pos.x - mStartPos.x,
|
||||
pos.y - mStartPos.y,
|
||||
pos.scale - mStartPos.scale,
|
||||
mStartPos.angle - pos.angle,
|
||||
clamp(pos.tilt, 0, Viewport.MAX_TILT) - mStartPos.tilt);
|
||||
|
||||
mStartPos.x = mPos.x;
|
||||
mStartPos.y = mPos.y;
|
||||
mStartPos.scale = mPos.scale;
|
||||
mStartPos.angle = mPos.angle;
|
||||
mStartPos.tilt = mPos.tilt;
|
||||
|
||||
mDeltaPos.x = longitudeToX(pos.getLongitude()) - mStartPos.x;
|
||||
mDeltaPos.y = latitudeToY(pos.getLatitude()) - mStartPos.y;
|
||||
|
||||
mDeltaPos.angle = mStartPos.angle - pos.angle;
|
||||
while (mDeltaPos.angle > 180)
|
||||
mDeltaPos.angle -= 360;
|
||||
while (mDeltaPos.angle < -180)
|
||||
mDeltaPos.angle += 360;
|
||||
|
||||
mDeltaPos.tilt = clamp(pos.tilt, 0, Viewport.MAX_TILT) - mStartPos.tilt;
|
||||
|
||||
mState = ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT;
|
||||
|
||||
animStart(duration);
|
||||
animStart(duration, ANIM_MOVE | ANIM_SCALE | ANIM_ROTATE | ANIM_TILT);
|
||||
}
|
||||
|
||||
public synchronized void animateZoom(long duration, double scale, float pivotX, float pivotY) {
|
||||
public synchronized void animateZoom(long duration, double scaleBy,
|
||||
float pivotX, float pivotY) {
|
||||
mMap.getMapPosition(mStartPos);
|
||||
|
||||
mViewport.getMapPosition(mPos);
|
||||
|
||||
if (mAnimEnd > 0 && (mState & ANIM_SCALE) != 0)
|
||||
scale = mDeltaPos.scale * scale;
|
||||
if (mState == ANIM_SCALE)
|
||||
scaleBy = (mStartPos.scale + mDeltaPos.scale) * scaleBy;
|
||||
else
|
||||
scale = mPos.scale * scale;
|
||||
scaleBy = mStartPos.scale * scaleBy;
|
||||
|
||||
scale = clamp(scale, Viewport.MIN_SCALE, Viewport.MAX_SCALE);
|
||||
mDeltaPos.scale = scale;
|
||||
scaleBy = clamp(scaleBy, Viewport.MIN_SCALE, Viewport.MAX_SCALE);
|
||||
|
||||
mScaleBy = scale - mPos.scale;
|
||||
|
||||
mStartPos.scale = mPos.scale;
|
||||
mStartPos.angle = mPos.angle;
|
||||
mDeltaPos.scale = scaleBy - mStartPos.scale;
|
||||
|
||||
mPivot.x = pivotX;
|
||||
mPivot.y = pivotY;
|
||||
|
||||
mState = ANIM_SCALE;
|
||||
|
||||
animStart(duration);
|
||||
}
|
||||
|
||||
public synchronized void animateTo(GeoPoint geoPoint) {
|
||||
animateTo(300, geoPoint, 1, true);
|
||||
animStart(duration, ANIM_SCALE);
|
||||
}
|
||||
|
||||
public synchronized void animateFling(int velocityX, int velocityY,
|
||||
@ -184,7 +154,7 @@ public class Animator {
|
||||
if (velocityX * velocityX + velocityY * velocityY < 2048)
|
||||
return;
|
||||
|
||||
mViewport.getMapPosition(mPos);
|
||||
mMap.getMapPosition(mStartPos);
|
||||
|
||||
mScroll.x = 0;
|
||||
mScroll.y = 0;
|
||||
@ -198,12 +168,12 @@ public class Animator {
|
||||
clamp(mVelocity.x, minX, maxX);
|
||||
clamp(mVelocity.y, minY, maxY);
|
||||
|
||||
mState = ANIM_FLING;
|
||||
|
||||
animStart(duration);
|
||||
animStart(duration, ANIM_FLING);
|
||||
}
|
||||
|
||||
private void animStart(float duration) {
|
||||
private void animStart(float duration, int state) {
|
||||
mState = state;
|
||||
mCurPos.copy(mStartPos);
|
||||
mDuration = duration;
|
||||
mAnimEnd = System.currentTimeMillis() + (long) duration;
|
||||
mMap.render();
|
||||
@ -225,30 +195,13 @@ public class Animator {
|
||||
long millisLeft = mAnimEnd - MapRenderer.frametime;
|
||||
|
||||
boolean changed = false;
|
||||
synchronized (mViewport) {
|
||||
Viewport v = mViewport;
|
||||
|
||||
Viewport v = mMap.viewport();
|
||||
|
||||
synchronized (v) {
|
||||
/* cancel animation when position was changed since last
|
||||
* update, i.e. when it was modified outside the animator. */
|
||||
if (v.getMapPosition(mPos)) {
|
||||
animCancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (millisLeft <= 0) {
|
||||
/* set final position */
|
||||
if ((mState & ANIM_MOVE) != 0)
|
||||
v.moveTo(mStartPos.x + mDeltaPos.x,
|
||||
mStartPos.y + mDeltaPos.y);
|
||||
|
||||
if ((mState & ANIM_SCALE) != 0) {
|
||||
if (mScaleBy > 0)
|
||||
doScale(mStartPos.scale + (mScaleBy - 1));
|
||||
else
|
||||
doScale(mStartPos.scale + mScaleBy);
|
||||
}
|
||||
|
||||
mMap.updateMap(true);
|
||||
if (v.getMapPosition(mCurPos)) {
|
||||
animCancel();
|
||||
return;
|
||||
}
|
||||
@ -256,25 +209,12 @@ public class Animator {
|
||||
float adv = clamp(1.0f - millisLeft / mDuration, 0, 1);
|
||||
|
||||
if ((mState & ANIM_SCALE) != 0) {
|
||||
if (mScaleBy > 0)
|
||||
doScale(mStartPos.scale + (mScaleBy * (Math.pow(2, adv) - 1)));
|
||||
else
|
||||
doScale(mStartPos.scale + (mScaleBy * adv));
|
||||
|
||||
changed = true;
|
||||
doScale(v, adv);
|
||||
}
|
||||
|
||||
if ((mState & ANIM_MOVE) != 0) {
|
||||
v.moveTo(mStartPos.x + mDeltaPos.x * adv,
|
||||
mStartPos.y + mDeltaPos.y * adv);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ((mState & ANIM_BBOX) != 0) {
|
||||
if (mPos.angle > 180)
|
||||
mPos.angle -= 360;
|
||||
v.setRotation(mPos.angle * (1 - adv));
|
||||
v.setTilt(mPos.tilt * (1 - adv));
|
||||
}
|
||||
|
||||
if ((mState & ANIM_FLING) != 0) {
|
||||
@ -282,30 +222,27 @@ public class Animator {
|
||||
double dx = mVelocity.x * adv;
|
||||
double dy = mVelocity.y * adv;
|
||||
if ((dx - mScroll.x) != 0 || (dy - mScroll.y) != 0) {
|
||||
|
||||
v.moveMap((float) (dx - mScroll.x),
|
||||
(float) (dy - mScroll.y));
|
||||
mScroll.x = dx;
|
||||
mScroll.y = dy;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if ((mState & ANIM_ROTATE) != 0) {
|
||||
v.setRotation(mStartPos.angle + mDeltaPos.angle * adv);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ((mState & ANIM_TILT) != 0) {
|
||||
v.setTilt(mStartPos.tilt + mDeltaPos.tilt * adv);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/* remember current map position */
|
||||
v.getMapPosition(mPos);
|
||||
if (millisLeft <= 0)
|
||||
animCancel();
|
||||
|
||||
/* remember current map position */
|
||||
changed = v.getMapPosition(mCurPos);
|
||||
}
|
||||
|
||||
/* continue animation */
|
||||
if (changed) {
|
||||
/* render and inform layers that position has changed */
|
||||
mMap.updateMap(true);
|
||||
@ -315,9 +252,13 @@ public class Animator {
|
||||
}
|
||||
}
|
||||
|
||||
private void doScale(double newScale) {
|
||||
mViewport.scaleMap((float) (newScale / mPos.scale),
|
||||
(float) mPivot.x, (float) mPivot.y);
|
||||
private void doScale(Viewport v, float adv) {
|
||||
double newScale;
|
||||
|
||||
newScale = mStartPos.scale + (mDeltaPos.scale * adv);
|
||||
|
||||
v.scaleMap((float) (newScale / mCurPos.scale),
|
||||
(float) mPivot.x, (float) mPivot.y);
|
||||
}
|
||||
|
||||
public synchronized void cancel() {
|
||||
|
@ -83,12 +83,13 @@ public abstract class Map {
|
||||
mViewport = new Viewport(this);
|
||||
mAnimator = new Animator(this, mViewport);
|
||||
|
||||
mMapPosition = new MapPosition();
|
||||
mLayers = new Layers(this);
|
||||
mAsyncExecutor = new AsyncExecutor(2);
|
||||
mMapPosition = new MapPosition();
|
||||
|
||||
mEventLayer = new MapEventLayer(this);
|
||||
mLayers.add(0, mEventLayer);
|
||||
|
||||
}
|
||||
|
||||
public MapEventLayer getEventLayer() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user