zoukankan      html  css  js  c++  java
  • Silverlight调用GP服务第二篇之调用GP服务(Geoprocessing Service)过程详解

     

    Silverlight调用GP服务详解

    上一篇主要讲了如何发布GP服来绘制等值线及等直面,这里主要将如何通过Silverlight来调用GP服务。

    这里先写一下具体的调用过程:

    1. 声明GP服务变量(Geoprocessor),并实例化
    2. 注册GP服务任务完成事件及失败事件
    3. 根据发布的GP服务,定义GP服务的参数
    4. 输入GP服务参数请求GP服务
    5. 获取结果:在Compeleted事件函数中完成获取结果的代码,对于是要素类结果,需要注册GetResultDataCompleted事件,对于是栅格数据结果需要注册GetResultImageLayerCompleted事件,然后在事件的回调函数中完成最终结果的获取。

    这里需要注意的问题:

    a.  GP服务是同步调用还是异步调用

    b.  获得结果的坐标系是否和当前一致

    c.  GP服务的输入参数必须和发布的GP服务一致(之后会详细说明)

    d.  获取结果的名称必须和发布的GP服务一致(之后会详细讲到)

    以上大致的说了一下GP服务调用的基本过程,下面就开始正式的工作吧。

    一.基本界面

    首先我们构建一个简单的Web界面,如下图所示:

     

       这里需要实现的基本功能是:可以保存每一次添加的Graphic(xml格式),并能够再次读取这些Graphic.根据加载的Graphic实现基本的预测,即调用GP服务。

    说明:为了节省时间,这里我已将用到的点的数据保存成了一个xml文档,所有需要的数据都从xml中读取。

     二.加载xml格式的Graphic信息

         这里就是遍历xml中所有Graphic节点,然后读取相应的信息(节点的名称根据我们保存xml时定义的不同而不同,后面会给出保存xml的代码)。读取xml信息的代码如下:

    View Code
     1  //打开加载数据对话框
     2             OpenFileDialog openFileDialog = new OpenFileDialog();
     3             //指定xml问价格式
     4             openFileDialog.Filter = "XML Files(*.xml)|*.xml";
     5             if (openFileDialog.ShowDialog() == true)
     6             {
     7                 using (Stream stream = openFileDialog.File.OpenRead())
     8                 {
     9                     XDocument doc = XDocument.Load(stream);
    10                     //遍历xml中的Graphic节点
    11                     foreach (XElement element in doc.Descendants("Graphic"))
    12                     {
    13                         //遍历Graphic节点下的Location节点
    14                         foreach (XElement LocationElement in element.Descendants("Location"))
    15                         {
    16                             //获得Location节点下的坐标
    17                             double LocationX = Convert.ToDouble(LocationElement.Element("LocationX").Value);
    18                             double LocationY = Convert.ToDouble(LocationElement.Element("LocationY").Value);
    19                             //获得Graphic节点下的浓度值
    20                             double PollutionC = Convert.ToDouble(element.Element("PolutionC").Value);
    21                             //绘制Graphic
    22                             CreatGraphic(LocationX, LocationY, PollutionC);
    23                         }
    24                     }
    25                 }
    26             }

         CreatGraphic方法表示在地图上根据获得的坐标和浓度值绘制出一个点。

    View Code
    //定义一个图层,所以的Graphic将在此图层上绘制
    private GraphicsLayer graphicsLayer = null;
    
    private void CreatGraphic(double locationx, double locationy, double pollutionc)
            {
                //构建一个Graphic,并定义其样式
                Graphic g = new Graphic()
                {
                    Geometry = new MapPoint()
                    {
                    X=locationx,
                    Y=locationy,
                    SpatialReference=map.SpatialReference
                    },
                    Symbol = new SimpleMarkerSymbol()
                    {
                        Size = 9,
                        Color = new SolidColorBrush(Colors.Blue),
                        Style = SimpleMarkerSymbol.SimpleMarkerStyle.Circle
                    },
                };
                
                if (map.Layers["GraphicsPoints"] == null)
                {
                    graphicsLayer = new GraphicsLayer()
                    {
                        ID = "GraphicsPoints"
                    };
                    map.Layers.Add(graphicsLayer);
                }
                //添加浓度属性
                g.Attributes.Add("PolutionC", pollutionc);
                //
                graphicsLayer.Graphics.Add(g);
            }

    三.保存xml格式的Graphic信息

         这里我们将GraphicLayer上所有的点的信息保存成xml格式。需要注意的是,xml中节点名称必须和读取xml文件时使用的节点名保持一致。否则之后我们无法读取我们保存的信息。具体代码如下:

    View Code
     1  //若要素图层不存在则返回
     2             if (map.Layers["GraphicsPoints"] == null)
     3                 return;
     4             //若图层要素为空也返回
     5             GraphicsLayer graphicslayer = map.Layers["GraphicsPoints"] as GraphicsLayer;
     6             if (graphicslayer.Graphics.Count <= 0)
     7                 return;
     8             //打开保存对话框
     9             SaveFileDialog saveFileDialog = new SaveFileDialog();
    10             //指定xml文件格栅
    11             saveFileDialog.DefaultExt = "xml";
    12             saveFileDialog.Filter = "XML Files (*.xml)|*.xml";
    13             //指定默认的文件名为当前的时间
    14             saveFileDialog.DefaultFileName = string.Format("GraphicInfo{0}", GetCurrentDateTimeString());
    15 
    16             if (saveFileDialog.ShowDialog() == true)
    17             {
    18                 using (Stream stream = saveFileDialog.OpenFile())
    19                 {
    20                     StreamWriter streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
    21                     int GraphicNum = 1;
    22 
    23                     foreach (Graphic g in graphicslayer.Graphics)
    24                     {
    25                         //调用自定义GetGeneratedXML方法,构建xml
    26                         GetGeneratedXML(GraphicNum, g);
    27                         GraphicNum++;
    28                     }
    29                     streamWriter.Write(doc.ToString());
    30                     streamWriter.Close();
    31                     stream.Close();
    32                 }
    33             }

     GetGeneratedXML方法代码如下:

    View Code
     1  private void GetGeneratedXML(int graphicID, Graphic g)
     2         {
     3             MapPoint mapPoint = g.Geometry as MapPoint;
     4             XElement graphic = new XElement("Graphic", new XAttribute("ID", graphicID),
     5                 new XElement("Location",
     6                 new XElement("LocationX", mapPoint.X),
     7                 new XElement("LocationY", mapPoint.Y)),
     8                 new XElement("PolutionC", Convert.ToDouble(g.Attributes["PolutionC"])));
     9             doc.Root.Add(graphic);
    10         }

    GetCurrentDateTimeString方法如下:

    View Code
     1   private string GetCurrentDateTimeString()
     2         {
     3             string TimeString;
     4             DateTime CurrentTime = new DateTime();
     5             CurrentTime = System.DateTime.Now;
     6             int year = CurrentTime.Year;
     7             int month = CurrentTime.Month;
     8             int day = CurrentTime.Day;
     9             int hour = CurrentTime.Hour;
    10             int minute = CurrentTime.Minute;
    11             int second = CurrentTime.Second;
    12             TimeString = string.Format("{0}{1}{2}{3}{4}{5}", year, month, day, hour, minute, second);
    13             return TimeString;
    14         }

    四.根据添加的点,进行预测及可视化表达(绘制等值线及等值面)

           到这里为止,才算是真正开始我们的GP服务。具体的调用过程在开始的时候作了一个大致的介绍,下面开始详细的讲解。

    4.1 定义GP服务变量

    View Code
    1  //定义GP服务变量
    2         private Geoprocessor InterpolationTask = null;//绘制等值面
    3         private Geoprocessor ContourTask = null;//绘制等值线

    并且实例化GP服务变量,并注册相应的事件

    View Code
     1             //等值线GP服务
     2             ContourTask = new Geoprocessor("http://qzj-pc/ArcGIS/rest/services/ContourService_with_Focal_Statistics/GPServer/ContourService");
     3             ContourTask.JobCompleted += new EventHandler<JobInfoEventArgs>(ContourTask_JobCompleted);
     4             ContourTask.GetResultDataCompleted += new EventHandler<GPParameterEventArgs>(ContourTask_GetResultDataCompleted);
     5             ContourTask.Failed += new EventHandler<TaskFailedEventArgs>(ContourTask_Failed);
     6             //等值面GP服务
     7             InterpolationTask = new Geoprocessor("http://qzj-pc/ArcGIS/rest/services/InterpolationService_Stretch/GPServer/InterpolationModel");
     8             InterpolationTask.JobCompleted += new EventHandler<JobInfoEventArgs>(InterpolationTask_JobCompleted);
     9             InterpolationTask.GetResultImageLayerCompleted += new EventHandler<GetResultImageLayerEventArgs>(InterpolationTask_GetResultImageLayerCompleted);
    10             InterpolationTask.Failed += new EventHandler<TaskFailedEventArgs>(InterpolationTask_Failed);

    4.2 定义GP服务的请求参数
     这里需要的参数必须和我们发布的GP服务一致。我们打开绘制等值线的GP服务链接,基本参数如下所示:

     以上是绘制等值面的GP服务参数列表,并给出了参数信息的详细说明,这里我们可以看出绘制等值面的GP服务只有一个输入参数:PollutionPoints,类型是GPFeatureRecordSetLayer,也就是要素集。同时只有一个输出参数:RasterData,类型是GPRasterDataLayer,即栅格数据。

    下面我们定义绘制等值面的GP服务参数。

     1  //添加这段代码,非常有用,否则将无法获取GP服务的结果
     2             HttpWebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
     3             //将从xml中解析出来的点构建成要素集,并作为我们GP服务输入的参数
     4             FeatureSet featureSet = new FeatureSet(graphicsLayer.Graphics);
     5             //定义GP服务参数:InterpolationJobParameter
     6             List<GPParameter>InterpolationJobParameter = new List<GPParameter>();
     7             //添加GP服务参数
     8             InterpolationJobParameter.Add(new GPFeatureRecordSetLayer("PollutionPoints", featureSet));
     9             //请求等直面GP服务
    10             InterpolationTask.SubmitJobAsync(InterpolationJobParameter);

    注意这里的PollutionPoints,这里的名称必须和之前我们发布的GP服务参数列表一致。而且还需要注意这里的GP服务参数类型,必须是要素集。
    同理,我们可以看看绘制等值线的GP服务参数列表,如下图所示:

     后台定义的绘制等值线的GP服务参数代码:

     1 //定义绘制等值线的GP服务参数
     2             List<GPParameter> ContourJobParameter = new List<GPParameter>();
     3             //添加要素集参数
     4             ContourJobParameter.Add(new GPFeatureRecordSetLayer("PollutionPoints", featureSet));
     5             //添加等值线间距参数
     6             ContourJobParameter.Add(new GPDouble("Contour_interval", 4.0001));
     7             //添加容差设置参数
     8             ContourJobParameter.Add(new GPLinearUnit("XY_Tolerance", esriUnits.esriMeters, 1));
     9             //请求等值线GP服务
    10             ContourTask.SubmitJobAsync(ContourJobParameter);

    注意上面的GP服务参数名称必须保持一致。


    五.获取GP服务的结果,并在地图上显示

         之前说过,请求GP服务结果都会有一个Completed事件,所以我们获取结果的代码将在该事件回调函数中完成。之前我们已注册了GP事件,其回调函数如下:

    下面我们就开始获取等值面的结果。

    在请求等值面GP服务的完成事件中添加如下代码:

     1  private void InterpolationTask_JobCompleted(object sender, JobInfoEventArgs e)
     2         {
     3             
     4             if (e.JobInfo.JobStatus == esriJobStatus.esriJobFailed)
     5             {
     6                 MessageBox.Show("请求服务失败!" + e.JobInfo.Messages.ToString());
     7                 return;
     8             }
     9             HttpWebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
    10            //获取GP服务结果,这里需要注意的是结果的名称必须和我们发布的GP服务参数列表一致
    11             InterpolationTask.GetResultImageLayerAsync(e.JobInfo.JobId, "RasterData");
    12         }

    注意这里的RasterData必须和之前我们发布的GP服务输出参数名称一致,否则将无法获取到结果。
    这里我们注意到,GetResultImageLayerAsync也是一个异步请求,因此我们需要在其完成事件的回调函数中获得最终的结果,之前我们已经注册了其完成的事件函数,现在添加如下代码:

     1  private void InterpolationTask_GetResultImageLayerCompleted(object sender, GetResultImageLayerEventArgs e)
     2         {
     3             //返回的结果实际上是一张图片
     4             GPResultImageLayer imagelayer = e.GPResultImageLayer;
     5            //定义图层的ID
     6             imagelayer.ID = "InterpolationLayer";
     7            //设置透明度
     8             imagelayer.Opacity = 0.7;
     9            //清空原有的结果
    10             if (map.Layers["InterpolationLayer"] != null)
    11             {
    12                 map.Layers.Remove(map.Layers["Interpolation"]);
    13             }
    14            //添加当前结果到图层中
    15             map.Layers.Add(imagelayer);
    16             MessageBox.Show("绘制完成!");
    17         }

    这里说明一点:由于栅格数据不支持在Web客户端直接读取,因此我们通过结果地图服务,将其在服务器端根据我们设置的渲染格式,生成一张图片。然后在客户端实际上是获取这张图片,而不是栅格数据,当客户端的地图范围发生改变时(移动,缩放),就会在服务器端动态的生成响应的图片,并在Web客户端显示其相应的结果。

    最后,你还可以在Failed事件中添加GP服务请求失败时的相应处理。

      private void InterpolationTask_Failed(object sender, TaskFailedEventArgs e)
            {
                MessageBox.Show("请求服务失败:" + e.Error.ToString());
            }

    以上的过程便是获取GP绘制等直面的结果。
    下面是获得的结果:

    点击加载xml文档,打开xml文件,就会添加相应的Graphic,如下图所示:

    接着点击预测,结果如下:

    接下来,我们看看如何获取等值线的结果。其过程和等值面的获取相似,只不过等值线的结果是线要素,而等值面则是一张图片,两则在获取和显示上有一点点的差别。

    下面是绘制等值线GP请求的Completed事件响应函数代码,和等值面的差不多,唯一不同的就是异步请求的函数,以及阐述不一样。

     1  private void ContourTask_JobCompleted(object sender, JobInfoEventArgs e)
     2         {
     3             if (e.JobInfo.JobStatus == esriJobStatus.esriJobFailed)
     4             {
     5                 MessageBox.Show("请求等值线服务失败:" + e.JobInfo.Messages);
     6                 return;
     7             }
     8             HttpWebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
     9            //请求绘制等值线GP服务,注意这里和等值面的异步请求函数不一样
    10             ContourTask.GetResultDataAsync(e.JobInfo.JobId, "ContourLine_shp");
    11         }

    同样需要注意请求结果的参数必须和发布的等值线GP服务输出参数名称一致。
    然后我们在GetResultDataCompleted事件响应函数中添加相应的代码获取结果,并在地图上显示出来。代码如下:

     1 private void ContourTask_GetResultDataCompleted(object sender, GPParameterEventArgs e)
     2         {
     3             if (map.Layers["ContourLayer"] != null)
     4             {
     5                 map.Layers.Remove(map.Layers["ContourLayer"]);
     6             }
     7             GraphicsLayer contourLayer = new GraphicsLayer() { 
     8             ID="ContourLayer"
     9             };
    10             
    11             GPFeatureRecordSetLayer featureSetLayer = e.Parameter as GPFeatureRecordSetLayer;
    12            //遍历结果获取其中包含的要素,并添加到等值线图层中
    13             foreach (Graphic graphic in featureSetLayer.FeatureSet.Features)
    14             {
    15                 //设置等值线的样式
    16                 graphic.Symbol = new SimpleLineSymbol()
    17                 {
    18                     Style = SimpleLineSymbol.LineStyle.Solid,
    19                     Color = new SolidColorBrush(Colors.Blue),
    20                     Width = 3
    21                 };
    22                 contourLayer.Graphics.Add(graphic);
    23             }
    24             //将结果添加到当前的地图中
    25             map.Layers.Add(contourLayer);
    26              MessageBox.Show("等值线绘制完成!");
    27         }

    同理添加GP服务请求失败处理函数:

     private void ContourTask_Failed(object sender, TaskFailedEventArgs e)
            {
                MessageBox.Show("请求等值线服务失败:" + e.Error.ToString());
            }

    这样获取等值线结果的工作已经完成,下面看一看效果:

    到此,关于Silverlight调用GP服务绘制等值线以及等值面的所有过程已经讲述完毕。

    (版权所有,转载请标明出处)

  • 相关阅读:
    Winpcap网络开发库入门
    主机字节序与网络字节序的转换
    WORD与DWORD
    TCP/IP各种数据包结构体
    解析IPV4报文 和IPV6 报文的 checksum
    TCP头校验和计算算法详解
    第九次作业:DFA最小化,语法分析初步
    第八次作业:非确定的自动机NFA确定化为DFA
    第七次:正规式、正规文法与自动机
    第六次作业:正规文法与正规式
  • 原文地址:https://www.cnblogs.com/potential/p/2752289.html
Copyright © 2011-2022 走看看