using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using KGIS.Framework.AE; using KGIS.Framework.Maps; using KGIS.Framework.Utils; using KGIS.Framework.Utils.Helper; using Kingo.Plugin.MapView.Model; using Kingo.PluginServiceInterface; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace Kingo.Plugin.MapView.Common { public class CommonHelper { public static string GetGDPDJB_BJ(IFeature feature, ESRI.ArcGIS.Carto.IFeatureLayer layerJC_DLTB, ESRI.ArcGIS.Carto.IFeatureLayer layerJC_PDT) { string poduMax = ""; try { /*GDPDJB取值 *1.变更前后均为耕地,耕地坡度级别继承基础库的耕地坡度级别; *继承时耕地坡度级别占比最大的;此时的耕地坡度级别属性为可编辑 *2.变更前为非耕地或部分耕地,变更后为耕地,耕地坡度级别根据坡度图面积占比最优赋值; * 此时的耕地坡度级别属性不可编辑 */ if (layerJC_DLTB == null || layerJC_DLTB.FeatureClass == null) { throw new Exception("[基础库_地类图斑]数据源为空,请确认工作目录设置是否正确!"); } int poduindex = layerJC_DLTB.FeatureClass.Fields.FindField("GDPDJB"); if (poduindex < 0) { throw new Exception("[基础库_地类图斑]无GDPDJB字段,请确认工作目录设置是否正确!"); } int dlbmindex = layerJC_DLTB.FeatureClass.Fields.FindField("DLBM"); if (dlbmindex < 0) { throw new Exception("[基础库_地类图斑]无DLBM字段,请确认工作目录设置是否正确!"); } ESRI.ArcGIS.Geometry.IGeometry geometry = feature.ShapeCopy; IFeatureClass featureClass = (layerJC_DLTB as ESRI.ArcGIS.Carto.IFeatureLayer).FeatureClass; if (geometry.SpatialReference.FactoryCode != (featureClass as IGeoDataset).SpatialReference.FactoryCode) { geometry.Project((featureClass as IGeoDataset).SpatialReference); } ISpatialFilter spatialFilter = new SpatialFilterClass() { Geometry = geometry, SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects }; Dictionary data = new Dictionary(); IFeatureCursor cursor = featureClass.Search(spatialFilter, true); IFeature fea; while ((fea = cursor.NextFeature()) != null) { data.Add(fea.ShapeCopy, fea); } System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor); System.Runtime.InteropServices.Marshal.ReleaseComObject(spatialFilter); //Dictionary data = Common.CommonHelper.IdentifyReturnIntersect(geometry, layerJC_DLTB); if (data == null || data.Count <= 0) { throw new Exception("未正确压盖[基础库_地类图斑]图层"); } Dictionary pdMj = new Dictionary(); //是否全是耕地 bool isALLGD = true; foreach (var item in data) { double mj = (item.Key as ESRI.ArcGIS.Geometry.IArea).Area; if (mj < 0.01) { continue; } //地类编码 if (item.Value.get_Value(dlbmindex) == null || !item.Value.get_Value(dlbmindex).ToString().StartsWith("01")) { isALLGD = false; break; } //耕地坡度级别 string pdjb = item.Value.get_Value(poduindex).ToString(); if (pdMj.ContainsKey(pdjb)) { pdMj[pdjb] = pdMj[pdjb] + (item.Key as ESRI.ArcGIS.Geometry.IArea).Area; } else { pdMj.Add(pdjb, (item.Key as ESRI.ArcGIS.Geometry.IArea).Area); } } if (isALLGD) { if (!System.Diagnostics.Debugger.IsAttached) { LogAPI.Debug(JsonConvert.SerializeObject(pdMj.OrderByDescending(x => x.Value))); } //计算取耕地坡度级别占比最大的 string caculateValue = pdMj.OrderByDescending(x => x.Value).FirstOrDefault().Key; //页面值 string featureValue = ""; if (feature.Fields.FindField("GDPDJB") > -1) { featureValue = feature.get_Value(feature.Fields.FindField("GDPDJB")).ToString(); } //为空赋值计算的值 if (string.IsNullOrWhiteSpace(featureValue)) { poduMax = caculateValue; } else { //原值与计算的值不一致 if (!caculateValue.Equals(featureValue)) { //弹出提示框,让用户确认是否核实 if (MessageHelper.ShowYesNoAndTips("变更前后均为耕地,计算占比最大坡度级别为“" + caculateValue + "”,与页面实际填写值“" + featureValue + "”不一致,是否已核实(以页面值为准)?") == System.Windows.Forms.DialogResult.Yes) { poduMax = featureValue; } else { poduMax = caculateValue; } } else { poduMax = featureValue; } } } else { poduMax = GetMaxAreaPDJB(feature.ShapeCopy, layerJC_PDT); } } catch (Exception ex) { KGIS.Framework.Utils.LogAPI.Debug("获取坡度级别异常:\r\n"); KGIS.Framework.Utils.LogAPI.Debug(ex); throw new Exception("获取坡度级别异常:" + ex.Message); } return poduMax; } public static Dictionary IdentifyReturnIntersect(IGeometry pGeo, ILayer pLayer) { Dictionary result = new Dictionary(); try { if (pGeo == null || pGeo.IsEmpty || pLayer == null) { return result; } IIdentify identify = pLayer as IIdentify; if (identify == null) return result; ESRI.ArcGIS.esriSystem.IArray array = identify.Identify(pGeo); if (array == null || array.Count < 1) return result; for (int i = 0; i < array.Count; i++) { IRowIdentifyObject row = (IRowIdentifyObject)array.get_Element(i); if (row == null) { continue; } IFeature f = row.Row as IFeature; //此处之所以重新根据OID获取要素,是因为使用(row.Row as IFeature)强制转换过来的要素坐标参考容差不正确,都是默认的千分之一0.001 IGeometry geometry = (pLayer as IFeatureLayer).FeatureClass.GetFeature(f.OID).ShapeCopy; IGeometry geo = KGIS.Framework.AE.FeatureAPI.InterSect(geometry, pGeo); if (geo != null && !geo.IsEmpty) { result.Add(geo, f); } } } catch (Exception ex) { throw ex; } return result; } /// /// 获取当前要素压盖到对应坡度级别面积之和最大的坡度 /// /// 要素 /// 坡度图图层 /// 坡度级别 public static string GetMaxAreaPDJB(IGeometry geometry, IFeatureLayer layerPodu = null) { string poduMax = ""; try { if (layerPodu == null || layerPodu.FeatureClass == null) { throw new Exception("未获取到[基础_省级下发坡度图],请检查工作目录坡度图是否设置正确"); } if (geometry == null || geometry.IsEmpty) { throw new Exception("图形为空!"); } ProjectInfo projectInfo = MapsManager.Instance.MapService.GetProjectInfo() as ProjectInfo; string pdjbFieldName = projectInfo.CODE.StartsWith("11") ? "GDPDJB" : "PDJB"; int poduindex = layerPodu.FeatureClass.Fields.FindField(pdjbFieldName); if (poduindex < 0) { throw new Exception($"[基础_省级下发坡度图]图层无{pdjbFieldName}字段!"); } if (geometry.SpatialReference.FactoryCode != (layerPodu.FeatureClass as IGeoDataset).SpatialReference.FactoryCode) { geometry.Project((layerPodu.FeatureClass as IGeoDataset).SpatialReference); } ISpatialFilter spatialFilter = new SpatialFilterClass() { Geometry = geometry, SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects }; Dictionary data = new Dictionary(); IFeatureCursor cursor = layerPodu.FeatureClass.Search(spatialFilter, true); IFeature fea; while ((fea = cursor.NextFeature()) != null) { data.Add(fea.ShapeCopy, fea); } System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor); System.Runtime.InteropServices.Marshal.ReleaseComObject(spatialFilter); //Dictionary data = IdentifyReturnIntersect(geometry, layerPodu); if (data == null || data.Count <= 0) { throw new Exception("未正确压盖坡度图图层,请检查工作目录坡度图是否设置正确!"); } Dictionary pdMj = new Dictionary(); foreach (var item in data) { string pdjb = item.Value.get_Value(poduindex).ToString(); if (pdMj.ContainsKey(pdjb)) { pdMj[pdjb] = pdMj[pdjb] + (item.Key as ESRI.ArcGIS.Geometry.IArea).Area; } else { pdMj.Add(pdjb, (item.Key as ESRI.ArcGIS.Geometry.IArea).Area); } } if (!System.Diagnostics.Debugger.IsAttached) { LogAPI.Debug(JsonConvert.SerializeObject(pdMj.OrderByDescending(x => x.Value))); } poduMax = pdMj.OrderByDescending(x => x.Value).FirstOrDefault().Key; } catch (Exception ex) { throw ex; } return poduMax; } /// /// 北京获取监测类型和管理部门字段值 /// /// /// /// /// /// /// public static Dictionary GetJCLXAndGLBM(IFeature feature, IFeatureLayer layerJC_DLTB, List bhjclxList, string dlbm, string ddtcdm) { Dictionary keys = new Dictionary(); try { if (layerJC_DLTB == null || layerJC_DLTB.FeatureClass == null) { throw new Exception("[基础库_地类图斑]数据源为空,请确认工作目录设置是否正确!"); } int jck_dlbmindex = layerJC_DLTB.FeatureClass.Fields.FindField("DLBM"); if (jck_dlbmindex < 0) { throw new Exception("[基础库_地类图斑]或[单图斑地类图斑更新层]无DLBM字段,请确认工作目录设置是否正确!"); } IGeometry geometry = feature.ShapeCopy; IFeatureClass featureClass = (layerJC_DLTB as ESRI.ArcGIS.Carto.IFeatureLayer).FeatureClass; if (geometry.SpatialReference.FactoryCode != (featureClass as IGeoDataset).SpatialReference.FactoryCode) { geometry.Project((featureClass as IGeoDataset).SpatialReference); } List features = FeatureAPI.Identify(geometry, layerJC_DLTB); if (features == null || features.Count <= 0) { throw new Exception("未正确压盖[基础库_地类图斑]图层"); } // 存储符合条件的配置项 List<(BHJCLX Config, double Area)> matchedConfigs = new List<(BHJCLX, double)>(); foreach (IFeature fea in features) { if (fea.ShapeCopy == null || fea.ShapeCopy.IsEmpty) { continue; } double area = (fea.ShapeCopy as IArea).Area; if (area <= 50) { continue; } string dltbdlbm = fea.get_Value(jck_dlbmindex).ToString(); // 遍历所有配置项,检查是否符合条件 foreach (BHJCLX config in bhjclxList) { // 1. 检查NewDLBM是否符合条件 bool newDLBMMatched = CheckDLBMCondition(dlbm, config.NewDLBM); if (!newDLBMMatched) { continue; } // 2. 检查OldDLBM是否符合条件 bool oldDLBMMatched = CheckDLBMCondition(dltbdlbm, config.OldDLBM); if (!oldDLBMMatched) { continue; } // 3. 如果CheckDDTC=true,则需检查DDTCDM是否匹配 if (config.CheckDDTC) { if (string.IsNullOrEmpty(config.DDTCDM)) // 配置未提供DDTCDM,跳过 { continue; } if (ddtcdm != config.DDTCDM) // DDTCDM不匹配,跳过 { continue; } } // 所有条件均满足,记录匹配的配置和面积 matchedConfigs.Add((config, area)); } } // 如果没有匹配项,返回空字典 if (matchedConfigs.Count == 0) { return keys; } // 按优先级(Priority)升序排序,再按面积降序排序 var sortedConfigs = matchedConfigs .OrderBy(x => x.Config.Priority) .ThenByDescending(x => x.Area) .ToList(); var mergedConfigs = sortedConfigs .GroupBy(x => x.Config.JCLX) .Select(g => new { Config = g.First().Config, TotalArea = g.Sum(x => x.Area) }) .OrderBy(x => x.Config.Priority) .ThenByDescending(x => x.TotalArea) .ToList(); LogAPI.Debug(Newtonsoft.Json.JsonConvert.SerializeObject(mergedConfigs)); // 取优先级最高且面积最大的配置 BHJCLX bestConfig = mergedConfigs[0].Config; keys.Add(bestConfig.JCLX, bestConfig.GLBM); return keys; } catch (Exception ex) { LogAPI.Debug("北京获取监测类型和管理部门失败:\r\n"); LogAPI.Debug(ex); throw new Exception("获取监测类型和管理部门异常:" + ex.Message); } } /// /// 获取空间相交要素的属性值(按面积加权) /// /// 查询要素 /// 目标图层 /// 要获取的属性字段名 /// 最小有效面积(默认0.01) /// 面积最大的属性值 public static string GetSpatialAttribute(IFeature feature, IFeatureLayer targetLayer, string fieldName, double minArea = 0.01) { if (targetLayer?.FeatureClass == null) { throw new ArgumentNullException(nameof(targetLayer), $"[{targetLayer?.Name}]数据源为空,请确认工作目录设置是否正确!"); } int fieldIndex = targetLayer.FeatureClass.Fields.FindField(fieldName); if (fieldIndex < 0) { throw new ArgumentException($"[{targetLayer.Name}]无{fieldName}字段,请确认工作目录设置是否正确!"); } try { // 1. 准备查询几何 IGeometry geometry = feature.ShapeCopy; IFeatureClass featureClass = targetLayer.FeatureClass; // 2. 坐标系统一 if (geometry.SpatialReference.FactoryCode != ((IGeoDataset)featureClass).SpatialReference.FactoryCode) { geometry.Project(((IGeoDataset)featureClass).SpatialReference); } // 3. 执行空间查询 //var intersectedFeatures = QueryIntersectedFeatures(geometry, featureClass); //Dictionary intersectedFeatures = new Dictionary(); //ISpatialFilter spatialFilter = new SpatialFilterClass //{ // Geometry = geometry, // SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects //}; //IFeatureCursor cursor = featureClass.Search(spatialFilter, true); //IFeature fea; //while ((fea = cursor.NextFeature()) != null) //{ // intersectedFeatures.Add(fea.ShapeCopy, fea); //} //if (cursor != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor); //System.Runtime.InteropServices.Marshal.ReleaseComObject(spatialFilter); //if (intersectedFeatures.Count == 0) //{ // throw new InvalidOperationException($"未正确压盖[{targetLayer.Name}]图层"); //} // 4. 按属性分组并计算面积 Dictionary attributeAreas = CalculateAttributeAreas(featureClass, feature, fieldIndex, targetLayer.Name, minArea); // 5. 返回面积最大的属性值 return attributeAreas.OrderByDescending(x => x.Value).FirstOrDefault().Key; } catch (Exception ex) { LogAPI.Debug($"获取{fieldName}属性失败:\r\n"); LogAPI.Debug(ex); throw new Exception($"获取{fieldName}属性异常:" + ex.Message, ex); } } /// /// 查询相交要素 /// private static Dictionary QueryIntersectedFeatures(IGeometry geometry, IFeatureClass featureClass) { var result = new Dictionary(); ISpatialFilter spatialFilter = new SpatialFilterClass { Geometry = geometry, SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects }; IFeatureCursor cursor = null; try { cursor = featureClass.Search(spatialFilter, true); IFeature feature; while ((feature = cursor.NextFeature()) != null) { result.Add(feature.ShapeCopy, feature); } } finally { if (cursor != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor); System.Runtime.InteropServices.Marshal.ReleaseComObject(spatialFilter); } return result; } /// /// 计算属性面积字典 /// private static Dictionary CalculateAttributeAreas(IFeatureClass featureClass, IFeature sourceFeature, int fieldIndex, string layerName, double minArea) { Dictionary intersectedFeatures = new Dictionary(); ISpatialFilter spatialFilter = new SpatialFilterClass { Geometry = sourceFeature.ShapeCopy, SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects }; IFeatureCursor cursor = featureClass.Search(spatialFilter, true); IFeature fea; while ((fea = cursor.NextFeature()) != null) { intersectedFeatures.Add(fea.ShapeCopy, fea.get_Value(fieldIndex)?.ToString() ?? string.Empty); } if (cursor != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(cursor); System.Runtime.InteropServices.Marshal.ReleaseComObject(spatialFilter); if (intersectedFeatures.Count == 0) { throw new InvalidOperationException($"未正确压盖[{layerName}]图层"); } Dictionary result = new Dictionary(); foreach (var item in intersectedFeatures) { double area = FeatureAPI.GetInterArea(item.Key, sourceFeature.ShapeCopy); //double area = ((IArea)item.Key).Area; if (area < minArea) continue; string attributeValue = item.Value; if (result.ContainsKey(attributeValue)) { result[attributeValue] += area; } else { result[attributeValue] = area; } } return result; } /// /// 检查DLBM是否符合配置条件(支持复合条件:StartsWith、in、not in) /// private static bool CheckDLBMCondition(string dlbm, string condition) { if (string.IsNullOrEmpty(condition)) { return false; } // 1. 分割条件(按 "、" 拆分) string[] subConditions = condition.Split('、'); // 2. 解析条件类型 bool startsWithOrInMatched = false; // 记录 StartsWith 或 in 是否匹配 bool notInMatched = true; // 记录 not in 是否匹配(默认true,若无 not in 则不影响) foreach (string subCondition in subConditions) { // 2.1 处理StartsWith条件(如 "StartsWith(03|04|11|12)") if (subCondition.StartsWith("StartsWith(") && subCondition.EndsWith(")")) { string prefix = subCondition.Substring("StartsWith(".Length, subCondition.Length - "StartsWith(".Length - 1); string[] prefixes = prefix.Split('|'); if (prefixes.Any(p => dlbm.StartsWith(p))) { startsWithOrInMatched = true; } } // 2.2 处理in条件(如 "in(1006)") else if (subCondition.StartsWith("in(") && subCondition.EndsWith(")")) { string valuesStr = subCondition.Substring("in(".Length, subCondition.Length - "in(".Length - 1); string[] values = valuesStr.Split('|'); if (values.Contains(dlbm)) { startsWithOrInMatched = true; } } // 2.3 处理not in条件(如 "not in(1109|1201)") else if (subCondition.StartsWith("not in(") && subCondition.EndsWith(")")) { string valuesStr = subCondition.Substring("not in(".Length, subCondition.Length - "not in(".Length - 1); string[] values = valuesStr.Split('|'); if (values.Contains(dlbm)) { notInMatched = false; // 如果DLBM在not in列表里,直接不匹配 } } // 2.4 默认情况(直接相等) else if (dlbm == subCondition) { startsWithOrInMatched = true; } } // 最终结果 = (StartsWith 或 in 匹配) 且 (not in 匹配) return startsWithOrInMatched && notInMatched; } } }