Permalink
Browse files

feature/#790: map scale merged into floating point zoom (#800)

* feature/#728 - related: more verbose assertions
Not very often the unit test fails. With more verbose assertions, we will be able to find out why.

Impacted class:
* `OpenStreetMapViewTest`: more verbose assertions

* feature/#790: map scale merged into floating point zoom

This is just a teaser, there are things to fix. For instance, the pinch gesture center is not yet taking into consideration (zooming in or out scrolls the map to the bottom right).
All comments are welcomed.

Impacted classes:
* `CompassOverlay`: used the new `Canvas` related `Matrix` methods of `Projection`
* `CopyrightOverlay`: used the new `Canvas` related `Matrix` methods of `Projection`
* `LinearRing`: integrated the fact that there's no map scale anymore / should be considered as equal to 1
* `MapController`
  * feature-related: edited `zoomToFixing` and `onAnimationUpdate`; simplified `onAnimationEnd`
  * refactoring: removed members `mZoomInAnimation` and `mZoomOutAnimation`; simplified methods `zoomIn`, `zoomInFixing`, `zoomOut`, `zoomOutFixing`
* `MapView`
  * feature-related: removed members `ZOOM_SENSITIVITY`, `ZOOM_LOG_BASE_INV`, `mTargetZoomLevel` and `mMultiTouchScale`; deprecated methods `getZoomLevel(final boolean aPending)`, `zoomIn`, `zoomOut` and `getMapScale`; simplified `canZoomIn` and `canZoomOut`; optimized `dispatchDraw` using the new `Canvas` related `Matrix` methods of `Projection`; created new methods `startAnimation`, `setMultiTouchScale` and new member `mStartAnimationZoom`; impacted pinch gesture methods `getPositionAndScale`, `selectObject` and `setPositionAndScale`
  * refactoring: removed members `sMotionEventTransformMethod` and `mMercatorPoint`; deprecated methods `getLatitudeSpan`, `getLongitudeSpan` and `getBoundingBoxE6`; simplified method `rotateTouchEvent`
* `MinimapOverlay`: removed the "display only when not animating" restriction
* `Projection`
  * feature-related: removed member `float mMultiTouchScale`; removed parameter `pScale` from constructor; removed scale operations from matrices; optimized the computation of `mCurrentCenter`; added methods `save` and `restore` that apply the matrices to canvas only if necessary.
  * refactoring: renamed member as `mWrapEnabled`; simplified the initialization of `mScreenRectProjection`; added generic method `apply` that apply a `Matrix` to a `Point`
* `ScaleBarOverlay`: used the new `Canvas` related `Matrix` methods of `Projection`
* `ZoomButtonsOverlay`: used the new `Canvas` related `Matrix` methods of `Projection`; restricted the zoom action to a `ACTION_UP` event

* Desperate try to resolve conflict

* Desperate try to resolve conflict

* Desperate try to resolve conflict

* Desperate try to resolve conflict

* Merging the pinch gesture scale into floating point zoom (last fix?)

Impacted classes:
* `Projection`: rewrote the code in order to comply with `ProjectionTest`'s important notice (cf. javadoc)
* `ProjectionTest`: fixed the call to `Projection` constructor

* Lousy attempt to decrease the time taken by travis.

Impacted classes:
* `ExtraSamplesTest`: limited to 60 the number of items to run.
  • Loading branch information...
