You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
559 lines
24 KiB
559 lines
24 KiB
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<CheckResult> 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<CheckResult>(); |
|
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<CheckResult> 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<CheckResult> CheckGeometry(IFeature pfeature) |
|
{ |
|
List<CheckResult> result = new List<CheckResult>(); |
|
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<CheckResult> AcuteAngle(IFeature pFeature) |
|
{ |
|
List<CheckResult> result = new List<CheckResult>(); |
|
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; |
|
} |
|
|
|
/// <summary> |
|
/// 获取最小角度 |
|
/// </summary> |
|
/// <param name="pGeo"></param> |
|
/// <returns></returns> |
|
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<IGeometry> rings = new List<IGeometry>(); |
|
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; |
|
} |
|
/// <summary> |
|
/// 计算角度 |
|
/// </summary> |
|
/// <param name="cenPoint"></param> |
|
/// <param name="firstPoint"></param> |
|
/// <param name="secondPoint"></param> |
|
/// <returns></returns> |
|
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米 |
|
/// <summary> |
|
/// 地类图斑变更层平均节点密度大于1米小于70米 |
|
/// </summary> |
|
/// <param name="pFeature"></param> |
|
/// <returns></returns> |
|
private CheckResult PointToPoint(IFeature pFeature) |
|
{ |
|
CheckResult result = null; |
|
List<double> Segmentslength = new List<double>(); |
|
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 |
|
} |
|
}
|
|
|