版权声明:本文为博主原创文章,不需博主允许即可随意转载。 https://blog.csdn.net/a_dev/article/details/83863937
代码:
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using Newtonsoft.Json;
using SyGisWebService.DataEnum;
using SyGisWebService.GlobalConfig;
using System;
using System.Collections.Generic;
namespace SyGisWebService.Common
{
public class RouteResourceAnalysis
{
public class LineSegment
{
[JsonProperty("Type")]
public string LineType { get; set; }
[JsonConverter(typeof(BoolConvert))]
[JsonProperty("Existence")]
public bool Existence { get; set; }
[JsonProperty("Shape")]
public GeoJSON.Net.Geometry.MultiLineString Shape { get; set; }
private double _shapeLength = 0;
[JsonProperty("Length")]
public double Length
{
get
{
if (null != Shape)
{
_shapeLength = GeometryFactory.CalculateLength(Shape);
}
return _shapeLength;
}
set => _shapeLength = value;
}
public LineSegment() { }
public LineSegment(LineSegment aLineSegment)
{
LineType = aLineSegment.LineType;
Existence = aLineSegment.Existence;
Shape = aLineSegment.Shape;
}
}
/// <summary>
/// 多段线信息(中心点,是否已过滤)
/// </summary>
public class MultiLineStringInfo
{
public GeoJSON.Net.Geometry.MultiLineString Shape { get; set; }
private GeoJSON.Net.Geometry.Position _centerPosition = null;
public GeoJSON.Net.Geometry.Position CenterPosition
{
get
{
if (null == _centerPosition && null != Shape)
_centerPosition = CalculateCenterPoint(Shape);
return _centerPosition;
}
set => _centerPosition = value;
}
}
/// <summary>
/// 几何对象信息(包括中心点伪坐标)
/// </summary>
public class GeometryInfo
{
public IGeometry Geometry { get; set; }
private GeoJSON.Net.Geometry.Position _centerPosition = null;
public GeoJSON.Net.Geometry.Position CenterPosition
{
get
{
if (null == _centerPosition && null != Geometry)
_centerPosition = CalculateCenterPoint(Geometry);
return _centerPosition;
}
set => _centerPosition = value;
}
public bool Used { get; set; }
}
public const string UnknownVirtualLineFlag = "UNKLK";
public const string PipeLineFlag = "PIPLK";
public const string SuspensionWireFlag = "SPWLK";
public const string RoadLineFlag = "ROALK";
public const string LedupLineFlag = "LDPLK";
public static List<string> RealLineType = new List<string> { PipeLineFlag, SuspensionWireFlag, LedupLineFlag };
public static List<string> VirtualLineType = new List<string> { RoadLineFlag, "VIRLK", "PPDLK" };
private const double MiniBufferRadius = 0.01;
private static Dictionary<string, List<GeometryInfo>> GetLine(IFeatureWorkspace pFeatureWorkspace, IQueryFilter pQueryFilter, List<string> lstFeatureClass)
{
var dictLine = new Dictionary<string, List<GeometryInfo>>();
try
{
if (null != lstFeatureClass)
{
using (var aComReleaser = new ComReleaser())
{
foreach (var sTableName in lstFeatureClass)
{
dictLine.Add(sTableName, new List<GeometryInfo>());
var pFeatureCursor = pFeatureWorkspace.OpenFeatureClass(sTableName).Search(pQueryFilter, false);
aComReleaser.ManageLifetime(pFeatureCursor);
for (var pFeature = pFeatureCursor.NextFeature(); pFeature != null; pFeature = pFeatureCursor.NextFeature())
{
dictLine[sTableName].Add(new GeometryInfo() { Geometry = pFeature.ShapeCopy, Used = false });
}
}
}
}
}
catch (Exception e)
{
ExceptionHelper.LogActionException(e);
}
return dictLine;
}
private static List<MultiLineStringInfo> SplitMultiLineString(GeoJSON.Net.Geometry.MultiLineString aMultiLineString)
{
var lstMultiLineStringInfo = new List<MultiLineStringInfo>();
try
{
Log.Loging.Info($"---> Input MultiLineString : {JsonConvert.SerializeObject(aMultiLineString)}");
if (null == aMultiLineString) return null;
var nCoordinatesCount = aMultiLineString.Coordinates[0].Coordinates.Count;
if (1 >= nCoordinatesCount) return null;
for (int i = 0; i < nCoordinatesCount - 1; i++)
{
var lstPosition = new List<GeoJSON.Net.Geometry.Position>
{
aMultiLineString.Coordinates[0].Coordinates[i],
aMultiLineString.Coordinates[0].Coordinates[i + 1]
};
var aNewMultiLineString = new GeoJSON.Net.Geometry.MultiLineString(
new List<GeoJSON.Net.Geometry.LineString>()
{ new GeoJSON.Net.Geometry.LineString(lstPosition) });
lstMultiLineStringInfo.Add(new MultiLineStringInfo() { Shape = aNewMultiLineString });
}
}
catch (Exception e)
{
ExceptionHelper.LogActionException(e);
}
return lstMultiLineStringInfo;
}
/// <summary>
/// 伪中心点(Z为Position个数)
/// </summary>
/// <param name="multiLineString"></param>
/// <returns></returns>
private static GeoJSON.Net.Geometry.Position CalculateCenterPoint(GeoJSON.Net.Geometry.MultiLineString multiLineString)
{
int nCount = 0;
double dTotalX = 0;
double dTotalY = 0;
foreach (var aLineString in multiLineString.Coordinates)
{
foreach (var aPosition in aLineString.Coordinates)
{
dTotalX += aPosition.X;
dTotalY += aPosition.Y;
nCount++;
}
}
return new GeoJSON.Net.Geometry.Position(dTotalX, dTotalY, nCount);
}
/// <summary>
/// 伪中心点(Z为Position个数)
/// </summary>
/// <param name="pGeometry"></param>
/// <returns></returns>
private static GeoJSON.Net.Geometry.Position CalculateCenterPoint(IGeometry pGeometry)
{
int nCount = 0;
double dTotalX = 0;
double dTotalY = 0;
if (pGeometry is IPointCollection pPointCollection)
{
for (int i = 0; i < pPointCollection.PointCount; i++)
{
dTotalX += pPointCollection.Point[i].X;
dTotalY += pPointCollection.Point[i].Y;
nCount++;
}
}
return new GeoJSON.Net.Geometry.Position(dTotalX, dTotalY, nCount);
}
/// <summary>
/// 是否位置相同
/// </summary>
/// <param name="positionA"></param>
/// <param name="positionB"></param>
/// <returns></returns>
private static bool SamePosition(GeoJSON.Net.Geometry.Position positionA, GeoJSON.Net.Geometry.Position positionB)
{
if (null == positionA && null == positionB) return true;
if (null == positionA || null == positionB) return false;
var dDistanceTolerance = positionA.Z * MiniBufferRadius;
return positionA.Z == positionB.Z && Math.Abs(positionA.X - positionB.X) < dDistanceTolerance && Math.Abs(positionA.Y - positionB.Y) < dDistanceTolerance;
}
/// <summary>
/// 添加线段
/// </summary>
/// <param name="multiLineStringInfo"></param>
/// <param name="bExitenceFlag"></param>
/// <param name="bFound"></param>
/// <param name="dictGeometryInfoList"></param>
/// <param name="lstTargetLineSegment"></param>
private static void AddLineSegment(MultiLineStringInfo multiLineStringInfo, bool bExitenceFlag, ref bool bFound, ref Dictionary<string, List<GeometryInfo>> dictGeometryInfoList, ref List<LineSegment> lstTargetLineSegment)
{
try
{
if (bFound) return;
foreach(var aGeometryInfoList in dictGeometryInfoList)
{
for (int i = 0; i < dictGeometryInfoList[aGeometryInfoList.Key].Count; i++)
{
if (dictGeometryInfoList[aGeometryInfoList.Key][i].Used)
continue;
if (SamePosition(multiLineStringInfo.CenterPosition, dictGeometryInfoList[aGeometryInfoList.Key][i].CenterPosition))
{
lstTargetLineSegment.Add(new LineSegment()
{
LineType = aGeometryInfoList.Key,
Existence = bExitenceFlag,
Shape = multiLineStringInfo.Shape
});
dictGeometryInfoList[aGeometryInfoList.Key][i].Used = true;
bFound = true;
break;
}
}
if (bFound)
break;
}
}
catch (Exception e)
{
ExceptionHelper.LogActionException(e);
}
}
/// <summary>
/// 自动敷设虚拟资源线段
/// </summary>
/// <param name="eLayerMethod"></param>
/// <param name="lstLineSegment"></param>
private static void AutoLayingVirtualLineSegment(LayingMethodEnum eLayerMethod, ref List<LineSegment> lstLineSegment)
{
if (null == lstLineSegment || 0 >= lstLineSegment.Count) return;
switch (eLayerMethod)
{
case LayingMethodEnum.Unknown:
break;
case LayingMethodEnum.Overhead:
ChangeVirtualLineType(SuspensionWireFlag, ref lstLineSegment);
break;
case LayingMethodEnum.Mixed:
ChangeVirtualLineType(null, ref lstLineSegment);
break;
case LayingMethodEnum.Buried:
ChangeVirtualLineType(PipeLineFlag, ref lstLineSegment);
break;
default:
break;
}
}
/// <summary>
/// 修改虚拟资源线段类型
/// </summary>
/// <param name="sResourceLineFlag"></param>
/// <param name="lstLineSegment"></param>
private static void ChangeVirtualLineType(string sResourceLineFlag, ref List<LineSegment> lstLineSegment)
{
if (null == lstLineSegment || 0 >= lstLineSegment.Count) return;
for (int i = 0; i < lstLineSegment.Count; i++)
{
if (lstLineSegment[i].Existence)
continue;
lstLineSegment[i].LineType =
string.IsNullOrEmpty(sResourceLineFlag) ?
(0 == string.Compare(lstLineSegment[i].LineType, RoadLineFlag, StringComparison.OrdinalIgnoreCase) ? PipeLineFlag : SuspensionWireFlag) :
sResourceLineFlag;
}
}
/// <summary>
/// 资源线段平滑处理
/// </summary>
/// <param name="lstLineSegment"></param>
private static void SmoothLineSegment(ref List<LineSegment> lstLineSegment)
{
if (null == lstLineSegment || 3 >= lstLineSegment.Count) return;
for (int i = 1; i < lstLineSegment.Count - 1; i++)
{
if (lstLineSegment[i].Existence) continue;
var sPreviousLineType = lstLineSegment[i - 1].LineType;
var sCurrentLineType = lstLineSegment[i].LineType;
var sNextLineType = lstLineSegment[i + 1].LineType;
//首尾类型相同,如果中间类型不同,则中间自动变为与首尾相同类型
if (0 == string.Compare(sPreviousLineType, sNextLineType, StringComparison.OrdinalIgnoreCase))
{
if (0 != string.Compare(sCurrentLineType, sPreviousLineType, StringComparison.OrdinalIgnoreCase))
{
lstLineSegment[i].LineType = sPreviousLineType;
}
}
//首尾类型不同,一端为引上,另一端为管道或吊线,中间自动变为管道或吊线,即与非引上的那一端相同
else if (0 == string.Compare(sPreviousLineType, LedupLineFlag, StringComparison.OrdinalIgnoreCase) || (0 == string.Compare(sNextLineType, LedupLineFlag, StringComparison.OrdinalIgnoreCase)))
{
if (0 == string.Compare(sPreviousLineType, LedupLineFlag, StringComparison.OrdinalIgnoreCase))
{
lstLineSegment[i].LineType = sNextLineType;
}
else
{
lstLineSegment[i].LineType = sPreviousLineType;
}
}
//首尾类型不同,一端为引上,另一端为吊线,中间自动变成引上
else
{
lstLineSegment[i].LineType = LedupLineFlag;
}
}
}
/// <summary>
/// 合并同类的多段短的资源线
/// </summary>
/// <param name="bUnion"></param>
/// <param name="lstLineSegment"></param>
private static void UnionLineSegment(bool bUnion, ref List<LineSegment> lstLineSegment)
{
if (!bUnion || null == lstLineSegment) return;
var nSegmentCount = lstLineSegment.Count;
if (0 >= nSegmentCount) return;
var lstNewLineSegment = new List<LineSegment>();
try
{
LineSegment aUnionLineSegment = null;
var lstPosition = new List<GeoJSON.Net.Geometry.Position>();
for (var i = 0; i < nSegmentCount; i++)
{
var aLineSegment = lstLineSegment[i];
if (0 == i)
{
aUnionLineSegment = new LineSegment(aLineSegment);
AddPointToCollection(aLineSegment.Shape, ref lstPosition);
}
else
{
var bSameExistence = aLineSegment.Existence == aUnionLineSegment.Existence;
var bSameType = (0 == string.Compare(aLineSegment.LineType, aUnionLineSegment.LineType, StringComparison.OrdinalIgnoreCase));
if (!(bSameExistence && bSameType))
{
aUnionLineSegment.Shape = CreateMultiLineString(lstPosition);
lstNewLineSegment.Add(aUnionLineSegment);
lstPosition.Clear();
aUnionLineSegment = new LineSegment(aLineSegment);
}
AddPointToCollection(aLineSegment.Shape, ref lstPosition);
}
if (i + 1 == nSegmentCount)
{
aUnionLineSegment.Shape = CreateMultiLineString(lstPosition);
lstNewLineSegment.Add(aUnionLineSegment);
lstPosition.Clear();
}
}
lstLineSegment = new List<LineSegment>(lstNewLineSegment);
}
catch (Exception e)
{
ExceptionHelper.LogActionException(e);
}
}
/// <summary>
/// 添加点到集合中
/// </summary>
/// <param name="aMultiLineString"></param>
/// <param name="lstPosition"></param>
private static void AddPointToCollection(GeoJSON.Net.Geometry.MultiLineString aMultiLineString, ref List<GeoJSON.Net.Geometry.Position> lstPosition)
{
if (null == aMultiLineString || null == lstPosition) return;
lstPosition.AddRange(aMultiLineString.Coordinates[0].Coordinates);
}
/// <summary>
/// 根据Position集合创建多段线
/// </summary>
/// <param name="lstPosition"></param>
/// <returns></returns>
private static GeoJSON.Net.Geometry.MultiLineString CreateMultiLineString(List<GeoJSON.Net.Geometry.Position> lstPosition)
{
var aLineString = new GeoJSON.Net.Geometry.LineString(lstPosition);
return new GeoJSON.Net.Geometry.MultiLineString(new List<GeoJSON.Net.Geometry.LineString>() { aLineString });
}
/// <summary>
/// 查询途经资源线(给外部调用的方法)
/// </summary>
/// <param name="sNetworkPath">本地分析网络数据gdb文件路径</param>
/// <param name="aRouteLine">路由线对象</param>
/// <param name="bUnion">是否合并同类连续的多段线</param>
/// <param name="eLayingMethod">敷设方式</param>
/// <returns></returns>
public static List<LineSegment> GetResourceLine(string sNetworkPath, GeoJSON.Net.Geometry.MultiLineString aRouteLine, bool bUnion = false, LayingMethodEnum eLayingMethod = LayingMethodEnum.Mixed)
{
var lstLineSegment = new List<LineSegment>();
try
{
using (SpatialConnectionLibrary.SpatialConnection aConnection = DatabaseConnection.GetSpatialConnection(sNetworkPath))
{
var pFeatureWorkspace = aConnection.Workspace as IFeatureWorkspace;
var pRouteLine = GeometryFactory.CreateEsriGeometryFromGeoJson(aRouteLine);
var pRouteBuffer = GeometryFactory.BufferEx(pRouteLine, MiniBufferRadius, esriBufferConstructionSideEnum.esriBufferFull, esriBufferConstructionEndEnum.esriBufferRound);
var pSpatialFilter = FilterFactory.CreateSpatialFilter(pRouteBuffer, esriSpatialRelEnum.esriSpatialRelContains);
var dictRealLineInfo = GetLine(pFeatureWorkspace, pSpatialFilter, RealLineType);
var dictVirtualLineInfo = GetLine(pFeatureWorkspace, pSpatialFilter, VirtualLineType);
var lstRouteMultiLineStringInfo = SplitMultiLineString(aRouteLine);
foreach (var aRouteMultiLineStringInfo in lstRouteMultiLineStringInfo)
{
var bFound = false;
AddLineSegment(aRouteMultiLineStringInfo, true, ref bFound, ref dictRealLineInfo, ref lstLineSegment);
AddLineSegment(aRouteMultiLineStringInfo, false, ref bFound, ref dictVirtualLineInfo, ref lstLineSegment);
if (!bFound)
{
lstLineSegment.Add(new LineSegment()
{
LineType = UnknownVirtualLineFlag,
Existence = false,
Shape = aRouteMultiLineStringInfo.Shape
});
}
Log.Loging.Info($"---> Add Line Segment : {JsonConvert.SerializeObject(lstLineSegment[lstLineSegment.Count - 1])}");
}
}
Log.Loging.Info($"---> Line Segment (Original) : {JsonConvert.SerializeObject(lstLineSegment)}");
AutoLayingVirtualLineSegment(eLayingMethod, ref lstLineSegment);
Log.Loging.Info($"---> Line Segment (Auto Laying by Method {eLayingMethod}) : {JsonConvert.SerializeObject(lstLineSegment)}");
SmoothLineSegment(ref lstLineSegment);
Log.Loging.Info($"---> Line Segment (Smooth) : {JsonConvert.SerializeObject(lstLineSegment)}");
UnionLineSegment(bUnion, ref lstLineSegment);
Log.Loging.Info($"---> Line Segment (Union) : {JsonConvert.SerializeObject(lstLineSegment)}");
}
catch (Exception e)
{
ExceptionHelper.LogActionException(e);
}
return lstLineSegment;
}
}
}