using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.DataSourcesGDB; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using KGIS.Framework.AE.ExtensionMethod; using KGIS.Framework.AE.GPHelper; using KGIS.Framework.DBOperator; using KGIS.Framework.Maps; using KGIS.Framework.Utils; using Kingo.PluginServiceInterface; using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Runtime.InteropServices; namespace Kingo.Plugin.DataCheck { public class BGHDataCheck : IDataCheck { List dataCheckResults = null; public event CheckDataPr DataCheckComplate; public string IDataCheckName => "BGHDataCheck"; public void FeatureCheck(object pParm) { } public void FeatureClassCheck(object pParm) { try { lock (this) { CheckParametr _Parm = pParm as CheckParametr; dataCheckResults = new List(); ExecuteCheck(); (pParm as CheckParametr).CheckResults = dataCheckResults; DataCheckComplate?.Invoke(dataCheckResults, _Parm); } } catch (Exception ex) { LogAPI.Debug(ex); } } #region 变更成果属性检查 private void ExecuteCheck() { //1.更新层标识码与对应更新过程层变更后标识码是否一致 IFeatureClass GXFC = null; IFeatureClass GXGCFC = null; IFeatureLayer Temp_DLTBGXGC = null; IWorkspaceFactory pFtWsFct = null; IFeature feature = null; IFeatureCursor featureCursor = null; try { #region 初始化数据 GXFC = MapsManager.Instance.MapService.GetFeatureClassByName("DLTBGX"); //地类图斑更新层 GXGCFC = MapsManager.Instance.MapService.GetFeatureClassByName("DLTBGXGC"); //地类图斑更新过程 string dbPath = System.IO.Path.GetDirectoryName((MapsManager.Instance.MapService.GetProjectInfo() as ProjectInfo).GetProjFilePath()) + @"\BGTJ.sqlite"; string gdbFolder = Directory.GetCurrentDirectory() + "\\Temp\\DLTBGXGCTempFile"; if (!Directory.Exists(gdbFolder)) Directory.CreateDirectory(gdbFolder); try { DelectDirect(gdbFolder); } catch { //删除临时数据异常 不做处理 } pFtWsFct = new FileGDBWorkspaceFactory(); string gdbFileName = Guid.NewGuid().ToString(); string path = System.IO.Path.Combine(gdbFolder, gdbFileName); pFtWsFct.Create(path, "TempGDB", null, 0); string TempfilePath = System.IO.Path.Combine(path, "TempGDB.gdb"); #endregion #region 更新层与更新过程层套合/标识码对应检查 GPParamClass paramClass = new GPParamClass() { FirstFeatureLayer =new FeatureLayerClass() { FeatureClass = GXFC }, SecondFeatureLayer =new FeatureLayerClass() { FeatureClass = GXGCFC }, OutFeatureClassPath = $"{TempfilePath}\\GX_GXGCUnion", IsGetOutPutFeature = true, PreserveAttributes = "ALL" }; GeoprocessorHelper.UnionAnalysis(paramClass, ref Temp_DLTBGXGC); IWorkspaceFactory pOutWorkFactory = null; pOutWorkFactory = new SqlWorkspaceFactoryClass(); IWorkspace pOutWork = pOutWorkFactory.OpenFromFile(dbPath, 0); IRDBHelper rdbHelper = RDBFactory.CreateDbHelper("Data Source=" + dbPath, DatabaseType.SQLite); rdbHelper.ExecuteSQL(" drop table GX_GXGCUnion "); IWorkspace ws = (Temp_DLTBGXGC.FeatureClass as FeatureClass).Workspace; //矢量数据至db文件 TableToTable(ws as IFeatureWorkspace, pOutWork, "GX_GXGCUnion"); DataTable table = rdbHelper.ExecuteDatatable("GX_GXGCUnion", " select OBJECTID,FID_DLTBGX,FID_DLTBGXGC from GX_GXGCUnion where FID_DLTBGX=-1 or BSM<>BGHTBBSM ", true); if (table != null && table.Rows.Count > 0) { foreach (DataRow row in table.Rows) { int FID_DLTBGX = row["FID_DLTBGX"].ToString().ToInt(); int OBJECTID = row["OBJECTID"].ToString().ToInt(); CheckResult result = new CheckResult(); if (FID_DLTBGX == -1) { result.ErrorDesc = "更新层与更新过程层数据不套合!"; result.Synopsis = "更新层/更新过程层数据错误"; result.ErrorCategory = "Graphic"; result.ErrorCode = "2001000399990021"; } else { result.ErrorDesc = "更新层标识码与更新过程成变更后图斑标识码不匹配!"; result.Synopsis = "标识码赋值错误!"; result.ObjectID = FID_DLTBGX; result.ErrorCategory = "Attribute"; result.ErrorCode = "1001000200000022"; } result.ErrorArea = Temp_DLTBGXGC.FeatureClass.GetFeature(OBJECTID).Shape.ToJson(); result.ErrorLayer = IDataCheckName; result.ErrorType = EnumErrorType.错误; dataCheckResults.Add(result); } } #endregion #region 更新层/更新过程层图形检查 featureCursor = GXFC.Search(null, true); while ((feature = featureCursor.NextFeature()) != null) { ExecuteGraphicCheck(feature); } #endregion } catch (Exception ex) { LogAPI.Debug(ex); throw ex; } finally { if (feature != null) Marshal.ReleaseComObject(feature); if (featureCursor != null) Marshal.ReleaseComObject(featureCursor); if (GXFC != null) Marshal.ReleaseComObject(GXFC); if (GXGCFC != null) Marshal.ReleaseComObject(GXGCFC); } } #endregion public void ExecuteGraphicCheck(IFeature feature) { try { //自相交/多部件 List liststr = CheckGeometry(feature); if (liststr != null && liststr.Count > 0) { dataCheckResults.AddRange(liststr); } //3、地类图斑变更层要素所有角度均应大于10度,同时不存在局部狭长图形 liststr = AcuteAngle(feature); if (liststr.Count > 0) { dataCheckResults.AddRange(liststr); } //4、地类图斑变更层平均节点密度大于1米小于70米 CheckResult result = PointToPoint(feature); if (result != null) { dataCheckResults.Add(result); } } catch (Exception ex) { LogAPI.Debug("变更成果检查异常:" + ex.Message); LogAPI.Debug(ex); } } public bool TableToTable(IFeatureWorkspace pInWork, IWorkspace pOutWork, string tableName, IQueryFilter queryFilter = null) { try { if (pInWork == null || pOutWork == null || string.IsNullOrEmpty(tableName)) return false; IWorkspace2 workspace2 = pInWork as IWorkspace2; if (workspace2 != null) { if (!workspace2.get_NameExists(esriDatasetType.esriDTFeatureClass, tableName)) { return false; } } ITable pInTable = pInWork.OpenTable(tableName); if (pInTable == null) return false; IDataset pIndataset = (IDataset)pInTable; IDatasetName pInDatasetName = (IDatasetName)pIndataset.FullName; IEnumDataset enumDataset = pOutWork.get_Datasets(esriDatasetType.esriDTTable); IDataset dataset; enumDataset.Reset(); while ((dataset = enumDataset.Next()) != null) { string[] names = dataset.Name.Split('.'); if (string.Equals(names[names.Length - 1], tableName, StringComparison.CurrentCultureIgnoreCase)) { dataset.Delete(); break; } } IDataset pOutDataset = (IDataset)pOutWork; IDatasetName pOutDatasetName = new TableNameClass(); pOutDatasetName.WorkspaceName = (IWorkspaceName)pOutDataset.FullName; pOutDatasetName.Name = tableName; //Validate the field names because you are converting between different workspace types. IFieldChecker fieldChecker = new FieldCheckerClass(); IFields targetFeatureClassFields = pInTable.Fields; IFields sourceFeatureClassFields = pInTable.Fields; IEnumFieldError enumFieldError; // Most importantly set the input and validate workspaces! fieldChecker.InputWorkspace = pInWork as IWorkspace; fieldChecker.ValidateWorkspace = pOutWork; fieldChecker.Validate(sourceFeatureClassFields, out enumFieldError, out targetFeatureClassFields); IFeatureDataConverter one2another = new FeatureDataConverterClass(); try { one2another.ConvertTable(pInDatasetName, queryFilter, pOutDatasetName, targetFeatureClassFields, "", 1000, 0); } finally { Marshal.ReleaseComObject(one2another); } return true; } catch (Exception ex) { LogAPI.Debug(ex); throw ex; } } private static void DelectDirect(string srcPath) { try { DirectoryInfo dir = new DirectoryInfo(srcPath); FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //返回目录中所有文件和子目录 foreach (FileSystemInfo i in fileinfo) { if (i is DirectoryInfo) //判断是否文件夹 { DirectoryInfo subdir = new DirectoryInfo(i.FullName); subdir.Delete(true); //删除子目录和文件 } else { File.Delete(i.FullName); //删除指定文件 } } } catch (Exception e) { throw; } } private static List CheckGeometry(IFeature pfeature) { List result = new List(); try { IPointCollection polygonVertices = new PolygonClass(); IPointCollection lineVertices = pfeature.ShapeCopy as IPointCollection; polygonVertices.AddPointCollection(lineVertices); ITopologicalOperator3 pTopology = polygonVertices as ITopologicalOperator3; esriNonSimpleReasonEnum reason = esriNonSimpleReasonEnum.esriNonSimpleOK; pTopology.IsKnownSimple_2 = false; if (!pTopology.get_IsSimpleEx(out reason)) { if (reason == esriNonSimpleReasonEnum.esriNonSimpleSelfIntersections)//自相交 { result.Add(new CheckResult() { ErrorDesc = "要素存在自相交!", Synopsis = "要素存在自相交!", ErrorCode = "200600", ErrorLayer = "BGHDataCheck", ErrorCategory = "Graphic", ObjectID = pfeature.OID, ErrorArea = pfeature.Shape.ToJson(), ErrorType = EnumErrorType.错误, }); } if (reason == esriNonSimpleReasonEnum.esriNonSimpleUnclosedRing)//存在不闭合的环 { IPolygon4 polygon = pfeature.ShapeCopy as IPolygon4; IGeometryBag bag = polygon.ExteriorRingBag;//获取多边形的所有外环 var xx = (bag as IGeometryCollection).GeometryCount; if ((bag as IGeometryCollection).GeometryCount > 1) { result.Add(new CheckResult() { ErrorDesc = "要素存在组合图斑(多部件)!", Synopsis = "要素存在组合图斑(多部件)!", ErrorCode = "200700", ErrorLayer = "BGHDataCheck", ErrorCategory = "Graphic", ObjectID = pfeature.OID, ErrorArea = pfeature.Shape.ToJson(), ErrorType = EnumErrorType.错误 }); } } if (reason == esriNonSimpleReasonEnum.esriNonSimpleShortSegments) { result.Add(new CheckResult() { ErrorDesc = "要素存在短线段!", Synopsis = "要素存在短线段!", ErrorCode = "200800", ErrorLayer = "BGHDataCheck", ErrorCategory = "Graphic", ObjectID = pfeature.OID, ErrorArea = pfeature.Shape.ToJson(), ErrorType = EnumErrorType.错误, }); } } } catch (Exception ex) { throw ex; } return result; } #region 要素不存在尖锐角和局部狭长图形(即不允许存在一个角度小于10度,或局部图形狭长的情况) private List AcuteAngle(IFeature pFeature) { List result = new List(); IGeometry refgeometry = null; double angle = GetMinAngle(pFeature.ShapeCopy, ref refgeometry);//获取图形的最小角度 if (angle < 10) { result.Add(new CheckResult() { ErrorDesc = "要素存在尖锐角!", Synopsis = "要素存在尖锐角!", ErrorCode = "200500", ErrorLayer = "BGHDataCheck", ErrorCategory = "Graphic", ObjectID = pFeature.OID, ErrorType = EnumErrorType.错误, ErrorArea = refgeometry.ToJson() }); } ITopologicalOperator topo = pFeature.ShapeCopy as ITopologicalOperator; IPolyline line1 = topo.Boundary as IPolyline; double length1 = line1.Length; int pointCount1 = (pFeature.ShapeCopy as IPointCollection).PointCount; IGeometry geo = topo.Buffer(-0.05); ITopologicalOperator topo2 = geo as ITopologicalOperator; IPolyline line2 = topo2.Boundary as IPolyline; double length2 = line2.Length; int pointCount2 = (geo as IPointCollection).PointCount - 1; double delta_length = length1 - length2; double avg_halfangle = 180 * (pointCount1 - 1 - 2) / (pointCount1 - 1) / 2; double conner_normal_length = 2 * 0.05 / Math.Tan(avg_halfangle * (Math.PI / 180)); if (delta_length > 8 * conner_normal_length * (pointCount1 - 1)) { result.Add(new CheckResult() { ErrorDesc = "要素存在局部狭长图形!", Synopsis = "要素存在局部狭长图形!", ErrorCode = "200900", ErrorLayer = "BGHDataCheck", ErrorCategory = "Graphic", ObjectID = pFeature.OID, ErrorArea = pFeature.Shape.ToJson(), ErrorType = EnumErrorType.错误, }); } return result; } /// /// 获取最小角度 /// /// /// private static double GetMinAngle(IGeometry pGeo, ref IGeometry refgeometry) { double result = -1; try { if (pGeo == null || pGeo.IsEmpty) return result; IPolygon4 poly4 = pGeo as IPolygon4; ITopologicalOperator topo = poly4 as ITopologicalOperator; if (topo != null) { topo.Simplify(); } GeometryBag geoBag = poly4.ExteriorRingBag as GeometryBag; if (geoBag == null) return result; IGeometryCollection geoCollection = geoBag as IGeometryCollection; List rings = new List(); for (int j = 0; j < geoCollection.GeometryCount; j++) { IGeometry geo = geoCollection.get_Geometry(j); rings.Add(geo); //内环图形 IGeometryBag InteriorBag = (pGeo as IPolygon4).get_InteriorRingBag(geo as IRing); if (InteriorBag != null) { IGeometryCollection InteriorRingGeometryCollection = InteriorBag as IGeometryCollection; for (int IR = 0; IR < InteriorRingGeometryCollection.GeometryCount; IR++) { rings.Add(InteriorRingGeometryCollection.get_Geometry(IR)); } } } foreach (IGeometry ring in rings) { if (ring.IsEmpty) continue; IPointCollection points = ring as IPointCollection; int num = points.PointCount - 1; for (int i = 0; i < num; i++) { IPoint p1 = null; IPoint p2 = points.get_Point(i); IPoint p3 = null; if (i == 0) { p1 = points.get_Point(num - 1); p3 = points.get_Point(i + 1); } else if (i == num - 1) { p1 = points.get_Point(i - 1); p3 = points.get_Point(0); } else { p1 = points.get_Point(i - 1); p3 = points.get_Point(i + 1); } double angle = GetAngle(p2, p1, p3); IGeometryCollection geometryCollection = new Polyline() as IGeometryCollection; IPointCollection pointCollection = new ESRI.ArcGIS.Geometry.Path(); if (result == -1) { result = angle; pointCollection.AddPoint(p1); pointCollection.AddPoint(p2); pointCollection.AddPoint(p3); geometryCollection.AddGeometry(pointCollection as IGeometry); refgeometry = geometryCollection as IGeometry; refgeometry.SpatialReference = pGeo.SpatialReference; } else { if (result > angle) { result = angle; pointCollection.AddPoint(p1); pointCollection.AddPoint(p2); pointCollection.AddPoint(p3); geometryCollection.AddGeometry(pointCollection as IGeometry); refgeometry = geometryCollection as IGeometry; refgeometry.SpatialReference = pGeo.SpatialReference; } } } } } catch (Exception ex) { throw ex; } return result; } /// /// 计算角度 /// /// /// /// /// private static double GetAngle(IPoint cenPoint, IPoint firstPoint, IPoint secondPoint) { double ma_x = firstPoint.X - cenPoint.X; double ma_y = firstPoint.Y - cenPoint.Y; double mb_x = secondPoint.X - cenPoint.X; double mb_y = secondPoint.Y - cenPoint.Y; double v1 = (ma_x * mb_x) + (ma_y * mb_y); double ma_val = Math.Sqrt(ma_x * ma_x + ma_y * ma_y); double mb_val = Math.Sqrt(mb_x * mb_x + mb_y * mb_y); if (ma_val * mb_val == 0) { return -1; } double cosM = v1 / (ma_val * mb_val); double angleAMB = Math.Acos(cosM) * 180 / Math.PI; return angleAMB; } #endregion #region 地类图斑变更层平均节点密度大于1米小于70米 /// /// 地类图斑变更层平均节点密度大于1米小于70米 /// /// /// private CheckResult PointToPoint(IFeature pFeature) { CheckResult result = null; List Segmentslength = new List(); IGeometryCollection _GeoColl = pFeature.ShapeCopy as IGeometryCollection; for (int i = 0; i < _GeoColl.GeometryCount; i++) { ISegmentCollection _segmColl = _GeoColl.Geometry[i] as ISegmentCollection; for (int j = 0; j < _segmColl.SegmentCount; j++) { Segmentslength.Add(_segmColl.Segment[j].Length); } } if (Segmentslength.Average() > 70 || Segmentslength.Average() < 1) { result = new CheckResult() { ErrorDesc = "地类图斑变更层平均节点密度大于1米小于70米!", Synopsis = "平均节点密度不在1-70米!", ErrorCode = "200400", ErrorLayer = "BGHDataCheck", ErrorCategory = "Graphic", ObjectID = pFeature.OID, ErrorArea = pFeature.Shape.ToJson(), ErrorType = EnumErrorType.错误, }; } return result; } #endregion } }