简介:这份资源面向GIS从业者、城市规划研究人员及地理信息相关专业学生,提供宁波地区的建筑物与高程空间数据,可直接用于地图制作、城市扩张分析、地形变化研究及防洪规划等场景。压缩包共8个文件,约7.2MB,以SHP格式为核心,包含shp几何数据、dbf属性数据、shx索引数据、prj投影信息及xml元数据等,各文件协同构成完整的空间数据集,采用WGS84全球通用坐标系,便于与其他地区数据叠加比对。目前已有671人学习下载。解压后可直接在ArcGIS、QGIS等软件中加载查看,获取宁波建筑物的形状、位置及对应高程信息,为空间分析与可视化提供基础数据支撑,适合需要快速获取区域建筑与地形底图的研究者使用。
1. 宁波建筑物及高程 shp 数据 wgs84 坐标系:拿到这份数据先别急着打开
如果你手里刚拿到一份「宁波建筑物及高程 shp 数据 wgs84 坐标系.zip」,第一反应大概率是双击解压、拖进 ArcGIS 看个热闹。但我见过太多人卡在第一步:图层能加载,位置却飘到几百米外,或者高程字段全是 0,又或者建筑物面跟底图对不上。问题不在数据本身,而在于 shp 这种格式对坐标系、字段类型和编码的依赖非常强,wgs84 只是地理坐标系,不是投影坐标系,直接量算面积和距离会得到以度为单位的结果,毫无工程意义。
这份数据通常包含两类内容:建筑物轮廓面图层,以及带高程属性的点或面图层。它的价值在于把宁波的建筑物 footprint 和高度信息绑在一起,能做城市三维白模、日照分析、容积率估算、洪水淹没模拟。适合做城市 GIS 分析、三维建模前期数据准备、以及需要本地建筑基底数据的开发者和规划从业者。但前提是,你得先把它从「能打开」变成「能用」。
2. 先搞懂 wgs84 和 shp 的脾气:为什么直接加载会翻车
2.1 wgs84 是地理坐标系,不是投影坐标系
wgs84 全称 World Geodetic System 1984,它是一个地心坐标系,用经纬度表示位置,单位是度。很多人看到 shp 属性里写着 wgs84 就以为可以直接算面积,结果 ArcGIS 里量出来是 0.0001 平方度,完全没法用。宁波位于东经 121° 左右、北纬 29° 到 30° 之间,在这个纬度上,1 度经度大约对应 97 公里,1 度纬度大约对应 111 公里。如果你用 wgs84 直接做缓冲区分析,缓冲区半径写 100,实际出来的是 100 度,直接绕地球好几圈。
常见做法是:保留 wgs84 作为存储和交换坐标系,分析时投影到适合宁波的投影坐标系。宁波常用的是 CGCS2000 3 度带高斯克吕格投影,中央经线 121°E,带号 40,EPSG 代码 4547 或 4526 附近。具体用哪个,取决于你的数据范围和精度要求。我一般会先看数据覆盖范围,如果只覆盖宁波市区,用 EPSG:4547 就够了。
提示:不要用 Web Mercator(EPSG:3857)做面积量算,它在高纬度变形极大,宁波虽然不算高纬,但用于正式分析仍然不合适。
2.2 shp 是文件集合,不是单个文件
shp 从来不是一个文件,而是一组同名文件:.shp 存几何,.shx 存索引,.dbf 存属性,.prj 存坐标系,.cpg 存编码。你解压后如果只看到 .shp,那说明压缩包可能不完整,或者被过滤了。缺少 .prj 时,ArcGIS 会提示「未知坐标系」,这时候你手动指定 wgs84 也能用,但一定要确认数据源确实是 wgs84,否则后续所有分析都是错的。
.dbf 文件是 dBase 格式,字段名不能超过 10 个字符,中文属性容易乱码。如果打开后看到「????」或者乱码,先检查 .cpg 文件里写的是不是 UTF-8。没有 .cpg 时,ArcGIS 默认按系统编码读,中文 Windows 下可能是 GBK,跨平台就会翻车。
2.3 高程字段可能是数字,也可能是字符串
建筑物高程数据常见的有两种:一种是面要素带「height」或「楼层数」字段,另一种是单独的点图层带高程值。我遇到过不少数据,高程字段在 .dbf 里被存成字符串,因为导出时没做类型转换。你在 ArcGIS 里看属性表是正常的,但一做符号化或统计就报错。判断方法很简单:打开属性表,看字段对齐方式,数字右对齐,字符串左对齐。如果是字符串,需要新建一个双精度字段,用字段计算器转换。
# 用 arcpy 检查字段类型并转换高程字段 import arcpy fc = r"C:\data\ningbo_building.shp" field_name = "height" # 列出所有字段及类型 for field in arcpy.ListFields(fc): print(f"{field.name}: {field.type}") # 如果 height 是 String 类型,新建 Double 字段并转换 if arcpy.ListFields(fc, field_name)[0].type == "String": arcpy.AddField_management(fc, "height_num", "DOUBLE") # 用 float() 转换,遇到空值或非数字给 0 arcpy.CalculateField_management( fc, "height_num", "float(!height!) if !height! not in (None, '', ' ') else 0", "PYTHON3" ) print("转换完成,新字段为 height_num")这段代码先列出字段类型,确认 height 是不是字符串。如果是,就新建一个双精度字段 height_num,然后用 Python 表达式逐行转换。注意!height!是 ArcGIS 字段计算器里的语法,不是标准 Python。空值和空格要单独处理,否则 float() 会抛异常。转换后不要急着删原字段,先对比几行数据,确认没有精度丢失。
3. 把 wgs84 的宁波建筑物数据用起来:投影、裁剪、高程提取
3.1 投影到 CGCS2000 3 度带,让面积和距离有意义
拿到 wgs84 数据后,第一步是投影。ArcGIS 里用「Project」工具,输出坐标系选 CGCS2000_3_Degree_GK_CM_121E,也就是 EPSG:4547。如果你用 QGIS,操作类似,在图层右键「导出」→「保存要素为」,CRS 选 EPSG:4547。投影后,单位变成米,面积和距离就正常了。
# 用 ogr2ogr 命令行投影,适合批量处理 ogr2ogr -f "ESRI Shapefile" \ -t_srs EPSG:4547 \ ningbo_building_projected.shp \ ningbo_building_wgs84.shp-t_srs指定目标坐标系,-f指定输出格式。ogr2ogr 会自动处理 .prj 文件。如果数据量大,加-progress看进度。投影后一定要检查:原来在 wgs84 下经度 121.5、纬度 29.8 的点,投影后 X 应该在 500000 左右,Y 在 3300000 左右。如果 X 是 121 开头,说明投影没生效。
3.2 用宁波行政边界裁剪,去掉多余区域
网上下载的建筑物数据经常覆盖整个浙江省甚至华东,但你只关心宁波。这时候需要一份宁波行政边界 shp,用「Clip」工具裁剪。裁剪前确保两个图层坐标系一致,都是投影后的 CGCS2000。如果边界是 wgs84,先投影再裁剪,否则会错位。
# arcpy 裁剪建筑物数据 import arcpy arcpy.env.workspace = r"C:\data" building = "ningbo_building_projected.shp" boundary = "ningbo_boundary_projected.shp" output = "ningbo_building_clipped.shp" arcpy.Clip_analysis(building, boundary, output) print(f"裁剪完成,输出:{output}")Clip 工具会保留落在边界内的几何,边界外的直接丢弃。如果建筑物面刚好跨边界,ArcGIS 默认会切割,保留边界内部分。裁剪后要素数量会减少,用「获取计数」确认一下。如果裁剪后一个要素都没有,八成是坐标系不一致,或者边界文件本身有问题。
3.3 从高程点提取建筑物高度,关联到面图层
如果高程是单独的点图层,需要把点的高程值赋给建筑物面。常见做法是「空间连接」:每个建筑物面落在哪个点上,就取那个点的高程。但一个面可能覆盖多个点,这时候取平均值、最大值还是最近点,取决于业务需求。做日照分析一般取最大值,做淹没模拟取最小值。
# 空间连接:把点的高程赋给建筑物面 import arcpy building = "ningbo_building_clipped.shp" points = "ningbo_elevation_points.shp" output = "ningbo_building_with_height.shp" # 用最近点匹配,每个面取最近点的高程 arcpy.SpatialJoin_analysis( building, points, output, "JOIN_ONE_TO_ONE", "KEEP_ALL", match_option="CLOSEST" ) print("空间连接完成")JOIN_ONE_TO_ONE表示每个面只保留一条记录,CLOSEST表示取最近的点。如果点图层的高程字段叫「elevation」,连接后会在输出里多一个「elevation」字段。如果字段名冲突,ArcGIS 会自动加后缀。连接后检查一下有没有空值,空值可能是面附近没有点,需要手动补或剔除。
4. 避坑与排查:宁波建筑物 shp 数据最常见的 5 个翻车现场
4.1 加载后位置偏移几百米
现象:数据加载到底图上,建筑物整体偏移,跟路网对不上。原因:坐标系定义错误。数据实际是 CGCS2000 或北京 54,但 .prj 写的是 wgs84,或者根本没有 .prj,ArcGIS 按默认坐标系处理。解决:用「定义投影」工具重新指定正确坐标系,不要用「投影」工具。定义投影只改元数据,不改坐标值。如果不知道正确坐标系,拿几个特征点跟底图对比,试几个常见坐标系,看哪个对上。
4.2 面积字段全是 0 或负数
现象:投影后计算面积,结果全是 0 或者负数。原因:几何有问题,比如自相交、环方向错误、或者面被写成了线。shp 对几何有效性要求高,但不会主动报错。解决:用「修复几何」工具先修一遍,然后再计算面积。如果修复后还有问题,用 QGIS 的「几何有效性」检查,或者用 Python 的 shapely 库逐条检查。
# 用 shapely 检查几何有效性 from shapely.geometry import shape import fiona with fiona.open("ningbo_building_projected.shp") as src: for feat in src: geom = shape(feat["geometry"]) if not geom.is_valid: print(f"无效几何:{feat['id']},原因:{geom.is_valid_reason}")这段代码逐条读取 shp,用 shapely 判断几何是否有效。无效的会打印出 ID 和原因。常见原因有「Self-intersection」和「Ring Self-intersection」。修复方法可以用buffer(0),但会轻微改变几何,慎用。
4.3 中文属性乱码
现象:属性表里中文显示为「????」或乱码。原因:.dbf 文件编码与 ArcGIS 读取编码不一致。没有 .cpg 文件时,ArcGIS 按系统区域设置读。解决:新建一个 .cpg 文件,内容写「UTF-8」或「GBK」,跟数据实际编码一致。如果不确定,用 Notepad++ 打开 .dbf 看编码。或者用 QGIS 打开,QGIS 对编码兼容性更好,能在图层属性里手动指定编码。
4.4 高程字段全是 0 或空
现象:高程字段有值,但符号化后所有建筑物高度一样,或者全是 0。原因:字段类型是字符串,或者高程值本身是 0。也可能是空间连接时匹配失败,所有记录都取了默认值。解决:先看属性表,确认字段类型和值。如果是字符串,按 2.3 的方法转换。如果是空间连接失败,检查点图层和面图层的坐标系是否一致,以及点是否真的落在面内。可以用「按位置选择」先选出一部分面,看有没有点。
4.5 数据量太大,ArcGIS 卡死
现象:打开 shp 后 ArcGIS 无响应,或者操作极慢。原因:shp 单文件上限 2GB,要素过多时属性表和几何索引会拖慢速度。宁波全市建筑物可能几十万条,直接加载确实吃力。解决:先按行政区拆分,或者只加载当前视图范围。也可以用 GeoPackage 或 File Geodatabase 替代 shp,性能更好。如果必须用 shp,建立空间索引,用「添加空间索引」工具。
5. 从 shp 到三维白模:用高程字段快速拉伸建筑体块
拿到带高程的建筑物面之后,最直接的进阶用法是拉伸成三维白模。ArcGIS Pro 里用「拉伸」图层属性,QGIS 里用「三维视图」加高度表达式,但如果你要批量生成、或者集成到 Web 端,用 Python 更灵活。我一般用 geopandas 读 shp,再用 pyvista 或 trimesh 做拉伸,导出成 glTF 或 3D Tiles,直接喂给 Cesium 或 Three.js。
# 用 geopandas 和 trimesh 把建筑物面拉伸成三维体块 import geopandas as gpd import trimesh import numpy as np gdf = gpd.read_file("ningbo_building_with_height.shp") # 确保投影坐标系,单位是米 gdf = gdf.to_crs(epsg=4547) meshes = [] for idx, row in gdf.iterrows(): height = row["height_num"] if height <= 0: continue # 获取面的外轮廓坐标 geom = row.geometry if geom.geom_type == "Polygon": coords = np.array(geom.exterior.coords) elif geom.geom_type == "MultiPolygon": # 取最大的多边形 largest = max(geom.geoms, key=lambda p: p.area) coords = np.array(largest.exterior.coords) else: continue # 用 trimesh 拉伸 mesh = trimesh.creation.extrude_polygon(geom, height) meshes.append(mesh) # 合并所有体块并导出 combined = trimesh.util.concatenate(meshes) combined.export("ningbo_buildings_3d.glb") print(f"导出完成,共 {len(meshes)} 个建筑体块")这段代码先读 shp,确认投影是 EPSG:4547,然后逐行取几何和高度。extrude_polygon把二维面沿 Z 轴拉伸成三维体。MultiPolygon 只取最大的一块,避免一个建筑拆成多个体块。最后合并导出 glb,可以直接拖进 Cesium 或 Blender 查看。注意高度单位是米,如果原始数据是楼层数,需要乘以层高,一般取 3 米。
参数方面,height_num是前面转换出来的双精度字段。如果字段名不同,改成你数据里的实际字段。extrude_polygon的第二个参数是拉伸高度,不能为负。如果建筑物有地下部分,需要单独处理。导出 glb 时,trimesh 会自动处理坐标系,但 Cesium 默认用 wgs84 地理坐标系,所以你可能需要在 Cesium 里再做一次投影转换,或者导出时直接写 wgs84 坐标。
我自己的习惯是:拿到任何 shp 数据,先看 .prj,再看字段类型,最后投影到本地坐标系。这三步做完,后面基本不会出大错。宁波这份数据质量整体不错,但高程字段偶尔有缺失,做三维白模时记得过滤掉高度为 0 的体块,否则会生成一堆贴地面的薄片,看着像地面裂缝。希望帮到你。
本文还有配套的精品资源,点击获取