☰
银川建筑轮廓SHP数据带高度属性WGS84坐标系实战指南
2026/10/17 15:51:04 网站建设 项目流程

简介:这份银川市建筑轮廓带高度属性矢量SHP数据合集,面向城市规划、建筑设计、GIS空间分析与灾害预防等领域的从业者及研究人员,提供可直接导入ArcGIS等软件的高精度建筑空间数据,用于天际线设计、光照与阴影分析、通风建模及城市管理决策。资源包共9个文件,约2.7MB,以shp主文件为核心,配套shx索引、dbf属性表、prj投影定义、cpg编码说明及sbn、sbx空间索引等,另含xml元数据与说明文本,完整覆盖SHP格式读取与编辑所需组件。数据采用WGS84坐标系,兼容性强,且明确为非OSM独立采集成果,保证独特与准确。每栋建筑均记录轮廓与高度属性,便于开展精确的空间查询、统计与三维分析。目前已有55人学习关注,适合需要银川本地建筑基底数据的中高级GIS用户快速上手使用。

1. 银川市建筑轮廓带高度属性矢量SHP数据合集wgs84坐标系(非OSM):这份数据到底能干什么

如果你做过城市三维建模、日照分析或者风电光伏选址,大概率遇到过这个场景:拿到一份建筑轮廓数据,打开属性表一看,只有几何面,没有高度字段。想做体块拉伸,只能靠楼层数估算,或者手动补录,一个片区几百栋楼,补到怀疑人生。银川市建筑轮廓带高度属性矢量SHP数据合集wgs84坐标系(非OSM)这个标题,核心卖点就两个:一是带高度属性,二是非OSM来源。带高度意味着你能直接做三维拉伸、容积率估算、天际线分析;非OSM意味着它的几何精度和属性完整度通常比开放街图数据更贴近实际测绘成果。这份数据适合做城市尺度空间分析的人——城市规划、GIS开发、遥感应用、建筑能耗模拟,只要你需要把建筑从二维平面立起来,它就能省掉你最头疼的那一步。坐标系是wgs84,也就是EPSG:4326,经纬度地理坐标系,不是投影坐标系,这一点后面会专门讲怎么处理。

2. 拿到SHP先别急着打开:搞清高度字段和坐标系的真实含义

2.1 高度属性到底存在哪一列

很多人拿到带高度的SHP,第一反应是双击打开看属性表,然后发现列名是英文缩写,不知道哪个是高度。常见的字段命名有几种:height、H、building_h、floor、floors、层数。这里有个关键区别:高度值和楼层数是两回事。高度值通常是米,楼层数是整数。如果字段叫floor,值是6,那它大概率是6层,不是6米。你需要先判断这个字段是高度还是层数,再决定怎么用。

判断方法很简单:看数值分布。高度值一般有小数,比如18.5、24.3;楼层数一般是整数,比如6、18。如果全是整数且最大值在30到60之间,基本可以确定是楼层数。这时候你需要乘以一个层高系数,常用的是3米或3.2米。但注意,不同建筑类型的层高不一样,住宅和商业差别很大,一刀切乘3米会有误差。如果数据里同时有height和floor两个字段,优先用height,楼层数只做参考。

还有一种情况:字段名是LEV或者LEVEL,这种一般是楼层数。如果字段名是ELEV,那可能是高程,不是建筑高度,别搞混。高程是建筑底面海拔,建筑高度是建筑本身的高度,两者差一个地面标高。

2.2 wgs84坐标系在SHP里的实际表现

wgs84是地理坐标系,单位是度,不是米。你打开SHP,看到坐标值是106.2, 38.5这种,那就是wgs84。这种坐标系的好处是通用,任何GIS软件都能直接读,和在线地图底图也能对上。坏处是:你不能直接用它算面积、算距离、算缓冲区。因为度不是长度单位,一度经度在赤道是111公里,在银川(北纬38度左右)只有大约87公里。你直接算面积,结果会偏得离谱。

所以拿到wgs84的SHP,第一步不是看属性,是投影。投影成什么?看你的用途。做银川市域分析,常用的是UTM投影,银川在UTM 48N带,EPSG:32648。或者用高斯克吕格投影,3度带,中央经线105度,EPSG:4544(CGCS2000 3度带105E)。注意,wgs84和CGCS2000在米级精度上差异很小,日常分析可以互换,但如果你要做高精度测量,需要做基准转换。

投影之后,面积单位变成平方米,距离单位变成米,这时候你算容积率、算建筑密度才有意义。投影这一步在QGIS里叫“导出-另存为”,在ArcGIS里叫“投影栅格”或“投影”,在Python里用geopandas的to_crs。后面会给具体代码。

