圖層是空間資料的載體,如果你對ArcGIS Server稍有瞭解的話,就能明白API裡不同類型的圖層對應了伺服器端發布的不同Service,可以分成兩大類:靜態圖層和動態圖層。
靜態圖層泛指緩衝過的地圖服務,除非服務端刪除或更新緩衝,否則用戶端請求的資料永遠是固定不變的,而動態圖層正好相反,伺服器根據每個請求動態產生資料,一靜一動各有用途。
表3-2-1 不同類型圖層的繼承關係
AGSLayer是所有圖層的基類,聲明了空間參考、最大範圍、初始範圍、單位和圖層委託等基本屬性,還有圖層載入的相關方法。
表3-2-2圖層類的屬性和方法
1 靜態圖層
靜態圖層根據一定的規則提前產生緩衝,這樣用戶端的請求就能直接調用緩衝地圖切片,顯著提高了地圖請求的響應速度。常常用於那些使用頻率高、更新周期長的基礎地理資料,包括大家常常用到的電子地圖、地形圖、衛星影像圖等。
AGSTiledLayer繼承自AGSLayer,同時也派生出不同類型的靜態圖層:
表3-2-3 靜態圖層的繼承關係
在MVC結構中,AGSTiledLayer屬於Model角色,對應的View角色是AGSTiledLayerView。其中實現了關鍵的非同步擷取切片資料操作,並擷取到切片服務的緩衝規則:
表3-2-4 靜態圖層的方法和屬性
注意:如果靜態服務圖層的空間參考與MapView的不一致,就無法顯示。
1.1 切片地圖服務圖層(AGSTiledMapServiceLayer)
切片地圖服務圖層是最常用的服務,ArcGIS線上提供了一系列,其切片規則(tiling Schema)裡描述了切片的尺寸、格式、比例尺、層級等資訊。
“雖然圖層已經初始化並添加到地圖中,但切片資訊還是空值?”,建議先判斷載入成功與否,尤其是在網速不好的情況下:
//圖層載入完成後才能擷取完整的屬性 if(layer.loaded){ NSLog(@"TilingScheme: %@", layer.tileInfo);}
1.2 微軟Bing服務圖層(AGSBingMapLayer)
由於Esri與微軟之間的合作關係,保證了ArcGIS使用者也能使用最新的微軟Bing全球影像地圖服務,當然這也是靜態服務,加入使用者的密匙(在ArcGISServer
Manager頁面可擷取)就能使用:
NSString* bingMapsKey = @"--your--key--"; AGSBingMapLayer* layer = [[AGSBingMapLayeralloc]initWithAppID:bingMapsKeystyle:AGSBingMapLayerStyleAerial];
*Bing服務空間參考為橫軸Web摩卡托:
WGS1984 Web Mercator (Auxiliary Sphere) ,WKID=102100:
1.3 OSM服務圖層(AGSOpenStreetMapLayer)
Esri與OpenStreetMap之間也建立了合作關係, ArcGIS使用者同樣也能使用OpenStreetMap全球向量地圖服務:
AGSOpenStreetMapLayer* OSMLyr = [[AGSOpenStreetMapLayeralloc]init];
*OpenStreetMap服務空間參考為橫軸Web摩卡托:
WGS1984 Web Mercator (Auxiliary Sphere) ,WKID=102100:
1.4 自訂切片圖層(Custom TiledLayer)
國內流行的切片地圖還有:Google地圖、百度地圖、MapABC、天地圖等,各家地圖的切片策略有差異但原理相同,瞭解其切片策略資訊後,繼承AGSTiledLayer拓展自訂切片圖層 (Custom TiledLayer),就能正常使用該切片地圖。
Esri提供了一個訪問本地切片(png或jpg)的類 “OfflineTiledLayer”,可以作為我們設計自訂切片圖層的參考,包含3部分:切片圖層對象,切片資料解析委託和切片請求操作。下面的流程能看出自訂切片載入的整個過程:
圖3-2-6 自訂切片圖層的調用流程
“OfflineTiledLayer“繼承了AGSTiledLayer,並重寫了切片資訊(tileInfo)和切片擷取方法(retrieveImageAsyncForTile),其初始化方法(initWithDataFramePath)也很簡單:
//繼承了AGSTiledLayer @interface OfflineTiledLayer :AGSTiledLayer { ... } //自訂切片服務中繼資料 @implementation OfflineTiledLayer -(AGSUnits) units { //todo } -(AGSSpatialReference*) spatialReference {//todo } -(AGSEnvelope*) fullEnvelope { //todo } -(AGSEnvelope*) initialEnvelope { //todo } -(AGSTileInfo*) tileInfo { //todo } -(NSOperation<AGSTileOperation>*)retrieveImageAsyncForTile:(AGSTile*)tile { //todo } //初始化方法-path:切片路徑 - (id)initWithDataFramePath:(NSString*)patherror:(NSError**)outError; ... @end
初始化方法中需要輸入“切片檔案路徑”,的樣本資料是10.0版本的鬆散型(Exploded)切片緩衝,切片服務中繼資料就儲存在conf.cdi和conf.xml兩個XML檔案中,其中conf.cdi記錄了地圖全圖範圍、而conf.xml記錄了空間參考、切片格式等資訊,其中和切片組織(LODInfos)對應了_alllayers目錄下的層級(L)-行號(R)-列號(C),簡單理解就是用指定網格按指定比例尺一層層的把地圖切成規則的圖片矩陣,建立起了網格與切片檔案的對應關係,使用時按網格檢索切片檔案,並動態拼接起來。
*關於切片規則的詳細介紹,請參考網上其他資料。
圖3-2-7 鬆散型切片的組織圖
1. 解析切片中繼資料:
“OfflineCacheParserDelegate“負責從中繼資料(conf.cdi和conf.xml)中解析出自訂的切片資訊並構建出關鍵的AGSTileInfo對象:
- (id)initWithDataFramePath:(NSString *)path error:(NSError**) outError { if (self = [super init]) { self.dataFramePath = path; //解析 conf.cdi NSString* confCDI = [[NSBundlemainBundle] pathForResource:@"conf" ofType:@"cdi"inDirectory: _dataFramePath ]; NSXMLParser* xmlParser = [[NSXMLParser alloc]initWithContentsOfURL:[NSURL fileURLWithPath:confCDI]]; OfflineCacheParserDelegate*parserDelegate = [[[OfflineCacheParserDelegate alloc] init] autorelease] ; [xmlParsersetDelegate:parserDelegate]; [xmlParser parse]; [xmlParser release]; //解析 conf.xml NSString* confXML = [[NSBundlemainBundle] pathForResource:@"conf" ofType:@"xml"inDirectory: _dataFramePath]; ...}
以下是XML中繼資料的具體解析方法:
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementNamenamespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{ if ([elementNameisEqualToString:@"LODInfo"]){ self.lod = [[[AGSLODalloc]initWithLevel:_level resolution:_resolution scale:_scale] autorelease]; [self.lods addObject:_lod]; }else if ([elementNameisEqualToString:@"CacheInfo"]){ _tileSize = CGSizeMake(_tileWidth,_tileHeight); self.spatialReference =[[[AGSSpatialReference alloc] initWithWKID:_WKID WKT:_WKT] autorelease]; self.tileOrigin = [[[AGSPointalloc] initWithX:_tileOriginX y:_tileOriginYspatialReference:_spatialReference] autorelease]; self.fullEnvelope = [AGSEnvelopeenvelopeWithXmin:_xmin ymin:_ymin xmax:_xmax ymax:_ymax spatialReference:_spatialReference]; self.tileInfo = [[[AGSTileInfoalloc] initWithDpi: _dpi format:_tileFormat lods:_lods origin:_tileOrigin spatialReference:_spatialReference tileSize:_tileSize] autorelease]; } }
2. 請求和擷取切片資料:
“OfflineTileOperation“按照地圖所請求AGSTile的level, row, column參數擷取本地切片圖片檔案,將其填充到Image屬性:
//根據 Level, Row,Column擷取切片 @try { //Level ('L' followed by 2 digits) NSString *decLevel = [NSStringstringWithFormat:@"L%02d",self.tile.level]; //Row ('R' followed by 8hexadecimal digits) NSString *hexRow = [NSStringstringWithFormat:@"R%08x",self.tile.row]; //Column ('C' followed by 8hexadecimal digits) NSString *hexCol = [NSStringstringWithFormat:@"C%08x",self.tile.column]; NSString*dir = [_allLayersPathstringByAppendingFormat:@"/%@/%@",decLevel,hexRow]; //尋找PNG格式切片 NSString *tileImagePath =[[NSBundle mainBundle] pathForResource:hexCol ofType:@"png"inDirectory:dir]; ... } @catch (NSException *exception) { NSLog(@"main: Caught Exception%@: %@", [exception name], [exception reason]); } @finally { //Invoke the layer's action method [_target performSelector:_actionwithObject:self]; }
*OfflineTiledLayer用來解釋自訂切片服務圖層設計原理,不適合大規模離線使用,因為鬆散型的切片小檔案分發、更新非常耗時,建議採用下一節的AGSLocalTiledLayer介面+切片包TPK壓縮格式。
*載入其他線上切片地圖(百度地圖、天地圖和Google地圖)的方法和代碼,我會在後續章節專門做介紹。
1.5 本地切片圖層(AGSLocalTiledLayer)
本地切片圖層(AGSLocalTiledLayer)也叫離線切片圖層,是上一節“OfflineTiledLayer”樣本的升級版,其面向的切片快取資料源是ArcGIS
10.1新推出的切片地圖包(.tpk檔案)。如果用localTiledLayerWithName方法載入,會依次遍曆該應用的bundle和Document目錄,意味著如果tpk檔案不大,可以直接將其打包在應用的資源檔中分發,如果tpk檔案很大,也允許使用者通過Itunes手動載入資料,前者的優點是分發簡單,後者的優點是應用與資料不綁定,自由載入。
AGSLocalTiledLayer* layer = [AGSLocalTiledLayerlocalTiledLayerWithName:@"world"];
切片地圖包(tile package)是緊湊型(compact)切片快取資料的壓縮包,提高了切片快取資料的分發效率,可以用10.1案頭“分享為TPK”,也可以自己手動構建,詳細過程可參考:http://blog.csdn.net/arcgis_mobile/article/details/8048549.