火星坐标(GCJ02)转GPS坐标(WGS84)没有标准的方法,网上倒是有很多第三方的。最近在做一款产品,要求非常精确的将火星坐标转换成GPS坐标。
我试过很多种方法,JZLocationConverter-Swift 算误差比较小了,有几米的误差。我找到另一种方法:二分法取中心点,逐步逼近。几乎可以算是零误差了,但有个问题。
算法详解
先说这个转换方法的逻辑,步骤如下:
火星坐标 A 转换GPS坐标 A1,对 A 的经纬度(lng,lat)分别 + - 0.5,得到4个值:
1
2
3
4最小经度 minLng: lng - 0.5
最大经度 maxLng: lng + 0.5
最小纬度 minLat: lat - 0.5
最大纬度 maxLat: lat + 0.5可以组成4个火星坐标:*注:方位只在东北半球适用,火星坐标也只中国用 : ( *
1
2
3
4左下角:a (minLng, minLat)
右下角:b (maxLng, minLat)
左上角:c (minLng, maxLat)
右上角:d (maxLng, maxLat)这4个坐标点得到一个正方形区域 M,A 是中心点,它们都属于火星坐标系
重点:将M区域 a,b,c,d 4个坐标看作是GPS坐标!获取中心点坐标 P (P是GPS坐标,A是火星坐标,数值相等,位置不同)
计算 P 与 A 的经纬度差,坐标系不同不能直接比较。将 P 转为火星坐标P1(有官方转换方法)
计算 P1 与 A 的经纬度相差之和 ( | P1lng - Alng | + | P1lat - Alat | ) < 0.00001,则认为P1和A重叠,那 P 就是 A 对应的GPS坐标。
如果 > 0.00001,二分法缩小区域,将a,b,c,d 4点转为火星坐标 a1,b1,c1,d1,以P1为准,计算A在P1的什么方位。看A在 P1-a1,P1-b1,P1-c1,P1-d1,哪个之间。
用二分法排除以外区域,比如:A在P1的左下角,就是A在P1-a1之间,得到新的区域:
1
2
3
4左下角:a(minLng, minLat)
右下角:b ((minLng + maxLng) / 2, minLat)
左上角:c (minLng, (minLat + maxLat) / 2)
右上角:d ((minLng + maxLng) / 2, (minLat + maxLat) / 2)6 - 8 步骤循环30次,一般情况下能得到差距 < 0.00001 的GPS坐标,即时达不到标准,结果也很接近。
这个转换一句话解释:用已知的GPS坐标,逐步逼近要转换的火星坐标
算法漏洞
在测试过程中,有一个坐标点出现了问题:上海虹桥机场2号航站楼 (latitude : 31.194248175984768 longitude : 121.32863948433301)
下面是算法输出的经纬度相差之和:
1 | 左上,0.49360417451567073 |
坐标点在循环第10次,四角坐标点从GPS转为火星坐标系时,逃出了限定区域,这时已没法继续二分法逼近了,只能返回差距0.001604743230569028
的坐标转换。
问题成因:GPS坐标在转换为火星坐标系时,四个点并非同步平移,正方形区域的GPS坐标,转为火星坐标时,就成了不规则的四边形,有时会把坐标点闪到外面。
正在想办法解决这个问题……
代码实现
1 | /// 火星坐标 -> GPS |