2.3 非OSM来源意味着什么

OSM的建筑轮廓数据,优点是覆盖广、免费、更新快,缺点是几何精度参差不齐,高度属性大量缺失,很多建筑只有轮廓没有高度。非OSM来源,通常意味着这份数据来自测绘部门、规划部门或者商业数据商,几何精度更高,属性更完整,尤其是高度字段,往往是实测或者从规划审批资料里提取的。

但非OSM不代表没有坑。常见的问题有:建筑轮廓有重叠、有缝隙、有自相交;高度字段有空值、有异常值(比如9999表示未知);数据分块存储,一个城市几十个SHP文件,需要合并。这些问题在OSM数据里也有,但非OSM数据因为精度高,反而更容易暴露拓扑错误。所以拿到数据后,先做几何检查,再做属性检查,顺序不能反。

3. 用Python把SHP读进来:字段清洗、投影转换、高度补全

3.1 读取SHP并检查字段和几何有效性

import geopandas as gpd import pandas as pd # 读取SHP文件,注意编码,中文路径和字段名可能需要指定encoding gdf = gpd.read_file("yinchuan_buildings.shp", encoding="utf-8") # 查看前5行和字段列表 print(gdf.head()) print(gdf.columns.tolist()) # 查看坐标系 print(gdf.crs) # 检查几何有效性 invalid = gdf[~gdf.geometry.is_valid] print(f"无效几何数量: {len(invalid)}") # 检查高度字段空值 height_col = "height" # 根据实际字段名修改 if height_col in gdf.columns: print(f"高度字段空值数量: {gdf[height_col].isna().sum()}") print(f"高度字段统计:\n{gdf[height_col].describe()}")

这段代码做了四件事:读文件、看字段、查坐标系、查几何有效性和高度空值。encoding="utf-8"是为了防止中文字段名乱码,如果报错可以试gbk。is_valid检查几何有没有自相交、重复点等问题,无效几何会导致后续空间分析出错。高度字段的空值数量决定了你要不要做补全,如果空值超过30%,这份数据的可用性就要打问号。

3.2 投影转换:从wgs84到适合算面积的投影坐标系

# 投影到UTM 48N,适合银川地区 gdf_utm = gdf.to_crs(epsg=32648) # 或者投影到CGCS2000 3度带105E # gdf_utm = gdf.to_crs(epsg=4544) # 计算面积,单位平方米 gdf_utm["area_m2"] = gdf_utm.geometry.area # 查看面积统计 print(gdf_utm["area_m2"].describe()) # 保存投影后的数据 gdf_utm.to_file("yinchuan_buildings_utm.shp", encoding="utf-8")

to_crs是geopandas的投影转换函数,epsg=32648是UTM 48N的代码。转换后,几何坐标从经纬度变成米,geometry.area算出来的就是平方米。注意,投影转换不会改变属性表,只改变几何坐标。保存时用to_file,格式还是SHP,但坐标系已经变了。如果你后续要做空间连接、缓冲区、叠加分析,都用这个投影后的数据,不要用原始的wgs84数据。

3.3 高度字段清洗:空值、异常值、楼层数转换

# 假设高度字段是height,楼层字段是floor # 先处理异常值:高度大于200米的建筑在银川极少,可能是错误值 gdf_utm.loc[gdf_utm["height"] > 200, "height"] = None # 空值用楼层数补全,层高按3米算 mask = gdf_utm["height"].isna() & gdf_utm["floor"].notna() gdf_utm.loc[mask, "height"] = gdf_utm.loc[mask, "floor"] * 3.0 # 如果楼层数也是空,用该区域中位数补全 median_height = gdf_utm["height"].median() gdf_utm["height"] = gdf_utm["height"].fillna(median_height) # 检查补全后的结果 print(f"补全后空值数量: {gdf_utm['height'].isna().sum()}") print(gdf_utm["height"].describe())

这段代码的逻辑是:先剔除明显异常的高度值(大于200米),然后用楼层数乘以3米补全,如果楼层数也没有,用中位数补全。中位数补全是一种保守做法,不会引入太大偏差,但会抹平区域差异。如果你做的是精细分析,建议按区域分组补全,比如按行政区或按网格,用局部中位数而不是全局中位数。

注意,floor字段如果是字符串类型,需要先转成数值:gdf_utm["floor"] = pd.to_numeric(gdf_utm["floor"], errors="coerce")。errors="coerce"会把无法转换的值变成NaN,避免报错。

3.4 合并多个SHP文件并统一字段

