ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

2005年全国路网矢量数据清洗与坐标系转换实战指南

2005年全国路网矢量数据清洗与坐标系转换实战指南 简介覆盖全国范围的矢量地理数据合集汇集道路、河流、铁路等多类要素专为GIS使用者打造适用于城市规划、交通分析、环境研究与历史变迁对比等场景尤其适合需要借助ArcGIS进行空间查询、制图和专题分析的读者。包内为RAR压缩包共161个文件大小约11.25MB其中包含22套shapefile标准要素文件shp/shx/dbf及prj投影定义、sbn/sbx空间索引还有GRID栅格数据adf/001、XML元数据、mxd地图文档等可直接加载到ArcGIS中开展多尺度地图工作。内容聚焦2005年全国铁路网与路网矢量信息涵盖高速铁路、普速铁路及各级公路的位置、等级与几何形态是历史路网回溯、区域通达性评估和交通设施规划的可靠底图。目前已有2567人浏览学习配合清晰的目录结构可快速定位所需图层适合城市规划、地理信息相关专业师生及从业者作为基础数据使用。1. 2005年全国路网矢量数据一份有年代感的“全国底图”做GIS的人迟早会被问到一句你有没有全国的道路、铁路、河流图层我手上常年放着一份2005年全国矢量数据图大全里面叠着国道、省道、县乡道、铁路、河流和境界道路河流铁路等要素分得清清楚楚。数据本身不新鲜但它的价值恰恰在于“旧”——带时间断面的路网、老式字段命名、一堆还在用北京54坐标系的shp文件刚好适合做历史对比、现状底图、流域模型前处理。适合三类人搞规划的要做路网演变分析做水文模型的要抠河网还有被要求“三天内上线一张全国路网地图”的。后面所有操作都基于这套老数据展开绕不开坐标系、编码和几何类型三个老问题。2. 解包先清点图层、字段与数据现状2.1 解压后先认清图层划分2005年的全国路网数据包常见格式是压缩包解压后一堆Shapefile偶尔混着E00交换格式和MapInfo的MIF/TAB。文件名不统一是常态但图层划分有规律。道路层有时是一个总文件ROAD_L有时按等级拆成ROAD_1、ROAD_2、ROAD_3铁路层通常是RAIL_L加一个火车站点层RAIL_STATION_P河流层分单线河RIVER_L和双线河RIVER_A前者是线后者是面境界和居民地也会单独成层。这个划分逻辑和现在的OSM路网风格不一样它是按当年制图规范走的核心是“分类分级”不是“每个要素一个ID”。收到数据先别急着拖进QGIS用命令行清点一遍搞清楚这个包里到底有几层、每层多少要素、是点线还是面。# 循环读取目录下所有Shapefile的图层概要输出到data_inventory.txt for f in *.shp; do echo $f ogrinfo -so $f $(basename $f .shp) done data_inventory.txt-so参数表示只输出概要包含要素数量、几何类型、字段列表。basename命令把“road.shp”去掉后缀变成“road”因为ogrinfo要用图层名。跑完打开data_inventory.txt你就能看到哪些是我们要的哪些可能是附属的注记点。这个过程花两分钟能避免后面对着错误图层白干半天。常见图层对应关系可以按下面这个表去理解真碰到名字不一样时心里有个底图层常见文件名几何主要用途道路ROAD_L、ROAD_1/2/3线路网分析、制图铁路RAIL_L、RAIL_STATION_P线点铁路网专题单线河RIVER_L、HYDL线水文分析、ArcSWAT双线河RIVER_A、HYDA面制图、水面统计境界BOUND_P、BOUND_L线/面行政区域裁剪2.2 属性字段哪些能直接用、哪些要小心清点完图层下一个任务是读属性表。2005年这一代数据的属性字段名普遍很短经常是“GC”“CLASS”“NAME”“CODE”这种。道路层你要找等级字段国省县乡四级通常编码为1/2/3/4或G/S/X/Y。铁路层关注“单线/复线”和“电气化”两个字段。河流层最重要的是NAME但流向信息不一定有。麻烦的是Shapefile的dbf格式对字段名长度有限制很多字段被截断成10个字符有的数据商干脆把一堆说明塞进一个REMARK字段里用分号隔开读取后要自己拆。更常见的问题是中文乱码这个后面避坑章节专门讲。先用一个Python脚本快速摸清每个字段的取值分布import geopandas as gpd # 读取道路层如果中文乱码就把encoding参数从默认改成gbk再试 road gpd.read_file(2005_road.shp, encodinggbk) # 逐列打印唯一值数量和一条样例快速判断哪些字段适合做分级和过滤 for col in road.columns: sample road[col].dropna().iloc[0] if road[col].notna().any() else NA print(col, unique, road[col].nunique(dropnaTrue), sample, sample)这段代码的价值在于快速区分“分类字段”和“标识字段”。如果某个字段只有三五个唯一值多半是等级或类型可以直接用来做分级渲染如果每个要素都不同那大概是ID或名称。打印sample能让你看到字段内容是不是乱码、是不是被截断。我一般跑完这个脚本再head一下前五行对数据的“脾气”就有数了。2.3 数据现状三查几何类型、坐标系、空值清点完字段动手前还要做三查一查几何类型二查坐标系三查空值和无效几何。这三项决定后面能不能顺利转格式、叠加、分析。import geopandas as gpd road gpd.read_file(2005_road.shp, encodinggbk) print(CRS:, road.crs) print(几何类型:, road.geom_type.unique()) print(空几何数量:, road.geometry.isna().sum()) print(无效几何数量:, (~road.geometry.is_valid).sum())打印出来的几何类型如果同时出现LineString和MultiLineString说明制图员在编辑时把同一道路的多个路段合并成了Multi这会影响后面按要素统计长度和做网络分析。空几何数量大于0说明原始数据有坏记录需要先删或补。无效几何多数是自相交或悬挂点用QGIS的“修复几何”工具可以批量处理。坐标系这一项最关键CRS如果显示None或EPSG:4326要警惕——很多2005年的数据实际是北京54投影但PRJ文件丢了读出来显示WGS84这就是坐标错位的根源。提示这三查做完把结果和文件名、日期一起存成一个文本作为这次数据处理的基础记录。后续所有转换和发布环节都以这份记录为准不要凭记忆。3. 坐标系统一从北京54到WGS84的转换参数与验证3.1 为什么2005年数据会混着三套坐标系2005年正好是坐标系统混乱期的尾声。八十年代以前大量成果用北京54九十年代以后新测的用西安80国际合作项目又转成WGS84。所以这份2005年路网数据如果一个包里混着三套坐标系一点都不奇怪。北京54和西安80不是简单平移关系它们用的椭球参数不同转换需要至少三个公共点求七参数而且没有公开统一参数。GDAL里直接做椭球变换时默认towgs84参数是0,0,0等于几乎不转转换后坐标和源坐标差不了多少。这就是为什么很多人发现“转了等于没转”或者转了之后偏差反而更大。更麻烦的是分带问题。北京54下全国道路数据通常按高斯克鲁格3度带存储带号选错转换结果不会变形而是整体平移几十公里甚至上百公里。我见过最典型的翻车用某一个3度带参数转全国数据转完范围只剩河北一角东西部全飞了。所以在动手转坐标系之前先搞清楚源数据和带号比什么都重要。3.2 批量查询SRS并转成EPSG:4326转换前先确认每个文件的SRS。有PRJ文件时GDAL能自动读但PRJ文件经常乱码或缺失。用ogrinfo查每个图层的SRS描述最可靠# 查看道路和河流的投影信息确认是投影坐标还是经纬度 ogrinfo -so 2005_road.shp 2005_road | grep -i SRS\|GEOGCS\|PROJCS ogrinfo -so 2005_river.shp 2005_river | grep -i SRS\|GEOGCS\|PROJCS输出里如果看到Krasovsky、Gauss_Kruger字样就是北京54投影坐标看到GCS_Beijing_1954说明是北京54经纬度完全没有SRS信息的多半是裸shp。对于裸shp先看坐标范围如果范围是经纬度数值比如经度75到135、纬度18到54说明它实际是经纬度数据只是丢了定义。这时用-a_srs强制声明ogr2ogr -overwrite -a_srs EPSG:4326 -t_srs EPSG:4326 road_wgs84.shp road_noprj.shp-a_srs是“分配源坐标系”只给没有PRJ的文件用它有PRJ时再写会覆盖原定义。确定源坐标系正确后正式转WGS84# 将北京54投影的2005年道路数据转成WGS84经纬度 ogr2ogr -overwrite -s_srs EPSG:21413 -t_srs EPSG:4326 2005_road_wgs84.shp 2005_road.shp这个s_srsEPSG:21413是北京54/3度带第13带适用于东经117度附近的区域其他区域要按实际经度换带号。如果你手里是全国拼接版建议直接用“先投影坐标转经纬度再统一拼接”的思路每个分带文件转成4326后再合并不要在投影坐标下直接拼接。3.3 转换后如何量化验证偏移转完不能只看坐标变了就收工。验证分三步范围、叠合、距离。先把转换后的坐标范围打出来# 查看转换后的坐标范围与全国经纬度范围做快速核对 ogrinfo -so 2005_road_wgs84.shp 2005_road_wgs84 | grep -i Extent全国范围经度应在75到135、纬度在18到54之间。如果范围只覆盖一个局部区域说明-s_srs的带号选错了。如果范围看起来正常再用叠加或距离的方式细验。有参考图层时用GeoPandas计算转换后数据与参考数据的最近距离中位数能反映整体偏移量import geopandas as gpd # 转换后的道路线 与 一份可信的WGS84省界线比较看质心偏移 road gpd.read_file(2005_road_wgs84.shp) ref gpd.read_file(province_wgs84.geojson) print(道路质心:, road.unary_union.centroid) print(参考质心:, ref.unary_union.centroid)质心差在0.5度以内可以接受超过1度基本就是坐标系搞错了。没有参考图层时至少在QGIS里叠加一张在线影像选三个不同位置的点放大看道路是否贴合。肉眼看着差几十米到一百米属于椭球转换的正常残留差几百米以上就要回头检查源坐标系声明。3.4 为GeoServer统一存储坐标系如果你要把这套路网发布出去GeoServer这条线提前规划。GeoServer发布矢量数据最常见的问题就是“原生坐标系”和“声明坐标系”不一致导致切片错位。建议的统一策略是所有2005年路网数据入库前转成EPSG:4326GeoServer里只对应选EPSG:4326前端瓦片请求时再让GeoServer自动重投影到EPSG:3857。新建Shapefile数据源时如果PRJ缺失必须在“声明坐标系”里手动选不能让它显示unknown。发布图层时“原生SRS”和“声明SRS”要一致这个细节漏了切片错位就跑不掉。入库后要检查每层的坐标范围在GeoServer的图层预览页里如果看到范围是负数或极小矩形说明SRS声明错了千万别点发布。另外矢量数据发布服务不是越新越好存储统一、SRS明确、字段精简才是长期稳定的基础。4. 从Shp到业务数据GeoJSON、ArcSWAT与拓扑修复4.1 转GeoJSON前的三个考量把2005年老数据转成GeoJSON是前端可视化和跨平台交付的高频操作。动手前想三件事编码、字段、坐标精度。Shapefile的dbf对字段名有长度限制中文列名也常出问题。GeoJSON没有字段名长度限制但字段名别带空格和特殊符号否则前端JS读取要额外处理。编码方面dbf常是GBKGeoJSON固定UTF-8转换时要把源编码指对。坐标精度也别无脑保留十几位小数全国数据几十万要素每一个坐标多几位文件体积成倍涨。经纬度保留6位小数实际精度约0.1米足够做路网显示和大部分分析。转换命令如下# 转GeoJSON输出RFC7946标准限制坐标小数位为6 ogr2ogr -f GeoJSON -lco RFC7946YES -lco COORDINATE_PRECISION6 road.geojson road_wgs84.shpRFC7946YES表示输出标准GeoJSON坐标顺序是经度在前。不写这个参数时GDAL输出的是老版GeoJSON大多数前端库能读但格式不完全符合新规范。COORDINATE_PRECISION6控制输出坐标小数位对文件体积影响非常明显。如果源文件的属性是GBK编码转换前记得设置环境变量# 强制按GBK读取源dbf避免转出来的中文变成问号 export OGR_ENCODINGGBK ogr2ogr -f GeoJSON -lco RFC7946YES road.geojson road_wgs84.shp注意OGR_ENCODING影响的是输入读取不影响输出源文件本身就是UTF-8时不要再设这个变量否则会二次转码出乱码。4.2 拓扑问题怎么处理省界断线与悬挂点全国路网数据跑不掉两个拓扑毛病省界缝合线、断头路。同一条国道相邻两省各画一遍拼接处两条线没有合在一起重叠部分造成长度重复统计。还有一种情况是道路明明连成一条属性里被切成几十个线段线头线尾差几米没接上做网络分析时直接断网。处理思路是先合并再打断。QGIS里可以用“修复几何”处理无效几何但全国级路网几条万条数据桌面工具卡到怀疑人生。我一般导到PostGIS里用ST_Node重建拓扑-- 把全部线段合并后打散生成节点完全相交的线网络 CREATE TABLE road_noded AS SELECT (ST_Dump(ST_Node(ST_Collect(geom)))).geom AS geom FROM road_raw;ST_Collect把所有线段收集成一个MultiLineStringST_Node在相交处加节点打断ST_Dump把打散的MultiLineString展开成多行单线。这个操作会丢失原始属性字段所以做之前先把FID和道路等级、名称备份到另一张表打断后通过空间位置把属性连接回来。如果不需要做网络分析只是统计路网长度可以考虑直接用原始线做Dissolve加属性统计省去打断这步。但如果要跑最短路径或做连通性分析ST_Node这步不能省。4.3 ArcSWAT前处理河流线、DEM坐标系、唯一IDArcSWAT做小流域分析要用什么矢量数据几乎每个入门的同学都问过。官方要的其实是三样DEM必选河流、土地利用、土壤等可选。2005年路网里的单线河数据正好适合做河网参考用来做burn-in让SWAT把实际河道刻进DEM。但这里有三个硬性要求。第一河流线必须和DEM使用相同的投影坐标系ArcSWAT不认经纬度。第二河流范围不能超出DEM范围超出部分会报错或产生无效河网。第三每段河流必须有唯一ID重复FID会导致流域划分混乱。先做投影和裁剪# 把单线河转成与DEM一致的UTM投影裁剪到DEM边界范围内 ogr2ogr -t_srs EPSG:32650 -clipsrc dem_extent.shp river_utm_clip.shp river_utm.shpEPSG:32650适合东经117到123度区域其它纬度带和经度带要换带号。裁剪用-clipsrc参数接收一个矩形范围或一个矢量图层这里用DEM边界shp做裁剪保证河流严格落在DEM内部。ArcSWAT的burn-in输入还要注意一个细节2005年河网数据往往很密直接全量导入会让SWAT生成的子流域边界被密河网“撕碎”。建议先按属性或长度筛选出主干河流比如双线河对应的单线河、长度大于阈值的主河道去掉季节河和细支流再进SWAT。这个筛选用QGIS按属性选择导出就行。5. 常见问题与避坑坐标系错位、乱码与几何类型翻车5.1 属性表中文乱码现象QGIS打开shp属性表中文全变成“锟斤拷”或问号GeoJSON加载后名称字段显示乱码。原因2005年数据的dbf属性多采用GBK/ANSI编码而QGIS、GeoPandas默认按UTF-8读取。GeoJSON输出端固定UTF-8输入源编码没指定就全乱了。解决读取时显式声明源编码。GeoPandas用read_file(..., encodinggbk)QGIS在数据源管理器里把编码从UTF-8改成GBK重新连接。命令行做转换时先export OGR_ENCODINGGBK再执行ogr2ogr。已经转坏的文件别靠“再存一次”修复回到原始shp重新转或者用字段计算器从原始dbf重新读一次。5.2 道路与铁路叠合偏差几百米现象国道和铁路在图上明显平行或共线叠加到遥感影像后横向差几百米。原因道路和铁路图层来自不同坐标系版本。典型的组合是道路层是北京54高斯投影铁路层是西安80投影两个椭球差异在部分地区能到200米。还有人把丢失PRJ的图层强制当成WGS84用偏差更大。解决两个图层统一转到同一坐标系再叠加。转换后如果仍差几十米且你有野外控制点就在QGIS里用配准工具或Vector Bender做局部纠正。不要试图用“图层平移”解决问题平移只处理固定偏移坐标系差异在空间上是不均匀的。5.3 全国图层分析和渲染卡死现象对全国路网做缓冲区或叠加分析QGIS转圈不动内存占用飙到几个G。原因数据量大、没有空间索引、几何类型混杂。全国道路线要素动辄几十万条桌面软件直接拿去计算内存和CPU全被吃满。解决先转成GeoPackage并建索引再考虑用数据库扛。GeoPackage默认带空间索引加载和分析都比shp快很多。更重的分析用PostGIS# 把Shapefile导入PostGIS自动创建空间索引并统一几何类型为Multi ogr2ogr -f PostgreSQL PG:dbnamegis userpostgres road.shp -nlt PROMOTE_TO_MULTI -lco SPATIAL_INDEXYESPROMOTE_TO_MULTI把所有线统一转成MultiLineString避免同一个图层里几何类型混合导致SQL报错。导入后确认索引存在CREATE INDEX ON road USING GIST (geom);如果Node数太多可以用ST_SimplifyPreserveTopology做适当化简山区道路节点密集处效果明显拓扑关系不会破坏。5.4 LineString和MultiLineString混乱现象处理时报“几何类型不匹配”或者统计长度时某条路长度异常。原因制图人员把同一条路的多个线段合并成了MultiLineString或反过来把原本的整段路拆成多个单线要素。两种类型混在同一图层里不少分析工具会直接拒绝。解决统一转成单一LineString# 将MultiLineString展开为单个LineString要素属性会复制到每段 ogr2ogr -nlt LINESTRING road_clean.shp road_raw.shp-nlt LINESTRING强制输出为单线几何MultiLineString会被拆成多条LineString属性跟着复制到每段。副作用是原一个要素可能变多段按名称统计时要先Dissolve。如果只是做长度统计用SQL的ST_LineMerge更合适不破坏原有属性关系。5.5 GeoServer发布后切片错位现象GeoServer加载全国路网浏览器里显示的位置和底图差一大截放大后越偏越远。原因图层数据源的“原生坐标系”设置错误或前端请求的坐标系与发布坐标系不一致。常见的是源shp丢PRJ后在GeoServer里没手动声明坐标系默认当成了EPSG:4326或WGS84。解决在GeoServer的“图层 → 数据”页面确认“原生SRS”和“声明SRS”一致。如果源数据是北京54原生SRS要先声明成对应的EPSG:214xx再在“定义SRS”里添加EPSG:4326用于发布。强烈建议发布前把数据统一转成EPSG:4326入库让GeoServer只做重投影不从错坐标系硬转。6. 进阶用等级宽度把旧路网缓冲成道路面老路网数据在浏览器里默认渲染成细线前端想画成按等级区分宽度的“道路面”最常见做法是把中心线缓冲成面。“GeoJSON高精度路网数据制作道路面”这件事关键不在工具而在每一级道路到底给多少缓冲宽度。缓冲宽度定得合适叠加到卫星影像上能看出高速公路和乡村道的区别定得太宽道路旁边的房子全被包进去。高速公路、国道、省道、县道、乡道五档我常用的宽度从30米、20米、15米、10米、6米递减。注意这个宽度不是路面实际宽度而是中心线向两侧各扩一半得到的整体宽度适应显示比例尺和分析精度。GeoPandas几行代码就能生成import geopandas as gpd road gpd.read_file(2005_road.geojson) # 按道路等级字段映射缓冲半径单位米 width_map {G: 15.0, S: 10.0, X: 7.5, Y: 5.0} road[buf] road[level].map(width_map).fillna(5.0) # 缓冲生成道路面坐标系必须是投影坐标系经纬度下单位不生效 road_face road.geometry.buffer(road[buf]) road_face gpd.GeoDataFrame(road[[name, level]], geometryroad_face) road_face.to_file(road_face.geojson, driverGeoJSON)这里最容易踩的坑是坐标系经纬度数据直接buffer宽度会被当成度10度宽的“道路面”能覆盖半个市。所以做缓冲之前先投影到UTM或其它投影坐标系buffer的宽度单位才是米。生成道路面后建议导出GeoPackage而不是GeoJSON几十万条面要素的GeoJSON文件体积会大得离谱前端加载卡成幻灯片。验证方法不复杂选两个不同地形区的县级市用最新卫星影像叠加道路面看面是否贴合真实路幅。山区道路弯道处如果出现锯齿或内切适当降低缓冲宽度平原高速如果被建筑包围可以把宽度调到实际路幅的一半再验一次。做这套流程时我养成的习惯是拿到任何老数据第一件事永远是看坐标系和编码这两个坑填平了后面基本不会再翻车。希望这套处理流程能帮你把2005年这份路网数据真正用起来。本文还有配套的精品资源点击获取
返回列表