本文内容为作者原创,转载务必标明出处!
关于使用百度地图、谷歌地图以及高德地图的坐标系转换问题,网络上各类非专业及专业的解释都有,其中有的讲法不经验证乱讲,这里特别就此问题做说明并实践验证。
首先是几点说明:
1.
高德地图采用的坐标系是gcj02火星坐标系,bd09和bd09ll是百度坐标系,谷歌地图安装版坐标系是国际通用的wgs84坐标系(网页版未找到坐标拾取器未知)。其中谷歌地图的坐标与实际gps接收设备数据基本接近,误差在几米之内。因此,谷歌坐标系并非网上所讲的gcj02.
2.
Gcj02是国家测绘局的简拼,是国家强制要求所有电子地图不允许使用真实坐标标注的结果,是原始gps采集坐标经过一个算法加密后的坐标系。然而,此算法已经在网上公开并且验证为正确。Bd09和bd09ll是百度公司的加密算法坐标系,网上文章讲是从gcj02加密而来,其实未必,也许也是直接从wgs84直接转换而来,因为网上公开的算法有误,故具体如何不得而知。
3.
由谷歌地图采集的wgs84坐标系坐标,经过网上公开的转换算法,gcj02的计算结果与高德地图十分吻合,误差在5m范围,剔除采点的手动误差,可以确定高德地图就是gcj02坐标系。故网上提供的此算法即可用,用于导航也可以。而百度地图拾取器拾取的坐标则与谷歌采集点经过算法算出的点距离甚远,误差从十几米到几十米不等,因此证明网上这段算法为假。但不排除百度曾经使用过该算法,后来被公开后做了修改。
以下是以上结论的数据来源,采用的是网络公开的代码编程计算值:
地点
天安门广场国旗西侧花圃东北角
上海陆家嘴快网网球俱乐部网球场西角
广州天河体育中心西体育馆西角
西安西北大学田径场西南角
重庆大学足
球场南角
谷歌坐标
116.39.134,
39.905461
121.491747,
31.240332
113.317158,
23.138083
108.925974,
34.250364
106.464588,
29.566417
谷歌坐标转
出gcj02坐标
116.396374,
39.906862
31.238342,
121.496209
113.322567,
23.135480
34.248749,
108.930590
29.563807,
106.468537
谷歌坐标
转出bd09坐标
116.402831,
39.912971
31.244335,
121.502697
113.329095,
23.141299
108.937204,
34.254435
29.569833,
106.4750096
高德采
集坐标
116.39637,
39.906827
121.496183,
31.23833
113.322601,
23.135432
108.930661,
34.248712
106.468549,
29.563776
百度采集坐标
116.40276,
39.913123
121.502768,
31.243926
113.329099,
23.141161
108.937202,
34.254804
无目标
高德
与gcj02误差
3.73m
2.68m
6m
7.92m
3.93m
百度
与bd09误差
17.68m
46.07m
15.39m
40.67m
无目标
由上表可见,高德地图完全可以由网上的算法直接从实际观测gps值转换过来,或者从谷歌地图采集转换而来,而百度地图数据因为bd09算法无公开的代码,用网上的公开代码是错误的,至少误差是不能接受的。
此算法的代码从网上随便即可搜索得到,更改为C#语言版本,调试无误,如下:
#region wgs84与gcj02等坐标系转换函数
public class Gps
{
private double wgLat;
private double wgLon;
public Gps(double wgLat, double wgLon)
{
setWgLat(wgLat);
setWgLon(wgLon);
}
public double getWgLat()
{
return wgLat;
}
public void setWgLat(double wgLat)
{
this.wgLat = wgLat;
}
public double getWgLon()
{
return wgLon;
}
public void setWgLon(double wgLon)
{
this.wgLon = wgLon;
}
public override stringToString()
{
return wgLat + "," + wgLon;
}
}
public class PositionUtil
{
public static String BAIDU_LBS_TYPE = "bd09ll";
public static double
pi = 3.1415926535897932384626;
public static double a
= 6378245.0;
public static double
ee = 0.00669342162296594323;
public static Gps
gps84_To_Gcj02(double lat,
double lon)
{
if (outOfChina(lat,
lon))
{
return null;
}
double dLat = transformLat(lon -
105.0, lat - 35.0);
double dLon = transformLon(lon -
105.0, lat - 35.0);
double radLat = lat / 180.0 *
pi;
double magic = Math.Sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.Sqrt(magic);
dLat
= (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) *
pi);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.Cos(radLat) * pi);
double mgLat = lat +
dLat;
double mgLon = lon +
dLon;
return new
Gps(mgLat, mgLon);
}
public static Gps
gcj02_To_Gps84(double lat,
double lon)
{
Gps gps = transform(lat,
lon);
double lontitude = lon * 2 -
gps.getWgLon();
double latitude = lat * 2 -
gps.getWgLat();
return new Gps(latitude, lontitude);
}
public static Gps
gcj02_To_Bd09(double gg_lat,
double gg_lon)
{
double x = gg_lon, y =
gg_lat;
double z = Math.Sqrt(x * x + y * y) + 0.00002 *
Math.Sin(y * pi);
double theta = Math.Atan2(y, x) + 0.000003 * Math.Cos(x * pi);
double bd_lon = z * Math.Cos(theta) + 0.0065;
double bd_lat = z * Math.Sin(theta) + 0.006;
return new Gps(bd_lat, bd_lon);
}
public static Gps
bd09_To_Gcj02(double bd_lat,
double bd_lon)
{
double x = bd_lon - 0.0065, y =
bd_lat - 0.006;
double z = Math.Sqrt(x * x + y * y) - 0.00002 *
Math.Sin(y * pi);
double theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * pi);
double gg_lon = z * Math.Cos(theta);
double gg_lat = z * Math.Sin(theta);
return new Gps(gg_lat, gg_lon);
}
public static Gps
bd09_To_Gps84(double bd_lat,
double bd_lon)
{
Gps gcj02 = PositionUtil.bd09_To_Gcj02(bd_lat,
bd_lon);
Gps map84 = PositionUtil.gcj02_To_Gps84(gcj02.getWgLat(),
gcj02.getWgLon());
return map84;
}
public static bool
outOfChina(double lat, double lon)
{
if (lon < 72.004 || lon >
137.8347)
return true;
if (lat < 0.8293 || lat >
55.8271)
return true;
return false;
}
public static Gps
transform(double lat, double lon)
{
if (outOfChina(lat,
lon))
{
return new Gps(lat,
lon);
}
double dLat = transformLat(lon -
105.0, lat - 35.0);
double dLon = transformLon(lon -
105.0, lat - 35.0);
double radLat = lat / 180.0 *
pi;
double magic = Math.Sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.Sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) *
pi);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.Cos(radLat) * pi);
double
mgLat = lat + dLat;
double mgLon = lon +
dLon;
return new Gps(mgLat, mgLon);
}
public static double
transformLat(double x, double y)
{
double ret = -100.0 + 2.0 * x + 3.0
* y + 0.2 * y * y + 0.1 * x * y
+ 0.2 * Math.Sqrt(Math.Abs(x));
ret += (20.0 * Math.Sin(6.0 * x
* pi) + 20.0 * Math.Sin(2.0 * x
* pi)) * 2.0 / 3.0;
ret += (20.0 * Math.Sin(y * pi)
+ 40.0 * Math.Sin(y / 3.0 * pi))
* 2.0 / 3.0;
ret += (160.0 * Math.Sin(y /
12.0 * pi) + 320 * Math.Sin(y *
pi / 30.0)) * 2.0 / 3.0;
return ret;
}
public static double
transformLon(double x, double y)
{
double ret = 300.0 + x + 2.0 * y +
0.1 * x * x + 0.1 * x * y + 0.1
* Math.Sqrt(Math.Abs(x));
ret += (20.0 * Math.Sin(6.0 * x
* pi) + 20.0 * Math.Sin(2.0 * x
* pi)) * 2.0 / 3.0;
ret += (20.0 * Math.Sin(x * pi)
+ 40.0 * Math.Sin(x / 3.0 * pi))
* 2.0 / 3.0;
ret += (150.0 * Math.Sin(x /
12.0 * pi) + 300.0 * Math.Sin(x
/ 30.0
* pi)) * 2.0 / 3.0;
return ret;
}
}
#endregion