ArcGIS for iOS 开发系列(4) – 基础篇-地图组件

    在“Hello World Map”里我们已经成功加载了地图,以前没接触过GIS的同学先得补一补功课,起码要了解空间对象和数据模型的基本概念。常见的地图服务,其背后都有一个地图文档(*.mxd或*.msd),文档中有很多页(图层Layer),每页上又有许多空间要素(点、线、面)可能对应了现实世界中的水井、道路、绿地等等,同时地图文档中还保存了可见性、符号化、比例尺等很多配置信息,用于控制地图的最终呈现效果。    

    地图组件MapView是地图最基本的容器,负责地图展示和用户交互,因此AGSMapView也是最重要的类,它提供了一系列接口帮助开发者轻松叠加不同的空间数据、漫游地图、显示信息等等。

1. 加载图层

    “Hello World Map”示例中叠加了两个图层,分别是基础底图图层(切片地图服务)和人口分布地图图层(动态地图服务),添加的方法很简单,其中Name参数是Layer的唯一标示,不能重名:

//按+1顺序添加图层
[self.mapView addMapLayer:tiledLyrwithName:@"TiledLayer"];
//按指定顺序插入图层
[self.mapView insertMapLayer:tiledLyrwithName:@"TiledLayer0" atIndex: 0];
//按名称删除指定图层
[self.mapViewremoveMapLayerwithName:@"TiledLayer"];

    看得出来,MapView中图层绘制的顺序是自下而上,第一个加载的图层意义比较特殊,常称为BaseMapLayer,它将初始化整个地图容器的空间参考(Spatial reference)、初始范围(Initial extent)和全图范围(Full extent),这很关键,因为如果接下来添加的图层空间参考不同,该图层就显示不出来(动态图层除外,可以重投影),那怎么知道是否加载成功?需要引用一个重要的协议:AGSMapLayerDelegate,图层消息委托,会在下一节中详细介绍。

    目前支持的图层类型包括了:

·         切片地图服务图层(AGSTiledMapServiceLayer)

·         动态地图服务图层(AGSDynamicMapServiceLayer)

·         影像服务图层(AGSImageServiceLayer)

·         要素服务图层(AGSFeatureLayer)

·         微软Bing服务图层(AGSBingMapLayer)

·         OSM服务图层(AGSOpenStreetMapLayer)

·         WMS服务图层(AGSWMSLayer)

·         离线切片服务图层(AGSLocalTiledLayer)

·         自定义切片服务图层(OfflineTiledLayer)

·         图形图层(AGSGraphicLayer)

·         草图绘制图层(AGSSketchLayer)

    这里先了解一下ArcGIS for iOS支持的图层类型,具体都干嘛使的,下一章再详细介绍;此外还有一种新型的智能地图类型:WebMap,也会单独介绍。

2. 图层控制

    地图每添加一个图层,MapView容器里就对应添加一个子视图,如果你希望控制该图层的可见性、透明度等参数,可以自己显式声明一个UIView,让其引用AGSLayerView协议,然后控制这个UIView就行了,如下:

//获取图层视图引用
UIView<AGSLayerView> *LyrView =[self.mapViewaddMapLayer: LyrwithName:@"PopulationLayer"];
//设置图层透明度
LyrView.alpha = 0.3;
//设置图层可见性
LyrView.hidden = NO;
//操作地图的同时允许绘制数据,会增加CPU消耗,建议仅对基础地图图层使用
LyrView.drawDuringPanning = YES;
LyrView.drawDuringZooming = YES;

3. 显示范围

    地图显示范围,默认是BaseMapLayer的全图范围,预先可以构建一个AGSEnvelope对象,并直接放大到该范围:

//设定地图初始化显示范围为中国
AGSEnvelope *chinaEnv = [AGSEnvelopeenvelopeWithXmin:7800000.00
                                                    ymin:44000.00
                                                     xmax:15600000.00
                                                    ymax:7500000.00
                                         spatialReference:self.mapView.spatialReference];
[self.mapViewzoomToEnvelope:chinaEnvanimated:YES];

 *缩放到的几何区域其空间参考必须和地图一致

地图还可以按指定点进行居中显示:

