|
@@ -0,0 +1,440 @@
|
|
|
+// const proj4 = require('proj4')
|
|
|
+import proj4 from 'proj4'
|
|
|
+/*****
|
|
|
+ * 地理帮助脚本
|
|
|
+ */
|
|
|
+const coordinate = {
|
|
|
+ x_PI: (Math.PI * 3000.0) / 180.0,
|
|
|
+ PI: Math.PI,
|
|
|
+ ee: 0.00669342162296594323,
|
|
|
+ a: 6378245.0,
|
|
|
+ projs: {
|
|
|
+ '01': 'wgs84', //84坐标
|
|
|
+ '02': 'gcj02', //火星坐标
|
|
|
+ '03': 'bd09', //百度坐标
|
|
|
+ '04': 'utm4', //utm坐标
|
|
|
+ '05': 'shcj', //城建坐标
|
|
|
+ '06': 'meter', //米制单位
|
|
|
+ '07': 'degree' // 度制单位
|
|
|
+ },
|
|
|
+ epsg: {
|
|
|
+ //WGS 84 - WGS84 - World Geodetic System 1984, used in GPS
|
|
|
+ '4326': '+proj=longlat +datum=WGS84 +no_defs',
|
|
|
+ //WGS 84 / Pseudo-Mercator - Spherical Mercator, Google Maps, OpenStreetMap, Bing, ArcGIS, ESRI
|
|
|
+ '3857':
|
|
|
+ '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs',
|
|
|
+ //CGCS2000 / 3-degree Gauss-Kruger zone 40
|
|
|
+ '4528':
|
|
|
+ '+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs'
|
|
|
+ },
|
|
|
+ bd09_to_gcj02: function (bd_lon, bd_lat) {
|
|
|
+ var x = bd_lon - 0.0065
|
|
|
+ var y = bd_lat - 0.006
|
|
|
+ var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_PI)
|
|
|
+ var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_PI)
|
|
|
+ var gg_lng = z * Math.cos(theta)
|
|
|
+ var gg_lat = z * Math.sin(theta)
|
|
|
+ return [gg_lng, gg_lat]
|
|
|
+ },
|
|
|
+
|
|
|
+ gcj02_to_bd09: function (lng, lat) {
|
|
|
+ var z =
|
|
|
+ Math.Sqrt(lng * lng + lat * lat) + 0.00002 * Math.Sin(lat * this.x_PI)
|
|
|
+ var theta = Math.Atan2(lat, lng) + 0.000003 * Math.Cos(lng * this.x_PI)
|
|
|
+ var bd_lng = z * Math.Cos(theta) + 0.0065
|
|
|
+ var bd_lat = z * Math.Sin(theta) + 0.006
|
|
|
+ return [bd_lng, bd_lat]
|
|
|
+ },
|
|
|
+
|
|
|
+ wgs84_to_gcj02: function (lng, lat) {
|
|
|
+ if (this.out_of_china(lng, lat)) {
|
|
|
+ [lng, lat]
|
|
|
+ } else {
|
|
|
+ var dlat = this.transformlat(lng - 105.0, lat - 35.0)
|
|
|
+ var dlng = this.transformlng(lng - 105.0, lat - 35.0)
|
|
|
+ var radlat = (lat / 180.0) * this.PI
|
|
|
+ var magic = Math.sin(radlat)
|
|
|
+ magic = 1 - this.ee * magic * magic
|
|
|
+ var sqrtmagic = Math.sqrt(magic)
|
|
|
+ dlat =
|
|
|
+ (dlat * 180.0) /
|
|
|
+ (((this.a * (1 - this.ee)) / (magic * sqrtmagic)) * this.PI)
|
|
|
+ dlng =
|
|
|
+ (dlng * 180.0) / ((this.a / sqrtmagic) * Math.cos(radlat) * this.PI)
|
|
|
+ var mglat = parseFloat(lat) + parseFloat(dlat)
|
|
|
+ var mglng = parseFloat(lng) + parseFloat(dlng)
|
|
|
+ return [mglng, mglat]
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ gcj02_to_wgs84: function (lng, lat) {
|
|
|
+ if (this.out_of_china(lng, lat)) {
|
|
|
+ return [lng, lat]
|
|
|
+ } else {
|
|
|
+ var dlat = this.transformlat(lng - 105.0, lat - 35.0)
|
|
|
+ var dlng = this.transformlng(lng - 105.0, lat - 35.0)
|
|
|
+ var radlat = (lat / 180.0) * this.PI
|
|
|
+ var magic = Math.sin(radlat)
|
|
|
+ magic = 1 - this.ee * magic * magic
|
|
|
+ var sqrtmagic = Math.sqrt(magic)
|
|
|
+ dlat =
|
|
|
+ (dlat * 180.0) /
|
|
|
+ (((this.a * (1 - this.ee)) / (magic * sqrtmagic)) * this.PI)
|
|
|
+ dlng =
|
|
|
+ (dlng * 180.0) / ((this.a / sqrtmagic) * Math.cos(radlat) * this.PI)
|
|
|
+ var mglat = lat + dlat
|
|
|
+ var mglng = lng + dlng
|
|
|
+ return [lng * 2 - mglng, lat * 2 - mglat]
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ out_of_china: function (lng, lat) {
|
|
|
+ // 纬度3.86~53.55,经度73.66~135.05
|
|
|
+ return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55)
|
|
|
+ },
|
|
|
+
|
|
|
+ transformlat: function (lng, lat) {
|
|
|
+ var 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 * this.PI) +
|
|
|
+ 20.0 * Math.sin(2.0 * lng * this.PI)) *
|
|
|
+ 2.0) /
|
|
|
+ 3.0
|
|
|
+ ret +=
|
|
|
+ ((20.0 * Math.sin(lat * this.PI) +
|
|
|
+ 40.0 * Math.sin((lat / 3.0) * this.PI)) *
|
|
|
+ 2.0) /
|
|
|
+ 3.0
|
|
|
+ ret +=
|
|
|
+ ((160.0 * Math.sin((lat / 12.0) * this.PI) +
|
|
|
+ 320 * Math.sin((lat * this.PI) / 30.0)) *
|
|
|
+ 2.0) /
|
|
|
+ 3.0
|
|
|
+ return ret
|
|
|
+ },
|
|
|
+
|
|
|
+ transformlng: function (lng, lat) {
|
|
|
+ var 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 * this.PI) +
|
|
|
+ 20.0 * Math.sin(2.0 * lng * this.PI)) *
|
|
|
+ 2.0) /
|
|
|
+ 3.0
|
|
|
+ ret +=
|
|
|
+ ((20.0 * Math.sin(lng * this.PI) +
|
|
|
+ 40.0 * Math.sin((lng / 3.0) * this.PI)) *
|
|
|
+ 2.0) /
|
|
|
+ 3.0
|
|
|
+ ret +=
|
|
|
+ ((150.0 * Math.sin((lng / 12.0) * this.PI) +
|
|
|
+ 300.0 * Math.sin((lng / 30.0) * this.PI)) *
|
|
|
+ 2.0) /
|
|
|
+ 3.0
|
|
|
+ return ret
|
|
|
+ },
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// web墨卡托经纬度转米
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="lng"></param>
|
|
|
+ /// <param name="lat"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ degree_to_meter: function (lng, lat) {
|
|
|
+ var x = (lng * 20037508.34) / 180
|
|
|
+ var y = Math.log(Math.tan(((90 + lat) * this.PI) / 360)) / (this.PI / 180)
|
|
|
+ y = (y * 20037508.34) / 180
|
|
|
+ return [x, y]
|
|
|
+ },
|
|
|
+
|
|
|
+ //Web墨卡托转经纬度
|
|
|
+ meter_to_degree: function (x, y) {
|
|
|
+ var lon = (x / 20037508.34) * 180
|
|
|
+ var lat = (y / 20037508.34) * 180
|
|
|
+ lat =
|
|
|
+ (180 / this.PI) *
|
|
|
+ (2 * Math.atan(Math.exp((lat * this.PI) / 180)) - this.PI / 2)
|
|
|
+
|
|
|
+ return [lon, lat]
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * @description wgs84坐标转上海城建
|
|
|
+ * @time 2020-09-02
|
|
|
+ * @author zhb
|
|
|
+ * @param {*} x
|
|
|
+ * @param {*} y
|
|
|
+ */
|
|
|
+ wgs84_to_shcj: function (x, y) {
|
|
|
+ let xy = []
|
|
|
+ xy = this.shcj_get_UTM_from_WGS(x, y)
|
|
|
+ return this.utm_to_shcj4(xy[0], xy[1])
|
|
|
+ },
|
|
|
+
|
|
|
+ utm_to_shcj4 (x, y) {
|
|
|
+ let DX, DY, T, K
|
|
|
+ DX = -500199.29965
|
|
|
+ DY = -3457078.805985
|
|
|
+ T = 0.0000001755
|
|
|
+ K = 1.0004000106
|
|
|
+ return this.covert_by_four_parm(x, y, DX, DY, T, K)
|
|
|
+ },
|
|
|
+
|
|
|
+ shcj_get_UTM_from_WGS: function (lon, lat) {
|
|
|
+ let a = 6378137
|
|
|
+ let b = 6356752.3142451
|
|
|
+ let f = (a - b) / a
|
|
|
+
|
|
|
+ let eSquare = 2 * f - f * f
|
|
|
+ let k0 = 0.9996
|
|
|
+ let lonOrigin = 121.46714714
|
|
|
+ let FN = 0
|
|
|
+ // # 确保longtitude位于-180.00----179.9之间
|
|
|
+ let lonTemp = lon + 180 - Math.floor((lon + 180) / 360) * 360 - 180
|
|
|
+ let latRad = (lat * this.PI) / 180
|
|
|
+ let lonRad = (lonTemp * this.PI) / 180
|
|
|
+ let lonOriginRad = (lonOrigin * this.PI) / 180
|
|
|
+ let e2Square = eSquare / (1 - eSquare)
|
|
|
+
|
|
|
+ let V = a / Math.sqrt(1 - eSquare * Math.pow(Math.sin(latRad), 2))
|
|
|
+ let T = Math.pow(Math.tan(latRad), 2)
|
|
|
+ let C = e2Square * Math.pow(Math.cos(latRad), 2)
|
|
|
+ let A = Math.cos(latRad) * (lonRad - lonOriginRad)
|
|
|
+ let M =
|
|
|
+ a *
|
|
|
+ ((1 -
|
|
|
+ eSquare / 4 -
|
|
|
+ (3 * Math.pow(eSquare, 2)) / 64 -
|
|
|
+ (5 * Math.pow(eSquare, 3)) / 256) *
|
|
|
+ latRad -
|
|
|
+ ((3 * eSquare) / 8 +
|
|
|
+ (3 * Math.pow(eSquare, 2)) / 32 +
|
|
|
+ (45 * Math.pow(eSquare, 3)) / 1024) *
|
|
|
+ Math.sin(2 * latRad) +
|
|
|
+ ((15 * Math.pow(eSquare, 2)) / 256 +
|
|
|
+ (45 * Math.pow(eSquare, 3)) / 1024) *
|
|
|
+ Math.sin(4 * latRad) -
|
|
|
+ ((35 * Math.pow(eSquare, 3)) / 3072) * Math.sin(6 * latRad))
|
|
|
+
|
|
|
+ // # x
|
|
|
+ let UTMEasting =
|
|
|
+ k0 *
|
|
|
+ V *
|
|
|
+ (A +
|
|
|
+ ((1 - T + C) * Math.pow(A, 3)) / 6 +
|
|
|
+ ((5 - 18 * T + Math.pow(T, 2) + 72 * C - 58 * e2Square) *
|
|
|
+ Math.pow(A, 5)) /
|
|
|
+ 120) +
|
|
|
+ 500000.0
|
|
|
+ // # y
|
|
|
+ let UTMNorthing =
|
|
|
+ k0 *
|
|
|
+ (M +
|
|
|
+ V *
|
|
|
+ Math.tan(latRad) *
|
|
|
+ (Math.pow(A, 2) / 2 +
|
|
|
+ ((5 - T + 9 * C + 4 * Math.pow(C, 2)) * Math.pow(A, 4)) / 24 +
|
|
|
+ ((61 - 58 * T + Math.pow(T, 2) + 600 * C - 330 * e2Square) *
|
|
|
+ Math.pow(A, 6)) /
|
|
|
+ 720))
|
|
|
+ //# 南半球纬度起点为10000000.0m
|
|
|
+
|
|
|
+ UTMNorthing += FN
|
|
|
+ let xy = []
|
|
|
+ xy[0] = UTMEasting
|
|
|
+ xy[1] = UTMNorthing
|
|
|
+ return xy
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @description 上海城建坐标转wgs84
|
|
|
+ * @time 2020-09-02
|
|
|
+ * @author zhb
|
|
|
+ * @param {*} x
|
|
|
+ * @param {*} y
|
|
|
+ */
|
|
|
+ shcj_to_wgs84: function (x, y) {
|
|
|
+ let xy = []
|
|
|
+ xy = this.shcj_to_utm4(x, y)
|
|
|
+ return this.shcj_get_WGS_from_UTM(xy[0], xy[1])
|
|
|
+ },
|
|
|
+
|
|
|
+ shcj_to_utm4: function (x, y) {
|
|
|
+ let DX, DY, T, K
|
|
|
+ DX = 499999.90104
|
|
|
+ DY = 3455696.403019
|
|
|
+ T = -0.0000001755
|
|
|
+ K = 0.999600149344
|
|
|
+ return this.covert_by_four_parm(x, y, DX, DY, T, K)
|
|
|
+ },
|
|
|
+
|
|
|
+ //四参数公式
|
|
|
+ covert_by_four_parm: function (x, y, dx, dy, a, k) {
|
|
|
+ let px = 0
|
|
|
+ let py = 0
|
|
|
+ px = x * k * Math.cos(a) - y * k * Math.sin(a) + dx
|
|
|
+ py = x * k * Math.sin(a) + y * k * Math.cos(a) + dy
|
|
|
+ let xy = []
|
|
|
+ xy[0] = px
|
|
|
+ xy[1] = py
|
|
|
+ return xy
|
|
|
+ },
|
|
|
+ shcj_get_WGS_from_UTM: function (x, y) {
|
|
|
+ //WGS84
|
|
|
+
|
|
|
+ let a = 6378137 //椭球体长半轴
|
|
|
+ let b = 6356752.3142451 //椭球体短半轴
|
|
|
+ // double a = 6378245 ;
|
|
|
+ // double b =6356863.018773047300000000;
|
|
|
+ x = 500000 - x
|
|
|
+ let k0 = 0.9996
|
|
|
+ let e = Math.sqrt(1 - Math.pow(b, 2) / Math.pow(a, 2))
|
|
|
+ // # calculate the meridional arc
|
|
|
+ let M = y / k0
|
|
|
+ //# calculate footprint latitude
|
|
|
+ let mu =
|
|
|
+ M /
|
|
|
+ (a *
|
|
|
+ (1 -
|
|
|
+ Math.pow(e, 2) / 4 -
|
|
|
+ (3 * Math.pow(e, 4)) / 64 -
|
|
|
+ (5 * Math.pow(e, 6)) / 256))
|
|
|
+ let e1 =
|
|
|
+ (1 - Math.pow(1 - Math.pow(e, 2), 1.0 / 2)) /
|
|
|
+ (1 + Math.pow(1 - Math.pow(e, 2), 1.0 / 2))
|
|
|
+
|
|
|
+ let J1 = (3 * e1) / 2 - (27 * Math.pow(e1, 3)) / 32
|
|
|
+ let J2 = (21 * Math.pow(e1, 2)) / 16 - (55 * Math.pow(e1, 4)) / 32
|
|
|
+ let J3 = (151 * Math.pow(e1, 3)) / 96
|
|
|
+ let J4 = (1097 * Math.pow(e1, 4)) / 512
|
|
|
+ let fp =
|
|
|
+ mu +
|
|
|
+ J1 * Math.sin(2 * mu) +
|
|
|
+ J2 * Math.sin(4 * mu) +
|
|
|
+ J3 * Math.sin(6 * mu) +
|
|
|
+ J4 * Math.sin(8 * mu)
|
|
|
+
|
|
|
+ // # Calculate Latitude and Longitude
|
|
|
+
|
|
|
+ let e2 = Math.pow(e, 2) / (1 - Math.pow(e, 2))
|
|
|
+ let C1 = e2 * Math.pow(Math.cos(fp), 2)
|
|
|
+ let T1 = Math.pow(Math.tan(fp), 2)
|
|
|
+ let R1 =
|
|
|
+ (a * (1 - Math.pow(e, 2))) /
|
|
|
+ Math.pow(1 - Math.pow(e * Math.sin(fp), 2), 3.0 / 2)
|
|
|
+ //# This is the same as rho in the forward conversion formulas above, but calculated for fp instead of lat.
|
|
|
+ let N1 = a / Math.pow(1 - Math.pow(e * Math.sin(fp), 2), 1.0 / 2)
|
|
|
+ //# This is the same as nu in the forward conversion formulas above, but calculated for fp instead of lat.
|
|
|
+ let D = x / (N1 * k0)
|
|
|
+
|
|
|
+ let Q1 = (N1 * Math.tan(fp)) / R1
|
|
|
+ let Q2 = Math.pow(D, 2) / 2
|
|
|
+ let Q3 =
|
|
|
+ ((5 + 3 * T1 + 10 * C1 - 4 * Math.pow(C1, 2) - 9 * e2) * Math.pow(D, 4)) /
|
|
|
+ 24
|
|
|
+ let Q4 =
|
|
|
+ ((61 +
|
|
|
+ 90 * T1 +
|
|
|
+ 298 * C1 +
|
|
|
+ 45 * Math.pow(T1, 2) -
|
|
|
+ 3 * Math.pow(C1, 2) -
|
|
|
+ 252 * e2) *
|
|
|
+ Math.pow(D, 6)) /
|
|
|
+ 720
|
|
|
+ let lat = ((fp - Q1 * (Q2 - Q3 + Q4)) * 180) / this.PI
|
|
|
+ // System.out.println("lat===="+Math.toRadians(fp - Q1*(Q2 - Q3 + Q4)));
|
|
|
+ let Q5 = D
|
|
|
+ let Q6 = ((1 + 2 * T1 + C1) * Math.pow(D, 3)) / 6
|
|
|
+ let Q7 =
|
|
|
+ ((5 -
|
|
|
+ 2 * C1 +
|
|
|
+ 28 * T1 -
|
|
|
+ 3 * Math.pow(C1, 2) +
|
|
|
+ 8 * e2 +
|
|
|
+ 24 * Math.pow(T1, 2)) *
|
|
|
+ Math.pow(D, 5)) /
|
|
|
+ 120
|
|
|
+ let lonmid = 121.46714714
|
|
|
+ let lon = lonmid - (((Q5 - Q6 + Q7) / Math.cos(fp)) * 180) / this.PI
|
|
|
+ //System.out.println("lon===="+(mMid - Math.toRadians((Q5 - Q6 + Q7)/Math.cos(fp))));
|
|
|
+ // System.out.println(lat+","+lon);
|
|
|
+ let xy = []
|
|
|
+ xy[0] = lon
|
|
|
+ xy[1] = lat
|
|
|
+ return xy
|
|
|
+ },
|
|
|
+
|
|
|
+ wgs84_to_bd09: function (x, y) {
|
|
|
+ let ll = this.wgs84_to_gcj02(x, y)
|
|
|
+ ll = this.gcj02_to_bd09(ll[0], ll[1])
|
|
|
+ return ll
|
|
|
+ },
|
|
|
+ bd09_to_wgs84: function (x, y) {
|
|
|
+ let ll = this.bd09_to_gcj02(x, y)
|
|
|
+ ll = this.gcj02_to_wgs84(ll[0], ll[1])
|
|
|
+ return ll
|
|
|
+ },
|
|
|
+ gcj02_to_shcj: function (x, y) {
|
|
|
+ let ll = this.gcj02_to_wgs84(x, y)
|
|
|
+ ll = this.wgs84_to_shcj(ll[0], ll[1])
|
|
|
+ return ll
|
|
|
+ },
|
|
|
+ shcj_to_gcj02: function (x, y) {
|
|
|
+ let ll = this.shcj_to_wgs84(x, y)
|
|
|
+ ll = this.wgs84_to_gcj02(ll[0], ll[1])
|
|
|
+ return ll
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * @description 坐标转换转换 01:84,02:高德,03.百度,04,UTM,05,上海城建,06:米制单位
|
|
|
+ * @param {} from
|
|
|
+ * @param {*} to
|
|
|
+ * @param {*} xy
|
|
|
+ * @time 2020-09-02
|
|
|
+ * @author zhb
|
|
|
+ */
|
|
|
+ convert_proj_from_to: function (from, to, xy) {
|
|
|
+ if (from === to) {
|
|
|
+ return xy
|
|
|
+ } else {
|
|
|
+ let fromProj = this.projs[from]
|
|
|
+ let toProj = this.projs[to]
|
|
|
+ let targetMethod = `${fromProj}_to_${toProj}`
|
|
|
+ return this[targetMethod](xy[0], xy[1])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * @description 坐标转换转换,from 和to 都是epsg ID,如4326,3857
|
|
|
+ * @param {} from 4528
|
|
|
+ * @param {*} to 4326
|
|
|
+ * @param {*} xy [x, y]
|
|
|
+ * @time 2021-01-19
|
|
|
+ * @author zhb
|
|
|
+ */
|
|
|
+ convert_proj_from_to2: function (from, to, xy) {
|
|
|
+ if (from === to) {
|
|
|
+ return xy
|
|
|
+ } else {
|
|
|
+ let fromProj = this.epsg[from]
|
|
|
+ let toProj = this.epsg[to]
|
|
|
+ if (fromProj && toProj) {
|
|
|
+ let coor = proj4(fromProj, toProj, xy)
|
|
|
+ return coor
|
|
|
+ } else {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// module.exports = coordinate
|
|
|
+export default coordinate
|