基于ArcEngine进行数据共边检查
问题描述:
用户提供的数据经常会存在共边问题,将数据提报给上级后审核不通过,导致需要数据反复修改,因此需要增加数据共边检查,自行检查无误后再进行上报,因为这些问题人工检查比较困难,因此考虑使用工具进行检查。
问题分析:
从用户提供数据分析,主要存在下面几种问题:
1、存在点偏移,应该是同一个点的坐标有细微偏差,可能会导致两个图形之间存在轻微的压盖、或者碎屑多边形等;
2、共边的点数不一致;
思路整理:
考虑使用ArcEngine工具编写相关的分析功能,主要是调用ToolBox工具箱中的工具以及GP服务进行分析,整理思路如下:
1、进行图形相交处理分析,输出结果为面,如果存在相交,则不合格,返回相关记录;
2、进行图形之间距离计算,如果距离大于0并小于阈值,则认为其应该是共点或者共边,返回相关记录;
3、进行数据擦除分析,使用数据的公共外接矩形擦除分析数据(我这里为了方便直接使用行政区的外接矩形),擦除后进行图形打散(因为擦除后返回一个图形,可能是多部件),检查是否存在碎屑多边形(面积小于阈值),返回相关记录;
4、进行分析数据相交处理,设置返回结果为线,获取到图形的公共边;循环每条公共边,获取和公共边线相交的图形(不包含点相交),然后判断公共边上面的点是否都图形之上,如果不符合则返回相关记录;
环境:
ArcEngine10.1 VS2012 DevExpress15.2
主要代码:
1、主程序窗口:

