Geoprocessor工具是ArcGIS进行数据处理与空间分析的利器。通过Geoprocessor框架我们可以很方便的将许多空间分析功能或者是自定义的业务处理流程以GP服务的形式实现在线处理与分享。与其他APIs中调用GP服务类似,ArcGIS Runtime for iOS中AGSGeoprocessor使用与Tasks使用方式相同,它需要包含的协议是AGSGeoprocessorDelegate。GP服务的调用分为同步方式和异步方式,具体调用方式应该和GP服务发布的方式或GP服务支持的操作方式对应。下面我将通过同步方式调用GP服务来实现空间人口分布的查询,向大家介绍Geoprocessor使用的一般流程。
同样,我们首先来新建一个支持ArcGIS的工程,然后添加AGSGeoprocessorDelegate协议以及相应的属性。这里我希望通过在地图上点击,首先通过GeometryServices生成一个多边形,然后用多边形作为Geoprocessor的输入参数,来查询当前范围内的人口情况,对于服务的参数与返回值情况,大家可以通过服务地址去查看。回顾下,我们这里添加的三个协议在之前的教程里都已经使用过了,AGSMapViewTouchDelegate协议实现地图点击的委托处理;AGSGeometryServiceTaskDelegate实现GeometryServiceTask的委托处理;具体的操作这里不再赘述。
这里介绍下给控件动态绑定操作的方法,类似与flex等绑定监听事件,之前,我们常用拖拽连线的形式,两者其实是等效的。
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically
.......................
self.mapView.touchDelegate=self;
[self.distance addTarget:self action:@selector(changeValue:) forControlEvents: UIControlEventValueChanged]; } -(void)changeValue:(id)sender {
//拖动改变缓冲半径 self.showDis.text=[NSString stringWithFormat:@"Distance:%0.0f",[self.distance value]]; }
另外,跟大家分享下使用GeometryEngine和GeometryService进行buffer的结果类型是有区别的。前者返回类型是AGSMutablePolygon,后者是AGSPolygon,在有些GP服务调用的参数类型并不支持AGSMutablePolygon,希望大家在使用时注意,以下是输出结果。
GeometryEngine geometry is :geometry: AGSMutablePolygon: [envelope: AGSEnvelope: xmin = 12983839.390300, ymin = 4875893.536200, xmax = 12985839.390300, ymax = 4877893.536200, spatial reference: [AGSSpatialReference: wkid = 102100, wkt = null]], symbol: <AGSSimpleFillSymbol: 0xb079ba0>, attributes: (null), visible: 1
GeomertyService geometry is geometry: AGSPolygon: [envelope: AGSEnvelope: xmin = 12974839.514609, ymin = 4866894.033494, xmax = 12994839.265942, ymax = 4886893.536163, spatial reference: [AGSSpatialReference: wkid = 102100, wkt = null]], symbol: <AGSSimpleFillSymbol: 0x9a66580>, attributes: (null), visible: 1
接着来看Geoprocessor,我们在GeometryService成功返回后继续将放回要素作为GP服务调用的输入参数
-(void)geometryServiceTask:(AGSGeometryServiceTask *)geometryServiceTask operation:(NSOperation *)op didReturnBufferedGeometries:(NSArray *)bufferedGeometries { //定义多边形要素的渲染样式 AGSSimpleFillSymbol *outerSymbol = [AGSSimpleFillSymbol simpleFillSymbol]; outerSymbol.color = [[UIColor yellowColor] colorWithAlphaComponent:0.25]; outerSymbol.outline.color = [UIColor darkGrayColor]; AGSGraphic *graphic=nil; for (AGSGeometry* g in bufferedGeometries) {
// initialize the graphic for geometry graphic= [[AGSGraphic alloc] initWithGeometry:g symbol:nil attributes:nil infoTemplateDelegate:nil]; graphic.symbol = outerSymbol; [self.graphicsLayer addGraphic:graphic]; //NSLog(@"gr is %@",graphic); [graphic release]; } [self.graphicsLayer dataChanged];
//以当前返回要素的区域对地图进行缩放 AGSMutableEnvelope *newEnv =[AGSMutableEnvelope envelopeWithXmin:graphic.geometry.envelope.xmin ymin:graphic.geometry.envelope.ymin xmax:graphic.geometry.envelope.xmax ymax:graphic.geometry.envelope.ymax spatialReference:self.mapView.spatialReference]; [newEnv expandByFactor:2.8]; [self.mapView zoomToEnvelope:newEnv animated:YES]; //Geoprocessor
//初始化Geoprocessor self.agp=[AGSGeoprocessor geoprocessorWithURL:[NSURL URLWithString:kGPurl]]; self.agp.delegate=self; self.agp.interval=10; self.agp.processSpatialReference=self.mapView.spatialReference; self.agp.outputSpatialReference=self.mapView.spatialReference; AGSFeatureSet *fs=[[[AGSFeatureSet alloc]init]autorelease]; fs.features=[NSArray arrayWithObjects:graphic, nil];
//创建调用GP服务的相应参数,其参数个数和类型(type)应该与GP服务的要求相对应
AGSGPParameterValue *param=[AGSGPParameterValue parameterWithName:@"inputPoly" type:AGSGPParameterTypeFeatureRecordSetLayer value:fs]; NSArray *params=[NSArray arrayWithObjects:param,nil ];
//使用同步方式调用GP服务
[self.agp executeWithParameters:params]; }
与其他Task使用方式相类似,接下来,我们需要实现AGSGeoprocessorDelegate协议中对GP服务调用的相应处理函数
-(void)geoprocessor:(AGSGeoprocessor *)geoprocessor operation:(NSOperation *)op didExecuteWithResults:(NSArray *)results messages:(NSArray *)messages { //成功执行Geoprocessor返回结果时数组类型的results,我们来进行相应处理 if (results!=nil && [results count]>0) {
//返回值数组包含的时AGSGParameterValue类型的对象,具体大家可以参考SDK自带帮助,很全面哦 AGSGPParameterValue *result=[results objectAtIndex:0]; AGSFeatureSet *resultFS= result.value; for (AGSGraphic *resultgr in resultFS.features) { NSDictionary *attr=resultgr.attributes; NSString *peo=[NSString stringWithFormat:@"%@",[attr objectForKey:@"SUM"]]; NSArray *peoArr=[peo componentsSeparatedByString:@"."]; NSLog(@"this is %@",peoArr[0]);
//输出要素的所有属性 for(id key in attr) { NSLog(@"key: %@,value: %@",key,[attr objectForKey:key]); } //将结果弹出显示 UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Geoprocessor Result" message:[NSString stringWithFormat:@"当前范围大约有%@人!", peoArr[0]] delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; [av show]; [av release]; } } }
同时,实现Geoprocessor执行出错的提示
-(void)geoprocessor:(AGSGeoprocessor *)geoprocessor operation:(NSOperation *)op didFailExecuteWithError:(NSError *)error { UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease]; [alert show]; }
运行程序,结果如图
以上就是同步方式执行Geoprocessor的使用流程,那么对于异步方式执行Geoprocessor使用思路与同步方式完全相同,除了调用方法和对应的结果处理
异步方式:[self.gpTask submitJobWithParameters:params]; 同步方式:[self.agp executeWithParameters:params];
对于调用结果的处理大家可以参考SDK中AGSGeoprocessorDelegate协议的相应方法
总结:本讲主要通过同步方式调用GP服务实现当前要素范围内人口分布状况查询,对于异步方式与同步类似,大家可以参考帮助。如果大家已经熟悉基于协议的代理模式实现相应操作的方式,那么也就熟悉了ArcGIS Runtime for iOS使用的基本流程。下一讲我将给大家介绍网络分析相关的操作,欢迎大家继续关注!