using ESRI.ArcGIS.SystemUI; using NetTopologySuite.Geometries; using NetTopologySuite.Index.Strtree; using NetTopologySuite.Operation.Overlay.Snap; using NetTopologySuite.Operation.Union; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Kingo.PluginServiceInterface.Helper { /// /// 边界吸附处理器 /// public static class BoundarySnapper { /// /// 执行边界吸附操作 /// /// 输入图斑集合 /// 吸附容差(单位与坐标一致) /// 修复后的图斑集合 public static List SnapBoundaries(List inputParcels, double tolerance = 0.001) { // 创建空间索引加速邻近查询 var spatialIndex = new STRtree(); foreach (var parcel in inputParcels) { spatialIndex.Insert(parcel.EnvelopeInternal, parcel); } spatialIndex.Build(); // 复制输入数据以避免修改原始集合 var outputParcels = new List(inputParcels); // 遍历每个图斑进行边界吸附 foreach (var currentParcel in inputParcels) { // 查询可能与当前图斑相邻的图斑 var nearbyCandidates = spatialIndex.Query(currentParcel.EnvelopeInternal); // 过滤出实际接触的相邻图斑 var neighbors = nearbyCandidates .Where(p => p != currentParcel && p.Touches(currentParcel)) .ToList(); foreach (var neighbor in neighbors) { // 使用NTS的GeometrySnapper执行吸附操作 var snapper = new GeometrySnapper(currentParcel); Geometry snappedGeometry = (Geometry)snapper.SnapTo(neighbor, tolerance); // 如果几何体发生改变,则更新结果集 if (!snappedGeometry.EqualsExact(currentParcel)) { outputParcels.Remove(currentParcel); outputParcels.Add(snappedGeometry); break; // 处理第一个匹配的邻居后跳出循环 } } } return outputParcels; } } /// /// 国土变更调查拓扑修复工具 /// 功能:边界对齐 + 重叠消除 + 拓扑验证 /// public class TopologyRepairEngine { #region 公开接口 /// /// 执行完整拓扑修复流程 /// /// 输入图斑集合 /// 拓扑容差(单位与坐标系一致) /// 最大修复迭代次数 /// 修复后的拓扑一致图斑集合 public static List FullRepair(List inputGeometries, double tolerance = 0.001, int maxIterations = 10) { // 阶段1:边界对齐处理 var snapped = SnapBoundaries(inputGeometries, tolerance, maxIterations); // 阶段2:全局重叠消除 var cleaned = ResolveOverlaps(snapped, tolerance); //// 阶段3:最终验证 //if (!ValidateTopology(cleaned, tolerance)) // throw new TopologyException("拓扑修复失败,存在未解决的拓扑错误"); return cleaned; } #endregion #region 核心算法 /// /// 多轮次边界吸附处理 /// private static List SnapBoundaries(List input, double tolerance, int maxIterations) { List workingSet = input.Select(g => (Geometry)g.Copy()).ToList(); bool hasChanges; int iteration = 0; do { hasChanges = false; var spatialIndex = BuildSTRTree(workingSet); var nextGeneration = new List(); foreach (var current in workingSet) { var neighbors = spatialIndex.Query(current.EnvelopeInternal) .Where(g => g != current && g.Touches(current)) .ToList(); Geometry processed = current; foreach (var neighbor in neighbors) { var snapper = new GeometrySnapper(processed); Geometry snapped = (Geometry)snapper.SnapTo(neighbor, CalculateDynamicTolerance(tolerance, iteration)); if (!snapped.EqualsTopologically(processed)) { processed = ValidateGeometry(snapped); hasChanges = true; break; // 单次只处理一个邻居 } } nextGeneration.Add(processed); } workingSet = nextGeneration; iteration++; } while (hasChanges && iteration < maxIterations); return workingSet; } /// /// 全局重叠消除处理 /// private static List ResolveOverlaps(List geometries, double tolerance) { var overlaps = DetectOverlaps(geometries, tolerance); if (overlaps.Count == 0) return geometries; var validOverlaps = overlaps .Where(g => g is Polygon&&!g.IsEmpty) // 仅保留多边形 .Where(g => g.IsValid)// 检查有效性 .Cast() .ToList(); var union = CascadedPolygonUnion.Union(validOverlaps); if(union==null) return geometries; var result = new List(); foreach (var geom in geometries) { if (geom.Intersects(union)) { var diff = geom.Difference(union); result.AddRange(ExtractValidPolygons((Geometry)diff)); } else { result.Add(geom); } } // 递归处理残留重叠 return ResolveOverlaps(result, tolerance); // 收紧容差 } #endregion #region 辅助方法 /// /// 构建空间索引 /// private static STRtree BuildSTRTree(IEnumerable geometries) { var tree = new STRtree(); foreach (var g in geometries) tree.Insert(g.EnvelopeInternal, g); tree.Build(); return tree; } /// /// 动态容差计算(随迭代次数衰减) /// private static double CalculateDynamicTolerance(double baseTolerance, int iteration) => baseTolerance * Math.Pow(0.9, iteration); /// /// 几何体有效性检查与修复 /// private static Geometry ValidateGeometry(Geometry geom) { if (!geom.IsValid) { // 使用缓冲区法修复常见错误 var buffered = geom.Buffer(0); return buffered.IsEmpty ? (Geometry)geom : (Geometry)buffered; } return geom; } /// /// 检测所有重叠区域 /// private static List DetectOverlaps(List geometries, double minArea) { var overlaps = new List(); var index = BuildSTRTree(geometries); foreach (var geom in geometries) { foreach (var other in index.Query(geom.EnvelopeInternal) .Where(g => g != geom && g.Intersects(geom))) { var overlap = geom.Intersection(other); if (overlap.Area > minArea * minArea) overlaps.Add((Geometry)overlap); } } return overlaps; } /// /// 从几何集合中提取有效多边形 /// private static IEnumerable ExtractValidPolygons(Geometry geom) { if (geom is Polygon p) return new[] { p }; if (geom is GeometryCollection coll) return coll.Geometries .Where(g => g is Polygon) .Select(g => ValidateGeometry((Geometry)g)); return Enumerable.Empty(); } #endregion #region 验证逻辑 /// /// 拓扑一致性验证 /// public static bool ValidateTopology(IEnumerable geometries, double tolerance) { var index = BuildSTRTree(geometries); return geometries.All(g => { // 检查自身有效性 if (!g.IsValid) return false; // 检查相邻关系 return index.Query(g.EnvelopeInternal) .Where(other => g != other) .All(other => !g.Intersects(other) || (g.Touches(other) && g.Boundary.Distance(other.Boundary) <= tolerance) ); }); } #endregion } /// /// 自定义拓扑异常 /// public class TopologyException : Exception { public TopologyException(string message) : base(message) { } } }