森林草原湿地荒漠调查
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.
 
 
 

587 lines
26 KiB

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<ESRI.ArcGIS.Geometry.IGeometry, IFeature> data = new Dictionary<IGeometry, IFeature>();
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<ESRI.ArcGIS.Geometry.IGeometry, IFeature> data = Common.CommonHelper.IdentifyReturnIntersect(geometry, layerJC_DLTB);
if (data == null || data.Count <= 0)
{
throw new Exception("未正确压盖[基础库_地类图斑]图层");
}
Dictionary<string, double> pdMj = new Dictionary<string, double>();
//是否全是耕地
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<IGeometry, IFeature> IdentifyReturnIntersect(IGeometry pGeo, ILayer pLayer)
{
Dictionary<IGeometry, IFeature> result = new Dictionary<IGeometry, IFeature>();
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;
}
/// <summary>
/// 获取当前要素压盖到对应坡度级别面积之和最大的坡度
/// </summary>
/// <param name="newFeature">要素</param>
/// <param name="layerPodu">坡度图图层</param>
/// <returns>坡度级别</returns>
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<ESRI.ArcGIS.Geometry.IGeometry, IFeature> data = new Dictionary<IGeometry, IFeature>();
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<ESRI.ArcGIS.Geometry.IGeometry, IFeature> data = IdentifyReturnIntersect(geometry, layerPodu);
if (data == null || data.Count <= 0)
{
throw new Exception("未正确压盖坡度图图层,请检查工作目录坡度图是否设置正确!");
}
Dictionary<string, double> pdMj = new Dictionary<string, double>();
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;
}
/// <summary>
/// 北京获取监测类型和管理部门字段值
/// </summary>
/// <param name="feature"></param>
/// <param name="layerJC_DLTB"></param>
/// <param name="bhjclxList"></param>
/// <param name="dlbm"></param>
/// <param name="ddtcdm"></param>
/// <returns></returns>
public static Dictionary<string, string> GetJCLXAndGLBM(IFeature feature, IFeatureLayer layerJC_DLTB, List<BHJCLX> bhjclxList, string dlbm, string ddtcdm)
{
Dictionary<string, string> keys = new Dictionary<string, string>();
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<IFeature> 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);
}
}
/// <summary>
/// 获取空间相交要素的属性值(按面积加权)
/// </summary>
/// <param name="feature">查询要素</param>
/// <param name="targetLayer">目标图层</param>
/// <param name="fieldName">要获取的属性字段名</param>
/// <param name="minArea">最小有效面积(默认0.01)</param>
/// <returns>面积最大的属性值</returns>
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<IGeometry, IFeature> intersectedFeatures = new Dictionary<IGeometry, IFeature>();
//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<string, double> 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);
}
}
/// <summary>
/// 查询相交要素
/// </summary>
private static Dictionary<IGeometry, IFeature> QueryIntersectedFeatures(IGeometry geometry, IFeatureClass featureClass)
{
var result = new Dictionary<IGeometry, IFeature>();
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;
}
/// <summary>
/// 计算属性面积字典
/// </summary>
private static Dictionary<string, double> CalculateAttributeAreas(IFeatureClass featureClass, IFeature sourceFeature, int fieldIndex, string layerName, double minArea)
{
Dictionary<IGeometry, string> intersectedFeatures = new Dictionary<IGeometry, string>();
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<string, double> result = new Dictionary<string, double>();
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;
}
/// <summary>
/// 检查DLBM是否符合配置条件(支持复合条件:StartsWith、in、not in)
/// </summary>
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;
}
}
}