using System; using System.Collections.Generic; using System.Linq; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using KGIS.Framework.AE; using KGIS.Framework.AE.ExtensionMethod; using KGIS.Framework.Maps; using KGIS.Framework.Utils; using KGIS.Framework.Utils.ExtensionMethod; using KGIS.Framework.Utils.Helper; using Kingo.Plugin.EngineEditor.Common; using Kingo.PluginServiceInterface.Helper; namespace Kingo.Plugin.EngineEditor.View { public partial class UCBoundaryFitting : BaseWindow { private IHookHelper m_hookHelper;//获取地图控件和主窗体 private Dictionary keys { get; set; } private EngineEditorClass _engineEdit = new EngineEditorClass(); private IFeatureLayer SelectFeatureLayer = null; public UCBoundaryFitting(object Helpers, EngineEditorClass m_engineEdit) { InitializeComponent(); try { if (this.m_hookHelper == null) this.m_hookHelper = Helpers as IHookHelper; //获取当前工程中的全部图层 List featureLayers = MapsManager.Instance.MapService.GetAllVisibleLayerInMap(); if (featureLayers != null && featureLayers.Count > 0) { keys = new Dictionary(); foreach (IFeatureLayer iFeatureLayer in featureLayers) { if (!keys.ContainsKey(iFeatureLayer.Name)) keys.Add(iFeatureLayer.Name, iFeatureLayer); } targetName.ItemsSource = keys.Keys; } _engineEdit = m_engineEdit; } catch (Exception ex) { LogAPI.Debug("UCBoundaryFitting异常:" + ex.Message); LogAPI.Debug("UCBoundaryFitting异常:" + ex.StackTrace); MessageHelper.ShowError("初始化边界修复界面异常" + ex.Message); } } #region 目标图层切换事件 private void targetName_SelectionChanged(object sender, System.Windows.RoutedEventArgs e) { try { if (keys != null) { IFeatureLayer featureLayer = keys[targetName.SelectedItem.ToTrim()]; if (featureLayer == null) return; SelectFeatureLayer = featureLayer; } } catch (Exception ex) { LogAPI.Debug("targetName_SelectionChanged异常:" + ex.Message); LogAPI.Debug("targetName_SelectionChanged异常:" + ex.StackTrace); } } #endregion #region 关闭窗体事件 private void BaseWindow_Closed(object sender, EventArgs e) { try { this.Close(); } catch (Exception ex) { LogAPI.Debug("BaseWindow_Closed异常:" + ex.Message); LogAPI.Debug("BaseWindow_Closed异常:" + ex.StackTrace); } } #endregion #region 确定 private void btnOK_Click(object sender, System.Windows.RoutedEventArgs e) { try { if (_engineEdit.EditState != esriEngineEditState.esriEngineStateEditing) { MessageHelper.ShowTips("请先开启编辑."); return; } IFeatureLayer TargetLayer = (_engineEdit as EngineEditorClass).TargetLayer as IFeatureLayer; if (SelectFeatureLayer == null || SelectFeatureLayer.FeatureClass == null || SelectFeatureLayer.FeatureClass.FeatureCount(null) == 0) { MessageHelper.ShowTips("请选择正确的参考图层."); return; } IEnumFeature enumFeature = m_hookHelper.FocusMap.FeatureSelection as IEnumFeature; enumFeature.Reset(); IFeature featuer = null; while ((featuer = enumFeature.Next()) != null) { try { _engineEdit.StartOperation(); IGeometry geometry = ExecuteRepair1(featuer); ITopologicalOperator topological = geometry as ITopologicalOperator; if (topological == null) continue; if (!topological.IsKnownSimple) topological.Simplify(); #region 检查图形是否存在尖锐角/狭长图形等问题 IPoint point = null; IPolyline polyline = null; if (AECommonHelper.SharpAngleDataCheck(geometry, ref point, ref polyline)) { if (polyline != null && point != null) { IPoint point1 = new PointClass(); var DistanceAlongCurve = 0.0001; var distanceFromCurve = 0.0001; bool bRightSide = true; polyline.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, point, false, point1, ref DistanceAlongCurve, ref distanceFromCurve, bRightSide); IPointCollection points = geometry as IPointCollection; var index = -1; for (int i = 0; i < points.PointCount - 1; i++) { IPoint tPoint = points.Point[i]; var refdistance = Math.Sqrt((point.X - tPoint.X) * (point.X - tPoint.X) + (point.Y - tPoint.Y) * (point.Y - tPoint.Y)); if (refdistance == 0 || Math.Abs(refdistance) < (1e-5)) { index = i; break; } } if (index > -1) { points.UpdatePoint(index, point1); } } //_engineEdit.AbortOperation(); //MessageHelper.ShowTips("修复后存在尖锐角/狭长图形,需手动修改."); //return; } #endregion #region MyRegion if (TargetLayer != null) { List referenceFeatures = FeatureAPI.Identify2(geometry, TargetLayer); if (referenceFeatures.Count > 1) { foreach (IFeature referenceFeature in referenceFeatures) { if (featuer.OID == referenceFeature.OID) continue; IGeometry Erasegeometry = FeatureAPI.Difference(referenceFeature.ShapeCopy, geometry); referenceFeature.Shape = Erasegeometry; referenceFeature.Store(); } } } #endregion featuer.Shape = geometry; FeatureAPI.SplitMultipartFeature(new List() { featuer });//拆分多部件 featuer.Store(); _engineEdit.StopOperation("边界修复"); m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewBackground, null, m_hookHelper.ActiveView.Extent); MessageHelper.ShowTips("修复完成."); return; } catch (Exception ex) { _engineEdit.AbortOperation(); throw ex; } } if (featuer == null) { MessageHelper.ShowTips("请选择要修复的图斑."); } } catch (Exception ex) { LogAPI.Debug("btnOK_Click异常:" + ex.Message); LogAPI.Debug("btnOK_Click异常:" + ex.StackTrace); MessageHelper.ShowError("边界修复异常:" + ex.Message); } } #endregion #region 取消 private void btnCancel1_Click(object sender, System.Windows.RoutedEventArgs e) { try { this.Close(); } catch (Exception ex) { LogAPI.Debug("btnCancel1_Click异常:" + ex.Message); LogAPI.Debug("btnCancel1_Click异常:" + ex.StackTrace); } } #endregion /// /// 执行修复逻辑 /// /// /// private IGeometry ExecuteRepair(IFeature feature) { IGeometry geometry = null; try { #region 创建一个点图层 IFeatureLayer Point_Layer = GeoDBAPI.CreateFeatureLayerInmemeory("Point_Layer", "点", (SelectFeatureLayer.FeatureClass as IGeoDataset).SpatialReference, esriGeometryType.esriGeometryPoint, SelectFeatureLayer.FeatureClass.Fields); (Point_Layer.FeatureClass as ITable).DeleteSearchedRows(null); IFeatureBuffer buf = Point_Layer.FeatureClass.CreateFeatureBuffer(); IFeatureCursor T_Cursor = Point_Layer.FeatureClass.Insert(true); #endregion geometry = feature.ShapeCopy; Dictionary repairpoints = Kingo.PluginServiceInterface.Helper.LayerHelper.GetAllPoints(geometry); List referenceFeatures = FeatureAPI.Identify2(geometry, SelectFeatureLayer); Dictionary repairpoints1 = new Dictionary(); if (referenceFeatures != null && referenceFeatures.Count > 0) { foreach (var Identify in referenceFeatures) { List referenceline = FeatureAPI.FeatureToLine(Identify); foreach (var line in referenceline) { if (line.GeometryType == esriGeometryType.esriGeometryPolyline) { Dictionary ReferencePoints = Kingo.PluginServiceInterface.Helper.LayerHelper.GetAllPoints(Identify.ShapeCopy); if (Point_Layer != null && Point_Layer.FeatureClass != null) (Point_Layer.FeatureClass as ITable).DeleteSearchedRows(null); foreach (var item in ReferencePoints) { buf.Shape = item.Value; T_Cursor.InsertFeature(buf); } T_Cursor.Flush(); foreach (var point in repairpoints) { if (repairpoints1.ContainsKey(point.Key)) continue; List Points = FeatureAPI.Snapping(point.Value, new List() { Point_Layer }); var mindistance = -0.1; IPoint ReferencePoint = new PointClass(); foreach (var point_temp in Points) { IPoint Point = point_temp.ShapeCopy as IPoint; var refdistance = Math.Sqrt((point.Value.X - Point.X) * (point.Value.X - Point.X) + (point.Value.Y - Point.Y) * (point.Value.Y - Point.Y)); if (mindistance == -0.1) { mindistance = refdistance; ReferencePoint = Point; continue; } if (refdistance < mindistance) { ReferencePoint = Point; mindistance = refdistance; } } if (mindistance < AttributeValue.Text.ToDouble() && mindistance != -0.1 && mindistance != 0) { IPointCollection points = geometry as IPointCollection; points.UpdatePoint(point.Key, ReferencePoint); //MapsManager.Instance.MapService.DrawGraph(ReferencePoint, true, 0, 0, 255); if (!repairpoints1.ContainsKey(point.Key)) repairpoints1.Add(point.Key, point.Value); continue; } IPolyline polyline = line as IPolyline; IPoint point1 = new PointClass(); var DistanceAlongCurve = 0.0001; var distanceFromCurve = 0.0001; bool bRightSide = true; polyline.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, point.Value, false, point1, ref DistanceAlongCurve, ref distanceFromCurve, bRightSide); var distance = Math.Sqrt((point.Value.X - point1.X) * (point.Value.X - point1.X) + (point.Value.Y - point1.Y) * (point.Value.Y - point1.Y)); if (distance < AttributeValue.Text.ToDouble() && distance != 0) { IPointCollection points = geometry as IPointCollection; points.UpdatePoint(point.Key, point1); //MapsManager.Instance.MapService.DrawGraph(ReferencePoint, true, 0, 0, 255); if (!repairpoints1.ContainsKey(point.Key)) repairpoints1.Add(point.Key, point.Value); continue; } } } } } #region 使用参考图形,修复 if (true) { repairpoints1 = new Dictionary(); referenceFeatures = FeatureAPI.Identify2(geometry, SelectFeatureLayer); if (referenceFeatures != null && referenceFeatures.Count > 0) { foreach (var Identify in referenceFeatures) { repairpoints = Kingo.PluginServiceInterface.Helper.LayerHelper.GetAllPoints(Identify.ShapeCopy); List referenceline = FeatureAPI.PolygonToLine(geometry); foreach (var line in referenceline) { if (line.GeometryType == esriGeometryType.esriGeometryPolyline) { Dictionary ReferencePoints = Kingo.PluginServiceInterface.Helper.LayerHelper.GetAllPoints(geometry); if (Point_Layer != null && Point_Layer.FeatureClass != null) (Point_Layer.FeatureClass as ITable).DeleteSearchedRows(null); foreach (var item in ReferencePoints) { buf.Shape = item.Value; T_Cursor.InsertFeature(buf); } T_Cursor.Flush(); foreach (var point in repairpoints) { if (repairpoints1.ContainsKey(point.Key)) continue; List Points = FeatureAPI.Snapping(point.Value, new List() { Point_Layer }); if (Points.Count == 0) continue; var mindistance = -0.1; IPoint ReferencePoint = new PointClass(); foreach (var point_temp in Points) { IPoint Point = point_temp.ShapeCopy as IPoint; var refdistance = Math.Sqrt((point.Value.X - Point.X) * (point.Value.X - Point.X) + (point.Value.Y - Point.Y) * (point.Value.Y - Point.Y)); if (mindistance == -0.1) { mindistance = refdistance; ReferencePoint = Point; continue; } if (refdistance < mindistance) { ReferencePoint = Point; mindistance = refdistance; } } if (mindistance == 0) continue; if (mindistance < AttributeValue.Text.ToDouble() && mindistance != -0.1 && mindistance != 0) { IPointCollection points = geometry as IPointCollection; int index = -1; foreach (var item in ReferencePoints) { if (FeatureAPI.GetEqual(item.Value, ReferencePoint)) { index = item.Key; break; } } if (index == -1) continue; points.UpdatePoint(index, ReferencePoint); if (!repairpoints1.ContainsKey(point.Key)) repairpoints1.Add(point.Key, point.Value); continue; } } } } } } } #endregion } } catch (Exception ex) { LogAPI.Debug("执行ExecuteRepair异常:" + ex.Message + ex.StackTrace); return geometry; } return geometry; } /// /// 执行修复逻辑 /// /// /// private IGeometry ExecuteRepair1(IFeature feature) { IGeometry geometry = null; try { geometry = feature.ShapeCopy; List repairpoints = Kingo.PluginServiceInterface.Helper.LayerHelper.GetMultipleRingPoints(geometry); var count = 0; foreach (var point in repairpoints) { count++; if (count == 34) { } var UpdatePoint = GetSnappingpoint(point, SelectFeatureLayer); if (UpdatePoint.Count == 0) { UpdatePoint = GetSnappingpoint(point, (_engineEdit as EngineEditorClass).TargetLayer as IFeatureLayer); } var Listpoint = UpdatePoint.OrderByDescending(x => x.Value).ToList(); IPoint moveToPoint = null; if (Listpoint.Count > 0) { #region 共点个数相同的情况下,取距离最近的点 var GroupBy = Listpoint.GroupBy(x => x.Value).ToList(); if (Listpoint.Count > 1) { double refdistance = -1; double mindistance = -1; var index = -1; for (int i = 0; i < Listpoint.Count; i++) { refdistance = Math.Sqrt((point.X - Listpoint[i].Key.X) * (point.X - Listpoint[i].Key.X) + (point.Y - Listpoint[i].Key.Y) * (point.Y - Listpoint[i].Key.Y)); if (mindistance == -1) { mindistance = refdistance; index = i; } else if (refdistance < mindistance) { mindistance = refdistance; index = i; } } if (index != -1) { moveToPoint = Listpoint[index].Key; Listpoint.RemoveAt(index); } } else { moveToPoint = Listpoint[0].Key; Listpoint.RemoveAt(0); } #endregion } if (moveToPoint != null) { IPointCollection points = geometry as IPointCollection; var index = -1; for (int i = 0; i < points.PointCount - 1; i++) { IPoint tPoint = points.Point[i]; var refdistance = Math.Sqrt((point.X - tPoint.X) * (point.X - tPoint.X) + (point.Y - tPoint.Y) * (point.Y - tPoint.Y)); if (refdistance == 0 || Math.Abs(refdistance) < (1e-5)) { index = i; break; } } if (index > -1) { points.UpdatePoint(index, moveToPoint); } //IHitTest iHitTest = geometry as IHitTest; //double hitDist = 0; int partIndex = 0; int vertexIndex = -1; bool bRightSide = false; //IPoint iHitPt = new ESRI.ArcGIS.Geometry.Point(); //if (iHitTest.HitTest(point, Convert.ToDouble(AttributeValue.Text.ToString()), esriGeometryHitPartType.esriGeometryPartVertex, // iHitPt, ref hitDist, ref partIndex, ref vertexIndex, ref bRightSide)) //{ // if (vertexIndex > -1) // points.UpdatePoint(vertexIndex, moveToPoint); //} List firstSnapPointList = Snapping(point, (_engineEdit as EngineEditorClass).TargetLayer as IFeatureLayer); if (firstSnapPointList != null && firstSnapPointList.Count > 1) { foreach (var item in firstSnapPointList) { IGeometryCollection collection = item.Geometry as IGeometryCollection; IGeometry geo = collection.get_Geometry(item.PartIndex); points = geo as IPointCollection; IPoint pt = points.get_Point(item.VertexIndex); points.UpdatePoint(item.VertexIndex, moveToPoint); item.Feature.Shape = item.Geometry; item.Feature.Store(); } } } if (Listpoint.Count > 0) { List referenceline = FeatureAPI.PolygonToLine(geometry); foreach (var line in referenceline) { if (line.GeometryType == esriGeometryType.esriGeometryPolyline) { bool SplitHappened; int newPartIndex; int newSegmentIndex; for (int i = 0; i < Listpoint.Count; i++) { if (Listpoint[i].Value > 1) { IPolyline polyline = line as IPolyline; IPoint point1 = new PointClass(); var DistanceAlongCurve = 0.0001; var distanceFromCurve = 0.0001; bool bRightSide = true; polyline.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, Listpoint[i].Key, false, point1, ref DistanceAlongCurve, ref distanceFromCurve, bRightSide); var distance = Math.Sqrt((Listpoint[i].Key.X - point1.X) * (Listpoint[i].Key.X - point1.X) + (Listpoint[i].Key.Y - point1.Y) * (Listpoint[i].Key.Y - point1.Y)); if (distance > 0.1 || distance < 0.0001) { continue; } (line as IPolyline).SplitAtPoint(Listpoint[i].Key, true, true, out SplitHappened, out newPartIndex, out newSegmentIndex); geometry = ConstructPolygonFromPolyline((line as IPolyline)); } } } } } } #region 判断当前图斑是否压盖多个图斑且存在碎图斑 var Identify2 = FeatureAPI.Identify2(geometry, SelectFeatureLayer); if (Identify2 != null && Identify2.Count > 1) { foreach (var feature1 in Identify2) { var geo = FeatureAPI.InterSect(geometry, feature1.ShapeCopy); if (geo.GetEllipseArea() < 0.1) { geometry = FeatureAPI.Difference(geometry, geo); } } } #endregion } catch (Exception ex) { LogAPI.Debug("执行ExecuteRepair异常:" + ex.Message + ex.StackTrace); return geometry; } return geometry; } /// /// 捕捉 /// /// /// /// /// /// private List Snapping(IPoint point, IFeatureLayer m_featureLayer) { double tol = 0.1; ITopologicalOperator pTopo = point as ITopologicalOperator; IGeometry pGeometry = pTopo.Buffer(tol).Envelope as IGeometry; IIdentify indentify = m_featureLayer as IIdentify; if (indentify == null) return null; IArray pIDs = indentify.Identify(pGeometry); if (pIDs == null || pIDs.Count == 0) return null; List pointList = new List(); for (int index = 0; index < pIDs.Count; index++) { IFeatureIdentifyObj pFeatIdObj = pIDs.get_Element(index) as IFeatureIdentifyObj; IRowIdentifyObject pRowObj = pFeatIdObj as IRowIdentifyObject; IFeature iF = pRowObj.Row as IFeature; IPoint iHitPt = new ESRI.ArcGIS.Geometry.Point(); IHitTest iHitTest = iF.Shape as IHitTest; double hitDist = 0; int partIndex = 0; int vertexIndex = 0; bool bRightSide = false; if (iHitTest.HitTest(point, tol, esriGeometryHitPartType.esriGeometryPartVertex, iHitPt, ref hitDist, ref partIndex, ref vertexIndex, ref bRightSide)) { point = iHitPt; pointList.Add(new MovePointStruct() { Feature = iF, Geometry = iF.Shape, PartIndex = partIndex, VertexIndex = vertexIndex }); } } this.m_hookHelper.ActiveView.Refresh(); return pointList; } /// /// GetpointDic /// /// /// /// /// /// private Dictionary GetSnappingpoint(IPoint point, IFeatureLayer m_featureLayer) { Dictionary pointList = new Dictionary(); try { double tol = Convert.ToDouble(AttributeValue.Text.ToString()); ITopologicalOperator pTopo = point as ITopologicalOperator; IGeometry pGeometry = pTopo.Buffer(tol).Envelope as IGeometry; IIdentify indentify = m_featureLayer as IIdentify; if (indentify == null) return null; IArray pIDs = indentify.Identify(pGeometry); if (pIDs == null || pIDs.Count == 0) return null; for (int index = 0; index < pIDs.Count; index++) { IFeatureIdentifyObj pFeatIdObj = pIDs.get_Element(index) as IFeatureIdentifyObj; IRowIdentifyObject pRowObj = pFeatIdObj as IRowIdentifyObject; IFeature iF = pRowObj.Row as IFeature; IPoint iHitPt = new ESRI.ArcGIS.Geometry.Point(); IHitTest iHitTest = iF.Shape as IHitTest; double hitDist = 0; int partIndex = 0; int vertexIndex = 0; bool bRightSide = false; if (iHitTest.HitTest(point, tol, esriGeometryHitPartType.esriGeometryPartVertex, iHitPt, ref hitDist, ref partIndex, ref vertexIndex, ref bRightSide)) { //point = iHitPt; IPolyline tempLine = new PolylineClass(); tempLine.FromPoint = iHitPt; bool isExit = false; foreach (var tempPoint in pointList.Keys) { tempLine.ToPoint = tempPoint; if (tempLine.Length < 0.001) isExit = true; } if (!isExit) { IArray pTempIDs = indentify.Identify(iHitPt); int num = 0; for (int i = 0; i < pTempIDs.Count; i++) { pFeatIdObj = pTempIDs.get_Element(i) as IFeatureIdentifyObj; pRowObj = pFeatIdObj as IRowIdentifyObject; iHitTest = ((pRowObj.Row as IFeature).Shape) as IHitTest; if (iHitTest.HitTest(iHitPt, 0.0001, esriGeometryHitPartType.esriGeometryPartVertex, iHitPt, ref hitDist, ref partIndex, ref vertexIndex, ref bRightSide)) { num++; } } pointList.Add(iHitPt, num); } } else if (iHitTest.HitTest(point, tol, esriGeometryHitPartType.esriGeometryPartBoundary, iHitPt, ref hitDist, ref partIndex, ref vertexIndex, ref bRightSide)) { //取距离boundary最近的点 IGeometryCollection collection = iF.ShapeCopy as IGeometryCollection; IGeometry geo = collection.get_Geometry(partIndex); ISegmentCollection points = geo as ISegmentCollection; ISegment pt = points.Segment[vertexIndex]; IPoint point1 = new PointClass(); var DistanceAlongCurve = 0.0001; var distanceFromCurve = 0.0001; bRightSide = true; pt.QueryPointAndDistance(esriSegmentExtension.esriNoExtension, point, false, point1, ref DistanceAlongCurve, ref distanceFromCurve, bRightSide); IPolyline tempLine = new PolylineClass(); tempLine.FromPoint = iHitPt; bool isExit = false; foreach (var tempPoint in pointList.Keys) { tempLine.ToPoint = tempPoint; if (tempLine.Length < 0.001) isExit = true; } if (!isExit) { pointList.Add(point1, 1); } } } } catch (Exception ex) { LogAPI.Debug($"GetSnappingpoint异常:{ex.Message + ex.StackTrace}"); } return pointList; } /// /// 线转面 /// /// 线对象 /// IGeometry 面对象 public static IGeometry ConstructPolygonFromPolyline(IPolyline pPolyline) { IGeometry newGeometry = null; try { IGeometryCollection pPolygonGeoCol = new PolygonClass(); if (pPolyline == null || pPolyline.IsEmpty) { return pPolygonGeoCol as IGeometry; } IGeometryCollection pPolylineGeoCol = pPolyline as IGeometryCollection; ISegmentCollection pSegCol = new RingClass(); ISegment pSegment = null; object missing = Type.Missing; for (int i = 0; i < pPolylineGeoCol.GeometryCount; i++) { ISegmentCollection pPolylineSegCol = pPolylineGeoCol.get_Geometry(i) as ISegmentCollection; for (int j = 0; j < pPolylineSegCol.SegmentCount; j++) { pSegment = pPolylineSegCol.get_Segment(j); pSegCol.AddSegment(pSegment, ref missing, ref missing); } pPolygonGeoCol.AddGeometry(pSegCol as IGeometry, ref missing, ref missing); } newGeometry = pPolygonGeoCol as IGeometry; if (newGeometry != null && !newGeometry.IsEmpty) { ITopologicalOperator topologicalOperator = newGeometry as ITopologicalOperator; if (!topologicalOperator.IsKnownSimple) { topologicalOperator.Simplify(); } } } catch (Exception ex) { throw ex; } return newGeometry; } } }