在本文档中主要内容是:代码实现创建的几何网络最短路径分析的代码。参考资料为: ArcGIS Engine 10开发手册。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.NetworkAnalysis;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Controls;
namespace 阵地部署辅助决策预案系统_3._10_.Services.MapDevelopClass
{
/// <summary>
/// 网络分析,包括几何网络分析和无向网络分析
/// </summary>
class NetWorkAnalysis
{
#region Geometric Network 几何网络分析,用于:A.寻找 连通的/不连通的管线 B.上/下游追踪 C.寻找环路 D.寻找通路 E.爆管分析
#region 获取工作区间
/// <summary>
/// 打开个人数据库,获取工作区
/// </summary>
/// <param name="_pGDBName"></param>
/// <returns></returns>
public IWorkspace GetWorkspace(String _pGDBName)
{
IWorkspaceFactory pWsFac = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsFac.OpenFromFile(_pGDBName, 0);
return pWs;
}
#endregion
#region 创建几何网络
/// <summary>
/// 创建几何网络,其中要素类和几何网络名可根据需要进行修改
/// </summary>
/// <param name="_pWorkspace"></param>
/// <param name="_pFeatureDatasetName"></param>
/// <param name="_pGeometricName"></param>
public void CreateGeometricNetwork(IWorkspace _pWorkspace, IFeatureDatasetName _pFeatureDatasetName, String _pGeometricName)
{
INetworkLoader2 pNetworkLoader = new NetworkLoaderClass();
// 创建网络的名称
pNetworkLoader.NetworkName = _pGeometricName;
// 创建网络的类型
pNetworkLoader.NetworkType = esriNetworkType.esriNTUtilityNetwork;
// 设置要素集名称
pNetworkLoader.FeatureDatasetName = (IDatasetName)_pFeatureDatasetName;
// 检查要建立几何网络的数据,每一个要素只能参与一个网络,PrimaryLine 是要素集中的线要素
if (pNetworkLoader.CanUseFeatureClass("PrimaryLine") ==
esriNetworkLoaderFeatureClassCheck.esriNLFCCValid)
{
pNetworkLoader.AddFeatureClass("PrimaryLine",
esriFeatureType.esriFTComplexEdge, null, false);
}
//Feeder是数据集中的点要素
if (pNetworkLoader.CanUseFeatureClass("Feeder") ==
esriNetworkLoaderFeatureClassCheck.esriNLFCCValid)
{
pNetworkLoader.AddFeatureClass("Feeder", esriFeatureType.esriFTSimpleJunction,
null, false);
}
// 数据中没有enable字段,所以用false。如果用true的话,就要进行相关的设置
INetworkLoaderProps pNetworkLoaderProps = (INetworkLoaderProps)pNetworkLoader;
pNetworkLoader.PreserveEnabledValues = false;
String defaultAncillaryRoleFieldName = pNetworkLoaderProps.DefaultAncillaryRoleField;
esriNetworkLoaderFieldCheck ancillaryRoleFieldCheck = pNetworkLoader.CheckAncillaryRoleField("Feeder", defaultAncillaryRoleFieldName);
switch (ancillaryRoleFieldCheck)
{
case esriNetworkLoaderFieldCheck.esriNLFCValid:
case esriNetworkLoaderFieldCheck.esriNLFCNotFound:
pNetworkLoader.PutAncillaryRole("Feeder",
esriNetworkClassAncillaryRole.esriNCARSourceSink,
defaultAncillaryRoleFieldName);
break;
default:
Console.WriteLine(
"The field {0} could not be used as an ancillary role field.",
defaultAncillaryRoleFieldName);
break;
}
pNetworkLoader.SnapTolerance = 0.02;
// 给几何网络添加权重
pNetworkLoader.AddWeight("Weight", esriWeightType.esriWTDouble, 0);
// 将权重和PrimaryLine数据中的SHAPE_Length字段关联
pNetworkLoader.AddWeightAssociation("Weight", "PrimaryLine", "SHAPE_Length");
// 构建网络
pNetworkLoader.LoadNetwork();
}
#endregion
#region 代码创建几何网络的最短路径分析
/// <summary>
/// 求解最短路径,使用方式如: SolvePath(axMapControl1.Map, GetGeometricNetwork(pFtDataset, "TestGeometric"), "Weight", pPointC, 1000, ref pPolyline, ref s); GetGeometricNetwork是自定义的获取几何网络名的方法
/// </summary>
/// <param name="_pMap">MapControl中的Map</param>
/// <param name="_pGeometricNetwork"></param>
/// <param name="_pWeightName"></param>
/// <param name="_pPoints"></param>
/// <param name="_pDist"></param>
/// <param name="_pPolyline"></param>
/// <param name="_pPathCost"></param>
public void SolvePath(IMap _pMap, IGeometricNetwork _pGeometricNetwork, string _pWeightName, IPointCollection _pPoints, double _pDist, ref IPolyline _pPolyline, ref double _pPathCost)
{
try
{ // 这4个参数其实就是一个定位Element的指标
int intEdgeUserClassID;
int intEdgeUserID;
int intEdgeUserSubID;
int intEdgeID;
IPoint pFoundEdgePoint;
double dblEdgePercent;
ITraceFlowSolverGEN pTraceFlowSolver = new TraceFlowSolverClass() as ITraceFlowSolverGEN;
INetSolver pNetSolver = pTraceFlowSolver as INetSolver;
//操作是针对逻辑网络的,INetwork是逻辑网络
INetwork pNetwork = _pGeometricNetwork.Network;
pNetSolver.SourceNetwork = pNetwork;
INetElements pNetElements = pNetwork as INetElements;
int pCount = _pPoints.PointCount;
//定义一个边线旗数组
IEdgeFlag[] pEdgeFlagList = new EdgeFlagClass[pCount];
IPointToEID pPointToEID = new PointToEIDClass();
pPointToEID.SourceMap = _pMap;
pPointToEID.GeometricNetwork = _pGeometricNetwork;
pPointToEID.SnapTolerance = _pDist;
for (int i = 0; i < pCount; i++)
{
INetFlag pNetFlag = new EdgeFlagClass() as INetFlag;
IPoint pEdgePoint = _pPoints.get_Point(i);
//查找输入点的最近的边线
pPointToEID.GetNearestEdge(pEdgePoint, out intEdgeID, out pFoundEdgePoint, out dblEdgePercent);
pNetElements.QueryIDs(intEdgeID, esriElementType.esriETEdge, out intEdgeUserClassID, out intEdgeUserID, out intEdgeUserSubID);
pNetFlag.UserClassID = intEdgeUserClassID;
pNetFlag.UserID = intEdgeUserID;
pNetFlag.UserSubID = intEdgeUserSubID;
IEdgeFlag pTemp = (IEdgeFlag)(pNetFlag as IEdgeFlag);
pEdgeFlagList[i] = pTemp;
}
pTraceFlowSolver.PutEdgeOrigins(ref pEdgeFlagList);
INetSchema pNetSchema = pNetwork as INetSchema;
INetWeight pNetWeight = pNetSchema.get_WeightByName(_pWeightName);
INetSolverWeightsGEN pNetSolverWeights = pTraceFlowSolver as INetSolverWeightsGEN;
pNetSolverWeights.FromToEdgeWeight = pNetWeight;//开始边线的权重
pNetSolverWeights.ToFromEdgeWeight = pNetWeight;//终止边线的权重
object[] pRes = new object[pCount - 1];
//通过FindPath得到边线和交汇点的集合
IEnumNetEID pEnumNetEID_Junctions;
IEnumNetEID pEnumNetEID_Edges;
pTraceFlowSolver.FindPath(esriFlowMethod.esriFMConnected,
esriShortestPathObjFn.esriSPObjFnMinSum,
out pEnumNetEID_Junctions, out pEnumNetEID_Edges, pCount - 1, ref pRes);
//计算元素成本
_pPathCost = 0;
for (int i = 0; i < pRes.Length; i++)
{
double m_Va = (double)pRes[i];
_pPathCost = _pPathCost + m_Va;
}
IGeometryCollection pNewGeometryColl = _pPolyline as IGeometryCollection;//QI
ISpatialReference pSpatialReference = _pMap.SpatialReference;
IEIDHelper pEIDHelper = new EIDHelperClass();
pEIDHelper.GeometricNetwork = _pGeometricNetwork;
pEIDHelper.OutputSpatialReference = pSpatialReference;
pEIDHelper.ReturnGeometries = true;
IEnumEIDInfo pEnumEIDInfo = pEIDHelper.CreateEnumEIDInfo(pEnumNetEID_Edges);
int Count = pEnumEIDInfo.Count;
pEnumEIDInfo.Reset();
for (int i = 0; i < Count; i++)
{
IEIDInfo pEIDInfo = pEnumEIDInfo.Next();
IGeometry pGeometry = pEIDInfo.Geometry;
pNewGeometryColl.AddGeometryCollection(pGeometry as IGeometryCollection);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/// <summary>
/// 获得需要的几何网络
/// </summary>
/// <param name="_pFeatureDataset"></param>
/// <param name="_pGeometricName"></param>
/// <returns></returns>
IGeometricNetwork GetGeometricNetwork(IFeatureDataset _pFeatureDataset, string _pGeometricName)
{
INetworkCollection pNetworkCollection = _pFeatureDataset as INetworkCollection;
return pNetworkCollection.get_GeometricNetworkByName(_pGeometricName);
}
/// <summary>
///
/// </summary>
/// <param name="axMapControl1"></param>
/// <param name="pGC"></param>
public void SolvePathTest(AxMapControl axMapControl1 ,IGraphicsContainer pGC,string workspacfile,string DataSetName,string NetwrokName,IMultipoint pmulti)
{
IWorkspace pWs = GetMDBWorkspace(workspacfile);
IFeatureWorkspace pFtWs = pWs as IFeatureWorkspace;
IFeatureDataset pFtDataset = pFtWs.OpenFeatureDataset(DataSetName);
double s = 0;
IPolyline pPolyline = new PolylineClass();
SolvePath(axMapControl1.Map, GetGeometricNetwork(pFtDataset, NetwrokName), "Weight", pPointC, 1000, ref pPolyline, ref s);
IRgbColor pColor = new RgbColorClass();
pColor.Red = 255;
IElement pElement = new LineElementClass();
ILineSymbol linesymbol = new SimpleLineSymbolClass();
linesymbol.Color = pColor as IColor;
linesymbol.Width = 100;
pElement.Geometry = pPolyline;
pGC.AddElement(pElement, 2);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
/// <summary>
/// 打开个人数据库
/// </summary>
/// <param name="_pGDBName"></param>
/// <returns></returns>
IWorkspace GetMDBWorkspace(String _pGDBName)
{
IWorkspaceFactory pWsFac = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsFac.OpenFromFile(_pGDBName, 0);
return pWs;
}
IPointCollection GetPoints(IMultipoint PMulit)
{
IPointCollection pPoints;
PMulit = new MultipointClass();
pPoints = PMulit as IPointCollection;
return pPoints;
}
#endregion
#endregion
}
}
其中几何网络名,featureSet,featureclass需要自己定义和创建,几何网络如何不是必须在程序后台创建的话,我建议在ArcCatalog中建好之后存储到GDB中。
以上的代码这是几何网络的分析,并不是无向网络的分析。无向网络的创建也分为两种,通过Catalog创建和通过代码创建。无向网络Network DataSet的分析与几何网络稍微不太一样。具体代码如下:
#region Network DataSet 无向网络分析,用于:A.最短路径 B.物流输送 C.临近设施分析 D.服务区分析 E.选址分析
/// <summary>
/// 代码创建几何网络
/// </summary>
/// <param name="_pWsName">个人数据库的路径</param>
/// <param name="_pDatasetName">要素数据集的路径</param>
/// <param name="_pNetName">建立网络的名称</param>
/// <param name="_pFtName">参与网络的要素类</param>
public void CreateNetworkDataset(string _pWsName, string _pDatasetName, string _pNetName, string _pFtName)
{
IDENetworkDataset2 pDENetworkDataset = new DENetworkDatasetClass();
pDENetworkDataset.Buildable = true;
IWorkspace pWs = GetMDBWorkspace(_pWsName);
IFeatureWorkspace pFtWs = pWs as IFeatureWorkspace;
IFeatureDataset pFtDataset = pFtWs.OpenFeatureDataset(_pDatasetName);
// 定义空间参考,负责会出错
IDEGeoDataset pDEGeoDataset = (IDEGeoDataset)pDENetworkDataset;
IGeoDataset pGeoDataset = pFtDataset as IGeoDataset;
pDEGeoDataset.Extent = pGeoDataset.Extent;
pDEGeoDataset.SpatialReference = pGeoDataset.SpatialReference;
// 网络数据集的名称
IDataElement pDataElement = (IDataElement)pDENetworkDataset;
pDataElement.Name = _pNetName;
// 参加建立网络数据集的要素类
INetworkSource pEdgeNetworkSource = new EdgeFeatureSourceClass();
pEdgeNetworkSource.Name = _pFtName;
pEdgeNetworkSource.ElementType = esriNetworkElementType.esriNETEdge;
// 要素类的连通性
IEdgeFeatureSource pEdgeFeatureSource = (IEdgeFeatureSource)pEdgeNetworkSource;
pEdgeFeatureSource.UsesSubtypes = false;
pEdgeFeatureSource.ClassConnectivityGroup = 1;
pEdgeFeatureSource.ClassConnectivityPolicy =esriNetworkEdgeConnectivityPolicy.esriNECPEndVertex;
//不用转弯数据
pDENetworkDataset.SupportsTurns = false;
IArray pSourceArray = new ArrayClass();
pSourceArray.Add(pEdgeNetworkSource);
pDENetworkDataset.Sources = pSourceArray;
//网络数据集的属性设置
IArray pAttributeArray = new ArrayClass();
// Initialize variables reused when creating attributes:
IEvaluatedNetworkAttribute pEvalNetAttr;
INetworkAttribute2 pNetAttr2;
INetworkFieldEvaluator pNetFieldEval;
INetworkConstantEvaluator pNetConstEval;
pEvalNetAttr = new EvaluatedNetworkAttributeClass();
pNetAttr2 = (INetworkAttribute2)pEvalNetAttr;
pNetAttr2.Name ="Meters";
pNetAttr2.UsageType = esriNetworkAttributeUsageType.esriNAUTCost;
pNetAttr2.DataType = esriNetworkAttributeDataType.esriNADTDouble;
pNetAttr2.Units = esriNetworkAttributeUnits.esriNAUMeters;
pNetAttr2.UseByDefault = false;
pNetFieldEval = new NetworkFieldEvaluatorClass();
pNetFieldEval.SetExpression("[METERS]", "");
//方向设置
pEvalNetAttr.set_Evaluator(pEdgeNetworkSource,
esriNetworkEdgeDirection.esriNEDAlongDigitized, (INetworkEvaluator)pNetFieldEval);
pEvalNetAttr.set_Evaluator(pEdgeNetworkSource,
esriNetworkEdgeDirection.esriNEDAgainstDigitized, (INetworkEvaluator)
pNetFieldEval);
pNetConstEval = new NetworkConstantEvaluatorClass();
pNetConstEval.ConstantValue = 0;
pEvalNetAttr.set_DefaultEvaluator(esriNetworkElementType.esriNETEdge,
(INetworkEvaluator)pNetConstEval);
pEvalNetAttr.set_DefaultEvaluator(esriNetworkElementType.esriNETJunction,
(INetworkEvaluator)pNetConstEval);
pEvalNetAttr.set_DefaultEvaluator(esriNetworkElementType.esriNETTurn,
(INetworkEvaluator)pNetConstEval);
// 一个网络数据集可以有多个属性,我只添加了一个
pAttributeArray.Add(pEvalNetAttr);
pDENetworkDataset.Attributes = pAttributeArray;
// 创建网络数据集,注意在创建几何网络的时候会锁定相应的要素类,因此不要用ArcMap或者catalog等打开参相应的数据
INetworkDataset pNetworkDataset = Create(pFtDataset, pDENetworkDataset);
//建立网络
INetworkBuild pNetworkBuild = (INetworkBuild)pNetworkDataset;
pNetworkBuild.BuildNetwork(pGeoDataset.Extent);
}
/// <summary>
/// 创建无向网络
/// </summary>
/// <param name="_pFeatureDataset"></param>
/// <param name="_pDENetDataset"></param>
/// <returns></returns>
public INetworkDataset Create(IFeatureDataset _pFeatureDataset, IDENetworkDataset2 _pDENetDataset)
{
IFeatureDatasetExtensionContainer pFeatureDatasetExtensionContainer = (IFeatureDatasetExtensionContainer)_pFeatureDataset;
IFeatureDatasetExtension pFeatureDatasetExtension = pFeatureDatasetExtensionContainer.FindExtension
(esriDatasetType.esriDTNetworkDataset);
IDatasetContainer2 pDatasetContainer2 = (IDatasetContainer2)pFeatureDatasetExtension;
IDEDataset pDENetDataset = (IDEDataset)_pDENetDataset;
INetworkDataset pNetworkDataset = (INetworkDataset)pDatasetContainer2.CreateDataset
(pDENetDataset);
return pNetworkDataset;
}
/// <summary>
/// _pFtClass参数为Stops的要素类,_pPointC是用鼠标点的点生成的点的集合,最后一个参数是捕捉距离
/// </summary>
/// <param name="_pNaContext"></param>
/// <param name="_pFtClass"></param>
/// <param name="_pPointC"></param>
/// <param name="_pDist"></param>
public void NASolve(INAContext _pNaContext, IFeatureClass _pFtClass, IPointCollection _pPointC, double _pDist)
{
INALocator pNAlocator = _pNaContext.Locator;
for (int i = 0; i < _pPointC.PointCount; i++)
{
IFeature pFt = _pFtClass.CreateFeature();
IRowSubtypes pRowSubtypes = pFt as IRowSubtypes;
pRowSubtypes.InitDefaultValues();
pFt.Shape = _pPointC.get_Point(i) as IGeometry;
IPoint pPoint = null;
INALocation pNalocation = null;
pNAlocator.QueryLocationByPoint(_pPointC.get_Point(i), ref pNalocation, ref pPoint, ref _pDist);
INALocationObject pNAobject = pFt as INALocationObject;
pNAobject.NALocation = pNalocation;
int pNameFieldIndex = _pFtClass.FindField("Name");
pFt.set_Value(pNameFieldIndex, pPoint.X.ToString() + "," + pPoint.Y.ToString());
int pStatusFieldIndex = _pFtClass.FindField("Status");
pFt.set_Value(pStatusFieldIndex, esriNAObjectStatus.esriNAObjectStatusOK);
int pSequenceFieldIndex = _pFtClass.FindField("Sequence");
pFt.set_Value(_pFtClass.FindField("Sequence"), ((ITable)_pFtClass).RowCount(null));
pFt.Store();
}
}
/// <summary>
/// 获取网络数据集
/// </summary>
/// <param name="_pFeatureWs"></param>
/// <param name="_pDatasetName"></param>
/// <param name="_pNetDatasetName"></param>
/// <returns></returns>
INetworkDataset GetNetDataset(IFeatureWorkspace _pFeatureWs, string _pDatasetName, string _pNetDatasetName)
{
ESRI.ArcGIS.Geodatabase.IDatasetContainer3 pDatasetContainer = null;
ESRI.ArcGIS.Geodatabase.IFeatureDataset pFeatureDataset = _pFeatureWs.OpenFeatureDataset(_pDatasetName);
ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtensionContainer pFeatureDatasetExtensionContainer = pFeatureDataset as ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtensionContainer; // Dynamic Cast
ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtension pFeatureDatasetExtension = pFeatureDatasetExtensionContainer.FindExtension(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset);
pDatasetContainer = pFeatureDatasetExtension as ESRI.ArcGIS.Geodatabase.IDatasetContainer3; // Dynamic Cast
ESRI.ArcGIS.Geodatabase.IDataset pNetWorkDataset = pDatasetContainer.get_DatasetByName(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset, _pNetDatasetName);
return pNetWorkDataset as ESRI.ArcGIS.Geodatabase.INetworkDataset; // Dynamic Cast
}
public void LoadNetDataSet(AxMapControl axMapControl1, INASolver pNASolveClass, INALayer pNALayer)
{
IWorkspace pWs = GetMDBWorkspace(@".\data\Geometric.mdb");
IFeatureWorkspace pFtWs = pWs as IFeatureWorkspace;
INetworkDataset pNetWorkDataset = GetNetDataset(pFtWs, "network", "network_ND");
pNASolveClass = new NARouteSolverClass();
loadNet(axMapControl1.Map, pNetWorkDataset);
pNALayer = GetNaLayer(pNASolveClass, GetSolverContext(pNASolveClass, pNetWorkDataset));
axMapControl1.Map.AddLayer(pNALayer as ILayer);
}
/// <summary>
/// 加载NetworkDataset到Map中
/// </summary>
/// <param name="_pMap"></param>
/// <param name="_pNetworkDataset"></param>
void loadNet(IMap _pMap, INetworkDataset _pNetworkDataset)
{
INetworkLayer pNetLayer = new NetworkLayerClass();
pNetLayer.NetworkDataset = _pNetworkDataset;
_pMap.AddLayer(pNetLayer as ILayer);
}
/// <summary>
/// 获取网络分析上下文,这个接口是网络分析中很重要的一个
/// </summary>
/// <param name="_pNaSolver"></param>
/// <param name="_pNetworkDataset"></param>
/// <returns></returns>
public INAContext GetSolverContext(INASolver _pNaSolver, INetworkDataset _pNetworkDataset)
{
//Get the Data Element
IDatasetComponent pDataComponent = _pNetworkDataset as IDatasetComponent;
IDEDataset pDeDataset = pDataComponent.DataElement;
INAContextEdit pContextEdit = _pNaSolver.CreateContext(pDeDataset as IDENetworkDataset, _pNaSolver.Name) as INAContextEdit;
//Prepare the context for analysis based upon the current network dataset schema.
pContextEdit.Bind(_pNetworkDataset, new GPMessagesClass());
return pContextEdit as INAContext;
}
/// <summary>
/// 获取NALayer
/// </summary>
/// <param name="_pNaSover"></param>
/// <param name="_pNaContext"></param>
/// <returns></returns>
INALayer GetNaLayer(INASolver _pNaSover, INAContext _pNaContext)
{
return _pNaSover.CreateLayer(_pNaContext);
}
#endregion
由于我使用的是MVVM框架,所以稍微修改了下ArcGIS Engine10开发手册中的代码,不过经过测试,还是可以正常使用的。