拟解决四个问题

1、已知两点经纬度,求一点相对于另一点方位角;
2、已知两点经纬度,求两点间距离;
3、已知一点经纬度及与另一点距离和方位角,求另一点经纬度;
4、问题1与问题2的简化算法。
注:简化算法的运算量和对系统的运算精度要求都大大降低,但只在短距离内(高纬地区建议10km以下)可以保证精度,除简化算法之外的算法可适用于地球上任意两点。这里只是出于便于理解的目的来解释“原理”,具体到不同的编程环境还要自己做化简和注意单位。

符号和单位约定

此处设定求B相对于A的方位角,即A为当前位置,B为目标位置
Aj:A点经度
Aw:A点纬度
Bj:B点经度
Bw:B点纬度
北纬为正,南纬为负;东经为正,西经为负
经纬度使用度,DDD.DDDDDD°,非度分或度分秒。
度数未加说明均采用角度制
R:地球平均半径
Azimuth:方位角,以真北为0度起点,由东向南向西顺时针旋转360度
在这里插入图片描述
A,B,C表示球面上的三个点及球面上“弧线”在该点处所夹的角
a,b,c表示A,B,C三点的对“弧”两端点与地心连线所夹的角(其实这里解释成ABC三点对弧的弧度更方便)
O为球心
L为AB两点间球面距离
(注:因我考虑欠缺,没有注意字母C大小写较难分辨,所以此处提醒读者在后面的公式中注意C的大小写。)

方位角求解

问题:已知A、B两点经纬度,如何求出B相对于A的方位角?
第一步:在知道AB点经纬度后,要用到第一个公式,三面角余弦公式;
cos ⁡ ( c ) = cos ⁡ ( a ) ∗ cos ⁡ ( b ) + sin ⁡ ( a ) ∗ sin ⁡ ( b ) ∗ c o s ( A   O C   B )   . \cos(c) = \cos(a)*\cos(b)+\sin(a)*\sin(b)* cos(A~O C~B)\,. cos(c)=cos(a)cos(b)+sin(a)sin(b)cos(A OC B).
AOCB是面AOC与面BOC的二面角(方便可见)
将已知数据代入,公式如下:
cos ⁡ ( c ) = cos ⁡ ( 90 − B w ) ∗ cos ⁡ ( 90 − A w ) + sin ⁡ ( 90 − B w ) ∗ sin ⁡ ( 90 − A w ) ∗ c o s ( B j − A j )   . \cos(c) = \cos(90-Bw)*\cos(90-Aw)+\sin(90-Bw)*\sin(90-Aw)* cos(Bj - Aj)\,. cos(c)=cos(90Bw)cos(90Aw)+sin(90Bw)sin(90Aw)cos(BjAj).
二面角AOCB的度数就是两点经度之差;
第二步:知道了角c的余弦值后我们要求得它的正弦值,所用的公式就是三角函数公式里最基本的“扣方加赛方等于1”的一个变形
sin ⁡ ( c ) = 1 − c o s ( c ) ∗ c o s ( c ) . \sin(c) = \sqrt{ 1-cos(c)*cos(c)}. sin(c)=1cos(c)cos(c) .
第三步:求得正弦后,接下来我们要用一个不太常用的公式,球面正弦公式
a s i n ( A ) = b s i n ( B ) + c s i n ( C ) . \frac{a}{sin(A)} =\frac{b}{sin(B)}+\frac{c}{sin(C)}. sin(A)a=sin(B)b+sin(C)c.
将已知数据代入,并稍微变形,公式如下
sin ⁡ ( A ) = sin ⁡ ( s i n ( 90 − B w ) ∗ s i n ( B j − A j ) s i n ( c ) ) . \sin(A) =\sin(\frac{sin(90 - Bw)*sin(Bj - Aj)}{sin(c)}). sin(A)=sin(sin(c)sin(90Bw)sin(BjAj)).
用反正弦函数求角度,于是上式可直接写成
A = arcsin ⁡ ( s i n ( 90 − B w ) ∗ s i n ( B j − A j ) s i n ( c ) ) . A =\arcsin(\frac{sin(90 - Bw)*sin(Bj - Aj)}{sin(c)}). A=arcsin(sin(c)sin(90Bw)sin(BjAj)).
注意事项:
由于是假设是求B点相对于A点的方位角,因此这里是Bj-Aj,不能写反,否则得不到正确的结果。
第四步,由于存在得到的结果不符合方位角的定义,因此需要根据B相对于A的位置在四个象限两个轴上进行讨论,依据不同情况对计算结果进行不同的处理。假设A点固定于远点,则:

  • B点在第一象限,Azimuth=A;
  • B在第二象限,Azimuth=360+A;
  • B在第三四象限,Azimuth=180-A。
    这里只说了象限的讨论结果,因为轴上的讨论更复杂些,要结合程序运行环境一起考虑,考虑的主要因素是系统的计算精度。譬如,在三面角余弦公式中,当AB点纬度值相同时,对公式的值起决定作用的就是cos(Bj-Aj)这一项,当Bj-Aj的值比较小时,例如0.0001(这在赤道地区对应的长度为11米左右),用一般的计算器计算时值为1,这样,后面的计算便不可能完成。但是,如果用计算机计算则为0.999999999998476913…………。所以,基于以上原因,需要对轴的“范围进项扩充”,要用单片机、手机运算的尤其要注意。
    经过一系列计算,最后,就得到了最终结果。
    似乎有人注意到了,以上的计算都是把地球看成标准的球体,而事实是地球是个椭圆,其实,地球的偏心率极低,各位可以将此法得到的计算结果与谷歌地球(WGS84坐标系统,我说的不是谷歌地图)上的结果进行对比,偏差是非常小的(我测的几个值,最大偏差0.5度)。

