坐标系转换
介绍
地球上同一个地理位置的经纬度,在不同的坐标系中,会有少许偏移,国内目前常见的坐标系主要分为三种:
- 地球坐标系——
WGS84
:常见于GPS
设备,Google
地图等国际标准的坐标体系。 - 火星坐标系——
GCJ-02
:中国国内使用的被强制加密后的坐标体系,高德坐标就属于该种坐标体系。 - 百度坐标系——
BD-09
:百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理。
注意 虽然偏差不多,但是不转换的话,还是影响高精度使用的。实测WGS84
和GCJ-02
差距至少小几十米的偏差。
坐标系转换
高德地图
高德提供了将其他坐标系经纬度转换为高德坐标系的接口或SDK API
,但是没有提供将高德坐标系转换为其他坐标系的接口。因为国家测绘局规定,中国互联网地图必须使用至少加密一次的GCJ-02坐标。
高德开放平台服务用的是国测局规定的GCJ-02
坐标系。为国内的标准坐标体系。区别于GPS
坐标(WGS-84
坐标系),是在其基础上进行了加密。我们可以点击使用高德坐标拾取器,查看高德坐标。
其他坐标系坐标与高德坐标的偏差
可以查看JS API 其他坐标系坐标转高德坐标示例示例和JS API 其他坐标系坐标转高德坐标(批量)示例示例,来查看其他坐标系坐标与高德坐标的偏差。并且可以在这里测试。
其他坐标系坐标转高德坐标
因此在使用高德坐标系前,我们需要使用 AMap.convertFrom()
方法将这些非高德坐标系转换为高德坐标系。
使用AMap.convertFrom()
方法将其他坐标系经纬度转换为高德坐标系,需要传入两个参数,第一个参数是经纬度数组,第二个参数是源坐标系类型。
var gps = [116.3, 39.9];
AMap.convertFrom(gps, 'gps', function (status, result) {
if (result.info === 'ok') {
var lnglats = result.locations; // Array.<LngLat>
}
});
使用WEB API
将其他坐标系经纬度转成高德坐标系经纬度。
注意 API
使用调用量限制的。
高德坐标转其他坐标系坐标
虽然高德没有提供将高德坐标系转换为其他坐标系的接口,但社区有一些非官方的解决方案。
社区的转换算法有多种,下面是一种社区提供的: GCJ02
转换为 WGS84
和 WGS84
转换为 GCJ02
转换算法如下:
/*
* @Author: matiastang
* @Date: 2024-12-12 16:57:44
* @LastEditors: matiastang
* @LastEditTime: 2024-12-12 16:59:29
* @FilePath: /ReactNativeMapbox/src/utils/convert.ts
* @Description: convert
*/
/**
* 高德地图坐标转GPS坐标算法
*/
//定义一些常量
const PI = 3.1415926535897932384626;
const a = 6378245.0; //长半轴
const ee = 0.00669342162296594323; //扁率
/**
* GCJ02 转换为 WGS84
* @param lng
* @param lat
* @returns {*[]}
*/
function gcj02towgs84(lng: number, lat: number) {
lat = +lat;
lng = +lng;
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];
}
}
/**
* WGS84 转换为 GCJ02
* @param lng
* @param lat
* @returns {*[]}
*/
function wgs84togcj02(lng: number, lat: number) {
lat = +lat;
lng = +lng;
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);
return [lng + dlng, lat + dlat];
}
}
/**
* 判断是否在国内,不在国内则不做偏移
* @param lng
* @param lat
* @returns {boolean}
*/
function out_of_china(lng: number, lat: number) {
lat = +lat;
lng = +lng;
// 纬度3.86~53.55,经度73.66~135.05
return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
}
function transformlat(lng: number, lat: number) {
lat = +lat;
lng = +lng;
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: number, lat: number) {
lat = +lat;
lng = +lng;
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;
}
export {
gcj02towgs84,
wgs84togcj02,
};
高德坐标转换为WGS84
坐标的方法gcj02towgs84
。我测试过,效果还不错,挺准的。
注意 这个转换方式,有一个明显的问题,就是判断是否在国内的方法,用的是一个包含中国全境的矩形来粗略估计,这是个明显的问题。