import os import glob # 假设数据分块存储在data文件夹下 shp_files = glob.glob("data/*.shp") gdf_list = [] for f in shp_files: temp = gpd.read_file(f, encoding="utf-8") # 统一字段名,假设不同文件里高度字段名不一样 if "H" in temp.columns: temp = temp.rename(columns={"H": "height"}) if "层数" in temp.columns: temp = temp.rename(columns={"层数": "floor"}) gdf_list.append(temp) # 合并 gdf_all = pd.concat(gdf_list, ignore_index=True) gdf_all = gpd.GeoDataFrame(gdf_all, crs=gdf_list[0].crs) # 去重,按几何和高度 gdf_all = gdf_all.drop_duplicates(subset=["geometry", "height"]) print(f"合并后建筑数量: {len(gdf_all)}") gdf_all.to_file("yinchuan_buildings_merged.shp", encoding="utf-8")

分块数据合并的核心是字段对齐。不同批次的SHP,高度字段可能叫H、height、building_h,楼层字段可能叫floor、层数、LEV。你需要先统一命名,再合并。pd.concat会把所有行拼在一起,gpd.GeoDataFrame确保结果还是地理数据框。去重按几何和高度,防止同一栋楼被重复录入。最后保存成一个完整的SHP。

4. 避坑指南:这五类问题我几乎每次都能遇到

4.1 坐标系标了wgs84但实际是其他坐标系

现象:数据打开后,和在线底图对不上,偏移几百米甚至几公里。原因:SHP的.prj文件写的是wgs84,但实际坐标可能是CGCS2000、北京54或者西安80。这几种坐标系在银川地区的差异,从几十米到几百米不等。解决:找一个已知地物,比如鼓楼或者某个大型立交桥,对比在线底图的坐标,如果偏移固定,就是坐标系错了。用QGIS的“坐标转换”工具试几个常用坐标系,找到对得上的那个。或者直接问数据提供方,别自己猜。

4.2 高度字段单位不是米而是分米或厘米

现象:建筑高度值普遍在100到300之间,但银川没有那么多300米高楼。原因:单位是分米,除以10才是米。解决:看数值分布,如果中位数在100左右,而实际建筑中位数高度在20到30米,那就是分米。除以10。如果中位数在1000左右,可能是厘米,除以100。还有一种可能是英尺,乘以0.3048。判断方法:拿几栋你知道高度的楼对比,比如一栋6层住宅,高度大约18米,如果数据里是180,那就是分米。

4.3 建筑轮廓有重叠导致面积重复计算

现象:算总建筑面积时,结果比实际大很多。原因:同一栋楼被拆成多个面,或者相邻建筑轮廓有重叠。解决:先用gdf.geometry.area算每个面的面积,然后做空间自相交检查。在geopandas里,可以用gdf.overlaps(gdf)找重叠对,但计算量大。更实用的方法是:按建筑ID分组,如果ID相同但几何不同,说明是同一栋楼被拆分,需要合并。如果ID不同但几何重叠,说明是数据错误,需要人工检查。合并用unary_union,但会丢失属性,建议先合并几何再重新关联属性。

4.4 高度空值用全局中位数补全导致区域偏差

现象:补全后,老城区建筑高度被拉高,新城区被拉低。原因:全局中位数没有考虑区域差异。老城区建筑普遍低,新城区普遍高,用全局中位数补全,两边都不准。解决:按空间网格分组补全。把研究区划分成500米×500米的网格,每个网格内用中位数补全。这样既保留了区域特征,又填补了空值。代码实现:用gdf.sjoin把建筑和网格关联,然后groupby网格ID算中位数,再fillna。

4.5 投影转换后面积算出来还是不对

现象:投影到UTM后,面积还是偏大或偏小。原因:UTM投影在高纬度地区有变形,银川在北纬38度,变形不大,但如果你用的是Web Mercator(EPSG:3857),变形会很大。Web Mercator是给在线地图用的,不是给面积计算用的。解决:确认投影坐标系是UTM还是高斯克吕格,不要用Web Mercator。另外,检查几何是否有效,无效几何算面积会出错。用gdf.geometry.is_valid检查,无效的用buffer(0)修复。

5. 从SHP到三维体块:用高度字段做拉伸和可视化

5.1 用QGIS快速做三维拉伸

QGIS有个内置的3D地图视图,可以直接把带高度的SHP拉伸成体块。步骤:打开QGIS,加载SHP,右键图层属性,找到3D视图设置,勾选“启用3D渲染”,高度字段选height,拉伸系数设1.0。然后打开“视图-3D地图视图”,就能看到建筑体块。这个方法适合快速验证高度字段对不对,不需要写代码。注意,QGIS的3D视图对大数据量支持一般,几万栋楼可能会卡,建议先按区域筛选。

5.2 用Python做体块拉伸和导出

