ArcGIS for iOS 開發系列(5) – 基礎篇-圖層-靜態圖層

arcgis_mobile發表於2012-10-24

    圖層是空間資料的載體,如果你對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)

    國內流行的切片地圖還有:谷歌地圖、百度地圖、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壓縮格式。

*載入其他線上切片地圖(百度地圖、天地圖和谷歌地圖)的方法和程式碼,我會在後續章節專門做介紹。

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.


相關文章