ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ArcGIS中自相交要素的精准筛查与批量导出方法

ArcGIS中自相交要素的精准筛查与批量导出方法 大家做数据处理的时候不知道有没有遇到过这种场景拿到的CAD转GIS图斑看着没啥问题一跑面积统计就出现一堆负值或者极小碎斑叠加分析出来的结果更是惨不忍睹。我最早碰到这类问题时第一反应是数据精度不够后来反复排查才发现问题出在图层里有一批要素“自己跟自己过不去”——边界绕了一圈又折回去压在自己身上这就是自相交要素。这篇就专门聊一件事怎么在ArcGIS里把这些自身相交的数据准确找出来并导出。文章覆盖ArcMap 10.x和ArcGIS Pro两个环境绝大多数工具路径和脚本都能通用。不管是做不动产权籍、国土空间规划、地类调查还是整理CAD转GIS的历史数据只要你需要对“自身相交”这个几何问题做质检和导出这篇都适合你。1. 自相交数据为什么让人头疼1.1 先从“自身相交”的定义说起ArcGIS里面的矢量要素无论是点、线、面从几何角度讲都有“合法”和“不合法”之分。所谓自身相交指的是同一个要素内部两条不连续的边或线段出现了交叉。面要素最常见的情况是“蝴蝶结”形状一个多边形的边界本身是环状的但这个环在某个位置拐了一个弯又穿回自己身体内部形成两个相互重叠的小圈。还有一种是“8字形”边界绕来绕去最后有一部分重合。线要素就更直接一条折线折返之后穿过自己或者中间某一段完全重复。从计算机几何的角度看ArcGIS判断一个要素是否合法核心指标之一是几何对象是否“简单”Simple。简单的线不允许自相交简单的面不允许边界环自相交。用ArcPy做自动化判断时我们用的就是几何对象的isSimple属性这个后面的脚本部分会详细讲。1.2 这些数据都是怎么“变坏”的根据我这些年的经验自相交要素往往不是人工一个个画出来的更多是格式转换和编辑操作的“副产品”。CAD数据转GISCAD里的多段线不要求闭合也不限制自相交。转成shp或地理数据库要素类时如果转换参数没设置好很多CAD的多段线会直接原封不动变成GIS要素原来那些交叉点也就跟着进来了。KML、GPX等第三方格式这些格式对拓扑有效性检查比较宽松导入ArcGIS之后容易暴露问题。要素合并、拆分操作对多个要素执行Merge或Union如果源要素本身边界有问题合并后的要素也很容易出现边界自重叠。手动作图在编辑状态下用“修改折点”工具拖动节点拖得过于激进时某段边界可能翻折回来压到自己身上。1.3 自相交数据在项目里会造成什么后果这种数据最大的坑在于表面上看不出来一旦进入分析流程问题就冒出来了。最典型的是面积计算。一个自相交的面要素ArcGIS计算面积时可能会得到错误结果甚至出现负面积。做叠加分析如Intersect、Clip时自相交边界会导致结果要素被“拦腰切断”产生一堆意想不到的狭长碎屑。更麻烦的是发布地图服务或要素服务时服务器端对几何有效性检查比较严格自相交要素可能直接导致发布失败或者服务运行时出错。当年我在做某个规划数据质检项目时一批CAD转换过来的用地图斑里面夹杂了上百个自相交要素面积统计表出来之后有些图斑面积比实际大了一倍多。外业核查人员拿着这些图斑去现场怎么都对不上号。后来把所有自相交要素导出来单独排查才发现大半都是CAD里重复闭合的圈引起的。所以从工作流的角度看“导出自身相交数据”这个动作本质上就是把有几何问题的要素从海量数据里隔离出来为后续修正、外业核查、责任判定提供最小集。2. 第一招用“检查几何”工具精准筛查并导出自相交要素2.1 检查几何工具的使用逻辑ArcGIS自带一个很基础的几何“体检”工具叫“检查几何”Check Geometry在工具箱里的位置是ArcMapArcToolbox → Data Management Tools → Features → Check GeometryArcGIS Pro分析 → 工具 → 搜索“检查几何”这个工具做的事情是遍历输入的要素类逐要素检查几何是否符合ArcGIS的几何有效性规则。检查结果会生成一个表格常用字段包括FEATURE_CLASS源要素类名称、FEATURE_ID源要素的OID、ERROR_TYPE错误类型。在错误类型里与本文相关的就是“自相交”Self-Intersections。注意检查几何工具判定的自相交指的是单个要素内部的交叉问题而不是多个要素之间的重叠。这一点先明确跨要素的重叠后面第三种方法会讲。2.2 完整操作步骤第一步把要检查的数据准备好。检查几何支持shapefile、文件地理数据库要素类、企业级地理数据库要素类基本都能用。第二步运行检查几何工具。输入要素类选择目标图层输出表位置选一个自己记得住的地方。工具跑完后输出表会加载到内容列表里。第三步打开输出表的属性表按ERROR_TYPE字段排序或筛选。错误类型里和自相交对应的记录会被标出来每一行记录对应源要素类里的一个要素FEATURE_ID就是那个要素的编号。第四步在源图层上按属性选择把OBJECTID或FID等于这些FEATURE_ID的要素选中。具体操作是打开图层属性→按属性选择或者直接右键图层→打开属性表→按属性选择输入类似OBJECTID IN (123, 456, 789)的语句。第五步右键源图层→数据→导出数据把选中的要素导出为新的要素类或shapefile。这就是最简单的“导出自身相交数据”实现方式。2.3 这个工具的边界和不足检查几何虽然简单但有两个明显的短板。第一个短板是容差不完全可控。检查几何的容差跟数据本身的空间参考精度有关默认情况下不会特别敏感。这就导致一些极其细微的自相交比如两个边只重叠了0.0001米可能不会被判定为错误。反过来如果数据的空间参考精度设置不当也可能把正常要素误判为错误。第二个短板是它只检查“单一要素内部几何问题”对于两个要素之间互相压盖、重叠的情况检查几何是管不着的。所以如果你遇到的是“想把所有互相重叠的图斑全部导出来”这类需求需要换成下一章的思路。还有一个使用技巧如果你不想一条一条看错误表可以先把源数据复制一份对副本运行“修复几何”Repair Geometry然后把修复前和修复后的数据做对比找出几何发生变化的所有要素。这个方法不需要读错误码在要素数量比较少的时候非常直观。3. 第二招用“按位置选择”把互相重叠/相交的要素导出来3.1 什么时候需要这招前面说过有些场景下用户说“导出自身相交数据”实际要的是把图层里“互相压盖”“互相重叠”的一批要素找出来。这种情况在行政边界、宗地数据、地类图斑里非常常见。多个面要素彼此交叠虽然不是“单个要素内部自相交”但对后续拓扑建库、冲突检测的影响是一样的。ArcGIS的“按位置选择”Select By Location功能天生就是干这个的。3.2 操作步骤ArcMap菜单栏 → Selection → Select By LocationArcGIS Pro地图选项卡 → 选择 → 按位置选择在弹出的对话框里把“目标图层”Target Layer和“源图层”Source Layer都设为同一个图层方法选择“相交”intersect点击确定。ArcGIS会遍历图层中的要素把所有在空间上和同一图层其他要素存在相交关系的要素全部选出来。然后右键图层 → 数据 → 导出数据就能得到一张新的只包含“重叠/相交要素”的图层。为了看清楚结果建议在导出之前给图层设置一个明显符号并在内容列表里只显示选中要素这样能直观看到哪些图斑被判定为相交。3.3 这一招的局限和变通按位置选择的本质是“要素与要素之间的空间关系判断”它不会去判断单个要素内部的几何合法性。所以如果你的需求是精确找到“一个图斑自己边界折回”的情况用这个方法可能会漏掉。但如果说是“找出一堆图斑互相重叠”的场景它又非常高效。想要更精确地把“重叠区域”也提取出来可以做一个变通用“相交”Intersect工具让图层自己跟自己求交。输入要素选择同一个图层输出结果就是那些重叠区域的多边形。再通过Join或者空间连接把这些重叠区域关联回原始要素就能追溯到具体是哪些图斑引起的重叠。这个流程相比纯按位置选择多了定位重叠位置的能力。4. 第三招ArcPy脚本批量导出适合大数据量和重复性工作4.1 为什么还需要写脚本检查几何和按位置选择在处理小数据量时够用但一旦要素数量到了几十万、上百万或者你需要每周、每月都跑一次质检图形化操作就有点疲于奔命了。这时候用ArcPy写一个小脚本把“遍历要素→判断自相交→筛选→导出”整个流程固化下来会舒服很多。4.2 用isSimple属性判定自相交的原理ArcPy的几何对象Geometry有一个属性叫isSimple。这个属性返回布尔值True表示几何是“简单”的False表示几何存在自相交或重复边一类的拓扑问题。用循环遍历要素类逐个检查几何的isSimple凡是返回False的就是我们要导出的目标。这里不推荐用geometry.isValid替代这两个属性的侧重点不同isValid更偏向于对象状态是否有效而isSimple更贴合我们讨论的自相交语义。4.3 完整的Python脚本示例在ArcMap的Python窗口或者ArcGIS Pro的Python环境中都可以运行下面这段脚本# -*- coding: utf-8 -*- import arcpy # 输入参数 src_fc arcpy.GetParameterAsText(0) # 源要素类 out_fc arcpy.GetParameterAsText(1) # 输出要素类 arcpy.env.overwriteOutput True desc arcpy.Describe(src_fc) oid_field desc.OIDFieldName bad_oids [] with arcpy.da.SearchCursor(src_fc, [oid_field, SHAPE]) as cursor: for oid, geom in cursor: if geom is not None and not geom.isSimple: bad_oids.append(oid) print(发现自相交要素数量: {}.format(len(bad_oids))) if bad_oids: # 用OID列表去源要素类中筛选 id_list ,.join([str(x) for x in bad_oids]) where_clause {} IN ({}).format( arcpy.AddFieldDelimiters(src_fc, oid_field), id_list ) temp_lyr bad_features_lyr arcpy.MakeFeatureLayer_management(src_fc, temp_lyr) arcpy.SelectLayerByAttribute_management(temp_lyr, NEW_SELECTION, where_clause) arcpy.CopyFeatures_management(temp_lyr, out_fc) else: # 没有自相交要素时仍生成一个空要素类保证输出路径有效 desc arcpy.Describe(src_fc) out_dir arcpy.Describe(out_fc).path out_name arcpy.Describe(out_fc).name arcpy.CreateFeatureclass_management( out_dir, out_name, desc.shapeType, spatial_referencedesc.spatialReference )脚本逻辑不复杂先用SearchCursor遍历源要素类把不满足isSimple的要素OID收集到一个列表里然后通过MakeFeatureLayer和SelectLayerByAttribute把符合条件的要素筛出来最后用CopyFeatures导出。两个地方值得注意SHAPE是搜游标里获取几何对象的简写方式比取SHAPE字段更高效。AddFieldDelimiters会自动根据数据格式补充字段定界符比如shapefile里的双引号、文件地理数据库里的方括号避免不同数据源之间命令格式不兼容的问题。在ArcMap里用这段脚本时直接在Python窗口粘贴运行即可在ArcGIS Pro里也一样。如果你想做成一个长期使用的工具可以新建一个工具箱添加脚本工具把src_fc和out_fc设置成参数别人用起来就不用改代码了。4.4 性能优化和注意事项几十万要素级别的数据脚本跑起来需要一点时间。有几个优化手段搜游标不需要取所有字段只需要取OID字段和SHAPE脚本里已经这么做了。判断isSimple本身是几何计算耗时跟几何复杂度正相关折点数特别多的要素会拖慢整体速度。可以先用Envelope做粗筛但实际操作中除非数据量超级大一般不用刻意优化。如果数据库是企业级地理数据库如SDE建议在非生产时间运行避免长时间锁表影响其他业务。还有一点要注意isSimple返回值在不同的ArcGIS版本里行为基本一致但如果用的是ArcMap 10.2以前的古老版本Geometry对象的方法可能需要调用geom.isSimple()带括号而不是属性写法。真遇到这种情况改一下调用方式就行。5. 避坑实录容差、坐标系、大文件导出这些细节5.1 拓扑容差能让结果“漂移”自相交的判定很大程度上受容差影响。ArcGIS在处理几何关系时默认会使用数据空间参考的xy容差通常是0.001米或对应的经纬度值。如果两个边之间的距离非常近小到容差范围之内ArcGIS可能会把它们视为“接触”而不是“交叉”从而不判定为自相交。反过来如果容差设得过大一些本来只是靠得很近但没交叉的边也会被识别为相交。实际操作中我给CAD转换数据的建议是先把容差明确设为0.001米投影坐标系下这个值基本够用。如果数据是地理坐标系经纬度则建议用0.00001度左右的容差。运行检查几何和修复几何时工具默认会使用当前环境的容差设置如果你发现检查结果跟预期偏差比较大先看看环境设置里的“XY容差”是不是被调过。5.2 坐标系不统一产生的“伪自相交”还有一类特殊情况看着像自相交其实是坐标系设置不当造成的。最典型的案例是跨180度经线的数据或者从Web地图服务导出的动态投影数据。因为某些坐标值在投影变换过程中发生翻转边界本来没有交叉投影之后却出现了假交叉。遇到这种情况先确认数据本身的空间参考是否正确。如果源数据是WGS84经纬度的而工具环境里设置的输出坐标系是某个投影坐标系ArcGIS会做动态投影动态投影过程中的几何计算很可能产生伪自相交。解决方法是把数据先投影到一个合适的坐标系再执行自相交检查和导出。5.3 大文件导出的性能与存储选择自相交检查本来就是逐要素计算数据量大了之后最直接的瓶颈是I/O和几何计算。这里建议优先使用文件地理数据库File Geodatabase要素类而不是shapefile。文件地理数据库的空间索引和读写性能要明显优于shapefile处理几十万要素时差距特别明显。导出结果时不要图省事直接存成shapefile。shapefile有很多限制字段名长度、字段类型、特殊字符都会被截断如果还要继续在ArcGIS里做分析要素类是最稳妥的选择。如果数据量实在太大几千万级别可以按区域或图幅分块导出最后再Merge成一个结果。这样每块跑得快中途出错也好排查。5.4 别忘了用拓扑规则做“官方”验证对于有更高精度要求的数据我更推荐直接在文件地理数据库里创建一个拓扑添加规则“不能自相交”Must Not Self-Intersect和“不能自重叠”Must Not Self-Overlap然后验证拓扑。验证之后生成的拓扑错误点或错误线可以直接用“导出错误要素”功能导出。拓扑规则的优点是权威、可视化好、错误位置一目了然。缺点是要求数据必须放在要素数据集里而且对数据量大时会比较敏感。如果你的项目里已经有要素数据集这一步值得做。6. 一个完整的项目闭环案例CAD转GIS图斑的自相交管控最后用一个实际项目流程把上面的方法串起来。背景是某地区批而未供用地数据整理原始数据是CAD文件需要转入GIS数据库做面积统计和空间分析。第一步CAD转出要素后先排除坐标系问题。CAD数据普遍没有正确的投影信息先用“定义投影”工具指定正确坐标系再项目到目标投影。第二步运行检查几何工具生成错误报告。把错误类型里所有“自相交”的记录筛选出来得到第一批问题要素清单。第三步运行上一章的ArcPy脚本把所有isSimpleFalse的要素导出为一个单独的问题要素类。对比检查几何的错误表基本能覆盖全部自相交问题。第四步对于导出的问题要素在ArcGIS Pro里逐个缩放查看确认是CAD重复闭合、折点翻折还是原始数据本身的问题。能编辑的直接用“修改折点”工具处理不能编辑的标注原因退回给CAD制图方修改。第五步把修正后的数据重新接回原图层再次跑检查几何和ArcPy脚本直到没有任何自相交错误再进入面积统计和后续叠加分析。这套流程看起来简单却把“数据来料质检”和“问题反馈”串起来了。我自己的体会是自相交这种几何问题越早发现越省事等它混进分析结果再回头找排查成本会翻好几倍。如果你平时主要用ArcMap建议把检查几何和导出分开做成两个模型放到同一个工具箱里。如果是ArcGIS Pro用户可以直接把脚本做成Python工具箱的脚本工具每次质检双击一下就行。处理频率高的团队甚至可以把“检查结果”作为附件字段一并导出方便责任部门直接定位和修改。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进