支持WGS84、大地2000、墨卡托投影、火星坐标(GCJ02)和百度坐标(BD09)之间的相互转换
每行一个坐标,格式:经度,纬度 或 经度 纬度
// GIS坐标转换工具
const PI = Math.PI;
const X_PI = PI * 3000.0 / 180.0;
const A = 6378245.0;
const EE = 0.006693421622965943;
const EARTH_RADIUS = 6378137.0;
function outOfChina(lng, lat) {
return lng < 72.004 || lng > 137.8347 || lat < 0.8293 || lat > 55.8271;
}
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 -> GCJ02
function wgs84ToGcj02(lng, lat) {
if (outOfChina(lng, lat)) return { 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: lng + dLng, lat: lat + dLat };
}
// GCJ02 -> WGS84
function gcj02ToWgs84(lng, lat) {
if (outOfChina(lng, lat)) return { 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: lng - dLng, lat: lat - dLat };
}
// GCJ02 <-> BD09
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 { lng: z * Math.cos(theta) + 0.0065, lat: z * Math.sin(theta) + 0.006 };
}
function bd09ToGcj02(lng, lat) {
const x = lng - 0.0065, y = 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);
return { lng: z * Math.cos(theta), lat: z * Math.sin(theta) };
}
// WGS84 <-> Web墨卡托
function wgs84ToMercator(lng, lat) {
const x = lng * EARTH_RADIUS * PI / 180;
const y = EARTH_RADIUS * Math.log(Math.tan((90 + lat) * PI / 360));
return { lng: x, lat: y };
}
function mercatorToWgs84(x, y) {
const lng = x / EARTH_RADIUS * (180 / PI);
const lat = Math.atan(Math.exp(y / EARTH_RADIUS)) * 360 / PI - 90;
return { lng, lat };
}
// 使用示例
const wgs84 = { lng: 116.397428, lat: 39.90923 }; // 北京天安门
console.log('WGS84:', wgs84);
console.log('GCJ02:', wgs84ToGcj02(wgs84.lng, wgs84.lat));import math
PI = math.pi
X_PI = PI * 3000.0 / 180.0
A = 6378245.0
EE = 0.006693421622965943
EARTH_RADIUS = 6378137.0
def out_of_china(lng: float, lat: float) -> bool:
return lng < 72.004 or lng > 137.8347 or lat < 0.8293 or lat > 55.8271
def transform_lat(lng: float, lat: float) -> float:
ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * math.sqrt(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
def transform_lng(lng: float, lat: float) -> float:
ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * math.sqrt(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
def wgs84_to_gcj02(lng: float, lat: float) -> tuple[float, float]:
"""WGS84 -> GCJ02"""
if out_of_china(lng, lat):
return lng, lat
d_lat = transform_lat(lng - 105.0, lat - 35.0)
d_lng = transform_lng(lng - 105.0, lat - 35.0)
rad_lat = lat / 180.0 * PI
magic = math.sin(rad_lat)
magic = 1 - EE * magic * magic
sqrt_magic = math.sqrt(magic)
d_lat = (d_lat * 180.0) / ((A * (1 - EE)) / (magic * sqrt_magic) * PI)
d_lng = (d_lng * 180.0) / (A / sqrt_magic * math.cos(rad_lat) * PI)
return lng + d_lng, lat + d_lat
def gcj02_to_wgs84(lng: float, lat: float) -> tuple[float, float]:
"""GCJ02 -> WGS84"""
if out_of_china(lng, lat):
return lng, lat
d_lat = transform_lat(lng - 105.0, lat - 35.0)
d_lng = transform_lng(lng - 105.0, lat - 35.0)
rad_lat = lat / 180.0 * PI
magic = math.sin(rad_lat)
magic = 1 - EE * magic * magic
sqrt_magic = math.sqrt(magic)
d_lat = (d_lat * 180.0) / ((A * (1 - EE)) / (magic * sqrt_magic) * PI)
d_lng = (d_lng * 180.0) / (A / sqrt_magic * math.cos(rad_lat) * PI)
return lng - d_lng, lat - d_lat
def gcj02_to_bd09(lng: float, lat: float) -> tuple[float, float]:
"""GCJ02 -> BD09"""
z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * X_PI)
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
def bd09_to_gcj02(lng: float, lat: float) -> tuple[float, float]:
"""BD09 -> GCJ02"""
x, y = lng - 0.0065, lat - 0.006
z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * X_PI)
theta = math.atan2(y, x) - 0.000003 * math.cos(x * X_PI)
return z * math.cos(theta), z * math.sin(theta)
def wgs84_to_mercator(lng: float, lat: float) -> tuple[float, float]:
"""WGS84 -> Web墨卡托"""
x = lng * EARTH_RADIUS * PI / 180
y = EARTH_RADIUS * math.log(math.tan((90 + lat) * PI / 360))
return x, y
def mercator_to_wgs84(x: float, y: float) -> tuple[float, float]:
"""Web墨卡托 -> WGS84"""
lng = x / EARTH_RADIUS * (180 / PI)
lat = math.atan(math.exp(y / EARTH_RADIUS)) * 360 / PI - 90
return lng, lat
# 使用示例
if __name__ == "__main__":
wgs84 = (116.397428, 39.90923) # 北京天安门
print(f"WGS84: {wgs84}")
print(f"GCJ02: {wgs84_to_gcj02(*wgs84)}")