资讯动态

shp转osm再转sumo:微观交通仿真路网构建全流程

发布时间:2026/10/14 20:27:41 来源:尧图企业网站定制
1. 从shp到osm再到sumo路网构建的完整思路拆解做交通仿真的人迟早会撞上一个很现实的问题手头拿到的路网数据是shp格式的但仿真工具要的是别的格式。尤其是用sumo做微观交通仿真的时候它原生支持的路网格式是net.xml而net.xml通常由osm文件或者netconvert工具从其他格式转换而来。shp文件作为GIS领域最常见的数据格式之一天然带着完整的几何信息和属性字段但sumo并不直接吃shp。所以中间需要一个桥梁osm文件就是这个桥梁的最佳选择。这个流程的核心逻辑其实不复杂shp文件里存的是矢量化的道路线要素每条线有坐标串、有道路等级、有车道数等属性osm文件是一种基于XML的开放地图数据格式用node和way来描述路网拓扑sumo的netconvert工具能读取osm文件自动识别道路连接关系、生成交叉口、分配车道最终输出可仿真的路网文件。整条链路是shp → osm → net.xml → sumo仿真。为什么非要绕这一圈直接用sumo的netconvert读shp不行吗实测下来netconvert对shp的支持非常有限它主要设计来读osm、vissim、openDRIVE等格式shp不在其原生支持列表里。即便有些版本能通过插件读取属性映射和拓扑构建也经常出问题。所以把shp先转成osm让osm承载完整的道路属性和拓扑信息再交给netconvert处理是目前最稳妥的路线。这个流程适合谁做城市交通仿真的研究生、交通规划院的工程师、智慧城市项目的开发人员以及任何需要把GIS路网数据导入微观仿真工具的人。前提是你对GIS软件的基本操作有了解知道什么是属性表、什么是坐标系同时对sumo的基本概念节点、边、车道、连接有初步认知。如果这两块都是零基础建议先补一下QGIS和sumo的基础教程否则中间任何一个环节卡住都会很痛苦。我自己的经验是这个流程的难点不在单个步骤而在数据质量的把控和属性字段的映射。shp文件里的道路属性五花八门字段名可能是中文、可能是拼音缩写、可能根本没有车道数字段。osm文件对道路类型有固定的tag体系sumo又对车道数、限速、优先级有明确要求。这三者之间的信息损失和补全才是真正花时间的地方。下面我会把每个环节拆开讲包括我踩过的坑和最终跑通的方案。2. 核心工具选型与数据准备要点2.1 工具链的确定QGIS JOSM sumo netconvert整个流程涉及三个核心工具每个都有替代方案但我最终选的是这套组合理由如下。QGIS负责shp文件的读取、属性检查、坐标转换和初步处理。它是开源GIS工具里最成熟的一个对shp的支持无可挑剔插件生态也丰富。替代方案有ArcGIS但ArcGIS是商业软件而且导出osm的插件不如QGIS灵活。QGIS还有一个关键优势它的Python控制台可以直接调用GDAL/OGR库批量处理属性字段非常方便。JOSM是OpenStreetMap的桌面编辑器用来打开和编辑osm文件。为什么不用其他osm编辑器因为JOSM对路网拓扑的校验能力最强它能自动检测断头路、重复节点、无效连接等问题而且支持自定义tag预设。当你从shp转换过来的osm文件存在拓扑错误时JOSM是最趁手的修复工具。sumo netconvert是sumo自带的命令行工具负责把osm转成net.xml。它的参数非常多但核心就那么几个道路类型映射、车道数推断、连接生成规则。后面会详细讲参数配置。注意三个工具的版本要匹配。QGIS建议用3.28以上JOSM用最新稳定版sumo用1.18以上。版本差异可能导致osm文件格式兼容性问题尤其是JOSM保存的osm版本和netconvert读取的版本不一致时会出现莫名其妙的解析错误。2.2 shp文件的预处理坐标系与属性字段拿到shp文件后第一件事不是急着转换而是检查两样东西坐标系和属性表。坐标系方面osm文件使用的是WGS84地理坐标系EPSG:4326单位是经纬度。如果你的shp文件用的是投影坐标系比如CGCS2000的某个高斯投影带或者Web Mercator必须先转换到WGS84。在QGIS里操作很简单右键图层 → 导出 → 保存要素为 → 选择CRS为EPSG:4326。但这里有个坑转换后的坐标精度会损失尤其是从投影坐标转地理坐标时小数点后位数要保留足够多建议至少7位小数否则路网会出现明显的偏移。属性表方面你需要确认几个关键字段是否存在字段用途常见字段名是否必须缺失时的处理道路等级type, road_type, fclass必须根据道路宽度或名称推断车道数lanes, lane_num, chedao建议有按道路等级默认赋值限速speed, maxspeed, xiansu建议有按道路等级默认赋值单双向oneway, danxiang建议有默认双向道路名称name, road_name可选留空即可如果车道数字段缺失后面在osm里就得手动补或者用netconvert的默认推断。我试过完全没有车道数的情况netconvert会根据道路等级自动分配但结果往往偏少导致仿真时道路通行能力不足。所以如果原始数据没有车道数建议在QGIS里用字段计算器按道路等级批量赋值比如快速路默认6车道、主干路4车道、次干路2车道、支路2车道。2.3 数据清洗去除无效要素与拓扑检查shp文件里经常混着一些不需要的要素断头路、重复线、悬挂线、自相交线。这些在GIS里可能不影响显示但转到osm后会导致拓扑错误netconvert处理时会报错或者生成奇怪的路网。在QGIS里做清洗的步骤删除重复几何矢量 → 几何工具 → 删除重复几何体。重复线会导致osm里出现重叠waynetconvert会生成多余的车道。修复几何有效性矢量 → 几何工具 → 修复几何。自相交的线在osm里会变成无效way。提取有效范围如果你的shp覆盖范围很大但只需要某个区域的路网用裁剪工具先裁出目标区域减少后续处理量。检查断头路用拓扑检查器插件找出悬挂节点dangling node。这些在osm里会变成死胡同如果实际不是死胡同需要手动连接。实操心得我一般会在QGIS里先做一个缓冲区分析把距离小于1米的平行线找出来这些往往是重复采集或者偏移的道路。处理掉之后osm的way数量能减少10%到20%netconvert的处理速度明显提升。3. shp转osm的实操过程与关键环节3.1 用QGIS导出osm格式的完整步骤QGIS本身没有直接的“导出为osm”菜单但可以通过插件或者Python脚本实现。我试过三种方法最终推荐用QGIS的OSM导出插件或者GDAL的ogr2ogr命令行。方法一QGIS插件导出在QGIS里加载清洗后的shp文件。安装插件插件 → 管理并安装插件 → 搜索“OSM” → 安装“OSM Export”或类似插件。右键图层 → 导出 → 导出为OSM文件。在导出对话框中需要做字段映射把shp的字段映射到osm的tag。比如把type字段映射到highway tag把lanes字段映射到lanes tag。这个方法的优点是可视化操作适合不熟悉命令行的用户。缺点是字段映射不够灵活复杂属性容易丢失。方法二ogr2ogr命令行这是我最推荐的方式因为可控性最强。GDAL的ogr2ogr工具支持直接转换shp到osm命令如下ogr2ogr -f OSM output.osm input.shp -dsco COMPRESSNO -lco COLUMN_TYPEShighwayString,lanesInteger但ogr2ogr直接转osm有个问题它生成的osm文件里way的tag是直接从shp字段名来的不会自动映射到osm的标准tag。比如shp里字段叫“road_type”ogr2ogr会生成tag kroad_type v主干路/而osm标准应该是tag khighway vprimary/。所以转换后还需要用脚本做tag重映射。我通常的做法是先用ogr2ogr转出基础osm然后用Python脚本批量替换tag键值。脚本逻辑很简单读入osm文件遍历所有way的tag按照映射表替换k和v。import xml.etree.ElementTree as ET tag_mapping { road_type: highway, chedao: lanes, xiansu: maxspeed } value_mapping { 主干路: primary, 次干路: secondary, 支路: residential, 快速路: motorway } tree ET.parse(output.osm) root tree.getroot() for way in root.findall(way): for tag in way.findall(tag): k tag.get(k) v tag.get(v) if k in tag_mapping: tag.set(k, tag_mapping[k]) if v in value_mapping: tag.set(v, value_mapping[v]) tree.write(output_mapped.osm, encodingutf-8, xml_declarationTrue)3.2 osm文件的结构与tag体系详解osm文件的基本结构是三层node、way、relation。node是节点有经纬度坐标way是一串node的引用代表一条道路relation用于描述复杂关系比如公交线路、多边形区域。路网转换主要涉及node和way。一个典型的道路way在osm里长这样way id123456 nd ref1001/ nd ref1002/ nd ref1003/ tag khighway vprimary/ tag klanes v4/ tag kmaxspeed v60/ tag koneway vyes/ tag kname v示例路/ /way其中highway tag是最关键的它决定了道路的类型和默认属性。osm的highway tag有一套完整的等级体系常用的有osm highway值含义sumo默认车道数sumo默认限速(km/h)motorway高速公路2120trunk快速路2100primary主干路280secondary次干路260tertiary支路150residential居住区道路130service服务道路120注意netconvert在读取osm时如果way上没有lanes tag它会用上表的默认值。这就是为什么前面强调要在shp里补全车道数否则默认值往往偏小。3.3 用JOSM修复拓扑与补充属性从shp转出来的osm文件拓扑上通常有几个问题节点没有合并两条路的交叉点有两个重合但独立的node、way的方向不一致、缺少连接关系。JOSM能自动修复大部分问题。打开JOSM加载osm文件然后合并重合节点编辑 → 合并节点 → 选择“在容差范围内合并”。容差设0.5米左右太小合并不了太大会把不该合并的节点也合并了。修复way方向工具 → 反转way方向。对于单行道确保方向正确。添加缺失的tag选中way在右侧属性面板里添加highway、lanes、maxspeed等tag。运行验证验证 → 验证数据。JOSM会列出所有拓扑错误和警告逐条修复。JOSM还有一个很实用的功能从地理数据导入。如果你有GPS轨迹或者参考底图可以叠加显示手动修正偏移的道路。不过对于批量处理还是以自动修复为主。实操心得JOSM的验证功能会报很多“way end node near other way”的警告这些是断头路。如果实际路网中这些路是连通的就用“连接节点”工具把它们连上。如果确实是断头路比如小区内部道路可以忽略。但netconvert对断头路很敏感可能会生成无法通行的死胡同影响仿真效果。4. osm导入sumonetconvert参数配置与路网生成4.1 netconvert的核心参数解析netconvert是sumo路网转换的核心工具命令格式如下netconvert --osm-files input.osm --output-file output.net.xml但这样直接跑生成的路网往往不能用。必须加上一系列参数来控制转换行为。我常用的参数组合netconvert \ --osm-files input.osm \ --output-file output.net.xml \ --geometry.remove \ --ramps.guess \ --junctions.join \ --tls.guess-signals \ --tls.discard-simple \ --tls.join \ --no-turnarounds \ --offset.disable-normalization \ --lefthand false \ --speed-in-kmh \ --lane-numbers-from-osm逐个解释这些参数的作用--geometry.remove移除不必要的几何节点简化路网。osm里很多way有大量中间节点这些节点对仿真没用反而增加计算量。--ramps.guess自动识别匝道。对于高速公路和快速路这个参数能正确生成出入口。--junctions.join合并距离很近的交叉口。osm里经常有多个节点表示同一个交叉口这个参数能把它们合并成一个。--tls.guess-signals根据道路等级和连接数自动推断信号灯位置。不是所有交叉口都需要信号灯这个参数让netconvert智能判断。--tls.discard-simple丢弃简单的信号灯只保留复杂的。避免生成大量不必要的信号灯。--no-turnarounds禁止掉头。除非你的仿真需要掉头否则禁止掉头能减少大量无效连接。--offset.disable-normalization禁用坐标归一化。保持原始坐标方便后续与GIS数据对齐。--lefthand false右侧通行。国内是右侧通行这个必须设对。--speed-in-kmh限速单位用km/h。osm里的maxspeed默认是km/h但netconvert有时会按m/s处理这个参数强制单位。--lane-numbers-from-osm从osm的lanes tag读取车道数。如果不加这个netconvert会用默认值。4.2 道路类型映射与车道数推断netconvert内置了一套osm道路类型到sumo道路类型的映射表但默认映射不一定符合国内情况。比如osm的“trunk”在国内通常对应快速路但netconvert可能把它当成高速公路处理限速设得过高。要自定义映射需要用--type-files参数指定一个类型映射文件。这个文件是XML格式定义了每种osm highway值对应的sumo道路类型、车道数、限速、优先级等。一个典型的类型映射文件片段types type nameprimary priority10 numLanes4 speed60 / type namesecondary priority8 numLanes3 speed50 / type nametertiary priority6 numLanes2 speed40 / type nameresidential priority4 numLanes2 speed30 / /types使用时加上--type-files mytypes.xml即可。这样netconvert就会按照你的定义来生成路网而不是用默认值。注意类型映射文件里的numLanes是默认车道数如果osm的way上有lanes tag且你加了--lane-numbers-from-osm那么osm的lanes会覆盖类型映射里的值。所以两个参数要配合使用。4.3 交叉口连接生成与信号灯配置netconvert最复杂也最容易出问题的部分是交叉口连接生成。一个交叉口有多条进口道和出口道每条进口道的每个车道可以连接到哪些出口道这决定了仿真时车辆能否正确转向。默认情况下netconvert会自动计算连接关系但结果往往不理想。常见问题包括左转车道没有左转连接、直行车道被分配到转弯连接、连接冲突导致死锁。要精细控制连接可以用--connection-files参数指定连接文件。但这个文件格式复杂手动写很痛苦。我的做法是先用netconvert自动生成然后在sumo的netedit工具里可视化检查和修改。netedit能直观显示每个交叉口的连接关系拖拽就能调整。信号灯方面--tls.guess-signals会自动推断但推断结果需要人工校验。在netedit里可以打开信号灯编辑器调整相位和配时。如果只是做路网构建信号灯配时可以先用默认值后续在sumo的additional文件里再细调。4.4 生成路网的验证与常见错误处理netconvert跑完后用sumo-gui打开net.xml检查几个关键点路网是否连通随机选几个点看能否找到路径。如果大量道路不连通说明拓扑有问题。车道数是否正确对比原始shp的车道数看是否有遗漏。限速是否合理检查主要道路的限速是否与实际情况相符。交叉口是否正常看交叉口的连接线是否合理有没有明显的缺失或多余。常见的netconvert错误和解决方法错误信息原因解决方法Could not find nodeosm里way引用了不存在的node用JOSM验证并修复Duplicate edge两条way的起点终点相同删除重复way或合并No connection between edges交叉口连接生成失败用netedit手动添加连接Invalid lane numberlanes tag值不是整数修正osm里的lanes值Speed out of rangemaxspeed值过大或过小修正osm里的maxspeed值实操心得netconvert的日志会输出大量警告和错误不要忽略它们。我一般会把日志重定向到文件然后逐条检查。很多错误看起来不起眼但会导致生成的路网在仿真时出现奇怪的行为比如车辆突然消失、路径规划失败等。5. 常见问题排查与避坑经验实录5.1 坐标偏移与路网变形问题这是最常见的问题之一。shp转osm时坐标系没转对或者转换过程中精度损失导致生成的路网整体偏移或者变形。排查方法在QGIS里同时加载原始shp和生成的net.xmlnet.xml可以用sumo的netconvert转成shp或者用sumo-gui截图后叠加看是否重合。如果不重合检查三个地方shp的原始坐标系、QGIS导出时的目标坐标系、netconvert的offset参数。我遇到过一次典型情况shp用的是地方坐标系带号搞错了转成WGS84后整体偏移了几百米。后来在QGIS里重新指定了正确的带号才解决。所以坐标系这件事一定要在第一步就确认清楚不要等到最后才发现。5.2 车道数丢失与属性映射错误shp里的车道数字段是中文“车道数”ogr2ogr转osm时生成的tag是tag k车道数 v4/netconvert不认识中文tag直接忽略结果所有道路都用默认车道数。解决方法在ogr2ogr转换后用脚本把中文tag键替换成英文标准tag。或者更彻底一点在QGIS里先把字段名改成英文再导出。类似的还有限速字段、单双向字段。原则就是osm的tag键必须是英文标准值netconvert只认标准tag。5.3 交叉口连接混乱与死锁netconvert自动生成的交叉口连接有时候会出现两个车道互相连接形成死锁。仿真时车辆在交叉口里转圈永远出不去。这个问题在netedit里很容易发现打开netedit加载net.xml看交叉口的连接线。如果看到连接线形成闭环那就是死锁。解决方法是删除多余的连接或者调整车道连接关系。预防措施在netconvert参数里加上--no-turnarounds和--junctions.join能减少大部分死锁情况。另外--check-lane-foes.all参数可以在生成时检查车道冲突提前发现问题。5.4 路网规模过大导致转换失败如果shp覆盖整个城市路网有几万条道路netconvert可能会内存溢出或者跑几个小时都跑不完。解决方法分区域处理。在QGIS里按行政区或者网格把shp切成小块每块单独转osm和net.xml最后用sumo的netmerge工具合并。或者用--simplify参数简化路网减少细节。我处理过一个中等城市的案例原始shp有8万多条道路。直接跑netconvert跑了40分钟还没完后来切成12个区域每个区域单独处理总共20分钟搞定而且每个区域的路网质量更好控制。5.5 仿真时车辆无法上路或路径规划失败路网生成后在sumo里加载车流发现车辆不动或者报“no route”错误。这通常是路网连通性问题。排查步骤用sumo的--net-file加载net.xml在sumo-gui里看路网是否完整。用duarouter工具测试路径规划随便选两个点看能否找到路径。检查net.xml里的edge是否有正确的from和to节点。检查交叉口的连接是否允许车辆通过。常见原因是交叉口连接缺失导致某些方向无法通行。在netedit里补上连接即可。实操心得我习惯在netconvert之后用sumo自带的netcheck工具做一次全面检查。它会输出路网的统计信息和潜在问题包括孤立节点、无效连接、车道数异常等。这个工具很多人不知道但非常实用。6. 从路网到仿真后续扩展与优化建议路网建好只是第一步真正做仿真还需要加载车流、配置信号灯、设置检测器等。但路网的质量直接决定了后续仿真的可信度。如果路网本身有拓扑错误或者属性缺失后面做再多调整都是白搭。如果你需要更精细的路网可以考虑在osm里补充更多tag比如turn:lanes描述转向车道、traffic_signals描述信号灯位置、crossing描述人行横道。这些tag netconvert都能识别生成的路网会更贴近现实。另外sumo的net.xml是可以手动编辑的但我不建议直接改XML。更好的方式是用netedit可视化编辑或者用sumo的additional文件在仿真时动态修改路网属性。这样原始net.xml保持干净后续调整也方便。这个流程我跑过不下几十次从最初的到处报错到现在基本一次跑通最大的体会就是数据预处理的时间要占总时间的70%。shp的清洗、坐标系的确认、属性字段的映射这些前期工作做扎实了后面的转换和仿真就是水到渠成。反过来如果前期偷懒后面会在各种奇怪的地方卡住而且排查起来非常痛苦。最后分享一个小技巧把整个流程写成脚本从ogr2ogr转换到Python tag映射到netconvert参数全部串起来。这样下次有新的shp数据改几个路径就能直接跑效率提升非常明显。我现在的脚本里还加了日志和错误检查每一步的输出都记录出问题能快速定位。这套流程跑顺了之后一个中等规模的路网从shp到可仿真状态半天时间足够了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