diff options
| author | Bananeweizen <bananeweizen@gmx.de> | 2013-08-20 08:05:48 +0200 |
|---|---|---|
| committer | Bananeweizen <bananeweizen@gmx.de> | 2013-08-20 08:05:48 +0200 |
| commit | c08ef3d80d4847389f0e6a39a254d6ec567260f8 (patch) | |
| tree | 672d4f29dd8dd4542ba84dbcca1676040189b794 | |
| parent | 672b3ca96cfb8273c0eafaa0ed3e1da73244af39 (diff) | |
| download | cgeo-c08ef3d80d4847389f0e6a39a254d6ec567260f8.zip cgeo-c08ef3d80d4847389f0e6a39a254d6ec567260f8.tar.gz cgeo-c08ef3d80d4847389f0e6a39a254d6ec567260f8.tar.bz2 | |
fix #2867: Multiple distance
* workaround distance calculation for all 4.2.x versions
| -rw-r--r-- | main/src/cgeo/geocaching/geopoint/Geopoint.java | 52 | ||||
| -rw-r--r-- | tests/src/cgeo/geocaching/geopoint/GeopointTest.java | 15 |
2 files changed, 53 insertions, 14 deletions
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/geopoint/Geopoint.java index e8a6dff..547ad29 100644 --- a/main/src/cgeo/geocaching/geopoint/Geopoint.java +++ b/main/src/cgeo/geocaching/geopoint/Geopoint.java @@ -6,6 +6,7 @@ import cgeo.geocaching.R; import org.apache.commons.lang3.StringUtils; import android.location.Location; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -13,12 +14,16 @@ import android.os.Parcelable; * Abstraction of geographic point. */ public final class Geopoint implements ICoordinates, Parcelable { - public static final double deg2rad = Math.PI / 180; - public static final double rad2deg = 180 / Math.PI; - public static final float erad = 6371.0f; - public static final Geopoint ZERO = new Geopoint(0.0, 0.0); + private static final double DEG_TO_RAD = Math.PI / 180; + private static final double RAD_TO_DEG = 180 / Math.PI; + private static final float EARTH_RADIUS = 6371.0f; + /** + * JIT bug in Android 4.2.1 + */ + private static final boolean DISTANCE_BROKEN = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1; + private final double latitude; private final double longitude; @@ -209,7 +214,11 @@ public final class Geopoint implements ICoordinates, Parcelable { * if there is an error in distance calculation */ public float distanceTo(final ICoordinates point) { - return pathTo(point.getCoords())[0] / 1000; + final Geopoint otherCoords = point.getCoords(); + if (DISTANCE_BROKEN) { + return (float) (getDistance(latitude, longitude, otherCoords.latitude, otherCoords.longitude) / 1000); + } + return pathTo(otherCoords)[0] / 1000; } /** @@ -235,15 +244,15 @@ public final class Geopoint implements ICoordinates, Parcelable { * @return the projected geopoint */ public Geopoint project(final double bearing, final double distance) { - final double rlat1 = latitude * deg2rad; - final double rlon1 = longitude * deg2rad; - final double rbearing = bearing * deg2rad; - final double rdistance = distance / erad; + final double rlat1 = latitude * DEG_TO_RAD; + final double rlon1 = longitude * DEG_TO_RAD; + final double rbearing = bearing * DEG_TO_RAD; + final double rdistance = distance / EARTH_RADIUS; final double rlat = Math.asin(Math.sin(rlat1) * Math.cos(rdistance) + Math.cos(rlat1) * Math.sin(rdistance) * Math.cos(rbearing)); final double rlon = rlon1 + Math.atan2(Math.sin(rbearing) * Math.sin(rdistance) * Math.cos(rlat1), Math.cos(rdistance) - Math.sin(rlat1) * Math.sin(rlat)); - return new Geopoint(rlat * rad2deg, rlon * rad2deg); + return new Geopoint(rlat * RAD_TO_DEG, rlon * RAD_TO_DEG); } @Override @@ -291,7 +300,7 @@ public final class Geopoint implements ICoordinates, Parcelable { /** * Returns formatted coordinates with default format. * Default format is decimalminutes, e.g. N 52° 36.123 E 010° 03.456 - * + * * @return formatted coordinates */ @Override @@ -552,4 +561,25 @@ public final class Geopoint implements ICoordinates, Parcelable { private static String getLatSign(final String latDir) { return "S".equalsIgnoreCase(latDir) ? "-" : ""; } + + /** + * Gets distance in meters (workaround for 4.2.1 JIT bug). + */ + public static double getDistance(double lat1, double lon1, double lat2, double lon2) { + double earthRadius = 6372.8; // for haversine use R = 6372.8 km instead of 6371 km + double dLat = toRadians(lat2 - lat1); + double dLon = toRadians(lon2 - lon1); + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); + //double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + //return R * c * 1000; + // simplify haversine: + return (2 * earthRadius * 1000 * Math.asin(Math.sqrt(a))); + } + + private static double toRadians(double angdeg) { + return angdeg * DEG_TO_RAD; + } + } diff --git a/tests/src/cgeo/geocaching/geopoint/GeopointTest.java b/tests/src/cgeo/geocaching/geopoint/GeopointTest.java index e64028f..9e65a02 100644 --- a/tests/src/cgeo/geocaching/geopoint/GeopointTest.java +++ b/tests/src/cgeo/geocaching/geopoint/GeopointTest.java @@ -1,10 +1,11 @@ package cgeo.geocaching.geopoint; -import junit.framework.Assert; - +import android.os.Build; import android.os.Bundle; import android.test.AndroidTestCase; +import junit.framework.Assert; + public class GeopointTest extends AndroidTestCase { public static void testCreation() { @@ -49,7 +50,15 @@ public class GeopointTest extends AndroidTestCase { final Geopoint gp2 = new Geopoint(-30.1, -2.3); final float d12 = gp1.distanceTo(gp2); - Assert.assertEquals(110.967995, d12, 1e-6); + + // broken distance calculation in 4.2.1 + if (Build.VERSION.SDK_INT == 17) { + Assert.assertEquals(110.83107, d12, 1e-6); + } + else { + Assert.assertEquals(110.967995, d12, 1e-6); + } + Assert.assertEquals(d12, gp2.distanceTo(gp1), 1e-6); // Bearing in both directions cannot be added, as this is |
