I am calculating the distance between two points recorded in the history of Yandex.Maps in the Android 11 app. Everything works well in the getPoints method. We write all the coordinates they were in our database to a list of arrays. I even implemented overflow, exit, and array checks. Again, up to this point, everything worked well and as expected.
public ArrayList<Double> getPoints () {
ArrayList<Double> location = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select latitude,longitude from "+Table_Name_Location,null);
if(cursor.getCount() > 0) {
while (cursor.moveToNext()) {
Double latitude = cursor.getDouble(cursor.getColumnIndex("Lat"));
Double longitude = cursor.getDouble(cursor.getColumnIndex("Longi"));
location.add(latitude);
location.add(longitude);
}
}
cursor.close();
return location;
}
However, when I try to calculate the length in the distance method, several latitudes and longitudes stored in the SQLite database incorrectly calculate the total distance, for example, 450 kilometres, and according to our data, we should get 230 km. A calculation error occurs.
private double distance(double lat1, double lon1, double lat2, double lon2) {
double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1))
* Math.sin(deg2rad(lat2))
+ Math.cos(deg2rad(lat1))
* Math.cos(deg2rad(lat2))
* Math.cos(deg2rad(theta));
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
return (dist);
}
private double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
}
I tried to calculate the distance using the haversine formula. I also wrote functions to convert radians to degrees and vice versa. In the distance method, I calculate the distance using the haversine formula. I suspect that the error is in calculating the distance, namely in the implementation of the haversine formula.
For distance you need the reverse Haversine formula:
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2(sqrt(a), sqrt(1-a))
d = R * c
R = 6371 # mean radius of the Earth in km
(source of formula: link)
The implementation of this in Java would look like the following:
private double distance(double lat1, double lon1, double lat2, double lon2) {
final int R = 6371;
double latDistance = Math.toRadians(lat2 - lat1);
double lonDistance = Math.toRadians(lon2 - lon1);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
/**
* Calculate the distance between two points in meters using the Haversine formula
*
* #param lat latitude of the first point
* #param lon longitude of the first point
* #param lat2 latitude of the second point
* #param lon2 longitude of the second point
* #return the distance between the two points in meters
**/
public static double distance(double lat, double lon, double lat2, double lon2) {
final double R = 6371e3;
final double la = lat * java.lang.Math.PI / 180;
final double laa = lat2 * java.lang.Math.PI / 180;
final double lo = (lat2 - lat) * java.lang.Math.PI / 180;
final double loo = (lon2 - lon) * java.lang.Math.PI / 180;
final double a = java.lang.Math.sin(lo / 2) * java.lang.Math.sin(lo / 2) + java.lang.Math.cos(la) * java.lang.Math.cos(laa) * java.lang.Math.sin(loo / 2) * java.lang.Math.sin(loo / 2);
final double c = 2 * java.lang.Math.atan2(java.lang.Math.sqrt(a), java.lang.Math.sqrt(1 - a));
return R * c;
}
I have this code segment from a forum, and it's used to calculate the distance from a line to a point. The problem is that I don't know the measure unit in which the result is returned. Here is the code:
private double distanceFromLineToPoint(Point A, Point B, Point C){ //A-B the line, C the point
double lat1=A.latitude;
double lon1=A.longitude;
double lat2=B.latitude;
double lon2=B.longitude;
double lat3=C.latitude;
double lon3=C.longitude;
double EARTH_RADIUS_KM=6371;
double y=Math.sin(lon3-lon1)*Math.cos(lat3);
double x = Math.cos(lat1) * Math.sin(lat3) - Math.sin(lat1) * Math.cos(lat3) * Math.cos(lat3 - lat1);
double bearing1=Math.toDegrees(Math.atan2(y,x));
bearing1=360-(bearing1+360%360);
double y2 = Math.sin(lon2 - lon1) * Math.cos(lat2);
double x2 = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lat2 - lat1);
double bearing2 = Math.toDegrees(Math.atan2(y2, x2));
bearing2 = 360 - (bearing2 + 360 % 360);
double lat1Rads = Math.toRadians(lat1);
double lat3Rads = Math.toRadians(lat3);
double dLon = Math.toRadians(lon3 - lon1);
double distanceAC = Math.acos(Math.sin(lat1Rads) * Math.sin(lat3Rads)+Math.cos(lat1Rads)*Math.cos(lat3Rads)*Math.cos(dLon)) * EARTH_RADIUS_KM;
return (Math.abs(Math.asin(Math.sin(distanceAC/EARTH_RADIUS_KM)*Math.sin(Math.toRadians(bearing1)-Math.toRadians(bearing2))) * EARTH_RADIUS_KM));
}
I have an arrayList of markers and I want to find the closest marker to my current location.
I had no idea how to find that marker so I searched and found same problem in here.
Google Maps Api v3 - find nearest markers
then I tried to convert those code to java but it doesn't work now.
closest doesn't change and always it is -1.
Is there any better solution for this problem or I can make the following code usable?
public void findNearMarker(){
double pi = Math.PI;
int R = 6371; //equatorial radius
double[] distances = new double[2];
double d = 0;
int i;
int closest = -1;
for ( i = 0; i == markerArrayList.size(); i++){
double lat2 = markerArrayList.get(i).getPosition().latitude;
double lon2 = markerArrayList.get(i).getPosition().longitude;
double chLat = lat2 - currentLocation.getLatitude();
double chLon = lon2 - currentLocation.getLongitude();
double dLat = chLat*(pi/180);
double dLon = chLon*(pi/180);
double rLat1 = currentLocation.getLatitude()*(pi/180);
double rLat2 = lat2 * (pi/180);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2)
* Math.sin(dLon /2) * Math.cos(rLat1) * Math.cos(rLat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
d = R * c;
distances[i] = d;
if (closest == -1 || d< distances[closest]){
closest = i;
}
}
}
first you need to import the location class of the android sdk
import android.location.Location;
ArrayList<Marker> markers = new ArrayList<>();
markers = sortListbyDistance(markers, currentLocation.getLocation());
public static ArrayList<Marker> sortListbyDistance(ArrayList<Marker> markers, final LatLng location){
Collections.sort(markers, new Comparator<Marker>() {
#Override
public int compare(Marker marker2, Marker marker1) {
//
if(getDistanceBetweenPoints(marker1.getLocation(),location)>getDistanceBetweenPoints(marker2.getLocation(),location)){
return -1;
} else {
return 1;
}
}
});
return markers;
}
public static float getDistanceBetweenPoints(double firstLatitude, double firstLongitude, double secondLatitude, double secondLongitude) {
float[] results = new float[1];
Location.distanceBetween(firstLatitude, firstLongitude, secondLatitude, secondLongitude, results);
return results[0];
}
and to get the nearest marker just get first item in markers, cheers :)
If you follow
Comparing two locations using their Longitude and Latitude
/** calculates the distance between two locations in MILES */
private double distance(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 3958.75; // in miles, change to 6371 for kilometer output
double dLat = Math.toRadians(lat2-lat1);
double dLng = Math.toRadians(lng2-lng1);
double sindLat = Math.sin(dLat / 2);
double sindLng = Math.sin(dLng / 2);
double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
* Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = earthRadius * c;
return dist; // output distance, in MILES
}
loop through your list with this function and get the lowest return value.
You can also use the Maps API
Location locationA = new Location("point A");
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
locationB.setLongitude(lngB);
float distance = locationA.distanceTo(locationB);
I'm trying to figure out how to represent geographic locations, and I can't seem to find any relevant classes in the SE documentation.
I would like to do something like this:
Location locA = new Location(aa.aaaaaaa, bb.bbbbbbb); //lat/long coordinates
Location locB = .....
int meters = locA.distanceTo(locB);
Ideally I would want something like the Android Location since most of my location data will be sent from android devices anyway. From my understanding it contains information about accuracy, latitude and speed, which would be useful (but not required).
I have an idea of how to implement it myself, but an open source alternative would save me some time.
It would also be extremely helpful if I could do some IP/Location lookup. But I guess that's a whole other issue.
Here is a method to calculate distance between 2 points, taken from Android Location class with small modification. It looks a little bit complicated--this is because it uses Vincenty's formulae to perform iterative calculations on WGS84 ellipsoid:
/** distance between 2 geographic points on Earth, in km **/
public static double geoDistance(GeoPoint gp1, GeoPoint gp2) {
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
// using the "Inverse Formula" (section 4)
int MAXITERS = 20;
// Convert lat/long to radians
double lat1 = gp1.getLat() * Math.PI / 180.0;
double lat2 = gp2.getLat() * Math.PI / 180.0;
double lon1 = gp1.getLon() * Math.PI / 180.0;
double lon2 = gp2.getLon() * Math.PI / 180.0;
double a = 6378.137; // WGS84 major axis
double b = 6356.7523142; // WGS84 semi-major axis
double f = (a - b) / a;
double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
double L = lon2 - lon1;
double A = 0.0;
double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
double cosU1 = Math.cos(U1);
double cosU2 = Math.cos(U2);
double sinU1 = Math.sin(U1);
double sinU2 = Math.sin(U2);
double cosU1cosU2 = cosU1 * cosU2;
double sinU1sinU2 = sinU1 * sinU2;
double sigma = 0.0;
double deltaSigma = 0.0;
double cosSqAlpha = 0.0;
double cos2SM = 0.0;
double cosSigma = 0.0;
double sinSigma = 0.0;
double cosLambda = 0.0;
double sinLambda = 0.0;
double lambda = L; // initial guess
for (int iter = 0; iter < MAXITERS; iter++) {
double lambdaOrig = lambda;
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
double t1 = cosU2 * sinLambda;
double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
double sinSqSigma = t1 * t1 + t2 * t2; // (14)
sinSigma = Math.sqrt(sinSqSigma);
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
sigma = Math.atan2(sinSigma, cosSigma); // (16)
double sinAlpha = (sinSigma == 0) ? 0.0 :
cosU1cosU2 * sinLambda / sinSigma; // (17)
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
cos2SM = (cosSqAlpha == 0) ? 0.0 :
cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
A = 1 + (uSquared / 16384.0) * // (3)
(4096.0 + uSquared *
(-768 + uSquared * (320.0 - 175.0 * uSquared)));
double B = (uSquared / 1024.0) * // (4)
(256.0 + uSquared *
(-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
double C = (f / 16.0) *
cosSqAlpha *
(4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
double cos2SMSq = cos2SM * cos2SM;
deltaSigma = B * sinSigma * // (6)
(cos2SM + (B / 4.0) *
(cosSigma * (-1.0 + 2.0 * cos2SMSq) -
(B / 6.0) * cos2SM *
(-3.0 + 4.0 * sinSigma * sinSigma) *
(-3.0 + 4.0 * cos2SMSq)));
lambda = L +
(1.0 - C) * f * sinAlpha *
(sigma + C * sinSigma *
(cos2SM + C * cosSigma *
(-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
double delta = (lambda - lambdaOrig) / lambda;
if (Math.abs(delta) < 1.0e-12) {
break;
}
}
return b * A * (sigma - deltaSigma);
}
GeoPoint class looks like the following:
/**
* Immutable point in geo coordinates (latitude, longitude) with accuracy in km
*/
public class GeoPoint {
private final double lat;
private final double lon;
private final double accuracy;
/**
* New geo point without accuracy
*/
public GeoPoint(double lat, double lon){
this(lat, lon, -1d);
}
/**
* New geo point with specified accuracy
* #param accuracy accuracy in km
*/
public GeoPoint(double lat, double lon, double accuracy){
this.lat = lat;
this.lon = lon;
this.accuracy = accuracy < 0 ? -1d : accuracy;
}
public double getLat(){
return this.lat;
}
public double getLon(){
return this.lon;
}
/**
* #return accuracy in km. If < 0, accuracy is not defined
*/
public double getAccuracy(){
return this.accuracy;
}
#Override
public String toString(){
return "lat = " + this.lat + "; lon = " + this.lon + (this.accuracy < 0 ? "" : ("; accuracy = " + this.accuracy));
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GeoPoint) || o == null) return false;
GeoPoint g = (GeoPoint) o;
return g.lat == this.lat && g.lon == this.lon && g.accuracy == this.accuracy;
}
}
Here's my try, it's just a snippet of my code:
final double RADIUS = 6371.01;
double temp = Math.cos(Math.toRadians(latA))
* Math.cos(Math.toRadians(latB))
* Math.cos(Math.toRadians((latB) - (latA)))
+ Math.sin(Math.toRadians(latA))
* Math.sin(Math.toRadians(latB));
return temp * RADIUS * Math.PI / 180;
I am using this formulae to get the latitude and longitude:
x = Deg + (Min + Sec / 60) / 60)
The Java code given by Dommer above gives slightly incorrect results but the small errors add up if you are processing say a GPS track. Here is an implementation of the Haversine method in Java which also takes into account height differences between two points.
/**
* Calculate distance between two points in latitude and longitude taking
* into account height difference. If you are not interested in height
* difference pass 0.0. Uses Haversine method as its base.
*
* lat1, lon1 Start point lat2, lon2 End point el1 Start altitude in meters
* el2 End altitude in meters
* #returns Distance in Meters
*/
public static double distance(double lat1, double lat2, double lon1,
double lon2, double el1, double el2) {
final int R = 6371; // Radius of the earth
double latDistance = Math.toRadians(lat2 - lat1);
double lonDistance = Math.toRadians(lon2 - lon1);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c * 1000; // convert to meters
double height = el1 - el2;
distance = Math.pow(distance, 2) + Math.pow(height, 2);
return Math.sqrt(distance);
}
Here's a Java function that calculates the distance between two lat/long points, posted below, just in case it disappears again.
private double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (unit == 'K') {
dist = dist * 1.609344;
} else if (unit == 'N') {
dist = dist * 0.8684;
}
return (dist);
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: This function converts decimal degrees to radians :*/
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
private double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: This function converts radians to decimal degrees :*/
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
private double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
}
System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'M') + " Miles\n");
System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'K') + " Kilometers\n");
System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'N') + " Nautical Miles\n");
Future readers who stumble upon this SOF article.
Obviously, the question was asked in 2010 and its now 2019.
But it comes up early in an internet search. The original question does not discount use of third-party-library (when I wrote this answer).
public double calculateDistanceInMeters(double lat1, double long1, double lat2,
double long2) {
double dist = org.apache.lucene.util.SloppyMath.haversinMeters(lat1, long1, lat2, long2);
return dist;
}
and
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-spatial</artifactId>
<version>8.2.0</version>
</dependency>
https://mvnrepository.com/artifact/org.apache.lucene/lucene-spatial/8.2.0
Please read documentation about "SloppyMath" before diving in!
https://lucene.apache.org/core/8_2_0/core/org/apache/lucene/util/SloppyMath.html
Note: this solution only works for short distances.
I tried to use dommer's posted formula for an application and found it did well for long distances but in my data I was using all very short distances, and dommer's post did very poorly. I needed speed, and the more complex geo calcs worked well but were too slow. So, in the case that you need speed and all the calculations you're making are short (maybe < 100m or so). I found this little approximation to work great. it assumes the world is flat mind you, so don't use it for long distances, it works by approximating the distance of a single Latitude and Longitude at the given Latitude and returning the Pythagorean distance in meters.
public class FlatEarthDist {
//returns distance in meters
public static double distance(double lat1, double lng1,
double lat2, double lng2){
double a = (lat1-lat2)*FlatEarthDist.distPerLat(lat1);
double b = (lng1-lng2)*FlatEarthDist.distPerLng(lat1);
return Math.sqrt(a*a+b*b);
}
private static double distPerLng(double lat){
return 0.0003121092*Math.pow(lat, 4)
+0.0101182384*Math.pow(lat, 3)
-17.2385140059*lat*lat
+5.5485277537*lat+111301.967182595;
}
private static double distPerLat(double lat){
return -0.000000487305676*Math.pow(lat, 4)
-0.0033668574*Math.pow(lat, 3)
+0.4601181791*lat*lat
-1.4558127346*lat+110579.25662316;
}
}
was a lot of great answers provided however I found some performance shortcomings, so let me offer a version with performance in mind. Every constant is precalculated and x,y variables are introduced to avoid calculating the same value twice. Hope it helps
private static final double r2d = 180.0D / 3.141592653589793D;
private static final double d2r = 3.141592653589793D / 180.0D;
private static final double d2km = 111189.57696D * r2d;
public static double meters(double lt1, double ln1, double lt2, double ln2) {
double x = lt1 * d2r;
double y = lt2 * d2r;
return Math.acos( Math.sin(x) * Math.sin(y) + Math.cos(x) * Math.cos(y) * Math.cos(d2r * (ln1 - ln2))) * d2km;
}
Here is a page with javascript examples for various spherical calculations. The very first one on the page should give you what you need.
http://www.movable-type.co.uk/scripts/latlong.html
Here is the Javascript code
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
Where 'd' will hold the distance.
package distanceAlgorithm;
public class CalDistance {
public static void main(String[] args) {
// TODO Auto-generated method stub
CalDistance obj=new CalDistance();
/*obj.distance(38.898556, -77.037852, 38.897147, -77.043934);*/
System.out.println(obj.distance(38.898556, -77.037852, 38.897147, -77.043934, "M") + " Miles\n");
System.out.println(obj.distance(38.898556, -77.037852, 38.897147, -77.043934, "K") + " Kilometers\n");
System.out.println(obj.distance(32.9697, -96.80322, 29.46786, -98.53506, "N") + " Nautical Miles\n");
}
public double distance(double lat1, double lon1, double lat2, double lon2, String sr) {
double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (sr.equals("K")) {
dist = dist * 1.609344;
} else if (sr.equals("N")) {
dist = dist * 0.8684;
}
return (dist);
}
public double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
public double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
}
}
Slightly upgraded answer from #David George:
public static double distance(double lat1, double lat2, double lon1,
double lon2, double el1, double el2) {
final int R = 6371; // Radius of the earth
double latDistance = Math.toRadians(lat2 - lat1);
double lonDistance = Math.toRadians(lon2 - lon1);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c * 1000; // convert to meters
double height = el1 - el2;
distance = Math.pow(distance, 2) + Math.pow(height, 2);
return Math.sqrt(distance);
}
public static double distanceBetweenLocations(Location l1, Location l2) {
if(l1.hasAltitude() && l2.hasAltitude()) {
return distance(l1.getLatitude(), l2.getLatitude(), l1.getLongitude(), l2.getLongitude(), l1.getAltitude(), l2.getAltitude());
}
return l1.distanceTo(l2);
}
distance function is the same, but I've created I small wrapper function, which takes 2 Location objects. Thanks to this, I only use distance function if both of locations actually have altitude, because sometimes they don't. And it can lead to strange results (if location doesn't know its altitude 0 will be returned). In this case, I fall back to classic distanceTo function.