-
Notifications
You must be signed in to change notification settings - Fork 982
/
GeoPointInterpolator.java
85 lines (72 loc) · 3.41 KB
/
GeoPointInterpolator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/* Copyright 2013 Google Inc.
Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0.html */
package org.osmdroid.samplefragments.animations;
import org.osmdroid.util.GeoPoint;
import static java.lang.Math.asin;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.pow;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;
public interface GeoPointInterpolator {
public GeoPoint interpolate(float fraction, GeoPoint a, GeoPoint b);
public class Linear implements GeoPointInterpolator {
@Override
public GeoPoint interpolate(float fraction, GeoPoint a, GeoPoint b) {
double lat = (b.getLatitude() - a.getLatitude()) * fraction + a.getLatitude();
double lng = (b.getLongitude() - a.getLongitude()) * fraction + a.getLongitude();
return new GeoPoint(lat, lng);
}
}
public class LinearFixed implements GeoPointInterpolator {
@Override
public GeoPoint interpolate(float fraction, GeoPoint a, GeoPoint b) {
double lat = (b.getLatitude() - a.getLatitude()) * fraction + a.getLatitude();
double lngDelta = b.getLongitude() - a.getLongitude();
// Take the shortest path across the 180th meridian.
if (Math.abs(lngDelta) > 180) {
lngDelta -= Math.signum(lngDelta) * 360;
}
double lng = lngDelta * fraction + a.getLongitude();
return new GeoPoint(lat, lng);
}
}
public class Spherical implements GeoPointInterpolator {
/* From github.com/googlemaps/android-maps-utils */
@Override
public GeoPoint interpolate(float fraction, GeoPoint from, GeoPoint to) {
// http://en.wikipedia.org/wiki/Slerp
double fromLat = toRadians(from.getLatitude());
double fromLng = toRadians(from.getLongitude());
double toLat = toRadians(to.getLatitude());
double toLng = toRadians(to.getLongitude());
double cosFromLat = cos(fromLat);
double cosToLat = cos(toLat);
// Computes Spherical interpolation coefficients.
double angle = computeAngleBetween(fromLat, fromLng, toLat, toLng);
double sinAngle = sin(angle);
if (sinAngle < 1E-6) {
return from;
}
double a = sin((1 - fraction) * angle) / sinAngle;
double b = sin(fraction * angle) / sinAngle;
// Converts from polar to vector and interpolate.
double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng);
double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng);
double z = a * sin(fromLat) + b * sin(toLat);
// Converts interpolated vector back to polar.
double lat = atan2(z, sqrt(x * x + y * y));
double lng = atan2(y, x);
return new GeoPoint(toDegrees(lat), toDegrees(lng));
}
private double computeAngleBetween(double fromLat, double fromLng, double toLat, double toLng) {
// Haversine's formula
double dLat = fromLat - toLat;
double dLng = fromLng - toLng;
return 2 * asin(sqrt(pow(sin(dLat / 2), 2) +
cos(fromLat) * cos(toLat) * pow(sin(dLng / 2), 2)));
}
}
}