monsieurtanuki authored and spyhunter99 committed Dec 16, 2017
1 parent c2f942c commit 850580d87264eb6dd9dc04d85453aa3b2711071d
@@ -73,6 +73,10 @@ private void executeTest(ISampleFactory sampleFactory){
Log.i(SamplesMenuFragment.TAG, "Memory allocation: INIT Free: " + Runtime.getRuntime().freeMemory() + " Total:" + Runtime.getRuntime().totalMemory() + " Max:" + Runtime.getRuntime().maxMemory());
for (int i = 0; i < fireOrder.length; i++) {
// lousy attempt to decrease the time taken by travis
if (i > 60) {
break;
}
for (int k = 0; k < 1; k++) {
@@ -117,8 +117,12 @@ private void checkCenter(final Projection pProjection, final GeoPoint pCenter, f
final Point point = pProjection.toPixels(pCenter, null);
assertTrue("MapView does not have layout. Make sure device is unlocked.", width_2 > 0 && height_2 > 0);
final Point expected = new Point(width_2, height_2);
assertEquals("the " + tag + " center of the map is in the pixel center of the map (X)", expected.x, point.x, roundingTolerance);
assertEquals("the " + tag + " center of the map is in the pixel center of the map (Y)", expected.y, point.y, roundingTolerance);
assertEquals("the " + tag + " center of the map is in the pixel center of the map (X)"
+"(zoom=" + pProjection.getZoomLevel() + ",center=" + pCenter + ")",
expected.x, point.x, roundingTolerance);
assertEquals("the " + tag + " center of the map is in the pixel center of the map (Y)"
+ "(zoom=" + pProjection.getZoomLevel() + ",center=" + pCenter + ")",
expected.y, point.y, roundingTolerance);
}
/**
@@ -5,7 +5,6 @@
import static org.osmdroid.util.MyMath.gudermannInverse;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.osmdroid.api.IGeoPoint;
@@ -32,20 +31,27 @@
// Fields
// ===========================================================
protected final double mLatNorth;
protected final double mLatSouth;
protected final double mLonEast;
protected final double mLonWest;
private double mLatNorth;
private double mLatSouth;
private double mLonEast;
private double mLonWest;
// ===========================================================
// Constructors
// ===========================================================
public BoundingBox(final double north, final double east, final double south, final double west) {
this.mLatNorth = north;
this.mLonEast = east;
this.mLatSouth = south;
this.mLonWest = west;
set(north, east, south, west);
}
/**
* @since 6.0.0
*/
public void set(final double north, final double east, final double south, final double west) {
mLatNorth = north;
mLonEast = east;
mLatSouth = south;
mLonWest = west;
//validate the values
// 30 > 0 OK
// 30 < 0 not ok
@@ -19,7 +19,6 @@
import org.osmdroid.events.ZoomEvent;
import org.osmdroid.util.BoundingBox;
import org.osmdroid.util.BoundingBoxE6;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView.OnFirstLayoutListener;
import org.osmdroid.views.util.MyMath;
@@ -43,8 +42,6 @@
protected final MapView mMapView;
// Zoom animations
private ValueAnimator mZoomInAnimation;
private ValueAnimator mZoomOutAnimation;
private ScaleAnimation mZoomInAnimationOld;
private ScaleAnimation mZoomOutAnimationOld;
@@ -67,18 +64,7 @@ public MapController(MapView mapView) {
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ZoomAnimatorListener zoomAnimatorListener = new ZoomAnimatorListener(this);
mZoomInAnimation = ValueAnimator.ofFloat(1f, 2f);
mZoomInAnimation.addListener(zoomAnimatorListener);
mZoomInAnimation.addUpdateListener(zoomAnimatorListener);
mZoomInAnimation.setDuration(Configuration.getInstance().getAnimationSpeedShort());
mZoomOutAnimation = ValueAnimator.ofFloat(1f, 0.5f);
mZoomOutAnimation.addListener(zoomAnimatorListener);
mZoomOutAnimation.addUpdateListener(zoomAnimatorListener);
mZoomOutAnimation.setDuration(Configuration.getInstance().getAnimationSpeedShort());
} else {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
ZoomAnimationListener zoomAnimationListener = new ZoomAnimationListener(this);
mZoomInAnimationOld = new ScaleAnimation(1, 2, 1, 2, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
@@ -254,12 +240,12 @@ public double setZoom(final double pZoomlevel) {
*/
@Override
public boolean zoomIn() {
return zoomTo(mMapView.getZoomLevel(false) + 1);
return zoomIn(null);
}
@Override
public boolean zoomIn(Long animationSpeed) {
return zoomTo(mMapView.getZoomLevel(false) + 1, animationSpeed);
return zoomTo(mMapView.getZoomLevelDouble() + 1, animationSpeed);
}
/**
@@ -270,106 +256,44 @@ public boolean zoomIn(Long animationSpeed) {
*/
@Override
public boolean zoomInFixing(final int xPixel, final int yPixel, Long zoomAnimation) {
mMapView.mMultiTouchScalePoint.set(xPixel, yPixel);
if (mMapView.canZoomIn()) {
double newZoomLevel = Math.min(mMapView.getZoomLevelDouble() + 1, mMapView.getMaxZoomLevel());
if (mMapView.mListener != null) {
mMapView.mListener.onZoom(new ZoomEvent(mMapView, newZoomLevel));
}
if (mMapView.mIsAnimating.getAndSet(true)) {
// TODO extend zoom (and return true)
return false;
} else {
float zoomDiffScale = (float) Math.pow(2.0, newZoomLevel - mMapView.getZoomLevel(false));
mMapView.mTargetZoomLevel.set(newZoomLevel);
if (zoomAnimation == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mCurrentAnimator = mZoomInAnimation;
mZoomInAnimation.setFloatValues(1f, zoomDiffScale);
mZoomInAnimation.start();
} else {
mMapView.startAnimation(mZoomInAnimationOld);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ZoomAnimatorListener zoomAnimatorListener = new ZoomAnimatorListener(this);
ValueAnimator mZoomInAnimation = ValueAnimator.ofFloat(1f, zoomDiffScale);
mZoomInAnimation.addListener(zoomAnimatorListener);
mZoomInAnimation.addUpdateListener(zoomAnimatorListener);
mZoomInAnimation.setDuration(Configuration.getInstance().getAnimationSpeedShort());
mZoomInAnimation.start();
} else {
ZoomAnimationListener zoomAnimationListener = new ZoomAnimationListener(this);
ScaleAnimation mZoomInAnimationOld = new ScaleAnimation(
1, zoomDiffScale, 1, zoomDiffScale,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
mZoomInAnimationOld.setDuration(Configuration.getInstance().getAnimationSpeedShort());
mZoomInAnimationOld.setAnimationListener(zoomAnimationListener);
mMapView.startAnimation(mZoomInAnimationOld);
}
}
return true;
}
} else {
return false;
}
return zoomToFixing(mMapView.getZoomLevelDouble() + 1, xPixel, yPixel, zoomAnimation);
}
@Override
public boolean zoomInFixing(final int xPixel, final int yPixel) {
return this.zoomInFixing(xPixel, yPixel, null);
return zoomInFixing(xPixel, yPixel, null);
}
@Override
public boolean zoomOut(Long animationSpeed) {
return zoomTo(mMapView.getZoomLevel(false) - 1, animationSpeed);
return zoomTo(mMapView.getZoomLevelDouble() - 1, animationSpeed);
}
/**
* Zoom out by one zoom level.
*/
@Override
public boolean zoomOut() {
return zoomTo(mMapView.getZoomLevel(false) - 1);
return zoomOut(null);
}
@Deprecated
@Override
public boolean zoomOutFixing(final int xPixel, final int yPixel) {
mMapView.mMultiTouchScalePoint.set(xPixel, yPixel);
if (mMapView.canZoomOut()) {
if (mMapView.mListener != null) {
mMapView.mListener.onZoom(new ZoomEvent(mMapView, mMapView.getZoomLevelDouble() - 1));
}
if (mMapView.mIsAnimating.getAndSet(true)) {
// TODO extend zoom (and return true)
return false;
} else {
mMapView.mTargetZoomLevel.set(mMapView.getZoomLevel(false) - 1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mCurrentAnimator = mZoomOutAnimation;
mZoomOutAnimation.start();
} else {
mMapView.startAnimation(mZoomOutAnimationOld);
}
return true;
}
} else {
return false;
}
return zoomToFixing(mMapView.getZoomLevelDouble() - 1, xPixel, yPixel, null);
}
@Override
public boolean zoomTo(int zoomLevel) {
return zoomToFixing(zoomLevel, mMapView.getWidth() / 2, mMapView.getHeight() / 2);
return zoomTo(zoomLevel, null);
}
/**
* @since 6.0
*/
@Override
public boolean zoomTo(int zoomLevel, Long animationSpeed) {
return zoomToFixing(zoomLevel, mMapView.getWidth() / 2, mMapView.getHeight() / 2, animationSpeed);
return zoomTo((double)zoomLevel, animationSpeed);
}
/**
@@ -390,8 +314,9 @@ public boolean zoomTo(double pZoomLevel, Long animationSpeed) {
return zoomToFixing(pZoomLevel, mMapView.getWidth() / 2, mMapView.getHeight() / 2, animationSpeed);
}
@Override
public boolean zoomTo(double pZoomLevel) {
return zoomToFixing(pZoomLevel, mMapView.getWidth() / 2, mMapView.getHeight() / 2);
return zoomTo(pZoomLevel, null);
}
@@ -404,64 +329,61 @@ public boolean zoomToFixing(double zoomLevel, int xPixel, int yPixel, Long zoomA
boolean canZoom = zoomLevel < currentZoomLevel && mMapView.canZoomOut() ||
zoomLevel > currentZoomLevel && mMapView.canZoomIn();
mMapView.mMultiTouchScalePoint.set(xPixel, yPixel);
if (canZoom) {
if (mMapView.mListener != null) {
mMapView.mListener.onZoom(new ZoomEvent(mMapView, zoomLevel));
}
if (mMapView.mIsAnimating.getAndSet(true)) {
// TODO extend zoom (and return true)
return false;
} else {
mMapView.mTargetZoomLevel.set(zoomLevel);
float end = (float) Math.pow(2.0, zoomLevel - currentZoomLevel);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ZoomAnimatorListener zoomAnimatorListener = new ZoomAnimatorListener(this);
ValueAnimator zoomToAnimator = ValueAnimator.ofFloat(1f, end);
zoomToAnimator.addListener(zoomAnimatorListener);
zoomToAnimator.addUpdateListener(zoomAnimatorListener);
if (zoomAnimationSpeed == null) {
zoomToAnimator.setDuration(Configuration.getInstance().getAnimationSpeedShort());
} else {
zoomToAnimator.setDuration(zoomAnimationSpeed);
}
mCurrentAnimator = zoomToAnimator;
zoomToAnimator.start();
} else {
if (zoomLevel > currentZoomLevel)
mMapView.startAnimation(mZoomInAnimationOld);
else
mMapView.startAnimation(mZoomOutAnimationOld);
ScaleAnimation scaleAnimation;
scaleAnimation = new ScaleAnimation(
1f, end, //X
1f, end, //Y
Animation.RELATIVE_TO_SELF, 0.5f, //Pivot X
Animation.RELATIVE_TO_SELF, 0.5f); //Pivot Y
if (zoomAnimationSpeed == null) {
scaleAnimation.setDuration(Configuration.getInstance().getAnimationSpeedShort());
} else {
scaleAnimation.setDuration(zoomAnimationSpeed);
}
scaleAnimation.setAnimationListener(new ZoomAnimationListener(this));
if (!canZoom) {
return false;
}
if (mMapView.mIsAnimating.getAndSet(true)) {
// TODO extend zoom (and return true)
return false;
}
if (mMapView.mListener != null) {
mMapView.mListener.onZoom(new ZoomEvent(mMapView, zoomLevel));
}
mMapView.setMultiTouchScaleInitPoint(xPixel, yPixel);
mMapView.startAnimation();
}
return true;
float end = (float) Math.pow(2.0, zoomLevel - currentZoomLevel);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ZoomAnimatorListener zoomAnimatorListener = new ZoomAnimatorListener(this);
ValueAnimator zoomToAnimator = ValueAnimator.ofFloat(1f, end);
zoomToAnimator.addListener(zoomAnimatorListener);
zoomToAnimator.addUpdateListener(zoomAnimatorListener);
if (zoomAnimationSpeed == null) {
zoomToAnimator.setDuration(Configuration.getInstance().getAnimationSpeedShort());
} else {
zoomToAnimator.setDuration(zoomAnimationSpeed);
}
mCurrentAnimator = zoomToAnimator;
zoomToAnimator.start();
return true;
}
if (zoomLevel > currentZoomLevel)
mMapView.startAnimation(mZoomInAnimationOld);
else
mMapView.startAnimation(mZoomOutAnimationOld);
ScaleAnimation scaleAnimation;
scaleAnimation = new ScaleAnimation(
1f, end, //X
1f, end, //Y
Animation.RELATIVE_TO_SELF, 0.5f, //Pivot X
Animation.RELATIVE_TO_SELF, 0.5f); //Pivot Y
if (zoomAnimationSpeed == null) {
scaleAnimation.setDuration(Configuration.getInstance().getAnimationSpeedShort());
} else {
return false;
scaleAnimation.setDuration(zoomAnimationSpeed);
}
scaleAnimation.setAnimationListener(new ZoomAnimationListener(this));
return true;
}
/**
* @since 6.0
*/
@Override
public boolean zoomToFixing(double zoomLevel, int xPixel, int yPixel) {
return this.zoomToFixing(zoomLevel, xPixel, yPixel, (Long) null);
return zoomToFixing(zoomLevel, xPixel, yPixel, null);
}
@Override
@@ -475,18 +397,11 @@ protected void onAnimationStart() {
}
protected void onAnimationEnd() {
final GeoPoint currentCenter = mMapView.getProjection().getCurrentCenter();
final double newZoom = mMapView.mTargetZoomLevel.get();
mMapView.mIsAnimating.set(false);
setZoom(newZoom);
mMapView.setCenter(currentCenter);
mMapView.mMultiTouchScale = 1f;
mMapView.resetMultiTouchScale();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mCurrentAnimator = null;
}
// Fix for issue 477
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
} else { // Fix for issue 477
mMapView.clearAnimation();
mZoomInAnimationOld.reset();
mZoomOutAnimationOld.reset();
@@ -525,7 +440,7 @@ public void onAnimationRepeat(Animator animator) {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mMapController.mMapView.mMultiTouchScale = (Float) valueAnimator.getAnimatedValue();
mMapController.mMapView.setMultiTouchScale((Float) valueAnimator.getAnimatedValue());
mMapController.mMapView.invalidate();
}
}
Oops, something went wrong.

0 comments on commit 850580d

Please sign in to comment.