diff --git a/pages/map/c.js b/pages/map/c.js new file mode 100644 index 0000000..487c5e1 --- /dev/null +++ b/pages/map/c.js @@ -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] + } +} \ No newline at end of file diff --git a/pages/map/index.vue b/pages/map/index.vue index 45d006a..3af60df 100644 --- a/pages/map/index.vue +++ b/pages/map/index.vue @@ -154,6 +154,7 @@