坐标系之间的转换
最近在做地图展示,同样的经纬度,在不同的地图上位置不一致,为什么要地图偏移,四个字,为了安全,我们从不同的渠道获取到的经纬度信息可能并不是在同一个坐标系下,以下是几个常见坐标系
- 高德地图、腾讯地图以及谷歌中国区地图使用的是GCJ-02坐标系
- 百度地图使用的是BD-09坐标系
- 天地图使用的是CGCS2000坐标系,这是一个地心坐标系,与WGS84坐标系相差不大
- 底层接口(HTML5 Geolocation或ios、安卓API)通过GPS设备获取的坐标使用的是WGS-84坐标系
踩坑:
在uniapp中调用三方地图,环境不同,所用坐标系也不同,在自定义基座调试时没问题,上线出现偏移,原来问题出在坐标系上,在自定义基座百度默认使用GCJ-02坐标系,上线后使用BD-09坐标系。
function initMap(){
let that = this;
var point = {
longitude: that.location.point.longitude, latitude: that.location.point.latitude
}
// 获取当前窗口
const currentWebview = that.$mp.page.$getAppWebview();
that.Map = plus.maps.create('map', {
width: '100%',
height: '80%',
center: new plus.maps.Point(point.longitude, point.latitude),
zoom: 19
});
currentWebview.append(that.Map);
// 地图状态变化 (设置中心点便能触发状态,以此来绘点、获取数据,避免重复调用产生屏幕闪烁)
that.Map.onstatuschanged = (evt) => {
let _point = evt.center;
// 这里自定义基座时为gjc02坐标 打包上线后为百度坐标 所以不需要转换变动
// 反向地理编码 将坐标点转换为地理位置信息
plus.maps.Map.reverseGeocode(_point, {
coordType: 'gcj02'
}, (res) => {
that.location = {
point: res.coord,
address: res.address
};
}, (err) => {
plus.nativeUI.toast(JSON.stringify(err));
});
};
}
GPS定位偏移
定位误差大,且规律明显的情况下可手动纠偏,同一地点,获取到定位经纬度和实际经纬度,进行两点之间距离的偏差计算
uni.getLocation({
type: 'wgs84',
success(point) {
},
fail(err) {
plus.nativeUI.toast('读取当前地理位置失败');
}
});
转换方法
国测局坐标转百度
function gcj02ToBaiDu(mars_point) {
var x_pi = (3.14159265358979324 * 3000.0) / 180.0
var baidu_point = {
longitude: 0,
latitude: 0,
};
var x = mars_point.longitude;
var y = mars_point.latitude;
var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
baidu_point.longitude = z * Math.cos(theta) + 0.0065;
baidu_point.latitude = z * Math.sin(theta) + 0.006;
return baidu_point;
}
百度转国测局
bd09ToGcj02(lnglat) {
var X_PI = (3.14159265358979324 * 3000.0) / 180.0
var x = lnglat.longitude - 0.0065;
var y = lnglat.latitude - 0.006;
var magic = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI);
var sqrtMagic = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI);
var mgLng = sqrtMagic * Math.cos(magic);
var mgLat = sqrtMagic * Math.sin(magic);
return {
longitude: mgLng,
latitude: mgLat
}
}
wgs84转国测局
function wgs84Togcj02(lng, lat) {
if (this.out_of_china(lng, lat)) {
return [lng, lat];
}
var that = this;
const x_PI = (3.14159265358979324 * 3000.0) / 180.0;
const PI = 3.1415926535897932384626;
const a = 6378245.0;
const ee = 0.00669342162296594323;
let dlat = that.transformlat(lng - 105.0, lat - 35.0);
let dlng = that.transformlng(lng - 105.0, lat - 35.0);
let radlat = (lat / 180.0) * PI;
let magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
let sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI);
dlng = (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [mglng, mglat];
}
function out_of_china(lng, lat) {
return (
lng < 72.004 || lng > 137.8347 || lat < 0.8293 || lat > 55.8271 || false
);
}
function transformlat(lng, lat) {
const x_PI = (3.14159265358979324 * 3000.0) / 180.0;
const PI = 3.1415926535897932384626;
const a = 6378245.0;
const ee = 0.00669342162296594323;
let ret =
-100.0 +
2.0 * lng +
3.0 * lat +
0.2 * lat * lat +
0.1 * lng * lat +
0.2 * Math.sqrt(Math.abs(lng));
ret +=
((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
2.0) /
3.0;
ret +=
((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) *
2.0) /
3.0;
ret +=
((160.0 * Math.sin((lat / 12.0) * PI) +
320 * Math.sin((lat * PI) / 30.0)) *
2.0) /
3.0;
return ret;
}
function transformlng(lng, lat) {
const x_PI = (3.14159265358979324 * 3000.0) / 180.0;
const PI = 3.1415926535897932384626;
const a = 6378245.0;
const ee = 0.00669342162296594323;
let ret =
300.0 +
lng +
2.0 * lat +
0.1 * lng * lng +
0.1 * lng * lat +
0.1 * Math.sqrt(Math.abs(lng));
ret +=
((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) *
2.0) /
3.0;
ret +=
((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) *
2.0) /
3.0;
ret +=
((150.0 * Math.sin((lng / 12.0) * PI) +
300.0 * Math.sin((lng / 30.0) * PI)) *
2.0) /
3.0;
return ret;
}