(十一)ArcGIS Server之扩展几何网络分析

1.引言

      在看博客之前,首先重点说明,本博客中使用的软件版本:

  • ArcGIS Server10.2
  • ArcGIS Object10.2

      如果你的版本是10.0,本博客中的代码肯定不可以用(10.0版本到10.1版本是一个大的提升)
      如果你的版本是10.1,本博客中的代码需要稍微修改(10.1版本到10.2版本会有小部分的修改)

      在本篇博客中主要以几何网络分析为例,介绍一下如果使用SOE来扩展我们的WebGIS应用。想要使用SOE扩展我们的WebGIS应用,需要对ArcGIS Object有一定的掌握。

2.在ArcGIS Object中进行几何网络分析。

在SOE扩展几何网络之前,先回顾一下如何使用ArcGIS Object来进行几何网络分析。

  • 首先在MapControl中绘制四类点(点标记listJunctionFlags,线标记listEdgeFlags,点障碍listJunctionBarrier,线障碍listEdgeBarrier)。

这里写图片描述

  • 使用IPointToEID接口,将我们的点转换成网络中的节点(其实就是寻找网络中满足容差最近的节点),转换成功之后的数组为:junctionFlags,edgeFlags,junctionBarrier,edgeBarrier
  • 然后设置网络的四个参数(点标记,线标记,点障碍,线障碍),选择合适的方法分析,比如我们使用公共祖先分析(FindCommonAncestors),分析之后得到结果,得到的结果是网络中的节点id(有节点id,也有线id)
  • 通过网络中的节点id获得相应的Feature,然后就可以在地图中显示。

3.SOE扩展几何网络分析难点

      在上面我们用文字简单的介绍了一下如何使用ArcGIS Object去分析几何网络,如果你熟悉AO,那么上面的过程你应该非常熟悉了。接下来我们就说一下在SOE中扩展WebGIS会遇到哪一些难点。

  • 难点一:假设我们要设置点标记(json数组),前台传来的是一个json数据,我们需要将json数组转换成List<IPoint>,然后通过IPointToEID,去查找网络中与改点最近的节点(在一定容差内)
  • 难点二:前面我们曾经说过,在ArcGIS 10.1之后,SOE开发中不可能获得IMap,ILayer对象,但是呢?IPointToEID这个接口需要传入IMap对象,所以IPointToEID这个接口在ArcGIS Server10.1之后不能使用了(SOE开发中不能用,AO中是可以使用的),但是这个接口的功能是我们必须要用到的,所以这个功能需要我们自己写代码实现。
  • 难点三:我们查询出来的结果,需要传给前台显示,这就需要我们将查询出来的结果序列化成json字符串,然后传给前台。

4.SOE扩展几何网络分析

      在前面我们说了,自己扩展几何网络分析会遇到哪一些困难,接下来,我们就扩展一个几何网络服务,然后解决掉上述遇到的问题。

4.1 获得地图服务中的几何网络

IMapServer3 mapServer = this.serverObjectHelper.ServerObject as IMapServer3;
IMapServerDataAccess dataAccess = (IMapServerDataAccess)mapServer;
IFeatureClass featureclass = (IFeatureClass)dataAccess.GetDataSource(mapServer.DefaultMapName, 0);
IFeatureDataset ds = featureclass.FeatureDataset;
INetworkCollection2 networkCollection2 = ds as INetworkCollection2;
//获得所需要的几何网络
IGeometricNetwork geometricNetwork = networkCollection2.get_GeometricNetwork(0);

4.2 接受前台传来的数据(以点标记为例)

//定义一个点标记数据
object[] listJunctionFlags;
//读取前台传来的数据(json数组)
operationInput.TryGetArray("listJunctionFlags", out listJunctionFlags);
//我们要将json数据转换成List<IPoint>对象
List<IPoint> junctionFlags = new List<IPoint>();
foreach (JsonObject jo in listJunctionFlags.Cast<JsonObject>().ToArray())
{
                IPoint location = Conversion.ToGeometry(jo, esriGeometryType.esriGeometryPoint) as IPoint;
                junctionFlags.Add(location);
}

4.3 自定义IPointToEID所具备的功能