距离的求解

通过对方位角求解的第一步进行反余弦函数,即可求得c的度数,再将度数转换为弧度,乘以地球半径就得到了两点间的球面距离。
c = arccos ⁡ ( 90 − B w ) ∗ cos ⁡ ( 90 − A w ) + sin ⁡ ( 90 − B w ) ∗ sin ⁡ ( 90 − A w ) ∗ c o s ( B j − A j )   . c = \arccos(90-Bw)*\cos(90-Aw)+\sin(90-Bw)*\sin(90-Aw)* cos(Bj - Aj)\,. c=arccos(90Bw)cos(90Aw)+sin(90Bw)sin(90Aw)cos(BjAj).
c ( 弧 度 ) = c 180 × π , . c(弧度) = \frac{c}{180}\timesπ,. c=180c×π,.
D = R × c ( 弧 度 ) , . D = R \times c(弧度),. D=R×c(),.
注意:D的单位和R的单位一致。
短距离(例如100米,30米)使用这个公式,计算出的结果与谷歌地球给出的距离偏差在0.5%以下,长距离计算时,偏差则可以降至0.01%以下。求算的距离越大,偏差越小,就是这个公式的特点,原因不说自明。
NOTE
对于一些GPS接收机,其数据格式为NMEA-0183,经纬度数据为DDDMM.MMMM,需要将它转换为度,公式为:
经纬度(度)=DDD+MM.MMMM/60

第二点经纬度的求解

已知Aj,Aw,D,R, Azimuth(这里的Azimuth依然定为B相对于A的方位角);
首先求算c,
c ( 弧 度 ) = D R . c(弧度) = \frac{D}{R}. c=RD.
c = c ( 弧 度 ) × 180 π , . c =c(弧度) \times \frac{180}{π},. c=c()×π180,.
然后求解a, 将已知量代入,公式为:
a = arccos ⁡ ( 90 − B w ) ∗ cos ⁡ ( c ) + sin ⁡ ( 90 − B w ) ∗ sin ⁡ ( c ) ∗ c o s ( A z i m u t h ) . a = \arccos(90-Bw)*\cos(c)+\sin(90-Bw)*\sin(c)* cos(Azimuth). a=arccos(90Bw)cos(c)+sin(90Bw)sin(c)cos(Azimuth).
再求解C点
C = arcsin ⁡ ( s i n ( c ) × s i n ( A z i m u t h ) s i n ( a ) ) . C = \arcsin(\frac{sin(c) \times sin(Azimuth)}{sin(a)}). C=arcsin(sin(a)sin(c)×sin(Azimuth)).
则第二点经纬度为:
B w = 90 − a . B j = A j + C . Bw =90 - a. Bj = Aj + C. Bw=90a.Bj=Aj+C.
NOTE
对于上面两个三角公式的理解,可以想象把A点作为北极点,相当于把方位角求算中的公式原封不动的再用一遍。

