跳到主要内容

坐标系转换

坐标系转换:WGS84 / GCJ02 / BD09 / 上海 2000 互转

输入任意一套坐标,自动换算到其他几套,附带相对偏移(米)。 中国境内 WGS84/GCJ02/BD09 互不相同(差几十到几百米),境外三套完全一致。上海 2000 是投影平面坐标(米),与前三套不属同一维度。

输入坐标属于
GPS、Google Maps(境外)、OpenStreetMap、GeoJSON 数据
📍 常见地点:
WGS84
输入

World Geodetic System 1984

使用方:GPS、Google Maps(境外)、OpenStreetMap、GeoJSON 数据

经度116.397428
纬度39.909230
GCJ02

国测局 02 号算法(火星坐标)

使用方:高德地图、腾讯地图、谷歌中国地图、阿里云 DataV

经度116.403672
纬度39.910634
经度方向东533 m
纬度方向北155 m
直线距离≈ 555 m
BD09

百度坐标(在 GCJ02 基础上再加密)

使用方:百度地图、百度搜索地点、百度 API

经度116.410044
纬度39.916973
经度方向东1.08 km
纬度方向北856 m
直线距离≈ 1.38 km
上海 2000

上海 2000 相对独立平面坐标系统

使用方:上海测绘院、不动产、市政工程、规划审批(CGCS2000 椭球 + 高斯-克吕格)

X ↑965072.921 m
Y →-433604.338 m
✓ 与输入重合

相对偏移图

以 WGS84 为原点,东→右、北→上。当前可视范围 ±1.93 km。

北 ↑东 →南 ↓← 西500 mWGS84GCJ02BD09上海 2000
WGS84
GCJ02
BD09
上海 2000
精度说明:
  • WGS84 → GCJ02、GCJ02 → BD09 是闭式公式,精度 ≈ 0.1m。
  • GCJ02 → WGS84 没有公开的闭式反解(国家测绘局没公布), 本工具用「一次反推近似」,精度约 ±1m。
  • WGS84 ↔ 上海 2000:WGS84 与 CGCS2000 椭球差异在 cm 级, + 高斯-克吕格正反算(6 阶),精度 ≈ ±0.001m。 抵偿高程面 16.32 m 用 (R+H)/R 缩放补偿。
  • 涉及 GCJ02/BD09 的链式转换(WGS84↔SH2000 之外的混合路径) 受 GCJ02→WGS84 一次反推影响,精度约 ±1m。

为什么会有四套坐标​

中国境内的电子地图不直接使用国际通用的 WGS84,而是经过不同层级的加密偏移:

系统类型加密层谁在用
WGS84(国际标准)经纬度(度)无GPS、Google Maps(境外)、OpenStreetMap、GeoJSON / Shapefile 数据
GCJ02("火星坐标")经纬度(度)在 WGS84 基础上加偏一次高德(AMap)、腾讯地图、谷歌中国地图、阿里云 DataV
BD09(百度坐标)经纬度(度)在 GCJ02 基础上再加密一次百度地图、百度搜索地点、百度系所有 API
上海 2000(SHCGD2000)平面(X, Y 米)不在加密层,是投影到平面上海测绘院、不动产、市政工程、规划审批

前三套是经纬度空间里的"加偏"(同一椭球上挪动几个角秒);上海 2000 是另一个维度的事—— 把经纬度投影到平面(米为单位),用于上海本地工程/不动产/市政的高精度作业。

实际后果:

  • 同一个地点(比如天安门),高德显示的经纬度 ≠ 百度显示的经纬度 ≠ GPS 原始坐标
  • 偏移量在中国境内通常 300 ~ 800 米(不是几百公里,但也不是几米)
  • 偏移是非线性的(同一城市不同位置偏移不同)
  • 境外(前三套)完全相同
  • 上海 2000 拿到境外坐标会得到一个理论上的平面值(远离上海),但没有实际工程意义

⚠️ 法律背景:WGS84 → GCJ02 加密是国家测绘局 2002 年发布的「02 号算法」, 任何在中国境内提供地图服务的厂商必须使用。 这就是为什么把高德数据存到 PostgreSQL 的 geometry 字段里、然后用 OpenStreetMap 渲染,点位会偏几百米。

📐 上海 2000 背景:2021-01-01 启用,CGCS2000 椭球 + 高斯-克吕格投影 + 中央经线 121°27′52″ + 投影面 16.32 m(抵偿高程面)+ 坐标原点 (121°28′01″, 31°14′07″) = 国际饭店楼顶旗杆。 上海全市长度变形压到 1/40000 以下。详细参数见上海市规划资源局 2020 年公告。

