我如何测量距离,并创build一个基于Java中的两个纬度和经度点的边界框?
我想find两个不同点之间的距离。 这个我知道可以用大圆距离来完成。 http://www.meridianworlddata.com/Distance-calculation.asp
一旦完成,用一个点和距离我想find距离北方的那个点,而这个距离的东方要在这个点附近创build一个方块。
我们使用OpenMap取得了一些成功,绘制了大量的位置数据。 有一个LatLonPoint类有一些基本的function,包括距离。
这里是Haversine公式的Java实现。 我在一个项目中使用它来计算纬度/经度之间的距离。
public static double distFrom(double lat1, double lng1, double lat2, double lng2) { double earthRadius = 3958.75; // miles (or 6371.0 kilometers) 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; }
或者你可以使用SimpleLatLng 。 Apache 2.0许可和使用在我知道的一个生产系统:我的。
短篇故事:
我正在寻找一个简单的地理库,并找不到一个适合我的需求。 谁想要在每个应用程序中重复编写和testing这些小型地理工具? 有一个更好的方法!
所以SimpleLatLng诞生了一种存储纬度 – 经度数据,进行距离计算以及创build成形边界的方法。
我知道我已经有两年时间来帮助原来的海报了,但是我的目标是帮助像我这样的人find这个问题。 我希望有一些人使用它,并为这个小轻量级实用程序的testing和愿景做出贡献。
对于更准确的距离(0.5毫米),您也可以使用Vincenty近似值:
/** * Calculates geodetic distance between two points specified by latitude/longitude using Vincenty inverse formula * for ellipsoids * * @param lat1 * first point latitude in decimal degrees * @param lon1 * first point longitude in decimal degrees * @param lat2 * second point latitude in decimal degrees * @param lon2 * second point longitude in decimal degrees * @returns distance in meters between points with 5.10<sup>-4</sup> precision * @see <a href="http://www.movable-type.co.uk/scripts/latlong-vincenty.html">Originally posted here</a> */ public static double distVincenty(double lat1, double lon1, double lat2, double lon2) { double a = 6378137, b = 6356752.314245, f = 1 / 298.257223563; // WGS-84 ellipsoid params double L = Math.toRadians(lon2 - lon1); double U1 = Math.atan((1 - f) * Math.tan(Math.toRadians(lat1))); double U2 = Math.atan((1 - f) * Math.tan(Math.toRadians(lat2))); double sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); double sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); double sinLambda, cosLambda, sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM; double lambda = L, lambdaP, iterLimit = 100; do { sinLambda = Math.sin(lambda); cosLambda = Math.cos(lambda); sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda)); if (sinSigma == 0) return 0; // co-incident points cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda; sigma = Math.atan2(sinSigma, cosSigma); sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1 - sinAlpha * sinAlpha; cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha; if (Double.isNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6) double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); lambdaP = lambda; lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); } while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0); if (iterLimit == 0) return Double.NaN; // formula failed to converge double uSq = cosSqAlpha * (a * a - b * b) / (b * b); double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))); double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))); double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); double dist = b * A * (sigma - deltaSigma); return dist; }
这个代码是从http://www.movable-type.co.uk/scripts/latlong-vincenty.html自由调整的;
一个快速的谷歌search变成了GeoTools ,它可能有你正在寻找的function。
修正Haversine距离公式….
public static double HaverSineDistance(double lat1, double lng1, double lat2, double lng2) { // mHager 08-12-2012 // http://en.wikipedia.org/wiki/Haversine_formula // Implementation // convert to radians lat1 = Math.toRadians(lat1); lng1 = Math.toRadians(lng1); lat2 = Math.toRadians(lat2); lng2 = Math.toRadians(lng2); double dlon = lng2 - lng1; double dlat = lat2 - lat1; double a = Math.pow((Math.sin(dlat/2)),2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2),2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return EARTH_RADIUS * c; }
http://www.movable-type.co.uk/scripts/latlong.html
public static Double distanceBetweenTwoLocationsInKm(Double latitudeOne, Double longitudeOne, Double latitudeTwo, Double longitudeTwo) { if (latitudeOne == null || latitudeTwo == null || longitudeOne == null || longitudeTwo == null) { return null; } Double earthRadius = 6371.0; Double diffBetweenLatitudeRadians = Math.toRadians(latitudeTwo - latitudeOne); Double diffBetweenLongitudeRadians = Math.toRadians(longitudeTwo - longitudeOne); Double latitudeOneInRadians = Math.toRadians(latitudeOne); Double latitudeTwoInRadians = Math.toRadians(latitudeTwo); Double a = Math.sin(diffBetweenLatitudeRadians / 2) * Math.sin(diffBetweenLatitudeRadians / 2) + Math.cos(latitudeOneInRadians) * Math.cos(latitudeTwoInRadians) * Math.sin(diffBetweenLongitudeRadians / 2) * Math.sin(diffBetweenLongitudeRadians / 2); Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return (earthRadius * c); }
您可以使用Java Geodesy Library for GPS ,它使用考虑了地球表面曲率的Vincenty公式 。
实现如下所示:
import org.gavaghan.geodesy.*; ... GeodeticCalculator geoCalc = new GeodeticCalculator(); Ellipsoid reference = Ellipsoid.WGS84; GlobalPosition pointA = new GlobalPosition(latitude, longitude, 0.0); GlobalPosition userPos = new GlobalPosition(userLat, userLon, 0.0); double distance = geoCalc.calculateGeodeticCurve(reference, userPos, pointA).getEllipsoidalDistance();
由此产生的距离是在米。
我知道有很多答案,但是在对这个主题进行一些研究之后,我发现这里的大多数答案使用Haversine公式,但是Vincenty公式实际上更准确。 有一个post改编了Javascript版本的计算,但是它非常笨拙。 我发现一个更好的版本,因为:
- 它也有一个开放的许可证。
- 它使用面向对象的原则。
- 它有更大的灵活性来select你想要使用的椭球。
- 它有更多的方法来允许将来进行不同的计算。
- 这是有据可查的。
VincentyDistanceCalculator
这种方法将帮助您find以km为单位的地理位置之间的距离。
private double getDist(double lat1, double lon1, double lat2, double lon2) { int R = 6373; // radius of the earth in kilometres double lat1rad = Math.toRadians(lat1); double lat2rad = Math.toRadians(lat2); double deltaLat = Math.toRadians(lat2-lat1); double deltaLon = Math.toRadians(lon2-lon1); double a = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) + Math.cos(lat1rad) * Math.cos(lat2rad) * Math.sin(deltaLon/2) * Math.sin(deltaLon/2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); double d = R * c; return d; }
我通常在映射工具箱中使用MATLAB,然后使用MATLAB Builder JA在我的Java中使用代码。 这让我的生活变得更加简单。 鉴于大多math校都有免费的学生访问,你可以尝试一下(或者拿到试用版来克服你的工作)。