2011年3月27日星期日

ArcGIS API for Windows Phone开发实例(5):对超市信息进行空间查询

  本文内容:ArcGIS API中Task的概念,QueryTask的使用,以及Draw对象。
  空间查询GIS中一个非常常用的功能:在地图上画出任意多边形,从自己感兴趣的事物中筛选出与所画多边形有指定空间关系(通常是相交)的要素来,进一步查看。在本次开发实例中,第二个功能就是空间查询。用手势在地图上画一个范围,筛选出落入该范围的超市店面,从而进一步查看它们的营业额统计信息。
  ArcGIS API中,给我们提供了许多Task类,来完成一些常见的GIS功能,比如属性/控件查询,几何对象的拓扑处理,特定工作流的地理任务等。它们都是已经封装好的Task类,使用起来都遵循3个步骤的原则:1、为某个Task设置所需的相应参数;2、通过Task对象向服务器发送处理请求;3、接受服务器端返回的结果。所有的计算和处理工作都是由ArcGIS Server发布的REST服务来完成,是典型的客户端请求,服务器端相应的流程。
  QueryTask是ArcGIS API提供的诸多Task之一,它接受Query类型的参数。该参数有几个常用的属性,比如Where属性和Geometry属性,通过对这两个属性的设置,我们就可以完成最常见的属性查询和空间查询功能。依然将空间查询这个功能封装成一个工具,在主界面中进行调用。