from shapely.geometry import Polygon import numpy as np def extrude_building(row): """把建筑轮廓拉伸成三维体块""" geom = row.geometry height = row["height"] if geom.is_empty or height <= 0: return None # 获取外环坐标 coords = list(geom.exterior.coords) # 底面和顶面 base = [(x, y, 0) for x, y in coords] top = [(x, y, height) for x, y in coords] # 侧面 sides = [] for i in range(len(coords)-1): side = [ (coords[i][0], coords[i][1], 0), (coords[i+1][0], coords[i+1][1], 0), (coords[i+1][0], coords[i+1][1], height), (coords[i][0], coords[i][1], height), (coords[i][0], coords[i][1], 0) ] sides.append(side) return base, top, sides # 对前10栋楼做拉伸,导出为GeoJSON sample = gdf_utm.head(10) for idx, row in sample.iterrows(): result = extrude_building(row) if result: base, top, sides = result # 这里可以进一步导出为CityGML或OBJ格式 print(f"建筑{idx}高度{row['height']}米,底面{len(base)}个点")

这段代码演示了拉伸的基本逻辑:把二维轮廓的每个点加上Z值,底面Z=0,顶面Z=height,侧面是四边形。实际项目中,你会用trimesh或pyvista做更高效的体块生成和导出。注意,拉伸前要确保几何是有效的简单多边形,带洞的多边形需要特殊处理,洞的边界也要拉伸成侧面。

5.3 高度字段的验证方法

做完拉伸,怎么验证高度对不对?三个方法:一是和已知地标对比,比如银川某座已知高度的建筑,看数据里的值是否接近;二是看高度分布,正常城市建筑高度应该符合幂律分布,大部分低层,少数高层,如果分布太均匀,可能有问题;三是做日照分析,用拉伸后的体块算阴影,看阴影长度是否和实际日照情况吻合。第三个方法最直观,但需要日照分析软件,比如Ladybug或Sunlight。

5.4 从体块到容积率:一个实际计算示例

# 假设有一个地块边界 plot = gpd.read_file("plot.shp").to_crs(epsg=32648) # 空间连接,找出地块内的建筑 buildings_in_plot = gpd.sjoin(gdf_utm, plot, predicate="within") # 计算总建筑面积(体块体积除以层高,或者直接用底面积乘以层数) # 这里用底面积乘以楼层数估算 buildings_in_plot["floor_area"] = buildings_in_plot.geometry.area * buildings_in_plot["floor"] # 按地块汇总 total_floor_area = buildings_in_plot.groupby("plot_id")["floor_area"].sum() plot_area = plot.set_index("plot_id").geometry.area # 容积率 far = total_floor_area / plot_area print(f"容积率:\n{far}")

容积率是地块内总建筑面积除以地块面积。这里用底面积乘以楼层数估算总建筑面积,比用高度除以层高更准,因为层高有差异。sjoin的predicate="within"表示建筑完全在地块内,如果建筑跨地块,需要用intersects然后按面积比例分摊。容积率算出来可以和规划指标对比,验证数据的合理性。

6. 进阶技巧:把高度属性用出花来的三个方向

第一个方向是建筑能耗模拟。带高度的建筑轮廓,加上朝向、窗墙比、围护结构参数,可以快速估算区域建筑能耗。常用工具是EnergyPlus或CitySim,输入就是体块模型加属性表。这里的关键是高度字段的精度,如果高度误差超过10%,能耗模拟结果偏差会很大。我一般会先用高度分布做敏感性分析,看哪些建筑的高度对结果影响最大,然后重点校验这些建筑。

第二个方向是城市风环境分析。建筑高度直接影响风道和涡流区。用CFD软件做风环境模拟,输入就是三维体块。这里有个坑:SHP的几何精度太高,几万个顶点,CFD网格划分会非常慢。我一般会先做几何简化,用simplify函数把顶点数降到原来的10%到20%,同时保留建筑轮廓的主要特征。简化容差取0.5到1米,太小了没效果,太大了建筑形状会变形。

第三个方向是日照分析。银川纬度较高,日照分析对建筑高度很敏感。用体块模型算日照,核心是阴影长度和遮挡关系。这里有个技巧:不要用所有建筑一起算,先按高度排序,只算高层建筑对周边的遮挡,低层建筑之间的遮挡影响很小。这样可以大幅减少计算量。验证方法:选一个已知日照情况的日期,比如冬至日,算出来的日照时数和实际观测对比,误差在15分钟以内就算合格。

最后一个习惯:每次拿到新的SHP数据,先做三件事——看坐标系、看高度字段分布、看几何有效性。这三件事花不了10分钟,但能避免后面80%的返工。我见过太多人拿到数据直接开干,跑到一半发现坐标系错了,或者高度字段是楼层数,全部重来。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询