https://software.intel.com/en-us/blogs/2012/11/30/calculating-a-bearing-between-points-in-location-aware-apps

Submitted by John Mechalas (... on Fri, 11/30/2012 - 08:37

Earlier this week I wrote about how to calculate the distance between two points in a location-aware app. Today, I am going to discuss a related topic: how to calculate the bearing between two points.

Like the shortest-distance problem, the bearing between two points on the globe is calculated using the great circle arc that connects them. With the exception of lines of latitude and longitude, great circle arcs do not follow a constant direction relative to true north and this means that as you travel along the arc your heading will vary.

This is made clear in the figure below, which is a gnomonic projection of the earth, showing our route from Portland to London (the gnomonic projection has a very special property: straight lines on the map correspond to great circle arcs). As you can see, the direction of travel changes along the path. The initial bearing, or forward azimuth, is about 33.6° but the final bearing as we approach London is about 141.5°.

As you travel along a great circle route your bearing to your destination changes. The dotted lines represent the direction of true north relative to the starting and ending points.

To calculate the initial bearing bearing we use the following formula. Note the use of the two-argument form of the arctangent, atan2(y,x), which ensures that the resulting angle is in the correct quadrant:

Θ = atan2( sin(Δλ) * cos(Φ2), cos(Φ1) * sin (Φ2) * cos(Δλ) )

This function will return the angle in radians from -π to π but what we want is an angle in degrees from 0 to 360. To accomplish this, we convert to degrees, add 360, and take the modulo 360:

Θd = ( Θ * 180 / π + 360 ) % 360

To get the final bearing, you reverse the latitudes and longitudes, and then take the angle that is in the opposite direction (180 degrees around).

Unlike our great circle distance calculation, the bearing calculation makes use of atan and it contains a singularity: when the two points converge, the angle becomes undefined. This makes perfect sense in the physical world, as if the source and the destination are exactly the same then there is no bearing between them. In practice, rounding errors would probably prevent a perfect equality from occurring, but it would still be good form to assume the points are coincident if their distance is below a threshold distance of a meter or two.

Code

Below are some code snippets that can be used to calculate the bearing between two points. You pass the latitude and longitude (in decimal degrees) for the first point as lat1 and long1, and for the second point in lat2 and long2.

For Windows developers, here is an implementation in C#:

class GreatCircleBearing
{
static Double degToRad = Math.PI / 180.0; static public Double initial (Double lat1, Double long1, Double lat2, Double long2)
{
return (_bearing(lat1, long1, lat2, long2) + 360.0) % ;
} static public Double final(Double lat1, Double long1, Double lat2, Double long2)
{
return (_bearing(lat2, long2, lat1, long1) + 180.0) % ;
} static private Double _bearing(Double lat1, Double long1, Double lat2, Double long2)
{
Double phi1 = lat1 * degToRad;
Double phi2 = lat2 * degToRad;
Double lam1 = long1 * degToRad;
Double lam2 = long2 * degToRad; return Math.Atan2(Math.Sin(lam2-lam1)*Math.Cos(phi2),
Math.Cos(phi1)*Math.Sin(phi2) - Math.Sin(phi1)*Math.Cos(phi2)*Math.Cos(lam2-lam1)
) * /Math.PI;
}
}

And in Javascript:

function bearingInitial (lat1, long1, lat2, long2)
{
return (bearingDegrees(lat1, long1, lat2, long2) + 360) % 360;
} function bearingFinal(lat1, long1, lat2, long2) {
return (bearingDegrees(lat2, long2, lat1, long1) + 180) % 360;
} function bearingDegrees (lat1, long1, lat2, long2)
{
var degToRad= Math.PI/180.0; var phi1= lat1 * degToRad;
var phi2= lat2 * degToRad;
var lam1= long1 * degToRad;
var lam2= long2 * degToRad; return Math.atan2(Math.sin(lam2-lam1) * Math.cos(phi2),
Math.cos(phi1)*Math.sin(phi2) - Math.sin(phi1)*Math.cos(phi2)*Math.cos(lam2-lam1)
) * 180/Math.PI;
}

And for Android developers, an implementation in Java:

    class GreatCircleBearing
{
static public double initial (double lat1, double long1, double lat2, double long2)
{
return (_bearing(lat1, long1, lat2, long2) + 360.0) % 360;
} static public double final(double lat1, double long1, double lat2, double long2)
{
return (_bearing(lat2, long2, lat1, long1) + 180.0) % 360;
} static private double _bearing(double lat1, double long1, double lat2, double long2)
{
static double degToRad = Math.PI / 180.0;
double phi1 = lat1 * degToRad;
double phi2 = lat2 * degToRad;
double lam1 = long1 * degToRad;
double lam2 = long2 * degToRad; return Math.atan2(Math.sin(lam2-lam1)*Math.cos(phi2),
Math.cos(phi1)*Math.sin(phi2) - Math.sin(phi1)*Math.cos(phi2)*Math.cos(lam2-lam1)
) * 180/Math.PI;
}
}

As with our distance calculations, the assumption behind these formulas is a spherical earth. This is sufficiently accurate for casual use but scientific applications will need a more sophisticated model.

Calculating a bearing between points in location-aware apps的更多相关文章

  1. How To Start Building Spatially Aware Apps With Google’s Project Tango

    How To Start Building Spatially Aware Apps With Google’s Project Tango “Tango can enable a whole new ...

  2. (转) [it-ebooks]电子书列表

    [it-ebooks]电子书列表   [2014]: Learning Objective-C by Developing iPhone Games || Leverage Xcode and Obj ...

  3. spring boot上传文件错误The temporary upload location [/tmp/tomcat.5260880110861696164.8090/work/Tomcat/localhost/ROOT] is not valid

    参考了:https://www.jianshu.com/p/cfbbc0bb0b84 再次感谢,但还是有些调整 一.在zuul服务中加入两个配置参数(location: /data/apps/temp ...

  4. Netron开发快速上手(一):GraphControl,Shape,Connector和Connection

    版权所有,引用请注明出处:<<http://www.cnblogs.com/dragon/p/5203663.html >> 本文所用示例下载FlowChart.zip 一个用 ...

  5. infoq - neo4j graph db

    My name is Charles Humble and I am here at QCon New York 2014 with Ian Robinson. Ian, can you introd ...

  6. How parse REST service JSON response

    1. get JSON responses and go to : http://json2csharp.com/ 2. write data contracts using C# All class ...

  7. Unsupervised Classification - Sprawl Classification Algorithm

    Idea Points (data) in same cluster are near each others, or are connected by each others. So: For a ...

  8. PhoneGap API Documentation API Reference

    API Reference-API参考 Accelerometer-加速度计 Tap into the device's motion sensor.-点击进入该设备的运动传感器. Camera-相机 ...

  9. Upgrade Guide

    Upgrade Guide This guide will point out the key points to be aware of when upgrading to version 3. A ...

随机推荐

  1. 机器学习 —— 概率图模型(Homework: Exact Inference)

    在前三周的作业中,我构造了概率图模型并调用第三方的求解器对器进行了求解,最终获得了每个随机变量的分布(有向图),最大后验分布(双向图).本周作业的主要内容就是自行编写概率图模型的求解器.实际上,从根本 ...

  2. Vim的可视模式

    可视模式可以看到选中的字符串, 并对其进行操作 v:进入字符选择模式 V:进入行选择模式 ctrl-v(Window是ctrl-q):进入block选择模式 o:移动光标到选择的另一端 O:移动光标到 ...

  3. Android studio编译之后显示中文乱码的问题解决办法

    在build.gradle文件中加上 android {compileOptions.encoding = "GBK"}

  4. ScaleGestureDetector缩放view

    public class ScaleGesture implements OnScaleGestureListener { private float beforeFactor; private fl ...

  5. HDU 4902

    数据太弱,直接让我小暴力一下就过了,一开始没注意到时间是15000MS,队友发现真是太给力了 #include <cstdio> #include <cstring> ],x[ ...

  6. 函数buf_read_page_low

    /********************************************************************//** Low-level function which r ...

  7. Java注解实践

    Java注解实践 标签 : Java基础 注解对代码的语意没有直接影响, 他们只负责提供信息给相关的程序使用. 注解永远不会改变被注解代码的含义, 但可以通过工具对被注解的代码进行特殊处理. JDK ...

  8. LA 3510 (置换 循环分解) Pixel Shuffle

    思路挺简单的,题目中的每个命令(包括命令的逆)相当于一个置换. 用O(n2k)的时间复杂度从右往左求出这些置换的乘积A,然后求m使Am = I(I为全等置换) 还是先把A分解循环,m则等于所有循环节长 ...

  9. UVA 11090 Going in Cycle!!(二分答案+判负环)

    在加权有向图中求平均权值最小的回路. 一上手没有思路,看到“回路”,第一想法就是找连通分量,可又是加权图,没什么好思路,那就转换题意:由求回路权值->判负环,求最小值->常用二分答案. 二 ...

  10. ti processor sdk linux am335x evm /bin/commom.sh hacking

    #!/bin/sh # # ti processor sdk linux am335x evm /bin/commom.sh hacking # 说明: # 本文主要对TI的sdk中的common.s ...