/*
searchTolerance:搜索容差
point:搜索的点,也就是上面我们转换得到的 List<IPoint> junctionFlags
elementType:搜索的类型,(搜索节点,还是搜索线)
geometricNetwork:搜索哪一个网络?
EID:搜索得到的节点id
geometry:搜索得到的几何形状
*/
public void GetEIDFromPoint(double searchTolerance, IPoint point, esriElementType elementType, IGeometricNetwork geometricNetwork, out int EID, out IGeometry geometry)
        {
            EID = -1;
            geometry = null;
            IEnumFeatureClass enumFeatureClassSimple = null;
            IEnumFeatureClass enumFeatureClassComlex = null;
            if (elementType == esriElementType.esriETEdge)
            {
                enumFeatureClassSimple = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTSimpleEdge);
                enumFeatureClassComlex = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTComplexEdge);
            }
            else if (elementType == esriElementType.esriETJunction)
            {
                enumFeatureClassSimple = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTSimpleJunction);
                enumFeatureClassComlex = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTComplexJunction);
            }
            double distance = double.PositiveInfinity;
            int featureClassID = -1;
            FindNearestDistance(enumFeatureClassSimple, point, searchTolerance, ref distance, ref featureClassID, ref geometry);
            FindNearestDistance(enumFeatureClassComlex, point, searchTolerance, ref distance, ref featureClassID, ref geometry);
            if (featureClassID == -1)
            {
                EID = -1;
                return;
            }
            IProximityOperator proximityPoint = geometry as IProximityOperator;
            IPoint p = proximityPoint.ReturnNearestPoint(point, esriSegmentExtension.esriNoExtension);
            if (elementType == esriElementType.esriETEdge)
            {
                EID = geometricNetwork.get_EdgeElement(p);
                return;
            }
            else if (elementType == esriElementType.esriETJunction)
            {
                EID = geometricNetwork.get_JunctionElement(p);
                return;
            }

            return;
        }
        private void FindNearestDistance(IEnumFeatureClass enumFeatureClass, IPoint point, double searchTolerance, ref double distance, ref int featureClassID, ref IGeometry featureGeometry)
        {
            enumFeatureClass.Reset();
            IFeatureClass featureClass = enumFeatureClass.Next();
            while (featureClass != null)
            {
                string shapeFieldName = featureClass.ShapeFieldName;
                ITopologicalOperator topologicalOperator = point as ITopologicalOperator;
                ISpatialFilter spatialFilter = new SpatialFilterClass();
                spatialFilter.Geometry = topologicalOperator.Buffer(searchTolerance);
                spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                spatialFilter.GeometryField = shapeFieldName;

                IFeatureCursor featureCursor = featureClass.Search(spatialFilter, true);
                IFeature feature = featureCursor.NextFeature();
                while (feature != null)
                {
                   IProximityOperator proximityOperator = feature.ShapeCopy as IProximityOperator;
                   double distanceCurrent = proximityOperator.ReturnDistance(point);
                   if (distance > distanceCurrent)
                   {
                     distance = distanceCurrent;
                     featureClassID = featureClass.FeatureClassID;
                     featureGeometry = feature.ShapeCopy;
                   }

                   feature = featureCursor.NextFeature();
                }             
                featureClass = enumFeatureClass.Next();
            }
        }

4.4 使用自定义的方法得到点标记id

			int eid;
            IGeometry geo;
            //points 是我们在4.2中转换得到的List<IPoint>对象
            for (int i = 0; i < points.Count; i++)
            {
                GetEIDFromPoint(tol, points[i], esriElementType.esriETJunction, this.geometricNetwork, out eid, out geo);
                if (geo != null)
                {
                    INetElements netElements = geometricNetwork.Network as INetElements;
                    int userClassID = 0;
                    int userID = 0;
                    int userSubID = 0;
                    netElements.QueryIDs(eid, esriElementType.esriETJunction, out userClassID, out userID, out userSubID);
                    INetFlag junctionFlag = new JunctionFlagClass() as INetFlag;
                    junctionFlag.UserClassID = userClassID;
                    junctionFlag.UserID = userID;
                     //jFlags类型为List<IJunctionFlag>,是我们分析真正用到的节点id
                    jFlags.Add(junctionFlag as IJunctionFlag);
                }

            }

4.5 设置网络的各种参数

//几何网络分析的具体接口
traceFlowSolverGEN = new TraceFlowSolverClass();
netSolver = traceFlowSolverGEN as INetSolver;
//设置几何网络
netSolver.SourceNetwork = geometricNetwork.Network;
//设置几何网络的点标记
IJunctionFlag[] arrayJunctionFlag = new IJunctionFlag[jFlags.Count];
for (int i = 0; i < listJunctionFlags.Count; i++)
     arrayJunctionFlag[i] = listJunctionFlags[i];
