ArcGIS移动客户端离线地图的⼏种解决⽅案
移动GIS中,通常将数据分为两⼤类:bamap layer和operational layer。前者是指
漫游或导航时起参考作⽤的图层,这些图层内容通常不会变化,只起到视觉辅助作
⽤,称为底图图层;后者是指存储GIS数据的图层,⽐如可通过这些图层来提供属性/
空间查询操作,或者对其内容进⾏编辑,然后与服务器端进⾏同步,称为业务图层。
春叶 ⽬前ArcGIS移动产品有5种,基于Windows Mobile平台的ArcPad和ArcGIS Mobile,这两个产品已经很成熟了,都有各⾃的离线缓存格式,其中ArcGIS Mobile
从10版本开始,可以直接读取ArcGIS Server缓存地图服务的切⽚⽂件做为bamap layer,⽀持exploded和compact两种格式。
相对于以上两个⽼牌移动产品,三个刚出道的⼩弟ArcGIS for iOS,ArcGIS for Android和ArcGIS for Windows Phone就⾛了不同路线:依赖于ArcGIS Server的REST服务。因此⼏乎所有操作,包括显⽰地图,都需要⽤到ArcGIS Server发布的各
种服务。这三个产品的离线功能将来肯定是会有的,但具体的时间表还⽆法确定。大象简笔画彩色
针对ArcGIS for iOS/Android/Windows Phone,本⽂提出3种可⾏的离线底图(bamap layer)的解决⽅案,供各位参考。以ArcGIS for Windows Phone为例。
1、ArcGIS Server地图服务的Exploded格式缓存⽂件
ArcGIS API for Windows Phone中,提供了ArcGISTiledMapServiceLayer⽤来加
载ArcGIS Server发布的缓存地图服务,它的原理是Map控件计算好需要加载的切⽚
的row,col,level参数,利⽤ArcGISTiledMapServiceLayer⾥的GetTileUrl⽅法提供企业成功的因素
如何获得指定参数的切⽚⽂件,最后拼接成完整的地图。
因此我们可以通过继承ArcGISTiledMapServiceLayer的⽗
类,TiledMapServiceLayer或TiledLayer,来实现⾃⼰的⾃定义图层,⽐如⽤它来加
载Google Maps,天地图等各种地图。加载这些在线地图都是通过重写GetTileUrl()⽅
法来实现的。
对于已经存放在硬盘上的缓存⽂件,该如何加载呢?这⼏个图层还有⼀个⽅
法,GetTileSource。这个⽅法有⼀个onComplete action,可以传⼊ImageSource类
型的参数,它⽐GetTileUrl来的更直接。其实GetTileSource⽅法中调⽤了GetTileUrl
⽅法的结果(⼀个获得tile的url字符串),利⽤这个字符串向服务器端发送请求,请
求回来的结果就是切⽚图⽚的⼆进制流,再将这个⼆进制流形成ImageSource,通过onComplete⽅法返回。
所以我们可以抛开GetTileUrl,直接重写GetTileSource⽅法,来根据
row,col,level参数,读取地图服务的缓存⽂件。⾸先将Exploded格式的地图服务缓
存⽂件拷贝到⼿机中:
包含conf.cdi(ArcGIS Server 10版本中才有,记录了缓存的全图范围)和l⽂件的好处是,
我们可以在代码中读取这两个⽂件来动态⽣成我们的Tiling Scheme,以完成图层初始化的⼯作。从配置⽂件中读取参数后,就可以重写GetTileSource⽅法了。部分代码如下:
创新人才培养
1:protected override void GetTileSource(int level, int row, int col, Action<System.Windows.Media.ImageSource> onComplete)
2: {
3:string f = string.Empty;
4:if (_cacheTileFormat.ToLower().Contains("png"))
5: f = ".png";
6:el if (_cacheTileFormat.ToLower().Contains("jpeg") || _cacheTileFormat.ToLower().Contains("jpg"))
7: f = ".jpg";
8:el
9:throw new Exception("切⽚格式不明:" + _cacheTileFormat);
10:#region Exploded读取
11:if (_storageFormat == StorageFormat.esriMapCacheStorageModeExploded)
12: {
13:string baUrl = _path;// "/WP_LocalCacheReader;component/Asts/usa_exploded/"
14: baUrl += @"/_alllayers";铁铲的拼音
15:string l = "L";
16: l = level.ToString().PadLeft(2, '0');
17:string r = "R";
18: r = String.Format("{0:X}", row).PadLeft(8, '0');
19:string c = "C";
20: c = String.Format("{0:X}", col).PadLeft(8, '0');
21:string str = baUrl
21:string str = baUrl
22: + @"/L" + l
23: + @"/R" + r
24: + @"/C" + c + f;
25: BitmapImage img = new BitmapImage(new Uri(str,UriKind.RelativeOrAbsolute))杏花风
26: {
27: CreateOptions = BitmapCreateOptions.DelayCreation
28: };
29: img.ImageFailed += (s, a) =>
30: {
31:string uri = _path + "/missing" + _tileRows.ToString() + f;
32: BitmapImage image = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute))
33: {
34: CreateOptions = BitmapCreateOptions.DelayCreation
35: };
36: onComplete(image);
37:return;
38: };
39: onComplete(img);
40: }
41:#endregion
42: }
当指定的切⽚⽂件不存在(也许还未创建)时,可以加载事先准备好的missing 图⽚来替换。
消防管理员2、ArcGIS Server地图服务的Compact格式缓存⽂件
这是ArcGIS Server 10推出的新的缓存格式,缓存图⽚都保存在.bundle⽂件中,⼀个bundle⽬前可存储128*128张切⽚。切⽚⽂件更少,主要⽬的是为了迁移⽅便。⽂档中并未给出读取这种格式⽂件的⽅法,不过⽜魔王已经凭空推断出了这种格式的内容,这⾥就借鉴了他的⽅法。还是先将缓存⽂件拷贝到⼿机中:
利⽤conf.cdi和l获得tiling scheme,之后重写GetTileSource⽅法。具体思路⽜魔王⽂中已经给出,感兴趣的同学还是看原⽂,学习⽜⽜的思路⽐较好。
下⾯是读取两种缓存⽂件的效果:
3、第三⽅离线地图⽂件
除了ArcGIS Server的缓存切⽚之外,我们还可以读取第三⽅的离线地图⽂件来做为我们的底图。⽐如以前⾯介绍过的Mobile Atlas Creator为例,我现在已经有了很多⾃⼰下载好的离线地图,如果能在ArcGIS移动客户端使⽤起步两全其美?其实在⽬前的离线导航软件中,很多都⽤sqlite数据库做为地图存储格式,因为它应⽤⼴泛,轻巧,紧凑,Android,iOS,Symbian等系统对它都有原⽣的⽀持。Mobile Atlas Creator中,RMaps和OruxMaps都⽤Sqlite保存离线地图。这⾥以应⽤较为⼴泛的RMaps格式为例,进⾏试验。
创建好的RMaps地图⽂件如下:
缺乏近义词 我们利⽤FireFox⾥的Sqlite Manager插件先来查看⼀下数据库的内容:
可以看出,我们所需的内容都保存在tiles这张表中,⽽x,y,z三个参数与我们所需的row,col,level很像。经过试验(保存⼀个全球范围的地图),很快验证出level=17-z。
参数有了,要如何读取切⽚呢?对于Sqlite,虽然⽬前Windows Phone还没有提供原⽣的⽀持,不过codeplex上已经有不少项⽬都提供了解决办法。我选择Sqlite Client for Windows Phone来读取RMaps的地图⽂件。下⾯是RMaps离线地图(Bing Maps)和ArcGIS Online上StreetMap叠加的效果: