推荐使用nlohmann/json搭配自定义几何类:它轻量高效,避免gdal重量级依赖和c++标准库无json支持的硬伤,能正确处理geojson坐标嵌套、type校验、coordinates多维结构及polygon内外环拓扑判定。

GeoJSON解析库选型:nlohmann/json + 自定义几何类比纯手写快得多
直接用 C++ 标准库解析 GeoJSON 几乎不可行——它本质是嵌套 JSON,而标准库无原生 JSON 支持。硬写 std::string 查找和切分,会卡在坐标数组嵌套、coordinates 类型多变(点/线/面/多层嵌套)、type 字段大小写敏感等细节上,三天也跑不通一个 Polygon。
推荐组合:nlohmann/json(头文件仅需 #include <json.hpp></json.hpp>)负责通用解析,再用轻量 C++ 类封装几何逻辑。不建议用 GDAL 的 C++ API——它依赖编译时链接、跨平台部署麻烦,且对纯 GeoJSON 解析过度重量级。
常见踩坑点:
-
nlohmann/json默认把数字全转成double,但 GeoJSON 坐标允许整数(如[116, 39]),解析后仍是double,无需额外转换 - 必须检查
type字段是否存在且值为"Point"/"LineString"/"Polygon"等合法字符串,否则j["geometry"]["type"]访问会抛json::type_error -
coordinates可能是[x,y]、[[x,y], [x,y]]或[[[x,y],...], [[x,y],...]],不能假设维度固定
Point 和 LineString 坐标提取:用 get<:vector>>()</:vector> 会崩溃,得用 get_ref<const std::vector>&>()</const>
直接调 j["coordinates"].get<:vector>>()</:vector> 在 Point 上能过,但在 LineString(数组 of 数组)上会触发类型断言失败。正确做法是先判断 coordinates 的 JSON 类型,再逐层解包。
实操建议:
- 对
Point:确认j["coordinates"].is_array() && j["coordinates"].size() == 2,再用j["coordinates"][0].get<double>()</double>和j["coordinates"][1].get<double>()</double> - 对
LineString:先auto& coords = j["coordinates"].get_ref<const std::vector>&>()</const>,再遍历每个元素,确保其.size() == 2且含两个数字 - 避免用
at(),它在键不存在时抛异常;用value()提供默认值更安全,例如j.value("crs", json::object()).is_null()
Polygon 外环内环分离:GeoJSON 规范要求第一个环为外环,后续为内环(洞),但很多数据源不守规矩
规范写明 Polygon 的 coordinates 是 [outerRing, innerRing1, innerRing2, ...],但实际遇到的文件常把内环顺序颠倒、甚至漏掉外环。不能只靠索引 0 判定外环。
关键处理逻辑:
- 先用射线法或面积符号(
shoelace formula)算每个环的有向面积:正为逆时针(通常外环),负为顺时针(通常内环) - 但注意:有些国家坐标系(如 Web Mercator)下面积计算需转回经纬度再算,否则变形严重
- 若所有环面积都为负,说明数据源统一反向了,可整体翻转顶点顺序,而非强行按索引拆分
-
nlohmann/json不支持原生多边形拓扑检查,需自己实现环是否闭合(首尾点距离
坐标系与 CRS 处理:99% 的 GeoJSON 实际是 WGS84,但显式声明 crs 字段已废弃,别信它
旧版 GeoJSON 允许 "crs": {"type": "name", "properties": {"name": "EPSG:4326"}},但 RFC 7946 明确废除该字段。现在合法 GeoJSON 不应含 crs,默认就是 WGS84 经纬度(单位:度)。
实操中真正要警惕的是:
- 用户上传的所谓 “GeoJSON” 实则是 Mapbox Vector Tile 或带投影坐标的 GeoJSON(如
[x_meter, y_meter]),这时coordinates数值远超 ±180/±90,需结合元数据或文件名判断 - 若必须支持非 WGS84,不要在解析层做投影转换——用 PROJ 库在几何对象构建后单独调
proj_trans() - 解析时遇到
crs字段,直接 warn 并忽略,否则可能误判坐标单位导致整个地图偏移几百公里
最易被忽略的点:坐标精度丢失。用 double 存经纬度足够,但若后续做空间索引(如 R-tree),需注意 std::abs(x - y) 这类比较在高纬度地区失效,得用角距离公式。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











