计算两个 GPS 坐标之间的罗盘方位问题
Posted
技术标签:
【中文标题】计算两个 GPS 坐标之间的罗盘方位问题【英文标题】:Issue with calculating compass bearing between two GPS coordinates 【发布时间】:2012-07-10 14:06:57 【问题描述】:在我的 web 应用程序中,有一个来自数据库查询的 JSON 数据响应,其中包括 1 到 n 个位置的纬度/经度坐标。我想计算从data[i]
位置到当前位置的方位。
我一直在修改代码here,但是返回的方位不正确。
//starting lat/long along with converting lat to rads
var endLat = toRad(location.lat());
var endLong = location.lng();
//loop over response, calculate new headings for links and add link to array
for(var i=0; i<data.length; i++)
//this link's lat/long coordinates, convert lat to rads
var startLat = toRad(data[i].lat);
var startLong = data[i].lon;
//get the delta values between start and end coordinates in rads
var dLong = toRad(endLong - startLong);
//calculate
var y = Math.sin(dLong)*Math.cos(endLong);
var x = Math.cos(startLat)*Math.sin(endLat)-Math.sin(startLat)*Math.cos(endLat)*Math.cos(dLong);
var bearing = Math.atan(y, x);
bearing = (toDeg(bearing) + 360) % 360;
panoLinks.push('heading': bearing, 'description': data[i].description, 'pano': data[i].description);
//radian/degree conversions
function toRad(convert)
return convert * Math.PI/180;
function toDeg(convert)
return convert * 180/Math.PI;
使用上面的函数和值
startLat= 43.6822, converts to 0.7623982145146669 radians
startLong= -70.450769
endLat= 43.682211, converts to 0.7623984065008848 radians
endLong= -70.45070
dLong = startLong - endLong, converts to 0.0000011170107216805305 radians
导致罗盘度数为
bearing= 0.000014910023935499339
这绝对是关闭的。我哪里出错了?
【问题讨论】:
罗盘方位基于magnetic north,它在真北以东和以西可能在 10° 到 20° 之间变化。您计算的方位角将是基于WGS 84 的球面方位角,它或多或少是正北。 我知道这一点。但是,我正在尝试计算相距约 10 米的两个位置之间的方位角。在那个距离上,从磁北到真北的偏差是无关紧要的。 20° 无关紧要?超过 10 米,您将指向 3.6m 以外的地方。 嗯,也许我应该编辑它。刚刚检查了我所在地区的磁偏角差异,磁北在真北以东 18 度。然而,这些罗盘方位是基于 GPS 坐标的,与方向无关。 您需要学习导航!查看我的第一条评论并点击链接。 :-) GPS 设备生成的纬度和经度(即“GPS 坐标”)基于与其他大地测量系统完全相同的坐标系。它们是地球的数学近似值,它们对于同一点的坐标和点之间的方位都略有不同。 【参考方案1】:试一试,我这辈子都不记得我在哪里弄到它了……
/**
* Calculate the bearing between two positions as a value from 0-360
*
* @param lat1 - The latitude of the first position
* @param lng1 - The longitude of the first position
* @param lat2 - The latitude of the second position
* @param lng2 - The longitude of the second position
*
* @return int - The bearing between 0 and 360
*/
bearing : function (lat1,lng1,lat2,lng2)
var dLon = (lng2-lng1);
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = this._toDeg(Math.atan2(y, x));
return 360 - ((brng + 360) % 360);
,
/**
* Since not all browsers implement this we have our own utility that will
* convert from degrees into radians
*
* @param deg - The degrees to be converted into radians
* @return radians
*/
_toRad : function(deg)
return deg * Math.PI / 180;
,
/**
* Since not all browsers implement this we have our own utility that will
* convert from radians into degrees
*
* @param rad - The radians to be converted into degrees
* @return degrees
*/
_toDeg : function(rad)
return rad * 180 / Math.PI;
,
【讨论】:
好的,我找到了参考:movable-type.co.uk/scripts/latlong.html 发现这个网站非常方便! 这与我正在运行的代码几乎完全相同。问题是,两个应该完全相反的不同位置之间只有 0.00001 度的差异。一个应该是 230 度,第二个应该是 70 度。 不错的尝试,但您的函数是基于数学轴承的。在数学中,0° 沿 +X 轴,角度逆时针方向进行,因此 90° 沿 +Y 轴向上,180° 沿 -X 等等。在映射中,0°(正北)在 +Y 轴上方,方位顺时针方向前进,因此 90°(正东)沿 +X 轴,180°(正南)沿 -Y 等等。 我会帮忙,但我的球面三角已经生锈了,再查规则为时已晚。 这是我能找到的最接近的答案。最大的不同是使用 atan2 函数而不是 atan。【参考方案2】:这是对已接受答案的编辑,并进行了一些修改,使其对我有用(主要是在 lat,lng 值上使用 toRad 函数)。
var geo =
/**
* Calculate the bearing between two positions as a value from 0-360
*
* @param lat1 - The latitude of the first position
* @param lng1 - The longitude of the first position
* @param lat2 - The latitude of the second position
* @param lng2 - The longitude of the second position
*
* @return int - The bearing between 0 and 360
*/
bearing : function (lat1,lng1,lat2,lng2)
var dLon = this._toRad(lng2-lng1);
var y = Math.sin(dLon) * Math.cos(this._toRad(lat2));
var x = Math.cos(this._toRad(lat1))*Math.sin(this._toRad(lat2)) - Math.sin(this._toRad(lat1))*Math.cos(this._toRad(lat2))*Math.cos(dLon);
var brng = this._toDeg(Math.atan2(y, x));
return ((brng + 360) % 360);
,
/**
* Since not all browsers implement this we have our own utility that will
* convert from degrees into radians
*
* @param deg - The degrees to be converted into radians
* @return radians
*/
_toRad : function(deg)
return deg * Math.PI / 180;
,
/**
* Since not all browsers implement this we have our own utility that will
* convert from radians into degrees
*
* @param rad - The radians to be converted into degrees
* @return degrees
*/
_toDeg : function(rad)
return rad * 180 / Math.PI;
,
;
/** Usage **/
var myInitialBearing = geo.bearing(0,0,45,45);
查找理论和在线计算器:http://www.movable-type.co.uk/scripts/latlong.html
【讨论】:
【参考方案3】:如果你想要一个非常粗略的短距离方法,你可以使用地球半径 6,378,137m(WGS84 椭球半长轴的长度)根据纬度差异计算三角形的边和经度。然后计算合适的方位角。这将是一个真正的方位,但在短距离内可能足够接近。
您需要让用户自行计算出当地的磁偏角。
例如以您为例:
startLat = 43.6822
startLong = -70.450769
endLat = 43.682211
endLong = -70.45070
diff lat = 0.000011 = 1.22m
diff long = 0.000069 = 7.68m
终点在起点的北和东,因此可以通过以下方式找到方位:
tan a = 7.68 / 1.22
a = 81°
所以方向是关于East by North。
这可能应该在测绘线程中。计算完数学后,就来这里寻求解决方案。
编辑
要将纬度转换为米,首先计算赤道(或任何大圆)处的地球周长:
c = 2πR where r = 6378137m
= 40,075,000 (approx)
然后得到360°外圆周的比例:
dist = c * deg / 360
= 40,075,000m * 0.000011° / 360°
= 1.223m
对于经度,距离随着纬度接近极点而变窄,因此使用相同的公式并将结果乘以纬度的余弦:
= 40,075,000m * 0.000069° / 360° * cos(0.000011°)
= 7.681m
地球半径的值不一定准确,地球不是一个完美的球体(它是一个扁球体,有点像梨形)。不同的地方使用了不同的近似值以获得更高的准确性,但我使用的那个应该足够好。
【讨论】:
嗨@RobG。请问,你是怎么得到 0.000011 = 1.22m 的?提前致谢! 为什么要将 diff_lat 和 diff_long 转换为米?如果您想知道角度 a,您可以使用度数或您正在使用的任何值(我什至更喜欢 rad 进行此类计算)并且当您将开始和结束之间的距离计算为角度时,您可以将其转换为米,如果您想以米为单位。这在很大程度上取决于您的应用程序,这正是海里的来源......我更喜欢从一个角度到海里,然后将它们转换为米(当谈到地球时......) @RemyNL——Manatok 已经给出了球面三角函数的答案。这只是在短距离使用平面触发的简单方法。纬度和经度在呈现给用户时通常以度数表示,这就是 OP 使用的。 ;-)以上是关于计算两个 GPS 坐标之间的罗盘方位问题的主要内容,如果未能解决你的问题,请参考以下文章