2026/10/7 2:55:10

北京400万栋带高度建筑物shp数据:从坐标纠偏到3D Tiles白模

北京400万栋带高度建筑物shp数据:从坐标纠偏到3D Tiles白模 简介2023年北京全域建筑物矢量数据覆盖北京市域超过四百万栋建筑包含完整平面边界与高度属性面向GIS数据分析师、城市规划师及三维建模人员可支撑城市密度评估、日照阴影模拟、应急灾害分析、交通规划等应用。数据以Shapefile格式发布压缩包共10个文件其中shp为核心矢量图层记录建筑轮廓几何dbf属性表保存建筑字段prj定义投影坐标xml提供元数据说明整体包体约547MB。该数据按区域分为A、B两个分片便于分块加载与处理。目前已有397人学习下载。结合高度字段可快速复原城市天际线、生成建筑体块并开展建筑密度统计、阴影遮挡模拟、疏散路径估算等量化计算直接导入ArcGIS、QGIS等常用平台即可读取查询也可作为城市数字孪生、三维仿真等空间规划研究的基础底图。1. 北京全域400万栋建筑物矢量shp数据带高度属性的城市数字底座拿到手先做这三件事上个月接手通州某片区的风环境模拟甲方张口就要“建筑轮廓高度”的完整矢量。翻遍手头资源百度地图矢量下载的只有平面轮廓遥感解译出的图斑又没有高度字段。最后用的正是2023年北京全域建筑物矢量shp数据四百多万栋每栋带高度一次把数据缺口补齐。这份数据最值钱的地方不是“有边界”而是每栋楼都挂了可计算的高度值省下了从影像解译、轮廓清洗到高度赋值的一整套脏活累活。它适合做城市风环境模拟、日照分析、通信基站选址以及把全域楼块批量转成Cesium白模。2. 拆开shp数据包文件组成、字段清单与坐标系带来的第一个坑拿到压缩包先别急着拖进ArcGIS。shp格式不是单文件而是一组互相配合的文件集合少一个都可能导致字段丢失、位置漂移。很多新手第一次解压后只看到了.shp和.dbf然后抱怨“打开是白的”“属性表是空的”问题往往就出在缺少配套文件。2.1 shp包里必须有这几样先核对文件清单再动手一份能正常工作的建筑物shp至少包括下面这些文件。文件后缀作用缺失后果.shp几何信息存放建筑轮廓坐标无法显示图形.shx几何索引连接几何与属性属性表关联错乱.dbf属性表存高度、楼层、用途等字段全部字段丢失.prj坐标系定义文件位置漂移.cpg字符编码声明中文乱码我的习惯是先解压到独立目录再用QGIS的Layer → Add Layer → Add Vector Layer加载。加载成功后立刻看左下角的状态栏确认要素数量接近“400多万”。如果数量级差太多比如只加载出几十万说明dbf属性表和shp几何文件的ID映射出了问题属于文件传输过程中被截断需要重新解压。2.2 高度字段先做一次统计确认单位是米而不是厘米不同数据源的建筑物shp高度字段命名习惯差很多。常见的有HEIGHT、HIGHT拼写错误也存在、FLOOR、FLOOR_NUM、TYPE这类字段名。我一般会在QGIS里选中疑似高度字段的列右键打开Field Statistics先看MIN、MAX和MEAN。最常用的校验逻辑是统计查询SELECT MIN(HEIGHT) AS min_h, MAX(HEIGHT) AS max_h, AVG(HEIGHT) AS avg_h, COUNT(*) AS cnt FROM beijing_buildings;在QGIS的DB Manager里选中图层执行。逻辑很简单通过聚合函数一次把高度范围、均值和总数算出来。参数说明MIN/MAX/AVG分别拿最小、最大和平均高度COUNT统计总要素数。如果最大高度在一百五六十米以下、均值在二三十米说明单位是米如果最大值上万就得怀疑单位是厘米甚至毫米需要整体除以100再做后续分析。2.3 坐标系是第一个分水岭源坐标系错了后面全白干建筑物shp基本上围绕CGCS2000或WGS84两种坐标系转。北京全域数据中如果prj文件里写了“CGCS2000”、“3-degree GK”这类词说明是投影坐标系坐标数值大致是几十万量级以米为单位。如果是经纬度数值范围在115到117之间单位是度。判断不唯一的场景最坑人同事传给你一份shpprj写的是WGS84但实际坐标值却是投影后的米制坐标或者反过来。我常用的校验手段是在QGIS里加载一个在线Ookla基图EPSG:3857让shp叠加一下看建筑轮廓是否贴合底图。最稳妥的预处理命令是不依赖图形界面的ogr2ogrogrinfo -so /path/beijing_buildings.shp beijing_buildingsogrinfo是GDAL自带的元数据查看工具。-so参数省略实际读取快速输出图层级信息重点看Geometry、Feature Count、Extent以及坐标系统描述。当extent范围在lng/lat量级时后面任何投影转换都要加-s_srs做强制指定否则GDAL会按prj里的描述走坐标乱套。3. 加载与投影转换的正确姿势在QGIS里处理400万栋建筑不卡死的实操四千多平方公里的建筑轮廓全部加载对软件和内存都是硬考验。第一次全量加载时我亲眼看着扇区旋转标记转了快一分钟才出图形。要是电脑配置一般直接全量加载自带属性表内存占用飙到十几GB别的程序直接崩。3.1 手工指定源坐标系的加载步骤先把图层拖进QGIS然后右键图层 → Properties → Source看“Coordinate Reference System”区域。如果QGIS自动识别出的CRS和prj里的描述不一致点一下“Select CRS”手工改回去。这个步骤多花十秒钟能避免后续重投影时发生几百米的偏移。这里有个容易被忽略的细节QGIS界面里显示的“CRS”只是告诉软件“这个图层的地理参考是什么”它不会改变数据文件里的坐标数字。真正改写坐标文件要靠Reproject工具这一步后面讲。3.2 为什么要做真正的投影转换显示不漂移和数据可测距是两回事有人看到建筑位置和底图对上了就以为不用做投影转换。对显示确实不漂移了但要用距离量算面积、测算楼间距就会得到离谱的结果。因为经纬度坐标下算两点之间的距离不考虑地球曲率是错的而GIS内在的量算工具都在投影坐标下才准。把CGCS2000或WGS84经纬度统一转到Web墨卡托EPSG:3857是后续做地图瓦片、Cesium展示最常见的选择。我一般用GDAL直接转ogr2ogr -t_srs EPSG:3857 -s_srs EPSG:4490 \ -nlt PROMOTE_TO_MULTI \ /output/beijing_3857.shp \ /input/beijing_buildings.shp逻辑说明-t_srs是目标坐标系-s_srs是源坐标系显式声明是避免误读-nlt PROMOTE_TO_MULTI把所有几何统一升级为Multi类型防止输出时出现单部件与多部件混存导致图层类型报错。参数说明四千多万要素量的转换大约需要几分钟换成固态硬盘会快得多转换过程中不要强制终止进程否则输出文件会损坏或残留半截。3.3 分块切分别让协作伙伴也面临全量加载如果你需要把这份数据分给几个同事同时干活最实际的做法是按行政区切分而不是让每台电脑都全量加载。QGIS里用Vector → Geoprocessing Tools → Clip能按边界裁剪但每次都要读一遍400万要素效率低。我更偏爱分割方式——Split Vector Layer。在这个场景下最灵活的是用ogr2ogr按空间范围框出研究区ogr2ogr -clipdst 116.28 39.80 116.60 39.95 \ -t_srs EPSG:4547 \ /output/cbd_clip.shp \ /input/beijing_buildings.shp逻辑说明-clipdst后面跟四个数字依次是研究区外接矩形的经纬度范围minx、miny、maxx、maxy。这样就可以在地图服务边界内快速切出一个小shp。参数说明这里矩形的坐标必须和源文件坐标系一致。源文件是经纬度-clipdst就用经纬度源文件是投影坐标就用米制坐标。写错量纲时会得到“empty layer”的结果然后回头重查。3.4 属性表乱码处理方案中文名称和用途字段变问号的解法数据是从多个渠道凑出来的常见问题是dbf文件字码为GBKQGIS或ArcGIS默认按UTF-8解码属性里中文全变成“?”。处理方式是手工建立.cpg文件。在shp同目录新建一个文本文件命名为和shp主名相同的.cpg内容写一行UTF-8。保存后再加载图层编码问题解决。如果还乱码去掉.cpg在QGIS的Layer Encoding下拉里手动切换到GBK或System再加载一次。这个问题的底层逻辑是dbf属性和几何分离存储编码类型全靠.cpg告诉软件怎么解码。文件缺失或声明错误就会显示乱码。用它作为数据质量的第一个检验点可以提前发现大批量采集数据普遍存在的编码隐患。4. 按高度、用途和研究区筛选把400万栋压缩成能进模型的小样本数据是全的但分析模型未必需要全部要素。做风环境模拟只需要研究区半径几百米内的建筑做天际线分析只需要挑出超高层做人口估算需要住宅类建筑。shp格式的好处是看得见摸得着配合QGIS表达式能快速过滤子集。4.1 按高度字段做单条件筛选选超高层还是选住宅QGIS里最常用的入口是Select by Expression。打开后在公式栏输入HEIGHT 100 AND HEIGHT 250逻辑说明把高度100米以上、250米以下的所有建筑全部选中。写上限250米是因为即使在北京核心区超过250米的超高层数量也很少高于这个阈值的多半是数据噪声。参数说明HEIGHT字段名按实际数据调整有的数据叫Height有的叫HH如果筛选后选中数量为0先确认字段名是否一致。如果目的是统计普通住宅就组合筛选HEIGHT 10 AND HEIGHT 6010到60米的区间基本覆盖多层和高层住宅范围。商业办公往往在60米以上。筛选完成后用Export → Save Selected Features As导出为新文件避免后续每一步都带着400万条数据跑。4.2 组合用途字段筛选住宅加商业一起看带用途分类字段的数据集常见字段名TYPE、USE、CLASS值有住宅、商业、办公、教育、医疗等适合做城市功能区分析TYPE IN (住宅, 商业) AND HEIGHT 20逻辑说明IN表示枚举匹配括号里列出目标用途满足其一即可选中再叠加高度条件只保留20米以上的要素。参数说明IN里的引号必须用和属性值一致的引号汉字值用单引号数值直接写数字。先跑一次Statistics by Category查看TYPE字段的代数值域再写筛选条件避免用中文匹配英文代码。4.3 用研究区多边形裁剪比框选矩形更精准做专题分析时研究区往往不是一个正矩形而是沿街道或河流的不规则边界。这时候更合适的空间操作是裁剪。QGIS顶部菜单Vector → Geoprocessing Tools → Clip输入图层选建筑shpOverlay图层选研究区边界点击Run。输出图层的Shape_Area字段不会自动重算如果要每个要素的基底面积在Field Calculator里新建字段表达式写$area/1000000把平方米换算成平方公里。这样处理完的建筑物子集高度、用途、面积三个关键属性都在直接能进后续的建模工具。4.4 导出为WKT或GeoJSON给程序化处理做数据交接如果后续要用PostGIS做空间查询或用Python脚本遍历把shp导成GeoJSON比直接用shp方便。shp的字段名长度限制在10个字符内中文和长字段名容易截断GeoJSON没有这个限制属性名可以很长。我常用的是Fiona脚本import fiona from shapely.geometry import shape, mapping with fiona.open(beijing_filter.shp, r) as src: features [] for feat in src: props feat[properties] h float(props.get(HEIGHT, 0)) if h 10: continue features.append({ type: Feature, properties: {height: h, type: props.get(TYPE, )}, geometry: mapping(shape(feat[geometry])) }) schema { geometry: Polygon, properties: {height: float, type: str}, } with fiona.open(beijing_filter.geojson, w, driverGeoJSON, schemaschema) as dst: dst.writerecords(features)逻辑说明这段脚本读取shp把所有HEIGHT小于10米的要素过滤掉然后把高度和用途字段写入GeoJSON。参数说明mapping(shape(feat[geometry]))把shp里的几何对象转为GeoJSON标准结构schema里geometry类型必须与数据实际类型一致若shp里有MultiPolygon这里也要写成MultiPolygon否则写入时会报schema不匹配。过滤条件h10放在这里主要是宁缺毋滥保留干净的数据减少后面步骤的异常场景。5. 避坑与常见问题坐标偏移、属性乱码、内存爆掉的4个现场还原这一章写的是我在处理这份数据时真实遇到的坑以及排查和解决办法。每个问题都按“现象→原因→解决”的顺序展开基本覆盖了新手和中等水平使用者会碰到的绝大多数场景。5.1 建筑整体偏移几百米问题出在坐标系混用现象把shp加载到在线影像底图上所有建筑轮廓统一往东南方向偏移了数百米底图的街景对不上。原因prj文件声明的是WGS84经纬度但数据内部实际坐标仍是CGCS2000投影坐标。QGIS读取时按prj的声明自动做了一次错误重投影导致位置整体平移。解决用ogrinfo确认extent数值。如果extent落在百万量级那说明是米制投影坐标需要在图层属性里手工改CRS或者用第3章的ogr2ogr强制指定-s_srs和-t_srs做一次真正的坐标转换再叠加比对。5.2 属性表里中文全变问号编码不匹配现象加载shp图层后NAME、TYPE、ADDRESS这些字段显示为“???”或“口口”。原因dbf属性表用GBK编码存储QGIS默认的UTF-8解码器读不懂汉字导致属性字节被错误解析成乱码。解决在shp目录下新建同名.cpg文件内容是UTF-8。如果仍然乱码打开QGIS的Layer encoding下拉切换到GBK或GB2312保存后重新加载。批量处理时用GDAL的iconv编码选项可一次性转换多个文件。5.3 全量加载400万栋卡到怀疑人生现象把整份shp拖进ArcScene或QGIS鼠标拖动时画面像PPT翻页内存占用到达十几个GB。原因shp格式没有空间索引也没有LOD细节层次加载时要一次性把全部几何和属性读进内存。四百多万个多边形在屏幕上全部显示CPU和显存都不可能流畅。解决按行政区切分或用第4章的方法只导出研究区。如果确实需要全量预览先在QGIS图层属性中关闭“Render”或者用数据库加速。另一个选择是把shp转成GeoPackage或PostGIS利用空间索引来加速渲染这两个格式都有原生R树索引查询和显示性能远优于shp。5.4 高度字段是估算值不是实测值别拿去卡红线现象分析某栋建筑高度显示256米但和航拍图对比明显不符。原因大批量建筑物高度数据多数是遥感影像反演或lidar点云滤波提取预测结果和真实值之间普遍有3到10米的误差个别特殊形状建筑误差更大。解决做限高合规分析时不能拿这个字段直接卡官方红线。正确做法是留出15%的容差比如官方限高100米筛选时把阈值放到115米以上再通知现场核验。做展示和模拟时随便用但做规划审批必须找测绘部门实测核对数据只是辅助初筛。5.5 导出GeoJSON后3D模型楼栋扎进地里现象把GeoJSON喂给3D建模工具后一批建筑底部沉入地形以下看起来整片建筑群都矮了十米。原因GeoJSON的几何坐标是二维XY高度在properties里3D建模工具在拉伸时默认用椭球高而从shp转GeoJSON过程中忽略了基准面差异导致高程基准不匹配。解决在转GeoJSON时就把高度字段写入geometry的Z坐标或者在地形工具中把基准面偏移设为0。如果工具支持直接导入原始shp再读高度字段比经过GeoJSON中转更稳。记得在三维软件里先指定地面高程再选“relative to ground”模式。6. 从shp到3D Tiles白模批量转出并验证高度正确性建筑矢量带高度最直接的变现路径就是转成3D Tiles拖进Cesium或自己的GIS平台做三维展示。shp转3dtiles没有官方一键方案自由度和坑都很多。我跑通过的一条路是shp转GeoJSON再把GeoJSON喂给三维切片工具。6.1 用Python把shp转成带高度的GeoJSON这一步复用第4章的Fiona脚本但输出时把高度统一塞进properties关键是保留高度字段名。切片工具通常只看properties里的某个高度键命名不一致会导致整批建筑都变成2米高的扁盒子。6.2 生成三维白模后做的三个验证动作生成完3D Tiles别急着放演示页面。我在本地用3D Tiles Inspector或Cesium Sandcastle做验证顺序固定第一打开某栋楼的属性面板看height值与源shp里同一ID的HEIGHT字段比较一致性检查。第二在场景里量楼顶到地面的垂直距离用Cesium的测量工具距离和属性高度误差在正负5%以内算正常。第三绕着建筑转一圈确认底面贴合地形没有悬浮或穿地。这套验证流程跑过之后数据显示才会被放心用而不是看一眼截图觉得“看起来对”就交付。从那以后我每次做shp转3D Tiles的活都会强制在流程里加一道高度复核不再跳过直接渲染。毕竟四百多万栋的数据里任何一个批次属性错位画面上都是整片白模歪掉找出错点比重跑一遍还痛苦。希望这次拆解能帮你把这份北京全域建筑物数据用得更顺手。本文还有配套的精品资源点击获取