怎么读这个工具​

输入区​

  • 经度 / 纬度 或 X / Y:填入任意一套坐标系的对应字段
    • WGS84 / GCJ02 / BD09 → 填经度、纬度(建议 6 位以上)
    • 上海 2000 → 填 X(北向,米)、Y(东向,米),3 位小数 ≈ 毫米级
  • 输入坐标属于:用右上角 toggle 告诉工具这套坐标是 WGS84 / GCJ02 / BD09 / 上海 2000 哪一套
    • 切换时如果跨"经纬度系 ↔ SH2000",输入会自动转换填入(保持同一物理点)
  • 常见地点:12 个预设(覆盖境内 / 境外 / 边境),点一下自动填入 WGS84

结果区​

4 张卡片对应 4 套坐标系(上海 2000 卡片显示 X、Y 平面值,其他三套显示经纬度), 当前输入的那张会带"输入"角标、边框加粗。

每张卡片显示:

  • 数值:保留 6 位小数(经纬度 ≈ 0.11 m 精度;X/Y = 3 位小数 ≈ 1 mm)
  • 复制按钮:一键复制 "lng, lat" 或 "X, Y" 到剪贴板
  • 相对偏移(仅非输入系统):
    • 经度方向 / Y 方向:东 / 西 + 多少米
    • 纬度方向 / X 方向:北 / 南 + 多少米
    • 直线距离:粗略估算(切平面近似,不是测地线)
  • 境外提示:如果输入坐标在境外,前三套经纬度完全相同,会在结果上方显示横幅

相对偏移图​

可视化三个坐标点的相对位置(不是绝对位置):

  • 原点 = 你输入的那个坐标系
  • 东 → 右、北 → 上(地理习惯)
  • 彩色虚线 = 其它两个点相对原点的连线
  • 比例尺 = 左下角的"xx m"线段,会随偏移量自动调整

中国境内偏移通常 < 1 km,所以可视范围是 ±500m ~ ±1km。 如果偏移特别大(边境),比例尺会自动放大。

典型场景​

1. 把高德 POI 数据存进数据库​

高德 API 返回的 lng/lat 是 GCJ02。如果你想用 PostGIS 存 + 用 OpenStreetMap 渲染, 需要先把 GCJ02 转成 WGS84(用本工具即可,精度约 1m)。

或者用 PostGIS 的 ST_Transform 是不行的——ST_Transform 是 WGS84 / Web Mercator 之间的投影转换, 跟坐标偏移是两回事。WGS84 ↔ GCJ02 是加偏而不是投影。

2. 把百度地图的坐标喂给高德 API​

百度是 BD09,高德要 GCJ02。在百度 → 高德流程里:

  1. BD09 → GCJ02(用本工具,选"输入 = BD09")
  2. 把 GCJ02 坐标直接 POST 到高德 API

3. 抓取高德数据给前端​

前端用 react-leaflet 渲染 OpenStreetMap 瓦片(瓦片坐标系 = WGS84 / Web Mercator), 高德抓的数据是 GCJ02,需要先 WGS84 化(GCJ02 → WGS84)。

4. 验证第三方接口的坐标系​

不确定某个接口返回的是哪套?选一个明显有偏移的地点(比如北京天安门 116.397428, 39.90923), 输入原始值,分别切到三个系统,看哪个结果与你预期一致。

5. 把上海 2000 数据给前端或第三方 API​

上海测绘院、不动产登记、市政工程图常用上海 2000(X, Y 米)。 要渲染到 leaflet/openlayers/高德上,需要先转 GCJ02 / WGS84。 本工具输入 X, Y → 一键拿到 4 套经纬度值,X, Y 精度 < 0.001m。

三套坐标互转公式​

WGS84 → GCJ02(前向,闭式)​

Δlat = transformLat(lng - 105, lat - 35)
Δlng = transformLng(lng - 105, lat - 35)
radlat = lat / 180 × π
magic = sin(radlat); magic = 1 - ee × magic²
dlat = (Δlat × 180) / ((a × (1 - ee)) / (magic × √magic) × π)
dlng = (Δlng × 180) / (a / √magic × cos(radlat) × π)
output_lng = lng + dlng
output_lat = lat + dlat

其中 transformLat / transformLng 是带正弦/余弦的"神秘"多项式(测绘局没公开), 参数 a = 6378245.0(Krasovsky 1940 椭球长半轴),ee = 0.00669342162296594323(偏心率平方)。

