/** * WGS84 → GCJ-02 → BD-09 坐标转换工具 * 百度地图需要使用 BD-09 坐标系 */ const PI = Math.PI const X_PI = (PI * 3000.0) / 180.0 const A = 6378245.0 const EE = 0.00669342162296594323 function transformLat(lng, lat) { 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, lat) { 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 } /** WGS84 → GCJ-02 (火星坐标) */ function wgs84ToGcj02(lng, lat) { let dLat = transformLat(lng - 105.0, lat - 35.0) let dLng = transformLng(lng - 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) dLng = (dLng * 180.0) / ((A / sqrtMagic) * Math.cos(radLat) * PI) return [lng + dLng, lat + dLat] } /** GCJ-02 → BD-09 (百度坐标) */ function gcj02ToBd09(lng, lat) { const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * X_PI) const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * X_PI) return [z * Math.cos(theta) + 0.0065, z * Math.sin(theta) + 0.006] } /** WGS84 → BD-09 一步转换 */ export function wgs84ToBd09(lng, lat) { const [gcjLng, gcjLat] = wgs84ToGcj02(lng, lat) return gcj02ToBd09(gcjLng, gcjLat) } /** 百度 BD-09 → WGS84,用于地图选点回填业务坐标 */ export function bd09ToWgs84(lng, lat) { const x = Number(lng) - 0.0065 const y = Number(lat) - 0.006 const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI) const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI) const gcjLng = z * Math.cos(theta) const gcjLat = z * Math.sin(theta) const [wgsLng, wgsLat] = wgs84ToGcj02Inverse(gcjLng, gcjLat) return [wgsLng, wgsLat] } function wgs84ToGcj02Inverse(lng, lat) { const [forwardLng, forwardLat] = wgs84ToGcj02(lng, lat) return [lng * 2 - forwardLng, lat * 2 - forwardLat] } /** 转换管线数据中的坐标数组 */ export function convertPipeline(pipeline) { return { ...pipeline, path: pipeline.path ? pipeline.path.map(([lng, lat]) => wgs84ToBd09(lng, lat)) : undefined, points: pipeline.points ? (Array.isArray(pipeline.points[0]) ? pipeline.points.map(([lng, lat]) => wgs84ToBd09(lng, lat)) : pipeline.points.map(p => ({ ...p, lng: wgs84ToBd09(p.lng, p.lat)[0], lat: wgs84ToBd09(p.lng, p.lat)[1] }))) : undefined } } /** 转换单个坐标点 */ export function convertCoord(lng, lat) { return wgs84ToBd09(lng, lat) } /** 批量转换点数组中的 lng/lat */ export function convertPoints(points) { return points.map(p => { const [lng, lat] = wgs84ToBd09(p.lng, p.lat) return { ...p, lng, lat } }) }