clip_image002

  这里为了清晰起见,我省去与空间查询功能无关的代码(所有程序代码会在教程完结后提供下载)。要使用QueryTask的功能,我们按照前面说三个步骤来做。首先设置好查询参数Query,然后通过QueryTask对象提交查询请求:

   1: void _draw_DrawComplete(object sender, DrawEventArgs e)
   2:         {
   3:             Polygon polygon = null;
   4:             if (_usingFreeHand) //geometry is freehand polyline
   5:             {
   6:                 Polyline polyline = e.Geometry as Polyline;
   7:                 ESRI.ArcGIS.Client.Geometry.PointCollection pc = polyline.Paths[0];
   8:                 pc.Add(pc[0]);
   9:                 polygon = new Polygon()
  10:                 {
  11:                     SpatialReference = map1.SpatialReference,
  12:                 };
  13:                 polygon.Rings.Add(pc);
  14:             }
  15:             else //geometry is polygon
  16:             {
  17:                 polygon = e.Geometry as Polygon;
  18:             }
  19:  
  20:             _GLayer.Graphics.Clear();
  21:             Graphic g = new Graphic()
  22:             {
  23:                 Geometry = polygon,
  24:                 Symbol = new SimpleFillSymbol()
  25:                 {
  26:                     Fill=new SolidColorBrush(Color.FromArgb(33,255,0,0)),
  27:                     BorderBrush=new SolidColorBrush(Colors.Red),
  28:                     BorderThickness=2
  29:                 }
  30:             };
  31:             _GLayer.Graphics.Add(g); //display the geometry created by Draw object
  32:  
  33:             QueryTask queryTask = new QueryTask(App.Current.Resources["BusinessLayer"] as string);
  34:             Query query = new Query();
  35:             //102100 to 4326
  36:             ESRI.ArcGIS.Client.Projection.WebMercator wm = new ESRI.ArcGIS.Client.Projection.WebMercator();
  37:             query.Geometry = wm.ToGeographic(polygon);
  38:             query.OutFields.AddRange(new string[] { "*" });//return all attributes fields
  39:             query.SpatialRelationship = SpatialRelationship.esriSpatialRelIntersects;
  40:             queryTask.ExecuteCompleted += new System.EventHandler<QueryEventArgs>(queryTask_ExecuteCompleted);
  41:             queryTask.Failed += (s, a) =>
  42:             {
  43:                 MessageBox.Show("查询失败" + a.Error.Message);
  44:             };
  45:             _busyIndicator.Visibility = Visibility.Visible;
  46:             queryTask.ExecuteAsync(query);     
  47:         }

  代码中,我们首先利用超市图层的服务地址,初始化了一个QueryTask对象。对于Query参数,这里设置了Geometry属性,作为空间查询的图形;对OutFields参数的设置表示在查询结果中返回所有属性字段;指定空间关系为与Geometry相交。然后通过ExecuteAsync方法将查询请求提交到服务器端。注意到在设置Query的Geometry属性之前,我们对Polygon对象做了空间参考的转换,将其从102100坐标系(WGS 1984 Web Mercator Auxiliary Sphere,这是地图控件的坐标系)转换到了4326坐标系(WGS 1984,这是超市图层的坐标系),如果Query中Geometry的坐标系不正确,查询结果往往会不可预料。
  发出请求后,我们就可以在设置好的queryTask_ExecuteCompleted方法中取得查询结果了。



   1: void queryTask_ExecuteCompleted(object sender, QueryEventArgs e)
   2:         {
   3:             _busyIndicator.Visibility = Visibility.Collapsed;
   4:             if (e.FeatureSet.Features.Count == 0) //typeof(e.FeatureSet.Features)==GraphicCollection
   5:             {
   6:                 MessageBox.Show("未选中任何店面");
   7:             }
   8:             else
   9:             {
  10:                 string str = "是否查看图表详情?";
  11:                 if (MessageBox.Show(str,
  12:                 "查询结果", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
  13:                 {
  14:                     //add selected graphics to app level, so spatialquerychart.xaml could retrieve them
  15:                     App app = Application.Current as App;
  16:                     if (app.AppParameters.ContainsKey("QueryedGraphics"))
  17:                         app.AppParameters["QueryedGraphics"] = e.FeatureSet.Features;
  18:                     else
  19:                         app.AppParameters.Add("QueryedGraphics", e.FeatureSet.Features);
  20:  
  21:                     (app.AppParameters["MainPage"] as PhoneApplicationPage).NavigationService.Navigate(new Uri("/Tools/SpatialQueryChart.xaml", UriKind.Relative));
  22:                 }
  23:                 _GLayer.ClearGraphics();
  24:             }
  25:         }


  可以看到,查询结果(落入所选范围内的超市)以Graphic的形式存储在事件参数中。Graphic的Geometry就是超市的图形信息,而Attributes属性中是我们想要的所有营业信息。如果查询结果不为空,我们将其存入全局变量中,以便在另一个页面中用图表的形式来显示。这里我们使用VisiFire控件来显示图表,它是一套可用于WP上的Silverlight插件,此处不进行过多讨论,有兴趣同学可自己搜索。
  整个查询的过程在QueryTask的帮助下变得非常简单。细心的朋友可能会有疑问,我们这个空间查询的图形是如何得到的?在前面的代码中可以看到,发起查询请求的代码是写在_draw_DrawComplete这个事件中的。_draw是我们提前定义好的一个Draw对象:private Draw _draw;。
  为了方便与用户的交互,ArcGIS API中提供了Draw这个类,可以利用鼠标或手势来交互地画出Point,Polyline,Polygon,Freehand(Polyline)等几何对象,在2.2版本的API中,Draw还新增了arrow,triangle,circle,ellipses几个原生图形。

clip_image002

  使用Draw这个对象也比较简单,初始化,设定好要画的几何图形类型,然后将其IsEnabled属性设为True,就进入了交互状态,绘制完毕后,就会触发DrawComplete事件,在事件的参数中就可以得到画出的Geometry结果,得到结果之后,就可以利用Graphic将这个看不见摸不着的Geometry显示出来了,这样就达到了交互的目的。我们空间查询的几何对象就是利用Draw得到的。

clip_image004

clip_image006

参考资料:

ArcGIS API中各种Task介绍:
http://bbs.esrichina-bj.cn/ESRI/thread-45302-1-1.html

Draw对象的使用:
http://help.arcgis.com/en/arcgismobile/10.0/apis/WindowsPhone/help/011v/011v00000019000000.htm

QueryTask的使用:
http://help.arcgis.com/en/arcgismobile/10.0/apis/WindowsPhone/help/011v/011v00000016000000.htm

VisiFire:
http://www.visifire.com/

没有评论:

发表评论