早在2010年年底,牛魔王中王在其博客空间牛魔王的作坊中对ArcGIS 10中推出的紧凑型缓存格式进行了详细的解读,详见《ArcGIS 切片缓存紧凑文件格式分析与使用》。紧随着的4年时间里,ArcGIS for Server本身经历了10、10.1.X和10.2.X各版本的逐级更替,特别是软件架构发生了显著的变化。然而,就紧凑型缓存本身而言,牛魔王中王的解读一直都是适用的。衷心地向我们的大牛致敬!

  直到2014年年底ArcGIS 10.3正式发布,Esri才推出了新的紧凑型缓存格式以增强用户的访问体验。新的缓存格式下,关键的差别在于Esri将缓存的索引信息.bundlx包含在了缓存的切片文件.bundle中。

  接下来,我们就简单解读一下这一新型的紧凑型缓存格式。俗语说,万变不离其宗。既然缓存文件夹下仅包含了bundle文件,可以想见,切片的索引,切片的偏移和切片的图片流都必然包含在这一文件中。根据经验,缓存本身遵循的是16进制的形式。依照这一思路,利用UltraEdit打开bundle文件并以16进制格式进行查看。

 为了便于分析,我们先创建一个在L00级只包含一个切片的缓存服务,并在UltraEdit中以16进制格式查看L00级下的R0000C0000.bundle文件。

  通过对这一文件中信息存储规律的分析,可初步得出如下结论:(1) 文件中包含大量04 00 00 00 00 00 00 00的16进制字节组,共计16893组;(2) 文件中仅包含一个PNG24的文件头字节组89504E47,即第一行第一列的切片,bundle文件中唯一的一张图片。图片流紧随(1)中所提到的字节组之后,但偏移4个字节;(3) (2)中所述的4字节偏移量的数值恰等于图片流的长度;(4) 文件第5行的起始4个字节44 00 02 00按照低位到高位换算出的数值等于131140,这一值与(2)中所述的PNG文件头位置恰恰吻合。

  综上分析:(1)起始4行是bundle的文件头信息,可忽略;(2)bundle的文件头之后记录了16384张切片的切片位置,仅4字节,从低位到高位,后4字节可忽略;(3)位置信息之后,对于切片的记录,先以4字节记录切片的长度,而后紧跟图片流信息。到此,bundle结束。

  下一步呢,我们将选择一个狭长的矩形面要素发布服务并切图,以分析行列切片在bundle文件中的具体存储规律。

  通过对bundle文件和对应的松散缓存在L02级别上的对比,可推断:(1)bundle中索引的存储是按行依次存储,即第1行的1至128,第2行的1至128,以此类推,直至最后一张切片即第128行128列;(2)bundle中图片流的存储仅包含非空切片。此外,通过对这一更复杂的地图缓存的分析,再次论证了前面的推论。

  既然上述的分析完毕,接下来就要对上述的分析进行一番验证啦。这里呢,我会利用ArcGIS Runtime SDK for Android实现抽象理论的实践工作。本次验证的核心在于,通过对TiledServiceLayer进行扩展,按照上面的存储推论覆写getTile(int mLevel, int mColumn, int mRow)方法。

  第一步,根据参数中的比例级别、列号和行号定位到Bundle文件。

     String level = Integer.toString(mLevel);
int levelLength = level.length();
if(levelLength == 1){
level = "0" + level;
}
level = "L" + level; int rowGroup = 128*(mRow/128);
String row = Integer.toHexString(rowGroup);
int rowLength = row.length();
if(rowLength < 4){
for(int i=0; i<4-rowLength; i++){
row = "0" + row;
}
}
row = "R" + row; int columnGroup = 128*(mColumn/128);
String column = Integer.toHexString(columnGroup);
int columnLength = column.length();
if(columnLength < 4) {
for(int i=0; i<4-columnLength; i++){
column = "0" + column;
}
}
column = "C" + column; String bundleName = String.format("%s/%s/%s%s", compactTileLoc, level, row, column) + ".bundle";

  第二步,读取bundle文件,根据前面分析中所推断出的切片的起始位置和切片的长度获取对应的切片并返回。

     int index = 128*(mRow - rowGroup) + (mColumn-columnGroup);

     RandomAccessFile isBundle = new RandomAccessFile(bundleFileName, "r");
isBundle.skipBytes(64 + 8*index); //获取位置索引并计算切片位置偏移量
byte[] indexBytes = new byte[4];
isBundle.read(indexBytes, 0, 4);
long offset = (long)(indexBytes[0]&0xff) +(long)(indexBytes[1]&0xff)*256 + (long)(indexBytes[2]&0xff)*65536
+ (long)(indexBytes[3]&0xff)*16777216; //获取切片长度索引并计算切片长度
long startOffset = offset - 4;
isBundle.seek(startOffset);
byte[] lengthBytes = new byte[4];
isBundle.read(lengthBytes, 0, 4);
int length = (int)(lengthBytes[0] & 0xff) + (int)(lengthBytes[1] & 0xff)*256 + (int)(lengthBytes[2] & 0xff) * 65536
+ (int)(lengthBytes[3] & 0xff) * 16777216; //根据切片位置和切片长度获取切片
ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] tileBytes = new byte[length];
int bytesRead = 0;
if(length > 0){
bytesRead = isBundle.read(tileBytes, 0, tileBytes.length);
if(bytesRead > 0){
bos.write(tileBytes, 0, bytesRead);
}
} tile = bos.toByteArray();

  呵呵,成功实现。直接奉上Android端的显示效果吧。

  

