HarmonyOS NEXT 华为地图与高德地图经纬度相互转化
·
背景:项目中如果仅仅只使用一套地图API,那是非常舒服的,也推荐这样做;但是如果技术选型完成之后,工作进入开发阶段,这时突然来了一个新需求,需要接入第三方而且会用到第三方地图,恰巧第三方地图的坐标系与当前项目使用的坐标系不是同一套,那么恭喜你,捡到宝了,这篇文档对你有很大的帮助。
抛出问题:WGS84(华为地图采用的坐标系,项目采用)与GCJ02(高德地图采用的坐标系,第三方采用)的相同经纬度,对应的地点信息有偏差,大概3公里左右。
话不多说直接上菜!
一.华为地图正常调用API,根据经纬度获取位置信息
async getLocalInfo(){
let cLocation = await geoLocationManager.getCurrentLocation(); //获取当前位置信息,包含经纬度信息
if (!cLocation?.latitude) {
return;
}
let info: geoLocationManager.ReverseGeoCodeRequest = { //逆地理编码对象
// 获取当前位置的纬度
latitude: cLocation.latitude,
// 获取当前位置的经度
longitude: cLocation.longitude,
// 获取次数大于10次以便获得cityCode
maxItems: 1
}
//调用逆地理编码服务,根据经纬度获取位置信息,拿到位置信息,可以在原生应用进行使用了
let address = await geoLocationManager.getAddressesFromLocation(info) || [];
if (address.length === 0) {
resolve('');
}
return address
}
二、需求是:第三方需要原生应用传入一个GCJ02的经纬度,根据经纬度来显示具体的定位信息
遇到的问题:第三方调用getLocalInfo()函数,得到的却是WGS84坐标系下的经纬度,就会出现定位偏差的问题。
目标是:调用该函数 得到高德使用的GCJ02坐标系的经纬度,那么就需要将WGS84下的经纬度转化为GCJ02坐标系下的经纬度。
解决方法:
一、使用鸿蒙内置的API
map.convertCoordinateSync()可以将WGS84转化为GCJ02,如果业务只有输出没有输入的话,推荐使用这种方式
缺点:GCJ02转WGS84没有直接的API,转化起来会比较麻烦
二、封装一个坐标系相互转化的工具,封装成一个ets即可
const x_PI = (3.14159265358979324 * 3000.0) / 180.0;
const PI = 3.1415926535897932384626;
const a = 6378245.0; //卫星椭球坐标投影到平面地图坐标系的投影因子。
const ee = 0.00669342162296594323; //椭球的偏心率。
//判断是否在国内,在中国国内的经纬度才需要做偏移
function out_of_china(lng:number, lat:number) {
return (
lng < 72.004 ||
lng > 137.8347 ||
(lat < 0.8293 || lat > 55.8271 || false)
);
}
//转化经度
function transformlng(lng:number, lat:number) {
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;
}
//转化纬度
function transformlat(lng:number, lat:number) {
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;
}
//wgs84 to gcj02 地球坐标系 转 火星坐标系
export function wgs84_to_gcj02(lng:number, lat:number) {
if (out_of_china(lng, lat)) {
return [lng, lat];
} else {
let dlat = transformlat(lng - 105.0, lat - 35.0);
let dlng = 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);
let mglat = lat + dlat;
let mglng = lng + dlng;
return [mglng, mglat];
}
}
//gcj02 to wgs84 火星坐标系 转 地球坐标系
export function gcj02_to_wgs84(lng:number, lat:number) {
if (out_of_china(lng, lat)) {
return [lng, lat]
}
else {
let dlat = transformlat(lng - 105.0, lat - 35.0);
let dlng = 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);
let mglat = lat + dlat;
let mglng = lng + dlng;
return [lng * 2 - mglng, lat * 2 - mglat]
}
}
三、使用工具转化坐标系
async getLocalInfo(){
//xxx 步骤一的代码,此处暂时省略
//待转换经纬度
const waitTransformLocation: ESObject = {}
waitTransformLocation.latitude = cLocation.latitude
waitTransformLocation.longitude = cLocation.longitude
//转换坐标 WGS84转GCJ02
const convertedLocation = wgs84_to_gcj02(waitTransformLocation.longitude,waitTransformLocation.latitude)
let addressInfo: PositionDto = {
latitude: convertedLocation.latitude, //更新经纬度
longitude: convertedLocation.longitude, //更新经纬度
address: address[0].placeName,
country: address[0].countryName,
province: address[0].administrativeArea,
city: address[0].subAdministrativeArea,
district: address[0].subLocality,
street: address[0].roadName || '' + address[0].subRoadName || '',
cityCode: address[0].descriptions && address[0].descriptions.length ?
address[0].descriptions[0] : '',
adcode: address[0].descriptions && address[0].descriptions.length ?
address[0].descriptions[1].slice(0, 6) : '',
}
if (!addressInfo.cityCode && addressInfo.province) {
// addressInfo.cityCode = AreaDataUtil.getCodeByName(addressInfo.province, addressInfo.city);
}
return addressInfo
}
这样处理之后,就可以将正确的位置信息和GCJ的经纬度传递给第三方了
如果需要接收第三方的GCJ02经纬度并进行处理显示的话,就需要使用工具函数中的gcj02_to_wgs84方法,方法同理
更多推荐


所有评论(0)