计算两个位置(纬度、经度)之间的方位角
Posted
技术标签:
【中文标题】计算两个位置(纬度、经度)之间的方位角【英文标题】:Calculate bearing between two locations (lat, long) 【发布时间】:2011-12-28 17:05:58 【问题描述】:我正在尝试开发自己的增强现实引擎。
在互联网上搜索,我发现这很有用 tutorial。阅读它,我发现重要的是用户位置、点位置和北方之间的方位。
以下图片来自该教程。
接着,我写了一个Objective-C方法来获取beta:
+ (float) calculateBetaFrom:(CLLocationCoordinate2D)user to:(CLLocationCoordinate2D)destination
double beta = 0;
double a, b = 0;
a = destination.latitude - user.latitude;
b = destination.longitude - user.longitude;
beta = atan2(a, b) * 180.0 / M_PI;
if (beta < 0.0)
beta += 360.0;
else if (beta > 360.0)
beta -= 360;
return beta;
但是,当我尝试它时,效果并不好。
所以,我检查了 iPhone AR Toolkit,看看它是如何工作的(我一直在使用这个工具包,但它对我来说太大了)。
而且,在ARGeoCoordinate.m 中还有另一种如何获得测试版的实现:
- (float)angleFromCoordinate:(CLLocationCoordinate2D)first toCoordinate:(CLLocationCoordinate2D)second
float longitudinalDifference = second.longitude - first.longitude;
float latitudinalDifference = second.latitude - first.latitude;
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
if (longitudinalDifference > 0)
return possibleAzimuth;
else if (longitudinalDifference < 0)
return possibleAzimuth + M_PI;
else if (latitudinalDifference < 0)
return M_PI;
return 0.0f;
它使用这个公式:
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
为什么 (M_PI * .5f) 在这个公式中?没看懂。
继续搜索,我发现另一个page 谈论如何计算两个位置的距离和方位。在此页面中还有另一个实现:
/**
* Returns the (initial) bearing from this point to the supplied point, in degrees
* see http://williams.best.vwh.net/avform.htm#Crs
*
* @param LatLon point: Latitude/longitude of destination point
* @returns Number Initial bearing in degrees from North
*/
LatLon.prototype.bearingTo = function(point)
var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
var dLon = (point._lon-this._lon).toRad();
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 = Math.atan2(y, x);
return (brng.toDeg()+360) % 360;
哪个是正确的?
【问题讨论】:
您解决过这个问题吗?我对您使用的解决方案感兴趣 是的,我必须尽快添加自己的答案。 【参考方案1】:计算方位
//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));
// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));
double dLon = (lng2-lng1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
double brng = Math.toDegrees((Math.atan2(y, x)));
brng = (360 - ((brng + 360) % 360));
将度数转换为弧度
Radians = Degrees * PI / 180
将弧度转换为度数
Degrees = Radians * 180 / PI
【讨论】:
您将值转换为度数,但纬度和经度不是以度为单位吗?您不应该先将它们转换为弧度吗? 我没有将纬度和经度转换为半径。我不认为这有什么区别 您是否尝试过在线轴承匹配进行测试?例如。通过此链接进行测试。 sunearthtools.com/tools/distance.php【参考方案2】:我知道这个问题很老,但这里有一个更简单的解决方案:
浮动轴承 = loc1.bearingTo(loc2);
【讨论】:
【参考方案3】:在公式中
float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);
术语(M_PI * .5f)
表示π/2,即90°。这意味着它与您最初所说的公式相同,因为对于上图它成立
β = arctan (a/b) = 90° - arctan(b/a)。
因此,如果a
指的是经度差,b
指的是纬度差,那么这两个公式是相似的。最后一个公式使用我的方程的第一部分再次计算出相同的结果。
【讨论】:
您将a
称为 lat 的差异,将 b
称为 long 的差异。请参阅我的回复,了解a
实际上应该如何区分 long 和 b
应该如何区分 lat。编辑您的答案以与图表保持一致可能会很有用,这样我们就不会在必要时混淆未来的读者?
谢谢你,Dolbz,你是对的,a和b应该改。我编辑了我的主要答案,以获得正确的答案。 :)【参考方案4】:
试试这个以获得准确的结果:
private static double degreeToRadians(double latLong)
return (Math.PI * latLong / 180.0);
private static double radiansToDegree(double latLong)
return (latLong * 180.0 / Math.PI);
public static double getBearing()
//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));
// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));
double fLat = degreeToRadians(lat1);
double fLong = degreeToRadians(lng1);
double tLat = degreeToRadians(lat2);
double tLong = degreeToRadians(lng2);
double dLon = (tLong - fLong);
double degree = radiansToDegree(Math.atan2(sin(dLon) * cos(tLat),
cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(dLon)));
if (degree >= 0)
return degree;
else
return 360 + degree;
您可以在http://www.sunearthtools.com/tools/distance.php 上测试轴承结果。
【讨论】:
我已经实现了这个数学部分(从双 dLon = 开始),当我计算倒数航向时,结果不是 +/- 180*,而是 +/- 180* + /- 0.25*。我是唯一一个看到这个问题的人吗?是数学如何(不精确)还是我做错了什么?【参考方案5】:图中a
是经度差,b
是纬度差,因此在您编写的方法中,您把它们弄错了。
a = destination.latitude - user.latitude; // should be b
b = destination.longitude - user.longitude; // should be a
尝试切换它们,看看会发生什么。
请参阅 Palund 的回复以获取其他问题的答案。
【讨论】:
谢谢,你是对的:我在 a 和 b 上犯了一个错误。我已经切换了它们,我得到了 beta = 9 度。但是,如果我使用 LatLon.prototype.bearingTo,在相同的位置,我得到 beta = 7 度。我认为第二个更准确,但我不明白它没有在 iPhone AR Toolkit 中实现。再次感谢。 这解决了问题。只需使用 arctan(b, a) 代替 (a,b)。【参考方案6】:/* Kirit vaghela 的答案已被修改.. Math.sin 给出弧度值,因此要获得度数值,我们需要在 Math.sin() 或 Math.cos() 中传递 Math.toRadians(value) */
double lat1 = 39.099912;
double lat2 = 38.627089;
double lng1 = -94.581213;
double lng2 = -90.200203;
double dLon = (lng2-lng1);
double x = Math.sin(Math.toRadians(dLon)) * Math.cos(Math.toRadians(lat2));
double y = Math.cos(Math.toRadians(lat1))*Math.sin(Math.toRadians(lat2)) - Math.sin(Math.toRadians(lat1))*Math.cos(Math.toRadians(lat2))*Math.cos(Math.toRadians(dLon));
double bearing = Math.toDegrees((Math.atan2(x, y)));
System.out.println("BearingAngle : "+bearing);
【讨论】:
【参考方案7】:如果您愿意,可以查看 mixare 增强现实引擎中使用的代码,它在 github 上,还有一个 iPhone 版本:github.com/mixare
【讨论】:
谢谢。我现在看到您已经使用了这个 ar 浏览器。你能帮我找出哪个类包含方位计算吗? 您好,我不是 iPhone 版本的开发人员,但根据以下位置提供的类文档:code.google.com/p/mixare/wiki/FileResponsibility 它应该是类 AugmentedViewController。来源为:github.com/mixare/mixare-iphone/blob/master/Classes/gui/…【参考方案8】:输入以度为单位。
#define PI 3.14159265358979323846
#define RADIO_TERRESTRE 6372797.56085
#define GRADOS_RADIANES PI / 180
#define RADIANES_GRADOS 180 / PI
double calculateBearing(double lon1, double lat1, double lon2, double lat2)
double longitude1 = lon1;
double longitude2 = lon2;
double latitude1 = lat1 * GRADOS_RADIANES;
double latitude2 = lat2 * GRADOS_RADIANES;
double longDiff= (longitude2-longitude1) * GRADOS_RADIANES;
double y= sin(longDiff) * cos(latitude2);
double x= cos(latitude1) * sin(latitude2) - sin(latitude1) * cos(latitude2) * cos(longDiff);
// std::cout <<__FILE__ << "." << __FUNCTION__ << " line:" << __LINE__ << " "
return fmod(((RADIANES_GRADOS *(atan2(y, x)))+360),360);
【讨论】:
以上是关于计算两个位置(纬度、经度)之间的方位角的主要内容,如果未能解决你的问题,请参考以下文章