用经纬度计算两点之间的距离?

下面是我的尝试,它只是我的代码片段:

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;

我用这个公式来得到经纬度:

x = Deg + (Min + Sec / 60) / 60)
198559 次浏览

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");

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.

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);
}

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;
}
}
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);
}




}

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

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;
}

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.