Tips:

  关于紧凑型切片,唠唠叨叨的我还是忍不住要嘱咐几句:(1)新型的紧凑型切片无法被直接用于先前版本的ArcGIS for Server;(2)新型的紧凑型切片可通过导出切片即export tiles获取先前格式的缓存;(3)老版本的紧凑型切片可直接在新版本的ArcGIS for Server中复用,但可通过升级存储格式即Upgrade Storage Format更新为新型紧凑型切片格式。

ArcGIS for Server 10.3.X 新型紧凑型缓存的解读和应用的更多相关文章

  1. ArcGIS for Server 10.2 发布Feature Service

    折腾一下午,终于把自带的例子发布成Feature Service了,这样就可以通过web编辑了.记录一下步骤. 环境:已经安装好SQL Server 2008 R2,ArcGIS for Deskto ...

  2. [转]arcgis for server 10.2 下载及安装

    转自:https://blog.csdn.net/nominior/article/details/80211963 https://blog.csdn.net/mrib/article/detail ...

  3. ArcGIS Server 10中的切图/缓存机制深入【转】

    http://blog.newnaw.com/?p=789 两年前我写过一篇关于ArcGIS地图切图/缓存原理的文章,<ArcGIS Server的切图原理深入>,里面以tiling sc ...

  4. [ ArcGIS for Server 10.1 系列 ] - 重新创建Site

    一般当ArcGIS Server Site发生错误.ArcGIS Server无法启动或者ArcGIS Server某服务没有实例,就可能需要重新的创建Site.有时可以通过重新创建Site,就发现其 ...

  5. ArcGIS for Server 10.2 开启GeometryService

    过程非常简单,所以网上文档比较少. 打开网站管理页面: http://localhost:6080/arcgis/manager/ 点左边Utilities

  6. ArcGIS for Sever 10.1 服务迁移与恢复

    === 声明:以下内容本是自己写给单位内部同事的参考手册,但是被传到百度文库中.陆续有用户就这方面的问题,通过电话,邮件等方式联系我.首先,感到荣幸.其次是,由于本人当时测试和编写的时候,由于仓促,可 ...

  7. arcgis for server 登陆manager失败解决办法

    版本是 arcgis for server 10.02 症状 1. manager网页无法打开http://localhost:6080/arcgis/manager/ 2. 查看服务无法启动,启动后 ...

  8. ArcGIS for Server新建站点异常,Failed to create the site.Failed to configure the server machine'XXXX',Server machine'XXXX' is not a local server machine.

      系统环境:操作系统Win7 64位,装在虚拟机VM中,ArcGIS for Server 10.2.1 问题描述:ArcGIS for Server 10.2.1安装并授权完成后,站点初始化时显示 ...

  9. ArcGIS for Server内置JS Viewer的离线部署和配置

    很多情况下,在地图服务发布完毕后,我们往往利用 ArcGIS for Server内置的 JS Viewer来查看和检测所发布的地图服务是否满足我们的要求.具体操作如下: 点击开始 -> 所有程 ...

随机推荐

  1. 怎么看时序图--nand flash的读操作详解

    出处:http://blog.chinaunix.net/uid-28852942-id-3992727.html 这篇文章不是介绍 nand flash的物理结构和关于nand flash的一些基本 ...

  2. centos7 install python3

    1. 过程 # 1. root权限, 安装依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-dev ...

  3. 【246】◀▶IEW-Unit11

    Unit 11 Transport 1. Model1题目分析 Some countries attempt to solve the problem of traffic congestion by ...

  4. string.Format的困惑

    今天在执行一个format时出现了这样一个问题,困惑了很久,就是 string.Format("{0:00}",“1”)结果是1 string.Format("{0:00 ...

  5. <c和指针>学习笔记3之函数和数组

    1 函数声明 (1)原型 告诉编译器函数的参数数量和每个参数的类型以及返回值的类型.编译器通过检查原型之后,就可以检查这个函数得调用,从而来确保参数正确,返回值无误. 通用技巧,将原型写在一个头文件当 ...

  6. unix环境高级编程附录 B 通用代码

    0.说明: 在测试 unix 环境高级编程中的代码时,需要一些作者事先写好的代码, 如: apue.h 包含某些标准系统头文件,定义许多常量及函数原型 还有两个作者自编的函数来对错误进行处理 1.ep ...

  7. 27.集成EFCore配置Client和API

    copy链接字符串,这是一个官方的字符串,直接复制过来,放在上面. 添加包的引用 引入IdentityServer4.EntityFramework的命名空间 主要是这个地方初始化我们的数据库 Ope ...

  8. UVaLive 4094 WonderTeam (贪心)

    题意:有n支队伍,每两支队伍打两场比赛(主客场各一次),胜得3分,平得1分,输不得分,比赛结束之后会评选出一个梦之队, 梦之队满足以下条件:进球总数最多,胜利场数最多,丢求总数最少,三个都不能并列,求 ...

  9. 存储过程接收JSON格式数据

    前端有可能一次性上传多笔记录,并使用JSON序列化. 现在在MS SQL Server 2016版本上,可以直接处理JSO数据. 如下面的前端序列化的数据: DECLARE @json_string ...

  10. uva1331 Minimax Triangulation

    题目大意: 按照顺时针或者逆时针的顺序给出多边的点,要将这个多边形分解成n-2个三角形,要求使得这些三角行中面积最大的三角形面积尽量小,求最小值. /* dp[i][j]表示从第i个点到第j个点,划分 ...