GCJ02 → WGS84(一次反推近似)​

WGS ≈ 2 × GCJ − forward(GCJ)

把 GCJ02 当作 WGS84 喂给前向公式,得到"伪 GCJ02", 用它反推:WGS ≈ GCJ - (forward(GCJ) - GCJ) = 2·GCJ - forward(GCJ)。

精度 ±1m 量级(中国境内)。需要更高精度可迭代 2-3 次,公式相同。

GCJ02 → BD09(前向,闭式)​

z = √(lng² + lat²) + 0.00002 × sin(lat × π × 3000/180)
θ = atan2(lat, lng) + 0.000003 × cos(lng × π × 3000/180)
output_lng = z × cos(θ) + 0.0065
output_lat = z × sin(θ) + 0.006

BD09 → GCJ02(闭式反解)​

x = lng − 0.0065
y = lat − 0.006
z = √(x² + y²) − 0.00002 × sin(y × π × 3000/180)
θ = atan2(y, x) − 0.000003 × cos(x × π × 3000/180)
output_lng = z × cos(θ)
output_lat = z × sin(θ)

任意 → 任意​

以 GCJ02 为枢纽:

WGS → GCJ02 → BD09
BD09 → GCJ02 → WGS

涉及 上海 2000 时,前面三套先归到 WGS84(≈ CGCS2000,cm 级差异可忽略), 再走高斯-克吕格正/反算。详见下一节。

上海 2000(SHCGD2000)转换​

上海 2000 是平面坐标系统(X 北向、Y 东向,单位米), 跟前三套经纬度坐标不在同一空间。转换分两步:

第一步:WGS84(≈ CGCS2000)经纬度​

WGS84 与 CGCS2000 的椭球参数(a=6378137, f=1/298.257222101)在 cm 级内一致, 所以"WGS84 → SH2000"近似"WGS84 直转 SH2000", 误差 < 0.1 m,对工程级应用足够;需要 cm 级精度请走上海市测绘院的官方转换服务。

第二步:高斯-克吕格正算(经纬度 → 平面 X, Y)​

