2. 地图数据获取与预处理
各位同学,今天我们来聊聊仿真脚本里最基础、也最容易被忽视的一步——地图数据的获取与预处理。
说实话,我刚开始做仿真的时候,总觉得地图数据嘛,网上随便拉一份就能用。结果呢?第一次跑仿真,坐标全飞到太平洋去了。嗯,从那以后,我再也不敢小看数据预处理了。
2.1 公开地图数据源
做仿真,地图数据从哪来?我个人最常用的就两个:OpenStreetMap 和 Google Earth。
2.1.1 OpenStreetMap(OSM)
OSM 是开源的地图数据,全球免费。你想想看,连 NASA 都在用,可靠性没得说。
- 优点:数据量大、更新快、完全免费
- 缺点:数据质量参差不齐,有些偏远地区可能不准
- 获取方式:通过 Overpass API 或直接下载 .osm 文件
osmium 工具先过滤一下。我只保留 highways、buildings 和 landuse 三个图层,其他的一概不要。这样文件大小能减少 80% 以上。
2.1.2 Google Earth
Google Earth 的数据精度高,尤其是卫星影像。但要注意,它是有使用限制的。
- 优点:影像清晰、坐标准确
- 缺点:商用需要授权,且不能直接导出矢量数据
- 获取方式:手动标注 KML 文件,或使用第三方工具导出
2.2 数据清洗与坐标系转换
数据拿到手,第一件事不是跑仿真,而是清洗。说白了,就是把脏数据扔掉,把坐标统一起来。
2.2.1 数据清洗
我在项目中遇到过最离谱的情况:一条道路的节点坐标居然是 (0, 0)。你想想看,这要是直接导入仿真,车全开到原点去了。
清洗步骤一般包括:
- 去除重复点:两个节点坐标完全一样,删掉一个
- 去除孤立点:没有连接关系的节点,直接扔掉
- 修复拓扑错误:比如道路断头、重叠等
2.2.2 坐标系转换:WGS84 转 UTM
为什么需要转换?因为 WGS84 是经纬度坐标,单位是度。而仿真场景需要的是米。你想想看,用经纬度直接算距离,误差会非常大。
UTM 坐标系把地球分成 60 个带,每个带内用米作为单位。转换公式其实不复杂,但手算太麻烦。我一般用 Python 的 pyproj 库。
import pyproj
# 定义 WGS84 和 UTM 投影
wgs84 = pyproj.Proj(init='epsg:4326')
utm = pyproj.Proj(init='epsg:32650') # 50 带,北半球
# 转换坐标
lon, lat = 116.397, 39.908 # 北京天安门
x, y = pyproj.transform(wgs84, utm, lon, lat)
print(f"UTM 坐标: {x:.2f}, {y:.2f} 米")
utm 这个 Python 库自动计算带号,省得自己算。
2.3 地图裁剪与简化
地图数据往往很大,一个城市的 OSM 文件可能有几百 MB。直接导入仿真,内存直接爆掉。所以,必须裁剪和简化。
2.3.1 地图裁剪
裁剪很简单,就是只保留你感兴趣的区域。比如你只仿真一个十字路口,那就只保留路口周围 500 米的数据。
我常用的工具是 osmium 和 ogr2ogr。
# 使用 osmium 裁剪
osmium extract -b 116.39,39.90,116.41,39.92 input.osm -o output.osm
# 使用 ogr2ogr 裁剪
ogr2ogr -clipsrc 116.39 39.90 116.41 39.92 output.geojson input.geojson
2.3.2 地图简化
简化,说白了就是减少节点数量。一条弯弯曲曲的道路,可能有几百个节点。但仿真时,你不需要那么精细。用 Douglas-Peucker 算法,可以把节点压缩到几十个。
我一般设置简化阈值为 1 米。也就是说,弯曲幅度小于 1 米的点,直接扔掉。这样地图文件能缩小 90% 以上,但视觉上几乎看不出区别。
2.4 本章知识体系
下面这张图,是我自己总结的地图数据预处理流程。你照着这个走,基本不会出错。
嗯,流程就是这样。每一步都很关键,跳过去的话,后面仿真跑起来全是坑。
可可精品资料库