main
parent
7ddfca4f3f
commit
6296f6a75a
2 changed files with 497 additions and 2 deletions
@ -0,0 +1,492 @@ |
||||
/* |
||||
* @Author: hisense.wuhongjian |
||||
* @Date: 2021-03-09 16:59:18 |
||||
* @LastEditors: hisense.wuhongjian |
||||
* @LastEditTime: 2022-03-14 16:37:49 |
||||
* @Description: 坐标系转换通用方法 提供百度坐标(BD-09)、国测局坐标(火星坐标,GCJ-02)和WGS84坐标系之间的转换 |
||||
*/ |
||||
|
||||
/** ******************************************************变量区*********************************************************/ |
||||
|
||||
const xPI = (3.14159265358979324 * 3000.0) / 180.0 |
||||
const PI = 3.1415926535897932384626 |
||||
const a = 6378245.0 |
||||
const ee = 0.00669342162296594323 |
||||
|
||||
// let EARTHRADIUS = 6370996.81
|
||||
const MCBAND = [12890594.86, 8362377.87, 5591021, 3481989.83, 1678043.12, 0] |
||||
const LLBAND = [75, 60, 45, 30, 15, 0] |
||||
|
||||
const MC2LL = [ |
||||
[ |
||||
1.410526172116255e-8, 0.00000898305509648872, -1.9939833816331, |
||||
200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, |
||||
2.57121317296198, -0.03801003308653, 17337981.2, |
||||
], |
||||
[ |
||||
-7.435856389565537e-9, 0.000008983055097726239, -0.78625201886289, |
||||
96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, |
||||
-16.50741931063887, 2.28786674699375, 10260144.86, |
||||
], |
||||
[ |
||||
-3.030883460898826e-8, 0.00000898305509983578, 0.30071316287616, |
||||
59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, |
||||
-3.29883767235584, 0.32710905363475, 6856817.37, |
||||
], |
||||
[ |
||||
-1.981981304930552e-8, 0.000008983055099779535, 0.03278182852591, |
||||
40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, |
||||
0.12923347998204, -0.04625736007561, 4482777.06, |
||||
], |
||||
[ |
||||
3.09191371068437e-9, 0.000008983055096812155, 0.00006995724062, |
||||
23.10934304144901, -0.00023663490511, -0.6321817810242, -0.00663494467273, |
||||
0.03430082397953, -0.00466043876332, 2555164.4, |
||||
], |
||||
[ |
||||
2.890871144776878e-9, 0.000008983055095805407, -3.068298e-8, |
||||
7.47137025468032, -0.00000353937994, -0.02145144861037, -0.00001234426596, |
||||
0.00010322952773, -0.00000323890364, 826088.5, |
||||
], |
||||
] |
||||
|
||||
const LL2MC = [ |
||||
[ |
||||
-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, |
||||
26112667856603880, -35149669176653700, 26595700718403920, |
||||
-10725012454188240, 1800819912950474, 82.5, |
||||
], |
||||
[ |
||||
0.0008277824516172526, 111320.7020463578, 647795574.6671607, |
||||
-4082003173.641316, 10774905663.51142, -15171875531.51559, |
||||
12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5, |
||||
], |
||||
[ |
||||
0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, |
||||
79682215.47186455, -115964993.2797253, 97236711.15602145, |
||||
-43661946.33752821, 8477230.501135234, 52.5, |
||||
], |
||||
[ |
||||
0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, |
||||
992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, |
||||
144416.9293806241, 37.5, |
||||
], |
||||
[ |
||||
-0.0003441963504368392, 111320.7020576856, 278.2353980772752, |
||||
2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, |
||||
-2710.55326746645, 1405.483844121726, 22.5, |
||||
], |
||||
[ |
||||
-0.0003218135878613132, 111320.7020701615, 0.00369383431289, |
||||
823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, |
||||
8.77738589078284, 0.37238884252424, 7.45, |
||||
], |
||||
] |
||||
|
||||
/** ******************************************************方法区*********************************************************/ |
||||
|
||||
/** |
||||
* @method bd09togcj02 百度坐标系(BD-09)转火星坐标系(GCJ-02)即百度地图 转成 谷歌地图、高德地图 |
||||
* @param bdLon 百度坐标系下的经度 |
||||
* @param bdLat 百度坐标系下的纬度 |
||||
* @return [gcjLon,gcjLat] 火星坐标系下的经纬度坐标 |
||||
*/ |
||||
function bdLL2gcjLL(bdLon, bdLat) { |
||||
const lon = +bdLon |
||||
const lat = +bdLat |
||||
|
||||
const x = lon - 0.0065 |
||||
const y = lat - 0.006 |
||||
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * xPI) |
||||
|
||||
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * xPI) |
||||
const gcjLon = z * Math.cos(theta) |
||||
const gcjLat = z * Math.sin(theta) |
||||
|
||||
return [gcjLon, gcjLat] |
||||
} |
||||
|
||||
/** |
||||
* @method gcj02_to_bd09 火星坐标系(GCJ-02)转百度坐标系(BD-09) 即谷歌地图、高德地图 转成 百度地图 |
||||
* @param gcjLon 火星坐标系下的经度 |
||||
* @param gcjLat 火星坐标系下的纬度 |
||||
* @returns [bdLon,bdLat] 百度坐标系下的经纬度坐标 |
||||
*/ |
||||
function gcjLL2bdLL(gcjLon, gcjLat) { |
||||
const lon = +gcjLon |
||||
const lat = +gcjLat |
||||
|
||||
const z = Math.sqrt(lon * lon + lat * lat) + 0.00002 * Math.sin(lat * xPI) |
||||
|
||||
const theta = Math.atan2(lat, lon) + 0.000003 * Math.cos(lon * xPI) |
||||
const bdLon = z * Math.cos(theta) + 0.0065 |
||||
const bdLat = z * Math.sin(theta) + 0.006 |
||||
|
||||
return [bdLon, bdLat] |
||||
} |
||||
|
||||
/** |
||||
* @method wgs84_to_gcj02 WGS84坐标系转火星坐标系(GCJ-02) |
||||
* @param wgsLon WGS84坐标系下的经度坐标 |
||||
* @param wgsLat WGS84坐标系下的纬度坐标 |
||||
* @returns [mglon,mglat] 转换后火星坐标系下的经纬度坐标 |
||||
*/ |
||||
function wgs84LL2gcjLL(wgsLon, wgsLat) { |
||||
const lon = +wgsLon |
||||
const lat = +wgsLat |
||||
|
||||
// 如果坐标不在国内范围,则直接返回,不做偏移处理
|
||||
if (out_of_china(lon, lat)) { |
||||
return [lon, lat] |
||||
} else { |
||||
let dlat = transform_lat(lon - 105.0, lat - 35.0) |
||||
let dlon = transform_lon(lon - 105.0, lat - 35.0) |
||||
|
||||
const radlat = (lat / 180.0) * PI |
||||
let magic = Math.sin(radlat) |
||||
magic = 1 - ee * magic * magic |
||||
const sqrtmagic = Math.sqrt(magic) |
||||
|
||||
dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI) |
||||
dlon = (dlon * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI) |
||||
|
||||
const mglat = lat + dlat |
||||
const mglon = lon + dlon |
||||
|
||||
return [mglon, mglat] |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @method gcj02_to_wgs84 火星坐标系(GCJ-02)转WGS84坐标系 |
||||
* @param gcjLon 火星坐标系下的经度坐标 |
||||
* @param gcjLat 火星坐标系下的纬度坐标 |
||||
* @returns [] 转换后WGS84坐标系下的经纬度坐标 |
||||
*/ |
||||
export function gcjLL2wgs84LL(gcjLon, gcjLat) { |
||||
const lon = +gcjLon |
||||
const lat = +gcjLat |
||||
|
||||
if (out_of_china(lon, lat)) { |
||||
return [lon, lat] |
||||
} else { |
||||
let dlat = transform_lat(lon - 105.0, lat - 35.0) |
||||
let dlon = transform_lon(lon - 105.0, lat - 35.0) |
||||
|
||||
const radlat = (lat / 180.0) * PI |
||||
let magic = Math.sin(radlat) |
||||
magic = 1 - ee * magic * magic |
||||
const sqrtmagic = Math.sqrt(magic) |
||||
|
||||
dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI) |
||||
dlon = (dlon * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI) |
||||
|
||||
const mglat = lat + dlat |
||||
const mglon = lon + dlon |
||||
|
||||
return [lon * 2 - mglon, lat * 2 - mglat] |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @method lonlat_to_webMercator_of_WGS84 经纬度坐标转墨卡托投影(WGS84) |
||||
* @param lon 待转换的经度坐标 |
||||
* @param lat 待转换的纬度坐标 |
||||
* @returns [x,y] 转换后的平面投影坐标 |
||||
*/ |
||||
function LL2ME_wgs84(lon, lat) { |
||||
// [114.32894, 30.585748]
|
||||
const earthRad = 6378137.0 |
||||
const x = ((lon * Math.PI) / 180) * earthRad |
||||
|
||||
const a = (lat * Math.PI) / 180 |
||||
const y = (earthRad / 2) * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a))) |
||||
|
||||
return [x, y] // [12727039.383734727, 3579066.6894065146]
|
||||
} |
||||
|
||||
/** |
||||
* @method webMercator_to_lonlat_of_WGS84 墨卡托投影转经纬度坐标(WGS84) |
||||
* @param x 待转换的平面投影经度坐标 |
||||
* @param y 待转换的平面投影纬度坐标 |
||||
* @returns [lon,lat] 转换后的经纬度坐标 |
||||
*/ |
||||
function ME2LL_wgs84(x, y) { |
||||
// [12727039.383734727, 3579066.6894065146]
|
||||
const lon = (x / 20037508.34) * 180 |
||||
let lat = (y / 20037508.34) * 180 |
||||
|
||||
lat = |
||||
(180 / Math.PI) * |
||||
(2 * Math.atan(Math.exp((lat * Math.PI) / 180)) - Math.PI / 2) |
||||
|
||||
return [lon, lat] // [114.32894001591471, 30.58574800385281]
|
||||
} |
||||
|
||||
/** |
||||
* @method wgs84_to_bd09 WGS84坐标系转百度坐标系(BD-09) |
||||
* @param wgsLon WGS84坐标系下的经度坐标 |
||||
* @param wgsLat WGS84坐标系下的纬度坐标 |
||||
* @returns bd_coordinate 转换后百度坐标系下的经纬度坐标 |
||||
*/ |
||||
export function wgs84LL2bdLL(wgsLon, wgsLat) { |
||||
const gcjCoordinate = wgs84LL2gcjLL(wgsLon, wgsLat) // WGS84坐标系 转 火星坐标系
|
||||
const bdCoordinate = gcjLL2bdLL(gcjCoordinate[0], gcjCoordinate[1]) // 火星坐标系 转 百度坐标系
|
||||
|
||||
return bdCoordinate |
||||
} |
||||
|
||||
/** |
||||
* @method bd09_to_wgs84 百度坐标系(BD-09)转WGS84坐标系 |
||||
* @param bdLon 百度坐标系下的经度坐标 |
||||
* @param bdLat 百度坐标系下的纬度坐标 |
||||
* @returns wgs_coordinate 转换后WGS84坐标系下的经纬度坐标 |
||||
*/ |
||||
export function bdLL2wgs84LL(bdLon, bdLat) { |
||||
const gcjCoordinate = bdLL2gcjLL(bdLon, bdLat) // 百度坐标系 转 火星坐标系
|
||||
const wgsCoordinate = gcjLL2wgs84LL(gcjCoordinate[0], gcjCoordinate[1]) // 火星坐标西 转 WGS84坐标系
|
||||
|
||||
return wgsCoordinate |
||||
} |
||||
|
||||
/** |
||||
* @method webMercator_to_lonlat_of_bd09 墨卡托投影转经纬度坐标(bd09) |
||||
* @param x 待转换的墨卡托投影平面经度坐标 |
||||
* @param y 待转换的墨卡托投影平面纬度坐标 |
||||
* @returns location 转换后百度坐标系下的经纬度坐标 |
||||
*/ |
||||
function ME2LL_bd09(x, y) { |
||||
let cF = null |
||||
x = Math.abs(x) |
||||
y = Math.abs(y) |
||||
for (let cE = 0; cE < MCBAND.length; cE++) { |
||||
if (y >= MCBAND[cE]) { |
||||
cF = MC2LL[cE] |
||||
break |
||||
} |
||||
} |
||||
if (cF !== null) { |
||||
const location = converter(x, y, cF) |
||||
return location |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @method lonlat_to_webMercator_of_bd09 经纬度坐标转墨卡托投影(bd09) |
||||
* @param lon 待转换的百度坐标系下的经度坐标 |
||||
* @param lat 待转换的百度坐标系下的纬度坐标 |
||||
* @returns [] 转换后墨卡托投影平面经纬度坐标 |
||||
*/ |
||||
function LL2ME_bd09(lon, lat) { |
||||
let cE = '' |
||||
lon = getLoop(lon, -180, 180) |
||||
lat = getRange(lat, -74, 74) |
||||
|
||||
for (let i = 0; i < LLBAND.length; i++) { |
||||
if (lat >= LLBAND[i]) { |
||||
cE = LL2MC[i] |
||||
break |
||||
} |
||||
} |
||||
|
||||
if (!cE) { |
||||
for (let i = LLBAND.length - 1; i >= 0; i--) { |
||||
if (lat <= -LLBAND[i]) { |
||||
cE = LL2MC[i] |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
return converter(lon, lat, cE) |
||||
} |
||||
|
||||
/** |
||||
* @method lonlat_of_wgs84_to_webMercator_of_bd09 WGS84坐标系转百度墨卡托 |
||||
* @param lon 待转换的WGS84坐标系下的经度坐标 |
||||
* @param lat 待转换的WGS84坐标系下的纬度坐标 |
||||
* @returns [] 转换后百度坐标系下的墨卡托投影平面坐标 |
||||
*/ |
||||
export function wgs84LL2bdME(lon, lat) { |
||||
const bd = wgs84LL2bdLL(lon, lat) |
||||
return LL2ME_bd09(bd[0], bd[1]) |
||||
} |
||||
|
||||
/** |
||||
* @method webMercator_of_bd09_to_lonlat_of_wgs84 百度墨卡托转WGS84坐标系 |
||||
* @param x 待转换的百度坐标系下墨卡托投影平面经度坐标 |
||||
* @param y 待转换的百度坐标系下墨卡托投影平面纬度坐标 |
||||
* @returns [] 转换后WGS84坐标系下的经纬度坐标 |
||||
*/ |
||||
function bdME2wgs84LL(x, y) { |
||||
if (!isNaN(x) && !isNaN(y)) { |
||||
const bd = ME2LL_bd09(x, y) |
||||
return bdLL2wgs84LL(bd[0], bd[1]) |
||||
} else { |
||||
return [0, 0] |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @method 判断经纬度坐标是否在国内,如果不在国内返回true,否则返回false |
||||
* @param longitude 经度坐标 |
||||
* @param latitude 纬度坐标 |
||||
* @returns {boolean} 如果不在国内返回true,在国内返回false |
||||
*/ |
||||
function out_of_china(longitude, latitude) { |
||||
const lon = +longitude |
||||
const lat = +latitude |
||||
|
||||
// 纬度3.86~53.55,经度73.66~135.05
|
||||
return !(lon > 73.66 && lon < 135.05 && lat > 3.86 && lat < 53.55) |
||||
} |
||||
|
||||
/** |
||||
* @method transform_lat 转换纬度坐标 |
||||
* @param longitude 待转换的经度坐标 |
||||
* @param latitude 待转换的纬度坐标 |
||||
* @returns {number} 返回转换后的纬度坐标 |
||||
*/ |
||||
function transform_lat(longitude, latitude) { |
||||
const lon = +longitude |
||||
const lat = +latitude |
||||
|
||||
let ret = |
||||
-100.0 + |
||||
2.0 * lon + |
||||
3.0 * lat + |
||||
0.2 * lat * lat + |
||||
0.1 * lon * lat + |
||||
0.2 * Math.sqrt(Math.abs(lon)) |
||||
ret += |
||||
((20.0 * Math.sin(6.0 * lon * PI) + 20.0 * Math.sin(2.0 * lon * 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 |
||||
} |
||||
|
||||
/** |
||||
* @method transform_lon 转换经度坐标 |
||||
* @param longitude 待转换的经度坐标 |
||||
* @param latitude 待转换的纬度坐标 |
||||
* @returns {number} 返回转换后的经度坐标 |
||||
*/ |
||||
function transform_lon(longitude, latitude) { |
||||
const lon = +longitude |
||||
const lat = +latitude |
||||
|
||||
let ret = |
||||
300.0 + |
||||
lon + |
||||
2.0 * lat + |
||||
0.1 * lon * lon + |
||||
0.1 * lon * lat + |
||||
0.1 * Math.sqrt(Math.abs(lon)) |
||||
ret += |
||||
((20.0 * Math.sin(6.0 * lon * PI) + 20.0 * Math.sin(2.0 * lon * PI)) * |
||||
2.0) / |
||||
3.0 |
||||
ret += |
||||
((20.0 * Math.sin(lon * PI) + 40.0 * Math.sin((lon / 3.0) * PI)) * 2.0) / |
||||
3.0 |
||||
ret += |
||||
((150.0 * Math.sin((lon / 12.0) * PI) + |
||||
300.0 * Math.sin((lon / 30.0) * PI)) * |
||||
2.0) / |
||||
3.0 |
||||
|
||||
return ret |
||||
} |
||||
|
||||
/** |
||||
* @method converter 墨卡托投影转百度坐标系经纬度坐标 |
||||
* @param x 墨卡托投影平面经度坐标 |
||||
* @param y 墨卡托投影平面纬度坐标 |
||||
* @param cE 转换系数数组 |
||||
* @returns [] 转换结果 |
||||
*/ |
||||
function converter(x, y, cE) { |
||||
let xTemp = cE[0] + cE[1] * Math.abs(x) |
||||
const cC = Math.abs(y) / cE[9] |
||||
let yTemp = |
||||
cE[2] + |
||||
cE[3] * cC + |
||||
cE[4] * cC * cC + |
||||
cE[5] * cC * cC * cC + |
||||
cE[6] * cC * cC * cC * cC + |
||||
cE[7] * cC * cC * cC * cC * cC + |
||||
cE[8] * cC * cC * cC * cC * cC * cC |
||||
xTemp *= x < 0 ? -1 : 1 |
||||
yTemp *= y < 0 ? -1 : 1 |
||||
|
||||
return [xTemp, yTemp] |
||||
} |
||||
|
||||
/** |
||||
* @method getLoop |
||||
* @param lng |
||||
* @param min |
||||
* @param max |
||||
* @returns {*} |
||||
*/ |
||||
function getLoop(lng, min, max) { |
||||
while (lng > max) { |
||||
lng -= max - min |
||||
} |
||||
while (lng < min) { |
||||
lng += max - min |
||||
} |
||||
return lng |
||||
} |
||||
|
||||
/** |
||||
* @method getRange |
||||
* @param lat |
||||
* @param min |
||||
* @param max |
||||
* @returns {*} |
||||
*/ |
||||
function getRange(lat, min, max) { |
||||
if (min != null) { |
||||
lat = Math.max(lat, min) |
||||
} |
||||
if (max != null) { |
||||
lat = Math.min(lat, max) |
||||
} |
||||
return lat |
||||
} |
||||
|
||||
|
||||
export function wgs84LL2gcjLL2(wgsLon, wgsLat) { |
||||
const lon = +wgsLon |
||||
const lat = +wgsLat |
||||
|
||||
// 如果坐标不在国内范围,则直接返回,不做偏移处理
|
||||
if (out_of_china(lon, lat)) { |
||||
return [lon, lat] |
||||
} else { |
||||
let dlat = transform_lat(lon - 105.0, lat - 35.0) |
||||
let dlon = transform_lon(lon - 105.0, lat - 35.0) |
||||
|
||||
const radlat = (lat / 180.0) * PI |
||||
let magic = Math.sin(radlat) |
||||
magic = 1 - ee * magic * magic |
||||
const sqrtmagic = Math.sqrt(magic) |
||||
|
||||
dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI) |
||||
dlon = (dlon * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI) |
||||
|
||||
const mglat = lat + dlat |
||||
const mglon = lon + dlon |
||||
|
||||
return [mglon, mglat] |
||||
} |
||||
} |
Loading…
Reference in new issue