ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ccvt:一个用 Rust 写的中国地图坐标系互转命令行工具

ccvt:一个用 Rust 写的中国地图坐标系互转命令行工具

ccvt 是面向命令行与数据管道的中国地图坐标转换工具,解决 WGS84 / GCJ02 / BD09 三个坐标系之间的互转。库 + CLI 双暴露,管道优先。

一、要解决的问题

在中国做地图开发,几乎每个人都踩过同一个坑:坐标系不统一

  • WGS84:GPS 原始坐标,数据库、硬件上报、国际 API 多用这个。
  • GCJ02(火星坐标):高德、腾讯地图在用,与真实经纬度偏移 100–500 米。
  • BD09:百度坐标,在 GCJ02 上再叠一层偏移。

「后端存 WGS84、前端高德要 GCJ02」每天都在发生。前端生态(Gcoord、coordtransform)成熟了,但后端 / 数据管道场景一直缺趁手的工具——要装 npm 依赖、写胶水脚本、海量数据时性能跟不上。ccvt 就是一条命令,在管道里批量转换。

本机实测:

$ echo "116.3975 39.9087" | ccvt -f wgs84 -t gcj02 116.40374357265176 39.91010349934476 $ echo '{"lng":116.3975,"lat":39.9087}' | ccvt -f wgs84 -t gcj02 -i json -o json {"lat":39.91010349934476,"lng":116.40374357265176}

二、解决方案:支持哪些功能

技术选型:Rust + clap + serde,GitHub Actions 发布 7 个平台制品。

功能清单

① 6 个转换方向——三个坐标系两两互转,无 API 依赖,纯公开算法:

wgs84->gcj02 : 116.40374357265176 39.91010349934476 wgs84->bd09 : 116.4101165864734 39.91644274963076 gcj02->wgs84 : 116.3912588656213 39.90729875233756 gcj02->bd09 : 116.40387297451515 39.915043351185915 bd09->wgs84 : 116.38487338089874 39.900991708020854 bd09->gcj02 : 116.39110932980803 39.90238879122332

② 3 种输入、2 种输出

格式说明
text默认,空格/逗号分隔,可-s指定分隔符
csv自动识别表头列名(lng/lon/longitude/x、lat/y),也可--lng/--lat指定
json单点对象或数组;兼容longitude/latitude/x/y别名和[lng,lat]形态

输出统一 text(lng lat)或 JSON({"lng":…,"lat":…})。

③ 管道与错误处理——成功结果只写 stdout,一切 warn/报错走 stderr;三态退出码(0 至少成功 / 1 严格模式部分失败 / 2 全失败或参数错)。空行跳过。

④ 坐标顺序可控——默认lng,lat(高德/百度习惯),--order latlng切到 Google 系习惯;JSON 用字段名、CSV 用列名定位,不依赖顺序。

精度与性能

  • 反向方向(GCJ02→WGS84、BD09→WGS84、BD09→GCJ02)用迭代逼近:公开的反向公式是「减去偏移」的近似式(固有误差 0.5–2m),改为用正向公式算偏移、迭代修正至收敛(阈值 1e-9°),往返误差达到机器精度(<1e-9°)。
往返验证(wgs84 → gcj02 → wgs84): 输入 116.3975 39.9087 转回 116.39749999999995 39.90869999999997 ← 误差 < 1e-13
  • 境外点原样返回:超出中国国境范围(公开公式有效域)的坐标不做偏移。
  • 性能:纯算法百万点 <0.1s;含 I/O 管道实测约 1s / 100 万行(release)。

结构

代码分层很直白:input.rs把三种输入格式统一成(lng, lat)convert.rs纯计算(不感知输入来源),output.rs格式化。解析层再复杂,算法层永远只面对一组数值。

三、期间面临的挑战

1. 反向精度被外部库「带偏」。最初用 gcoord(JS 独立实现)生成测试参考值,一跑反向方向差异 ~1e-6°——查了半天发现是 gcoord 自己用了一步近似逆,ccvt 反而更准:gcoord 与 coordtransform 在这个方向互相分歧 98/100 个点。结论:参考实现也可能是近似,交叉验证要先量化对方误差再定容差,否则会把正确结果"改错"。

2. 设计文档里的「闭式逆」是错的。文档写「BD09→GCJ02 用闭式逆」,实现时发现公开闭式逆是近似式(往返误差 ~1e-5°),改为迭代逼近后达机器精度。结论:公开算法资料的「标准答案」也可能是近似的,实现前先验证往返误差。

3. JSON 输入形态爆炸。单点对象、数组、点数组、字段别名……最后收敛成一个parse_json函数、全部规约成内部(lng, lat)。结论:用统一内部表示兜住所有形态,解析层复杂、算法层永远简单。

四、经验收获

  1. 求逆向,优先迭代逼近而不是一步近似式——只要正向映射可算,用正向迭代求逆通常能拿到机器精度,可迁移到任何「正向可算、反向难」的映射。
  2. 参考实现不是金标准,第三方库 / 公开公式也可能是近似,交叉验证前先量化对方误差。
  3. 管道工具黄金法则:成功走 stdout、告警走 stderr,让下游永远消费干净数据。
  4. 隐式约定靠结构兜底——JSON 用字段名、CSV 用列名、text 才依赖顺序,把最容易错位的坐标顺序交给格式自身解决。

五、代码与安装

仓库:https://github.com/Angryshark128/ccvt (MIT License,Rust,无运行时依赖)

安装(macOS arm64 示例,下载预编译制品):

curl-LOhttps://github.com/Angryshark128/ccvt/releases/latest/download/ccvt-aarch64-apple-darwin.tar.gztar-xzfccvt-aarch64-apple-darwin.tar.gzsudomvccvt /usr/local/bin/

Windows 解压 zip 加 PATH;Linux 同理。也可cargo build --release源码构建。

运行

# text 输入echo"116.3975 39.9087"|ccvt-fwgs84-tgcj02# CSV 批量(自动识别表头)catdb.csv|ccvt-fwgs84-tgcj02-icsv# JSON API 转换curlapi|ccvt-fwgs84-tgcj02-ijson-ojson# 非标准表头ccvt-fwgs84-tgcj02-icsv--lat纬度--lng经度<china.csv# 严格模式ccvt-fwgs84-tgcj02--strict<bad.txt

Rust 库调用:

useccvt::convert::wgs84_to_gcj02;let(lng,lat)=wgs84_to_gcj02(116.3975,39.9087);
返回列表