当前位置: 首页 > news >正文

使用 Python 自动化检查矢量面数据的拓扑错误(含导出/删除选项)

在地理信息系统(GIS)数据处理中,矢量面数据的拓扑关系至关重要。如果拓扑错误没有及时发现和修复,可能会影响后续空间分析、建模与可视化效果。本文介绍如何使用 GeoPandas + Shapely 进行拓扑检查,并提供扩展功能(打印、导出、删除问题要素)。

一、拓扑错误常见类型

在多边形矢量数据中,常见的拓扑问题包括:

非法几何(Invalid Geometry)
多边形自相交或几何结构错误。

带洞要素(Polygons with Holes)
多边形内部包含空洞(通常需要视业务是否允许)。

极小面(Small Polygons)
面积过小的碎片,通常是误差或无意义的边角。

完全重复几何(Duplicate Geometries)
两个要素几何完全相同。

同层重叠(Self-Overlap / Overlap within Layer)
两个多边形在同一层里相互叠压。

二、Python 拓扑检查脚本

# -*- coding: utf-8 -*-
"""
矢量面数据拓扑检查与清洗
记得先把数据加上投影奥
- 检查项:非法几何、带洞、极小面、重复几何、同层重叠
- 可选操作:打印 / 导出 / 删除
"""import geopandas as gpd
from shapely.validation import explain_validity
from shapely.geometry import Polygon, MultiPolygon, box
import shapely
import os# ========= 基本参数 =========
SRC = r""
MIN_AREA_M2 = 10.0            # 极小面阈值(平方米)
FIX_INVALID_BEFORE = True     # 检查前修复非法几何
EXPORT_PROBLEMS = True        # 是否导出问题要素
DELETE_PROBLEMS = False       # 是否直接删除问题要素(谨慎使用)OUT_DIR = os.path.dirname(SRC)# ========= 读取数据 =========
gdf = gpd.read_file(SRC)
print(f"读取完成:{len(gdf)} 要素;原CRS = {gdf.crs}")if gdf.crs is None:gdf = gdf.set_crs(epsg=4326, allow_override=True)print("未检测到CRS,已强制设置 EPSG:4326")# ========= 构造米制副本 =========
try:utm_crs = gdf.estimate_utm_crs()gdf_m = gdf.to_crs(utm_crs)print(f"用于量测的米制CRS:{utm_crs}")
except Exception as e:print("UTM估算失败,仍使用原CRS:", e)gdf_m = gdf.copy()# ========= 几何修复函数 =========
def fix_geom(geom):if geom is None or geom.is_empty:return geomif not geom.is_valid:try:return shapely.make_valid(geom)except Exception:return geom.buffer(0)return geomif FIX_INVALID_BEFORE:gdf["geometry"] = gdf["geometry"].apply(fix_geom)gdf_m["geometry"] = gdf_m["geometry"].apply(fix_geom)# ========= 检查1:非法几何 =========
invalid_idx = [i for i, geom in gdf.geometry.items() if not geom.is_valid]# ========= 检查2:带洞要素 =========
def has_holes(geom):if isinstance(geom, Polygon):return len(geom.interiors) > 0if isinstance(geom, MultiPolygon):return any(len(p.interiors) > 0 for p in geom.geoms)return Falseholes_idx = [i for i, geom in gdf.geometry.items() if has_holes(geom)]# ========= 检查3:极小面 =========
small_idx = [i for i, geom in gdf_m.geometry.items() if geom.area < MIN_AREA_M2]# ========= 检查4:完全重复几何 =========
dup_idx = list(gdf.index[gdf.geometry.duplicated(keep=False)])# ========= 检查5:同层重叠 =========
print("\n[同层重叠] 正在扫描 ...")
overlap_pairs, overlap_ids = [], set()
sindex = gdf_m.sindexfor i, geom in enumerate(gdf_m.geometry):if geom.is_empty:continuecandidate_idx = sindex.query(box(*geom.bounds))for j in candidate_idx:if j <= i:continueg2 = gdf_m.geometry.iloc[j]inter = geom.intersection(g2)if not inter.is_empty and inter.area > 0:overlap_pairs.append((i, j, float(inter.area)))overlap_ids.update([i, j])# ========= 汇总 =========
print("\n—— 拓扑检查汇总 ——")
print(f"非法几何:{len(invalid_idx)}")
print(f"带洞要素:{len(holes_idx)}")
print(f"极小面(<{MIN_AREA_M2} m²):{len(small_idx)}")
print(f"完全重复几何:{len(dup_idx)}")
print(f"同层重叠:{len(overlap_pairs)} 对,涉及 {len(overlap_ids)} 个要素")# ========= 导出 / 删除选项 =========
problem_idx = sorted(set(invalid_idx + holes_idx + small_idx + dup_idx + list(overlap_ids)))if problem_idx:print(f"\n⚠️ 检测到 {len(problem_idx)} 个问题要素:{problem_idx[:20]}{' ...' if len(problem_idx)>20 else ''}")if EXPORT_PROBLEMS:out_path = os.path.join(OUT_DIR, "problems.shp")gdf.loc[problem_idx].to_file(out_path, encoding="utf-8")print(f"已导出问题要素到: {out_path}")if DELETE_PROBLEMS:gdf_clean = gdf.drop(problem_idx)out_clean = os.path.join(OUT_DIR, "cleaned.shp")gdf_clean.to_file(out_clean, encoding="utf-8")print(f"已删除问题要素,结果保存到: {out_clean}")
else:print("\n✅ 数据没有发现拓扑问题!")

三、功能说明

打印模式:直接在终端显示各类拓扑问题数量和索引。

导出模式(EXPORT_PROBLEMS=True):将有问题的要素保存到单独的 problems.shp 文件,方便在 ArcGIS / QGIS 中查看。

删除模式(DELETE_PROBLEMS=True):自动清洗数据,生成 cleaned.shp,但要谨慎使用。

http://www.dtcms.com/a/359656.html

相关文章:

  • 【C++ 】STL详解(六)—手撸一个属于你的 list!
  • Lua基础知识精炼
  • vscode+EIDE+Clangd环境导入keil C51以及MDK工程
  • PortSwigger靶场之Stored XSS into HTML context with nothing encoded通关秘籍
  • AG32 Nano开发板的烧录与调试工具(二)
  • LabVIEW 瀑布图与游标操作
  • Python人工智能机器学习汇总
  • MySQL 常用语法
  • CTFshow系列——命令执行web69-72
  • 贝叶斯分类(Bayes Classify)
  • 【嵌入式DIY实例】-空中鼠标
  • Ubuntu安装NVIDIA显卡驱动
  • C#基础(③CMD进程)
  • 【C2000】C2000的国产替代现状与技术关键路径
  • unity3d 中 R3 实际使用 安装方法
  • 吴恩达机器学习作业十 PCA主成分分析
  • 【量化回测】backtracker整体架构和使用示例
  • arm容器启动spring-boot端口报错
  • linux 内核 - 常见的文件系统介绍
  • 【K8s】整体认识K8s之存储--volume
  • shell脚本(略)
  • 【Flink】并行度的设置
  • nrf52840 flash 分区
  • 3【鸿蒙/OpenHarmony/NDK】如何在鸿蒙应用中使用NDK?
  • 线阵相机和镜头选型案例介绍
  • 【不懂就问】-手机相关学习
  • 打开多个Excel文件后快速关闭所有的文档,并且退出Excel应用
  • Docker一小时快速上手(附报错解决方式)
  • 并发编程——11 并发容器(Map、List、Set)实战及其原理分析
  • deep seek的对话记录如何导出