/** * 坐标系转换工具 * WGS84(地球坐标系)与 GCJ02(火星坐标系)相互转换 */ // 地标转国测常量 const X_PI = (3.14159265358979324 * 3000.0) / 180.0; const PI = 3.1415926535897932384626; const A = 6378245.0; // 卫星椭球坐标投影到平面地图坐标系的投影因子 const EE = 0.00669342162296594323; // 椭球的偏心率 /** * 坐标点类型定义 */ export interface CoordinatePoint { lng: number; // 经度 lat: number; // 纬度 } /** * 判断是否在国内,在中国国内的经纬度才需要做偏移 * @param lng 经度 * @param lat 纬度 * @returns 是否在国外 */ function outOfChina(lng: number, lat: number): boolean { return ( lng < 72.004 || lng > 137.8347 || lat < 0.8293 || lat > 55.8271 ); } /** * 转化经度 * @param lng 经度 * @param lat 纬度 * @returns 转换后的经度偏移量 */ function transformLng(lng: number, lat: number): number { 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; } /** * 转化纬度 * @param lng 经度 * @param lat 纬度 * @returns 转换后的纬度偏移量 */ function transformLat(lng: number, lat: number): number { 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; } /** * WGS84坐标系转GCJ02坐标系(地球坐标系转火星坐标系) * @param lng 经度 * @param lat 纬度 * @returns 转换后的坐标 [经度, 纬度] */ export function wgs84ToGcj02(lng: number, lat: number): [number, number] { if (outOfChina(lng, lat)) { return [lng, lat]; } const dlat = transformLat(lng - 105.0, lat - 35.0); const 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); const transformedLat = (dlat * 180.0) / (((A * (1 - EE)) / (magic * sqrtmagic)) * PI); const transformedLng = (dlng * 180.0) / ((A / sqrtmagic) * Math.cos(radlat) * PI); const mglat = lat + transformedLat; const mglng = lng + transformedLng; return [mglng, mglat]; } /** * GCJ02坐标系转WGS84坐标系(火星坐标系转地球坐标系) * @param lng 经度 * @param lat 纬度 * @returns 转换后的坐标 [经度, 纬度] */ export function gcj02ToWgs84(lng: number, lat: number): [number, number] { if (outOfChina(lng, lat)) { return [lng, lat]; } const dlat = transformLat(lng - 105.0, lat - 35.0); const 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); const transformedLat = (dlat * 180.0) / ((A * (1 - EE)) / (magic * sqrtmagic) * PI); const transformedLng = (dlng * 180.0) / (A / sqrtmagic * Math.cos(radlat) * PI); const mglat = lat + transformedLat; const mglng = lng + transformedLng; return [lng * 2 - mglng, lat * 2 - mglat]; } /** * 对象形式的坐标转换 - WGS84转GCJ02 * @param point 坐标点对象 {lng: 经度, lat: 纬度} * @returns 转换后的坐标点对象 */ export function wgs84ToGcj02Point(point: CoordinatePoint): CoordinatePoint { const [lng, lat] = wgs84ToGcj02(point.lng, point.lat); return { lng, lat }; } /** * 对象形式的坐标转换 - GCJ02转WGS84 * @param point 坐标点对象 {lng: 经度, lat: 纬度} * @returns 转换后的坐标点对象 */ export function gcj02ToWgs84Point(point: CoordinatePoint): CoordinatePoint { const [lng, lat] = gcj02ToWgs84(point.lng, point.lat); return { lng, lat }; } /** * 批量转换坐标点 - WGS84转GCJ02 * @param points 坐标点数组 * @returns 转换后的坐标点数组 */ export function batchWgs84ToGcj02(points: CoordinatePoint[]): CoordinatePoint[] { return points.map(point => wgs84ToGcj02Point(point)); } /** * 批量转换坐标点 - GCJ02转WGS84 * @param points 坐标点数组 * @returns 转换后的坐标点数组 */ export function batchGcj02ToWgs84(points: CoordinatePoint[]): CoordinatePoint[] { return points.map(point => gcj02ToWgs84Point(point)); } // 默认导出 export default { wgs84ToGcj02, gcj02ToWgs84, wgs84ToGcj02Point, gcj02ToWgs84Point, batchWgs84ToGcj02, batchGcj02ToWgs84, outOfChina };