traceFlowSolverGEN.PutJunctionOrigins(ref arrayJunctionFlag);
//同理设置线标记,点障碍,和线障碍
//进行几何网络分析(以公共祖先为例)
//junctionEIDs是分析结果的 节点id
//edgeEIDs是分析结果的 线id
traceFlowSolverGEN.FindCommonAncestors(esriFlowElements.esriFEJunctionsAndEdges,
                        out junctionEIDs, out edgeEIDs);

4.6 将分析的结果转换成json字符串

INetElements netElements = geometricNetwork.Network as INetElements;
int userClassID = -1;
int userID = -1;
int userSubID = -1;
int eid = -1;
IFeature feature;
IFeatureClass featureClass = null;
objectJson = new JsonObject();
//没有查找到线
if (edgeEIDs.Count == 0)
{
        objectJson.AddArray("edges", (new List<JsonObject>()).ToArray());
}
else
{
		//如果有查询到线,将线的geometry和属性封装成json对象
        JsonObject[] featureSet = new JsonObject[edgeEIDs.Count];
        for (int i = 0; i < edgeEIDs.Count; i++)
        {
               eid = edgeEIDs.Next();
               netElements.QueryIDs(eid, esriElementType.esriETEdge, out userClassID, out userID, out userSubID);
               featureClass = GetFeatureClassByUserID(userClassID);
               if (featureClass != null)
               {
                      feature = featureClass.GetFeature(userID);
                      featureSet[i] = new JsonObject();
                      featureSet[i].AddJsonObject("geometry", Conversion.ToJsonObject(feature.Shape));
                      JsonObject[] arr = new JsonObject[feature.Fields.FieldCount];
                      for (int j = 0; j < feature.Fields.FieldCount; j++)
                      {
                             IField field=feature.Fields.Field[j];
				             arr[j] = new JsonObject();
			                 arr[j].AddObject(field.AliasName, feature.get_Value(j));
					  }
                                featureSet[i].AddArray("attr",arr);

               }
         }
         objectJson.AddArray("edges", featureSet);
}
//没有查找到点
if (junctionEIDs.Count == 0)
{
       objectJson.AddArray("junctions", (new List<JsonObject>()).ToArray());
}
else
{
		  //如果有查询到点,将点的geometry和属性封装成json对象
          JsonObject[] featureSet = new JsonObject[junctionEIDs.Count];
          for (int i = 0; i < junctionEIDs.Count; i++)
          {
            eid = junctionEIDs.Next();
            netElements.QueryIDs(eid, esriElementType.esriETJunction, out userClassID, out userID, out userSubID);
            featureClass = GetFeatureClassByUserID(userClassID);
            if (featureClass != null)
            {
              feature = featureClass.GetFeature(userID);
              featureSet[i] = new JsonObject();
                            featureSet[i].AddJsonObject("geometry", Conversion.ToJsonObject(feature.Shape));
              JsonObject[] arr = new JsonObject[feature.Fields.FieldCount];
              for (int j = 0; j < feature.Fields.FieldCount; j++)
              {
                  IField field = feature.Fields.Field[j];
                  arr[j] = new JsonObject();
	              arr[j].AddObject(field.AliasName, feature.get_Value(j));
              }
              featureSet[i].AddArray("attr", arr);

           }
       }
       objectJson.AddArray("junctions", featureSet);
}
//GetFeatureClassByUserID方法
private IFeatureClass GetFeatureClassByUserID(int userClassID)
{
     IMapServer3 serverObject = this.serverObjectHelper.ServerObject as IMapServer3;
     IMapLayerInfos mapLayerInfos = serverObject.GetServerInfo(serverObject.DefaultMapName).MapLayerInfos;

     for (int i = 0; i < mapLayerInfos.Count; i++)
     {
          IMapLayerInfo mapLayerInfo = mapLayerInfos.get_Element(i);
          if (mapLayerInfo.IsFeatureLayer)
          {
              IFeatureClass featureClass = this.GetFeatureClass(mapLayerInfo.ID);
              if (featureClass.FeatureClassID == userClassID)
                  return featureClass;
          }
     }
     return null;
}

4.7 将结果返回给客户端

return Encoding.UTF8.GetBytes(objectJson.ToJson());

4.8 运行结果

这里写图片描述

5.数据及代码下载地址

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值