using DevExpress.XtraEditors; using ESRI.ArcGIS.AnalysisTools; using ESRI.ArcGIS.DataManagementTools; using ESRI.ArcGIS.DataSourcesGDB; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Geoprocessing; using ESRI.ArcGIS.Geoprocessor; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace SDECatalog { public partial class frmMain : Form { public frmMain() { InitializeComponent(); } /// <summary> /// 加载数据源 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_AddShape_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e) { //打开文件对话框 OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Title = "加载shapefile数据";//设置title openFileDialog.Filter = "(*.shp)|*.shp";//设置过滤模式 if (openFileDialog.ShowDialog() == DialogResult.OK) { //设置路径 btn_AddShape.Text = openFileDialog.FileName;//全部路径 } } private void btn_check_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(btn_AddShape.Text) || string.IsNullOrEmpty(btn_AddShape.Text.Trim())) { XtraMessageBox.Show("请先选择shape文件路径!"); return; } if (!btn_AddShape.Text.EndsWith("shp") && !btn_AddShape.Text.EndsWith("SHP")) { XtraMessageBox.Show("请选择shape文件!"); return; } //创建工作空间 string strDataPath = Application.StartupPath + @"\data\" + DateTime.Now.ToString("yyyyMMddHHmmss"); if (!Directory.Exists(strDataPath)) { Directory.CreateDirectory(strDataPath); } string strMDBTemp = Application.StartupPath + @"\DataMDB\DataCheck.mdb"; File.Copy(strMDBTemp, strDataPath + @"/DataCheck.mdb"); string strResult = GISOper.GP_Copy(btn_AddShape.Text, strDataPath + @"\DataCheck.mdb", "PDDK"); if (strResult != "SUCCESS") { MessageBox.Show("复制shape到mdb失败,请检查shape文件是否存在!" + strResult); return; } //存储结果的表格 DataTable dt = CreateTable(); strResult = GISOper.GP_Intersect(strDataPath + @"/DataCheck.mdb/PDDK", strDataPath + @"/DataCheck.mdb/GGLINE", "LINE"); if (strResult != "SUCCESS") { MessageBox.Show("提取公共边失败!" + strResult); return; } //进行相交检查 strResult = GISOper.GP_Intersect(strDataPath + @"/DataCheck.mdb/PDDK", strDataPath + @"/DataCheck.mdb/PDIntersect", null); if (strResult != "SUCCESS") { MessageBox.Show("进行图形相交失败!" + strResult); return; } //开始用gp工具的擦除来做,擦除之后在进行拆分,但是擦除一直报ERROR 000824: The tool is not licensed.错误,因此改用了拓扑来做 //如果用擦除工具,效果会更好,但是注意一定要设置容差(0.0001),用拓扑对于差距很小的无法识别出来 strResult = GISOper.GP_Erase(strDataPath + @"\DataCheck.mdb\XZQ", strDataPath + @"\DataCheck.mdb\PDDK", strDataPath + @"\DataCheck.mdb\CCJG"); if (strResult != "SUCCESS") { MessageBox.Show("进行图形擦除失败!" + strResult); return; } IWorkspaceFactory pWF = new AccessWorkspaceFactoryClass(); IWorkspace pWS = pWF.OpenFromFile(strDataPath + @"\DataCheck.mdb", 0); IFeatureWorkspace pFeatWorkspace = pWS as IFeatureWorkspace; IFeatureClass feaClsPDIntersect = pFeatWorkspace.OpenFeatureClass("PDIntersect"); IFeatureClass feaClsXZQ = pFeatWorkspace.OpenFeatureClass("XZQ"); IFeatureClass feaClsPDDK = pFeatWorkspace.OpenFeatureClass("PDDK"); //进行相交检查 IFeatureCursor feaCurTemp = feaClsPDIntersect.Search(null, false); IFeature feaPDIntersect = feaCurTemp.NextFeature(); while (feaPDIntersect != null) { IArea are = feaPDIntersect.ShapeCopy as IArea; if (are.Area > 0) { DataRow dr = dt.NewRow(); dr[0] = feaPDIntersect.OID; dr[1] = "无"; dr[2] = ""; dr[3] = "存在图形相交,请检查图形"; dt.Rows.Add(dr); } feaPDIntersect = feaCurTemp.NextFeature(); } //进行图形之间的距离检查 IFeatureCursor feaCurTTemp = feaClsPDDK.Search(null, false); IFeature feaPDDK = feaCurTTemp.NextFeature(); while (feaPDDK != null) { IGeometry geo = feaPDDK.ShapeCopy; ITopologicalOperator pTopo = geo as ITopologicalOperator; IGeometry pGeoBuffer = pTopo.Buffer(5); ISpatialFilter filter = new SpatialFilterClass(); filter.Geometry = pGeoBuffer; filter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; IFeatureCursor curT = feaClsPDDK.Search(filter, false); if (curT == null) { feaPDDK = feaCurTTemp.NextFeature(); continue; } IFeature feaTT = curT.NextFeature(); while (feaTT != null) { double dis = GISOper.GetTwoGeometryDistance(feaPDDK.ShapeCopy, feaTT.ShapeCopy); if (dis != 0) { DataRow dr = dt.NewRow(); dr[0] = feaPDDK.OID; dr[1] = feaTT.OID; dr[2] = dis; dr[3] = "存在图形距离过近,请检查图形"; dt.Rows.Add(dr); } feaTT = curT.NextFeature(); } feaPDDK = feaCurTTemp.NextFeature(); } IFeature fea = feaClsXZQ.Search(null, false).NextFeature(); if (fea == null) { MessageBox.Show("获取裁剪的空间图形失败!"); return; } //如果擦除工具有问题,可以用图形循环擦除的方法 //EraseClass eraseCls = new EraseClass(fea, feaClsPDDK); //bool bSuccess = eraseCls.EraseOperate(); //if (!bSuccess) //{ // MessageBox.Show("进行图形擦除失败!"); // return; //} //strResult = GISOper.GP_MultipartToSinglepart(strDataPath + @"\DataCheck.mdb\XZQ", strDataPath + @"\DataCheck.mdb\XZQ_SPLIT"); strResult = GISOper.GP_MultipartToSinglepart(strDataPath + @"\DataCheck.mdb\CCJG", strDataPath + @"\DataCheck.mdb\XZQ_SPLIT"); if (strResult != "SUCCESS") { MessageBox.Show("擦除后结果进行多部件拆分失败!" + strResult); return; } IFeatureClass feaClsXZQ_SPLIT = pFeatWorkspace.OpenFeatureClass("XZQ_SPLIT"); IFeatureCursor feaCursor = feaClsXZQ_SPLIT.Search(null, false); if (feaCursor != null) { IFeature feaTT = feaCursor.NextFeature(); while (feaTT != null) { IArea area = (IArea)feaTT.ShapeCopy; double d = area.Area; if (d < 50) { DataRow dr = dt.NewRow(); dr[0] = d.ToString(); dr[1] = "无"; dr[2] = ""; dr[3] = "存在碎屑多边形(面积小于50),请检查图形"; dt.Rows.Add(dr); } feaTT = feaCursor.NextFeature(); } } IFeatureClass feaclsLINE = pFeatWorkspace.OpenFeatureClass("GGLINE"); IFeatureCursor feaCur = feaclsLINE.Search(null, false); IFeature feaLINE = feaCur.NextFeature(); while (feaLINE != null) { ISpatialFilter filterTemp = new SpatialFilterClass(); filterTemp.Geometry = feaLINE.Shape as IGeometry; //这里用相交,会出现线两头的面也会被搜索出来,而不仅仅是线所在的面,但是别的没法返回想要的结果 filterTemp.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; IFeatureCursor feacurTemp = feaClsPDDK.Search(filterTemp, false); IFeature feaTemp = feacurTemp.NextFeature(); int i = 0; while (feaTemp != null) { //相交可能只有一个点相交,对于这种情况应该排除掉 ITopologicalOperator topoOperator = feaTemp.ShapeCopy as ITopologicalOperator; IGeometry geo = topoOperator.Intersect(feaLINE.ShapeCopy, esriGeometryDimension.esriGeometry1Dimension); if (!geo.IsEmpty) { IPointCollection Pc = geo as IPointCollection; if (Pc.PointCount <= 1) { feaTemp = feacurTemp.NextFeature(); continue; } } else { feaTemp = feacurTemp.NextFeature(); continue; } IPointCollection pcPDDK = feaTemp.Shape as IPointCollection; IPointCollection pcLINE = feaLINE.Shape as IPointCollection; bool bcontain = bPcContainsPc(pcLINE, pcPDDK); if (bcontain) { DataRow dr = dt.NewRow(); dr[0] = feaLINE.OID; dr[1] = feaTemp.OID; //dr[2] = feaTemp.OID; dr[3] = "公共边所有的点都包含在地块要素上"; dt.Rows.Add(dr); } else { DataRow dr = dt.NewRow(); dr[0] = feaLINE.OID; dr[1] = feaTemp.OID; //dr[2] = feaTemp.get_Value(feaclsPDDK.FindField("KCDJDKID")).ToString(); dr[3] = "!!!注意:存在公共边的点不在在地块要素上!!!"; dt.Rows.Add(dr); } //不管用,好像一直返回线图层的点信息 //ITopologicalOperator topoOperator = feaLINE.Shape as ITopologicalOperator; //IGeometry geo = topoOperator.Intersect(feaTemp.Shape as IGeometry, esriGeometryDimension.esriGeometryNoDimension); //if (!geo.IsEmpty) //{ //IPointCollection Pc = geo as IPointCollection; //} feaTemp = feacurTemp.NextFeature(); } feaLINE = feaCur.NextFeature(); } grdCtrlResult.DataSource = dt; grdCtrlResult.RefreshDataSource(); } /// <summary> /// 点集pc1是否完全在pc2中 /// </summary> /// <param name="pc1"></param> /// <param name="pc2"></param> /// <returns></returns> public bool bPcContainsPc(IPointCollection pc1, IPointCollection pc2) { int mixCount = 0; for (int i = 0; i < pc1.PointCount; i++) { IPoint pp = pc1.get_Point(i); for (int a = 0; a < pc2.PointCount; a++) { //double dd = Math.Abs(pp.X - pc2.get_Point(a).X); //double ss = Math.Abs(pp.Y - pc2.get_Point(a).Y); //注意这里的容差,必须设置,现在的图形为保留三维小数 if (Math.Abs(pp.X - pc2.get_Point(a).X) < 0.0001 && Math.Abs(pp.Y - pc2.get_Point(a).Y) < 0.001) { mixCount++; break; } } } if (mixCount == pc1.PointCount) { return true; } else { return false; } } /// <summary> /// 创建结果datatable /// </summary> /// <returns></returns> public DataTable CreateTable() { DataTable dt = new DataTable(); try { DataColumn dcDsName = new DataColumn("线OID"); DataColumn dcFeaClsName = new DataColumn("地块OID"); DataColumn dcDKID = new DataColumn("地块ID"); DataColumn dcFeaClsAliasName = new DataColumn("说明"); dt.Columns.Add(dcDsName); dt.Columns.Add(dcFeaClsName); dt.Columns.Add(dcDKID); dt.Columns.Add(dcFeaClsAliasName); return dt; } catch (Exception) { return null; } } private void btn_exportExcel_Click(object sender, EventArgs e) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Title = "导出Excel"; saveFileDialog.FileName = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Millisecond.ToString(); saveFileDialog.Filter = "Excel文件(*.xls)|*.xls"; DialogResult dialogResult = saveFileDialog.ShowDialog(this); if (dialogResult == DialogResult.OK) { DevExpress.XtraPrinting.XlsExportOptions options = new DevExpress.XtraPrinting.XlsExportOptions(); grdCtrlResult.ExportToXls(saveFileDialog.FileName); XtraMessageBox.Show("保存成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } }
2、主要GP分析函数:
using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.DataManagementTools; using ESRI.ArcGIS.DataSourcesFile; using ESRI.ArcGIS.DataSourcesGDB; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Geoprocessing; using ESRI.ArcGIS.Geoprocessor; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace SDECatalog { public class GISOper { /// <summary> /// 复制SHAPE到mdb /// </summary> /// <param name="inPath"></param> /// <param name="strOutPath"></param> /// <returns></returns> public static string GP_Copy(string inPath, string strOutPath, string strOutName) { Geoprocessor GP = new Geoprocessor(); GP.OverwriteOutput = true; //覆盖原有文件并重写 try { ESRI.ArcGIS.ConversionTools.FeatureClassToFeatureClass feaClsToFeaCls = new ESRI.ArcGIS.ConversionTools.FeatureClassToFeatureClass(); feaClsToFeaCls.in_features = inPath; feaClsToFeaCls.out_path = strOutPath; feaClsToFeaCls.out_name = strOutName; Geoprocessor gp = new Geoprocessor { OverwriteOutput = true }; IGeoProcessorResult2 result = gp.Execute(feaClsToFeaCls as IGPProcess, null) as IGeoProcessorResult2; return "SUCCESS"; } catch (Exception ex) { string str = ""; for (int i = 0; i < GP.MessageCount; i++) { str += GP.GetMessage(i); str += "\n"; } return "执行复制操作失败!" + str; } } /// <summary> /// 执行GP相交 /// 这里注意,如果是多个图层做相交处理,in_features参数如下:XXX图层全路径 + ";" + XXX图层全路径; /// </summary> public static string GP_Intersect(string strINPath, string strOutPutPath, string strOutType) { Geoprocessor GP = new Geoprocessor(); GP.OverwriteOutput = true; //覆盖原有文件并重写 try { //初始化Merge ESRI.ArcGIS.AnalysisTools.Intersect intersect = new ESRI.ArcGIS.AnalysisTools.Intersect(); intersect.in_features = strINPath; intersect.join_attributes = "ALL"; intersect.out_feature_class = strOutPutPath; if (!string.IsNullOrEmpty(strOutType)) { intersect.output_type = strOutType; } IGeoProcessorResult tGeoResult = GP.Execute(intersect, null) as IGeoProcessorResult; return "SUCCESS"; } catch (Exception ex) { string str = ""; for (int i = 0; i < GP.MessageCount; i++) { str += GP.GetMessage(i); str += "\n"; } return "执行相交操作失败!" + str; } } /// <summary> /// 执行GP擦除 /// 因为一直出现ERROR 000824: The tool is not licensed.错误,因此改用了拓扑来实现 /// </summary> public static string GP_Erase(string strINPath, string strINPath2, string strOutPutPath) { Geoprocessor GP = new Geoprocessor(); GP.OverwriteOutput = true; //覆盖原有文件并重写 try { //初始化Merge ESRI.ArcGIS.AnalysisTools.Erase erase = new ESRI.ArcGIS.AnalysisTools.Erase(); erase.in_features = strINPath; erase.erase_features = strINPath2; erase.cluster_tolerance = 0.0001; erase.out_feature_class = strOutPutPath; IGeoProcessorResult tGeoResult = GP.Execute(erase, null) as IGeoProcessorResult; //IFeatureClass resultFeaCls = GP.Open(tGeoResult.ReturnValue) as IFeatureClass; return "SUCCESS"; } catch (Exception ex) { string str = ""; for (int i = 0; i < GP.MessageCount; i++) { str += GP.GetMessage(i); str += "\n"; } return "执行擦除操作失败!" + str; } } /// <summary> /// 拆分多部件 /// </summary> public static string GP_MultipartToSinglepart(string strINPath, string strOutPutPath) { Geoprocessor GP = new Geoprocessor(); GP.OverwriteOutput = true; //覆盖原有文件并重写 try { ESRI.ArcGIS.DataManagementTools.MultipartToSinglepart cf = new MultipartToSinglepart(); cf.in_features = strINPath; cf.out_feature_class = strOutPutPath; IGeoProcessorResult tGeoResult = GP.Execute(cf, null) as IGeoProcessorResult; //IFeatureClass resultFeaCls = GP.Open(tGeoResult.ReturnValue) as IFeatureClass; return "SUCCESS"; } catch (Exception ex) { string str = ""; for (int i = 0; i < GP.MessageCount; i++) { str += GP.GetMessage(i); str += "\n"; } return "执行拆分操作失败!" + str; } } /// <summary> /// 获取两个几何图形的距离 /// </summary> /// <param name="pGeometryA">几何图形A</param> /// <param name="pGeometryB">几何图形B</param> /// <returns>两个几何图形的距离</returns> public static double GetTwoGeometryDistance(IGeometry pGeometryA, IGeometry pGeometryB) { IProximityOperator pProOperator = pGeometryA as IProximityOperator; if (pGeometryA != null || pGeometryB != null) { double distance = pProOperator.ReturnDistance(pGeometryB); return distance; } else { return 0; } } } }
posted on 2025-09-10 11:39 jingkunliu 阅读(6) 评论(0) 收藏 举报
 
                     
                    
                 
                    
                 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号