简化算法

由于以上算法对于运算精度低的系统简直是噩梦。所以,需对算法进行简化。简化算法的结果在短距离内可以保证精确度,但是在长距离时,因为地球球面的特性,是万万不能用的。
简化算法的基本思路就是将以经纬度表示的球坐标转换成三维直角坐标,再利用平面几何知识去解决。
求算距离
设:Xa、Ya、Za为三维直角坐标下A点的坐标,B点坐标同样式, Ha为A点海拔高度,Hb为b点海拔高度
则:
X a = ( R + H a ) × c o s ( A w ) × c o s ( A j ) Xa = (R + Ha) \times cos(Aw) \times cos(Aj) Xa=(R+Ha)×cos(Aw)×cos(Aj)
Y a = ( R + H a ) × c o s ( A w ) × s i n ( A j ) Ya = (R + Ha) \times cos(Aw) \times sin(Aj) Ya=(R+Ha)×cos(Aw)×sin(Aj)
Z a = ( R + H a ) × s i n ( A w ) Za = (R + Ha) \times sin(Aw) Za=(R+Ha)×sin(Aw)
X b = ( R + H b ) × c o s ( B w ) × c o s ( B j ) Xb = (R + Hb) \times cos(Bw) \times cos(Bj) Xb=(R+Hb)×cos(Bw)×cos(Bj)
Y b = ( R + H b ) × c o s ( B w ) × s i n ( B j ) Yb = (R + Hb) \times cos(Bw) \times sin(Bj) Yb=(R+Hb)×cos(Bw)×sin(Bj)
Z b = ( R + H b ) × s i n ( B w ) Zb = (R + Hb) \times sin(Bw) Zb=(R+Hb)×sin(Bw)
(注:此处坐标转换为诱导公式化简后的形式,关于球坐标转直角坐标的原公式可点此查看:球坐标转直角坐标)
δ X = X a − X b \delta X= Xa - Xb δX=XaXb
δ Y = Y a − Y b \delta Y= Ya - Yb δY=YaYb
δ Z = Z a − Z b \delta Z= Za - Zb δZ=ZaZb
知道三个坐标轴方向上的差值后再用勾股定理就可以求出两点间距离了,即:
D = δ X 2 + δ Y 2 + δ Z 2 D=\sqrt{\delta X^{2} + \delta Y^{2} + \delta Z^{2}} D=δX2+δY2+δZ2
这里说明一下,海拔高度H可有可无,如果有的话,注意H与R单位要统一。普通GPS接收机给出的海拔一般很不准确,所以不推荐使用。另外NMEA规范报文中有两个量涉及到海拔,注意计算。

求算方位角
如果想直接由经纬度求算方位角,则可以避开上面的坐标转换,直接使用下式求即可:
A = a r c t a n ( B j − A j ) × c o s ( B w ) B w − A w A=arctan \frac{(Bj - Aj) \times cos(Bw)}{Bw - Aw} A=arctanBwAw(BjAj)×cos(Bw)
上面这个式子的基本思路就是将经度和纬度差转化成地面距离再运用平面几何知识求解,化简之后即为上式(过程从略,可自行推导)

B点在第一象限及Y轴正半轴,Azimuth=A;
B在第二象限,Azimuth=360+A;
B在第三四象限及Y轴负半轴,Azimuth=180+A。
对于某些系统,再单独设定B位于X正负半轴上的值就可以了,有些系统可以返回arctan(X/0)=90。
这种求方位角的算法代入了几个坐标值与谷歌地球比对,短距离内偏差在0.1度以下。

如果仅民用领域,仅需了解WGS84坐标和火星坐标系GCJ-02坐标系。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