如何计算一个点距离另一个点的距离?
在地图上画一个圆圈我有一个以米为单位的中心GLatLng(A)和半径(r)。
这是一张图表:
----------- --/ \-- -/ \- / \ / \ / r \ | *-------------* \ A / B \ / \ / -\ /- --\ /-- -----------
如何计算位置B的GLatLng? 假定r平行于赤道。
当使用GLatLng.distanceFrom()方法给出A和B时,获得半径是微不足道的 – 但是以相反的方式进行。 似乎我需要做一些更重的math。
我们将需要一种方法,在给定方位和距离源点的距离时返回目标点。 幸运的是,Chris Veness在计算距离,方位和纬度/经度点之间有很好的JavaScript实现。
以下内容已经过修改,适用于google.maps.LatLng
类:
Number.prototype.toRad = function() { return this * Math.PI / 180; } Number.prototype.toDeg = function() { return this * 180 / Math.PI; } google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { dist = dist / 6371; brng = brng.toRad(); var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + Math.cos(lat1) * Math.sin(dist) * Math.cos(brng)); var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1), Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2)); if (isNaN(lat2) || isNaN(lon2)) return null; return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); }
你可以简单地使用它,如下所示:
var pointA = new google.maps.LatLng(25.48, -71.26); var radiusInKm = 10; var pointB = pointA.destinationPoint(90, radiusInKm);
以下是使用Google Maps API v3的完整示例:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>Google Maps Geometry</title> <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> </head> <body> <div id="map" style="width: 400px; height: 300px"></div> <script type="text/javascript"> Number.prototype.toRad = function() { return this * Math.PI / 180; } Number.prototype.toDeg = function() { return this * 180 / Math.PI; } google.maps.LatLng.prototype.destinationPoint = function(brng, dist) { dist = dist / 6371; brng = brng.toRad(); var lat1 = this.lat().toRad(), lon1 = this.lng().toRad(); var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + Math.cos(lat1) * Math.sin(dist) * Math.cos(brng)); var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1), Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2)); if (isNaN(lat2) || isNaN(lon2)) return null; return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg()); } var pointA = new google.maps.LatLng(40.70, -74.00); // Circle center var radius = 10; // 10km var mapOpt = { mapTypeId: google.maps.MapTypeId.TERRAIN, center: pointA, zoom: 10 }; var map = new google.maps.Map(document.getElementById("map"), mapOpt); // Draw the circle new google.maps.Circle({ center: pointA, radius: radius * 1000, // Convert to meters fillColor: '#FF0000', fillOpacity: 0.2, map: map }); // Show marker at circle center new google.maps.Marker({ position: pointA, map: map }); // Show marker at destination point new google.maps.Marker({ position: pointA.destinationPoint(90, radius), map: map }); </script> </body> </html>
截图:
更新:
在回答保罗的下面的评论时,这是围绕其中一个极点的时候发生的事情。
在北极附近绘制一个半径为1000公里的pointA
:
var pointA = new google.maps.LatLng(85, 0); // Close to north pole var radius = 1000; // 1000km
pointA.destinationPoint(90, radius)
屏幕截图:
这个问题的答案可以在这里find: http:
如果你在地球表面上的2 lat / lng点之间,那么你可以在这里findjavascript:
http://www.movable-type.co.uk/scripts/latlong-vincenty.html
这是在android.location.Location::distanceTo
Android API中使用的公式
您可以轻松地将代码从JavaScript转换为Java。
如果你想计算给定的起点,方位和距离的目标点,那么你需要这个方法:
http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
这里是在java中的公式:
public class LatLngUtils { /** * @param lat1 * Initial latitude * @param lon1 * Initial longitude * @param lat2 * destination latitude * @param lon2 * destination longitude * @param results * To be populated with the distance, initial bearing and final * bearing */ public static void computeDistanceAndBearing(double lat1, double lon1, double lat2, double lon2, double results[]) { // 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 lat1 *= Math.PI / 180.0; lat2 *= Math.PI / 180.0; lon1 *= Math.PI / 180.0; lon2 *= Math.PI / 180.0; double a = 6378137.0; // WGS84 major axis double b = 6356752.3142; // 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; } } double distance = (b * A * (sigma - deltaSigma)); results[0] = distance; if (results.length > 1) { double initialBearing = Math.atan2(cosU2 * sinLambda, cosU1 * sinU2 - sinU1 * cosU2 * cosLambda); initialBearing *= 180.0 / Math.PI; results[1] = initialBearing; if (results.length > 2) { double finalBearing = Math.atan2(cosU1 * sinLambda, -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda); finalBearing *= 180.0 / Math.PI; results[2] = finalBearing; } } } /* * Vincenty Direct Solution of Geodesics on the Ellipsoid (c) Chris Veness * 2005-2012 * * from: Vincenty direct formula - T Vincenty, "Direct and Inverse Solutions * of Geodesics on the Ellipsoid with application of nested equations", Survey * Review, vol XXII no 176, 1975 http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf */ /** * Calculates destination point and final bearing given given start point, * bearing & distance, using Vincenty inverse formula for ellipsoids * * @param lat1 * start point latitude * @param lon1 * start point longitude * @param brng * initial bearing in decimal degrees * @param dist * distance along bearing in metres * @returns an array of the desination point coordinates and the final bearing */ public static void computeDestinationAndBearing(double lat1, double lon1, double brng, double dist, double results[]) { double a = 6378137, b = 6356752.3142, f = 1 / 298.257223563; // WGS-84 // ellipsiod double s = dist; double alpha1 = toRad(brng); double sinAlpha1 = Math.sin(alpha1); double cosAlpha1 = Math.cos(alpha1); double tanU1 = (1 - f) * Math.tan(toRad(lat1)); double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1; double sigma1 = Math.atan2(tanU1, cosAlpha1); double sinAlpha = cosU1 * sinAlpha1; double cosSqAlpha = 1 - sinAlpha * sinAlpha; 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 sinSigma = 0, cosSigma = 0, deltaSigma = 0, cos2SigmaM = 0; double sigma = s / (b * A), sigmaP = 2 * Math.PI; while (Math.abs(sigma - sigmaP) > 1e-12) { cos2SigmaM = Math.cos(2 * sigma1 + sigma); sinSigma = Math.sin(sigma); cosSigma = Math.cos(sigma); deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM))); sigmaP = sigma; sigma = s / (b * A) + deltaSigma; } double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1; double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1, (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)); double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1); double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha)); double L = lambda - (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM))); double lon2 = (toRad(lon1) + L + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalise // to // -180...+180 double revAz = Math.atan2(sinAlpha, -tmp); // final bearing, if required results[0] = toDegrees(lat2); results[1] = toDegrees(lon2); results[2] = toDegrees(revAz); } private static double toRad(double angle) { return angle * Math.PI / 180; } private static double toDegrees(double radians) { return radians * 180 / Math.PI; } }
JavaScript的许多测地计算(直接和反问题,面积计算等)。 可在
示例用法显示在
http://geographiclib.sourceforge.net/scripts/geod-calc.html
谷歌地图界面提供在
http://geographiclib.sourceforge.net/scripts/geod-google.html
这包括绘制测地线(蓝色),测地圆(绿色)和测地线(红色)。
要计算一个纬度,一个给定方位的长点和距离,可以使用google的JavaScript实现:
var pointA = new google.maps.LatLng(25.48, -71.26); var distance = 10; // 10 metres var bearing 90; // 90 degrees var pointB = google.maps.geometry.spherical.computeOffset(pointA, distance, bearing);
请参阅https://developers.google.com/maps/documentation/javascript/reference#spherical有关文档;