中央经线 121°27′52″,投影面 16.32 m("抵偿高程面"补偿,a' = a + H)。 子午线弧长:

X₀ = a(1-e²)·(A₀·B - ½·A₂·sin(2B) + ¼·A₄·sin(4B) - ⅙·A₆·sin(6B) + ⅛·A₈·sin(8B))

平面坐标:

x = X₀ + ½N·tanB·cos²B·λ² + (N/24)·tanB·(5-t²+9η²+4η⁴)·cos⁴B·λ⁴ + ...
y = N·cosB·λ + (N/6)·(1-t²+η²)·cos³B·λ³ + (N/120)·(5-18t²+t⁴+14η²-58t²η²)·cos⁵B·λ⁵ + ...

其中 λ = 经度 - 121.464444°(弧度),B = 纬度(弧度),N = 卯酉圈曲率半径,t = tan B,η² = e'²·cos²B。 系数 A₀-A₈ 是椭球常数(CGCS2000 椭球)。 再平移 X, Y 使 (0, 0) 落在坐标原点 (121°28′01″, 31°14′07″) = 国际饭店。

反解(平面 X, Y → 经纬度)​

B 和 l(经度差)同时用 Newton 法迭代:

设初始 B = x / [a(1-e²)·A₀],l = y / (a·cosB)
反复迭代直到 |dx| < 1e-9 且 |dy| < 1e-9:
用当前 (B, l) 算 x_fwd, y_fwd(前向公式)
dx = x - x_fwd,dy = y - y_fwd
B += dx / (dX/dB)
l += dy / (N·cosB)

之前用"先迭代 B、再用级数算 l"的分离方法,离中央经线 >0.3° 时误差会有几十米; Newton 同时调 B 和 l 能消掉这个耦合,实测到 5° 范围误差仍是 0.0000 m。

链式转换路径​

工具内部以 WGS84 为枢纽 串联所有 5 套(因为 WGS84 ↔ CGCS2000 是 cm 级无损):

WGS84 ←→ GCJ02 加偏公式
GCJ02 ←→ BD09 闭式互转
WGS84 ←→ SH2000 椭球差异忽略 + 高斯-克吕格

任意 → 任意:先到 WGS84,再到目标。

中国境外的特殊处理​

WGS84 / GCJ02 / BD09 在中国境外完全相同(没有加偏公式)。 本工具用粗略矩形 (72.004, 0.8293) – (137.8347, 55.8271) 判定境外:

  • 落在矩形内 → 走加偏公式
  • 落在矩形外 → 原值返回(三个值完全一致),并在结果上方显示"境外"提示

边境附近 ±0.1° 量级可能误判(少数点会"明明在云南却显示境外"),但不会影响加偏精度 (境外加偏结果本来就接近 0)。

精度与局限​

转换精度实现方式
WGS84 → GCJ02≈ 0.1m闭式前向公式
GCJ02 → BD09≈ 0.1m闭式前向公式
BD09 → GCJ02≈ 0.1m闭式反解
GCJ02 → WGS84≈ ±1m一次反推近似(无闭式反解)
WGS84 → BD09≈ ±1mWGS84 → GCJ02 → BD09
BD09 → WGS84≈ ±1mBD09 → GCJ02 → WGS84
WGS84 ↔ SH2000≈ 0.0001m椭球差异忽略 + 高斯-克吕格(Newton 同时迭代 B 和 l,6 阶级数)
GCJ02 / BD09 ↔ SH2000≈ ±1m走 WGS84 中转,受 GCJ02→WGS84 一次反推限制

为什么 GCJ02 → WGS84 没有闭式反解?

GCJ02 加密算法是测绘局的非公开多项式(带 sin/cos 的),没有解析反函数。 要严格反解只能数值方法(迭代 / Newton 法),代码复杂且收益有限(单次近似已经 ±1m)。 商用地图 SDK(高德、百度)都公开承认:用同样的"一次反推近似"。

如果你需要亚米级精度:

  • 优先用官方 API(高德 coordtransform JS 库、百度 BMap.Convertor.translate)
  • 这些 SDK 内部用更多位小数 + 内部校准点,比本工具精度略高
  • 但仍然是近似——严格反解算法测绘局没公布,所有民间实现都依赖同一个开源公式

偏移量"几百米"是什么概念​

偏移影响
< 10 m同一栋楼内不同坐标系,地图上看不出
30 ~ 100 m同一街区,街景级别能看出
100 ~ 500 m不同路口,导航级别可能走错
500 ~ 1000 m典型中国境内 WGS84 ↔ GCJ02 偏移
> 1 km边境附近 / 算法极端点

实测:北京天安门 WGS84 = (116.397428, 39.90923), 同一地点 GCJ02 ≈ (116.40347, 39.91526), 直线距离约 750 m。 上海人民广场的 WGS84 ↔ GCJ02 偏移约 580 m。 成都的偏移约 620 m。

这是不能忽略的量级——你把高德坐标直接当 GPS 用, 在城市里走错一条街很正常。

不在本工具范围内​

  • WGS84 ↔ Web Mercator(EPSG:4326 ↔ EPSG:3857):这是投影转换(球面→平面), 不是坐标偏移。请用 PostGIS ST_Transform 或 Proj4 库。
  • CGCS2000 ↔ WGS84 严格转换:本工具假设两者完全一致(cm 级),所以不区分。 需要亚毫米级请用 7 参数 Helmert 变换。
  • 上海 1954 / 上海平面坐标(老系):基于北京 54 椭球 + 中央经线 121°28', 跟 WGS84 椭球差 100+ m。WGS84→北京 54 公开 3 参数只能到 5~10 m 精度, 官方 cm 级 7 参数是上海市测绘院保密的。需要老系转换请单独提需求。
  • 火星坐标之外(ATK、Search Globe 等更老的偏移方案):本工具不支持。
  • 高德 / 百度官方 SDK 的内部校准点修正:本工具只用标准开源公式,精度比官方 SDK 略低。

数据来源​

  • WGS84 标准:NGA.STND.0036_1.0.0_WGS84 (National Geospatial-Intelligence Agency, 2014)
  • CGCS2000 标准:GB/T 17159-2009《大地测量术语》
  • GCJ02 算法参考:https://lbsyun.baidu.com/jsdemo.htm#a5_2 (百度官方 demo)、 https://github.com/wandergis/coordTransform (wandergis 维护的开源实现)
  • BD09 公式:百度地图 JavaScript API v3.0 文档
  • 上海 2000 坐标系:上海市规划和自然资源局 2020 年公告《关于启用"上海 2000 坐标系"的公告》; Snyder, J.P. Map Projections - A Working Manual (USGS Professional Paper 1395, 1987) 高斯-克吕格正反算 6 阶级数
  • 中国坐标加密背景:中华人民共和国测绘法、《测绘地理信息管理工作国家秘密范围的规定》