//居中显示
AGSPoint *newPoint = [AGSPoint pointWithX:-93.032201 y:49.636213 spatialReference:self.mapView.spatialReference];
[self.mapView centerAtPoint:newPoint animated:NO];

    另外属性visibleArea(取代了原来的envelope返回结果是当前地图的外接矩形:

AGSPolygon* mapExtent = self.mapView.visibleArea;

    而属性MaxEnvelope可以设定地图的最大显示范围,所有操作都无能超该范围:

self.mapView.maxEnvelope = mapExtent.envelope;

4. 手势

    MapView默认会响应以下手势操作:

表3-2-1 地图支持的手势

手势

地图响应

轻划(Swipe)

平移

撑开(Pinch-Out)

放大

捏合(Pinch-In)

缩小

点击(Tap)

查看

常按(Long Press)

启用放大镜

双击(Double Tap)

放大

两点点击(Two finger Tap)

缩小

两点转动(Two finger Twist)*

旋转

*地图旋转前提是MapView的allowRotationByPinching属性为YES。

5. 图例

    一图胜千言的佳话里肯定少不了图例(MapLegend),尤其当要素类型复杂时,通过图例能简明标示关键要素,图例包括一组符号图片和对应的文字标注。

ArcGIS for iOS 开发系列(4) – 基础篇-地图组件_第1张图片

图3-2-3-1 常见的地图图例样式

   ArcGIS for iOS v1.8之后下列图层都支持获取图例信息:

·        切片地图服务图层

·        动态地图服务图层

·        要素服务图层

·        图形图层

5.1. 对于切片和动态地图服务图层:

    ArcGIS Server v10 SP1以上版本发布的切片和动态地图服务提供了图例信息,通过AGSMapServiceInfo对象的retrieveLegendInfo方法异步获取到legendLabelslegendImages

//AGSMapServiceInfoDelegate 方法
-(void) mapServiceInfo:(AGSMapServiceInfo *)mapServiceInfo operationDidRetrieveLegendInfo:(NSOperation *)op {
    //loop through all sub-layers
    NSArray* layerInfos = mapServiceInfo.layerInfos;
    for(int i=0;i<[layerInfos count];i++){
        //access legend information of each sub-layer
        AGSMapServiceLayerInfo* layerInfo = [layerInfos objectAtIndex:i];
        NSArray* legendLabels = layerInfo.legendLabels;
        NSArray* legendImages = layerInfo.legendImages;
        ...
    }
}

5.2. 对于要素和图形图层:

    成功加载了要素和图形服务,其符号和文件标注已经下载到终端,所以只需要导出简单符号或渲染色带就好:

    //导出symbol图片
    AGSSymbol* symbol = ...;
    UIImage* image = [symbol swatchForGeometryType:AGSGeometryTypePoint size:CGSizeMake(20,30)];
    //导出渲染色带
    AGSRenderer* renderer = ...;
    AGSGraphic* graphic = ...;
    UIImage* image = [renderer swatchForGraphic:graphic size:CGSizeMake(20,30)];

    目前还没有封装成拿来即用的组件,需要开发者手动填充到ViewUITableView里,稍显麻烦

6. 经向环绕

    平面地图都是从经度-180展开到180,如果你要同时浏览东西经180的数据就很不方便,因此在v1.8中新增加了经向环绕“Wrap Around”的设置,使得地图数据在东西向平移时无缝环绕:

//地图组件开启环绕
self.mapView.wrapAround = YES;

    经向环绕的原理类似与屏幕扩展:-180~180是当前屏幕0,-180再往西就是屏幕-1(-180~-540),而正180再往东就是屏幕1(180~-540)。在采集坐标时这会造成困扰,因此需要先对进行标准化(normalize),Geometry Engine里提供了该方法normalizeCentralMeridianOfGeometry。

    经向环绕的使用条件:

·        最大范围覆盖全球

·        地图空间参考是WGS 84 (WKID=4326) 或Web Mercator (WKID=102113, 102100, or 3857)

·        支持WKT关键字的动态服务(ArcGIS Server10.0以上版本发布)

7. 时态展示

    包含时间信息的地理数据在服务器端注册成“时态(Time-aware Layer)”数据后, 客户端就能展示时态,比如:24小时内飓风的推进过程、1周的气温变化过程等。支持时态的地图服务都是动态服务,包括:动态地图服务、影像服务和要素服务。

    时间范围(TimeExtent)属性,定义了显示数据的时间区间,利用它能快速过滤时态数据,范围外的数据都不会显示:

NSDate* now = [NSDate date]; 
NSDate* yesterday = ... [NSDate dateWithTimeIntervalSinceNow: -(24 * 60 * 60)]; 
//过滤显示最近1天的数据
AGSTimeExtent* extent = [[AGSTimeExtent alloc] initWithStart:now end: yesterday]; map.timeExtent = extent;
//只显示某一时间点的数据
AGSTimeExtent* extent = [[AGSTimeExtent alloc] initWithStart:now end: now]; map.timeExtent = extent;

*要表示截止某时间点前(后),起始(终止)时间参数可以输入nil。

    

    如果输入时间的时区是本机的系统时区(如:中国上海-香港-乌鲁木齐时间),而请求的时态服务又是其他时区,则需要统一时间格式:

//定义时间格式
NSDateFormatter* inputFormatter = [[NSDateFormatter alloc] init];
 [inputFormatter setDateFormat:@"M/d/yyyy h:mm a"];
//设定时区
[inputFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
 
//按格式构造NSDate
NSDate* date = [inputFormatter dateFromString:@"1/1/2001 12:00 AM"];
AGSTimeExtent* extent = [[AGSTimeExtent alloc] initWithStart:date end:date];

*更多NSDate时间转换的内容请参考博文-http://blog.csdn.net/diyagoanyhacker/article/details/7096612

    

    如果不需要按时间过滤,设定图层的时间开关(useTime)为false即可:

AGSLayerTimeOptions* op = [[[AGSLayerTimeOptions alloc] init] autorelease];op.layerId = 1; 
//关闭指定图层的时态响应
op.useTime = FALSE;
    



你可能感兴趣的:(ios,文档,UIView,bing,reference,layer)