欢迎光临
我们一直在努力

坐标系转换实战:WGS84、GCJ-02、BD-09 互转代码与“地图整体偏移“排查

凌晨两点,值班群弹出一条:“线上地图所有 POI 都偏了,大概几百米,全上海的点都往一个方向挪。”

第一反应是瓦片服务挂了。查了一圈,地图正常、接口正常、数据正常——直到发现新导入的一批 POI 是 GPS 设备直出的 WGS84 坐标,直接喂给了 GCJ-02 的地图。

几百米不是偏差,是坐标系没转。这篇把三坐标系互转的代码、适用场景和排查方法一次讲清。结论先说:采集层统一转 GCJ-02 入库,展示层不再转;WGS84↔GCJ-02 没有官方公开算法,网上实现是近似解,涉及计费/围栏/考勤必须走官方转换接口。

💰 商用授权成本自测:坐标转换接口(ws/coord/v1/translate)免费额度只用于测试,商用无论调用量多少都要办商业授权(基础版 5 万/年)。文末有免费测算入口。


一、事故现场:三个坐标系是怎么来的

国内地图有三层坐标系,关系是层层加密:

  • WGS84:GPS 卫星原始坐标,设备直出。硬件(手机、定位器、车载终端)拿到的都是它。
  • GCJ-02(火星坐标):国测局对 WGS84 做非线性偏移,国内绝大多数互联网地图的基础坐标系——腾讯、高德都用它。
  • BD-09:百度在 GCJ-02 基础上再次加密,国内(含港澳台)默认用它,海外才用 WGS84。

事故的根源:数据源(WGS84)、地图底图(GCJ-02 或 BD-09)、你调的服务 API——三者坐标系一旦混用,偏差就是百米级、肉眼可见,还会一路污染到围栏判定和轨迹里程。

二、修复代码:三段可复用的转换函数

先给能直接用的。GCJ-02 ↔ BD-09 的互转公式是业界通用实现(百度文档同款逻辑);WGS84 ↔ GCJ-02 没有官方公开算法,以下为社区通行近似实现,标注清楚适用范围:

const X_PI = Math.PI * 3000.0 / 180.0

// GCJ-02 → BD-09(百度地图坐标系)
function gcj02ToBd09(lng, lat) {
const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * X_PI)
const t = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * X_PI)
return [z * Math.cos(t) + 0.0065, z * Math.sin(t) + 0.006]
}

// BD-09 → GCJ-02(从百度回到通用坐标系)
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 t = Math.atan2(y, x) 0.000003 * Math.cos(x * X_PI)
return [z * Math.cos(t), z * Math.sin(t)]
}

// WGS84 → GCJ-02(GPS 坐标上图前必转)
// 注意:此为社区近似实现,非官方算法,展示用可以,计费/围栏/考勤别用
function wgs84ToGcj02(lng, lat) {
// …(较长,社区实现,按精度要求选用)
// 有责任边界的场景,请改用腾讯位置服务官方转换接口
// GET https://apis.map.qq.com/ws/coord/v1/translate
}

两个必懂的点:

  • 转换只做一次,在数据入口统一做。 设备 WGS84 → 服务端接收层转 GCJ-02 → 入库 → 之后围栏、轨迹、渲染全用 GCJ-02,不再转。最怕业务代码里东一处西一处地转,那是偏移事故的主要来源。
  • BD-09 是死胡同。 只要你的地图不是百度,就别引入 BD-09。一旦数据进了 BD-09,想转出来又没官方接口,只能靠近似算法,误差累积。
  • 三、继续排查:事故里还有哪些隐蔽坑

    坑一:百度同厂两个 SDK 坐标系不一致。 百度官方 FAQ 白纸黑字:地图 SDK 国内默认 BD09,而定位 SDK 默认输出 GCJ02。你以为"都是百度不会错",实际定位点喂给地图就偏。这也是"没换供应商却偏了"的隐蔽来源。

    坑二:ws/coord/v1/translate 是单向的。 官方描述是"从其它坐标系转换到腾讯地图坐标系"——GCJ-02 转回 WGS84 没有官方接口。网上 gcj02towgs84() 全是拟合近似解,做司法举证、计费复核这类场景不能用来做结论。

    坑三:转换函数传参顺序。 locations 参数纬度在前、经度在后,跟大多数人习惯相反。写反了某些区域不报错,只是给你一个几百公里外的坐标——比偏移更难排查。

    四、预防:一套坐标系贯穿到底

    上线后这次事故的修复方案,其实就一句话:规定数据流里只有一个坐标系。

    • 采集层:设备 WGS84,服务端入口统一转 GCJ-02
    • 存储层:全库 GCJ-02,字段名带 _gcj02 后缀,杜绝歧义
    • 展示层:腾讯/高德直接渲染 GCJ-02,百度场景才在出口转 BD-09
    • 有责任边界的场景(计费里程、考勤围栏、司法举证):保留原始 WGS84 字段做底稿,转换结果只用于计算和展示

    相关阅读:本系列《地图 API 选型对比》讲了坐标系选型为什么决定接入成本;《轨迹纠偏四开关对照》讲轨迹坐标的处理;坐标转换接口的单向性在《坐标系转换方向性》里展开过。


    帮你把坐标系账算清楚

    坐标转换这种接口,授权费(基础版 5 万/年)是固定成本、跟调用量无关;真正能省的是流量包——同一点反复转换毫无意义,按坐标截断 4 位(≈11 米)做缓存键,同栋楼的转换结果直接命中缓存,能省下一大截调用。

    你的数据源是什么(GPS 设备 / 小程序 / 存量 BD-09)?出口在哪(腾讯 / 高德 / 百度)?把这两个坐标信息丢评论区,或填成本测算表(6 项,2 分钟),我按官方档位帮你算授权版本 + 流量包预估,包括转换链路怎么设计最省。免费,1 个工作日内回。

    赞(0)
    未经允许不得转载:171主机测评 » 坐标系转换实战:WGS84、GCJ-02、BD-09 互转代码与“地图整体偏移“排查
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址