C#+AE切出与ArcGIS Server地图服务缓存兼容的瓦片(180815更新)
最近在做个切片程序,切的瓦片可以和ArcGIS Server和GeoServer兼容,可以选择ArcGIS Online、谷歌的切片方案,也可以自定义切片方案。切好的瓦片ArcGIS Server发布的地图服务可以作为缓存直接调用。最近整理了下过程,本文将影像切片的原理、方法、程序思路进行介绍。先上效果图。
目录
1.效果图
图1与ArcGIS Server兼容的瓦片图
图2使用ArcGIS Server打开的缓存服务
图3编写的切片工具
2.背景
使用ArcGIS Server做地图发布,为了提升浏览性能,通常会使用现时比较流行的地图缓存技术(通俗的说法为“瓦片技术”)。如目前的MapABC和GoogleMap正是使用该技术。
所谓的地图缓存技术,就是按照一定的数学规则,把地图提前按照不同比例尺切成一定规格的图片保存到计算机硬盘里,当用户通过客户端浏览器访问地图服务时,服务器直接返回当前地图坐标区域所对应的“瓦片”,而不是由服务器动态创建出一幅图片来送到客户端,从而达到降低服务器负担,提升地图浏览速度的效果。
地图缓存技术一般针对相对稳定的数据,因为地图切为瓦片以后,以图片的形式存在,对于数据的变化(这里指的是数据的几何形状变化)不能及时的反应,这就是地图缓存技术不足之处。要想地图的变化得到及时的反映,那就必须重建地图缓存。而重建地图缓存要视地图的区域范围和缓存的比例尺而定,时间为几分钟到几十个小时不等。因此,缓存的管理是一件相对麻烦的事情。
2.1为何应缓存地图?
使用缓存时,您为绘制地图所造成的性能损失付出代价的唯一时间是在创建缓存时。因此,创建缓存可能要花费很长时间。然而,缓存的好处足可以弥补创建缓存所花费的时间。缓存的一些主要优势如下:
性能:部署已缓存地图时,用户可以做更多的事情,因为他们所花费的等待地图绘制的时间更少。
质量:使用缓存时,性能不会受到地图详细程度的影响。无论是否使用晕渲地貌、透明度还是 Maplex 标注引擎创建地图,性能都不会受到影响。缓存只是图像的集合,服务器返回这些不同的缓存图像所花费的时间大致相同。
行业标准:您是否去过某个流行的 Internet 制图站点并观看过平移和缩放时的小方形切片填充?显示出所有的切片通常只需要几分之一秒的时间。这是因为它们使用的是缓存。使用 ArcGIS Server 地图缓存,您可以让地图实现类似的性能。
参考:
https://blog.****.net/abc553226713/article/details/8668799
3.关键概念
1. 切片
名词:瓦片、地图缓存中的图片,动词:将大范围的影像分块重采样到一张张图片中,目的:避免浏览器加载地图图片时实时重采样,将工作提前,提高用户浏览效率。
2. 切片方案
Tiling Scheme 用于构建地图瓦片的各种参数,包括切片方案原点、瓦片格式、瓦片大小、多级切片比例尺及对应的地图分辨率等。ArcGIS Server中,这些参数均存储在切片方案文件conf.xml 中,使用ArcGIS Server发布缓存服务时会自动生成。可以自定义统一的切片方案,也可以选择使用熟知的 ArcGIS Online、Google 地图和 Bing 地图切片方案,以便可以将您的缓存轻松地叠加到这些在线地图服务上
3. 切片方案原点
Tiling SchemeOrigin,位于切片格网中左上角的点。切片原点通常不是创建切片的起始点。通常切片原点位于地图之外很远的地方,以确保覆盖地图区域,并可确保具有相同切片原点的其他缓存可以与您的缓存叠加。注意:切片方案原点只会影响瓦片的行列号。
4. 瓦片格式
图片格式,常用的有PNG、JPEG等。
5. 瓦片尺寸
瓦片的宽度和高度,以像素为单位,瓦片的默认宽度和高度为 256 像素。如果要合并两套瓦片,应确保对两个缓存均使用相同的瓦片宽度和高度,以及相同的切片原点和比例尺。选择较小的切片宽度和高度可提高向缓存请求切片的应用程序的性能,因为需要传输的数据较少。但对于松散缓存,切片越小,缓存越大且创建时间越长。
6. 切片比例尺
比例尺又称缩尺,指的是图上一个单位代表实际多少距离,设置此属性指出在哪些比例尺下切片。公式为:比例尺=图上距离/实地距离。创建切片方案时,采用哪些地图比例创建切片是最为重要的选择。选择一组比例的简便方法是:确定用户查看地图时需要使用的最接近比例(或最大缓存比例),然后重复地将比例的分母乘以 2,直至达到仅在一或两个切片内便可包含全部关注区域的比例(最小缓存比例)。例如,如果正为某个城市设计切片方案,用户查看地图应使用的最接近比例为 1:2,000,则比例可能为 1:2,000、1:4,000、1:8,000、1:16,000 或 1:32,000,直到达到一个可在计算机屏幕上一次性看到整个城市的比例。注意想要创建切片的最小最大比例,不必是切片方案中的最小最大比例,即切片方案中可以定义,但是您可以选择不切。
7. DPI
图片上每英寸像素点数。默认值 96 通常完全可满足需要,不建议调整。请注意,调整DPI会影响切片的比例,DPI是和打印相关的属性,它定义了在一英寸(2.54cm)的距离上,打印机所打印的点数,离开了打印这个需求,DPI这个属性是没有存在的意义的,所以它是一个密度单位。 代表图片上每个像素的长度。
8. 地图原点
切片起始点Map Origin,进行切片缓存时地图上的起始点,不同于切片方案原点。
9. Resolution
Resolution 的实际含义代表当前地图范围内,1像素代表多少地图单位(X地图单位/像素),由比例尺决定,可以计算瓦片位置(在地图中的行列号)。
指地图分辨率,表示图片中1个像素所占的地图单位长度;S表示当前比例尺,1:S表示图片中1米代表地图上有S米;0.0254m为1英寸的长度,单位m;DPI指图片中每英寸的像素点数量; 表示图片上,每个像素的长度(非地图单位长度)。
最后注意:
切片方案中
起点坐标的设置跟比例尺和分辨率没有关系,
图片大小的设置跟比例尺和分辨率也没有关系
DPI跟屏幕像素没有关系。
4.设计思路
地球周长:WGS84经纬度坐标下用到,直接决定了瓦片的地理宽度
将影像中某块区域Cell导出为图片,需要获得Cell的地理坐标范围(影像内容),图片尺寸,图片的DPI。部分代码:
IActiveView.output(…)方法
采用IActiveView接口下的output方法,可以将地图输出为上十种格式,具体的格式受IExport类型限制,如ExportBMP,ExportPNG、ExportJPEG等,下面以输出为JPEG格式来说明。
首先定义ExportJPEG的实例pExport,然后设置其相关的参数,过程比较简单,这里重点描述一下相关的参数设置。
方法:IActiveView.OutPut(hdc, Dpi, pixelBounds,VisibleBounds, TrackCancel )
6.C#代码讲解
【1】图片尺寸:设置统一的输出图片大小
int width = pInput.ImgWidth;
int height = pInput.ImgHeight;
IEnvelope imgSize = new Envelope() as IEnvelope;
imgSize.PutCoords(0, 0, width, height);
【2】地图填充尺寸,设置统一的地图在图片中所占尺寸,一般与图片尺寸相同
tagRECT exportRECT = new tagRECT() { left = 0, top = 0, right = width, bottom = height };
【3】设置采样率,决定图片中影像精细度,图片长和宽像素都大于868才起作用。默认是3,范围是1-5,值越小,影像越精细
IOutputRasterSettings outRasterSetting = pAE.MapControl.ActiveView.ScreenDisplay.DisplayTransformation as IOutputRasterSettings;
outRasterSetting.ResampleRatio = 1;
【4】遍历出图
foreach (var kv in dicRecords)
{
progressBar.Value = a++;
IFeature feature = kv.Value.Feature;
Record record = kv.Value; //自定义数据结构
string expression = pInput.Field_LXBM + "='" + record.LXBM + "'";
pAE.setFeatureLayerDefinition(pFeatLayer, expression);
//【5】地理范围:设置每幅图包含的地理范围
IEnvelope visualMap = new Envelope() as IEnvelope; //瓦片的地理范围
IEnvelope featEnve = feature.Shape.Envelope; //要素范围
featEnve.QueryEnvelope(visualMap);
double multiple = pInput.Multiple - 1; ;
double outWidth = multiple * visualMap.Width;
double outHeight = multiple * visualMap.Height;
visualMap.XMin -= outWidth;
visualMap.XMax += outWidth;
visualMap.YMin -= outHeight;
visualMap.YMax += outHeight;
string recordKey = kv.Key;
//【6】设置图片路径,出图
pFeatLayer.Visible = true;
pAE.MapControl.ActiveView.Refresh();
string imgPath1 = pInput.ImgTempPath+"\\" +recordKey + "_路线图" + ".jpg";
Output(pAE.MapControl, imgSize, exportRECT, visualMap, imgPath1, pInput.DelayTime);
pFeatLayer.Visible = false;
pAE.MapControl.ActiveView.Refresh();
string imgPath2 = pInput.ImgTempPath+"\\" + recordKey + "_影像图" + ".jpg";
Output(pAE.MapControl, imgSize, exportRECT, visualMap, imgPath2, pInput.DelayTime);
record.ImgPathLXT = imgPath1;
record.ImgPathYXT = imgPath2;
}
private void Output(IMapControlDefault mapControl, IEnvelope imgSize,
tagRECT exportRECT, IEnvelope visibleEnvelope, string imgPath,int delayTime)
{
IExport export = new ExportJPEG() as IExport;
export.ExportFileName = imgPath;
export.PixelBounds = imgSize;//图片尺寸,像素单位,如512*512像素
mapControl.ActiveView.Extent = visibleEnvelope;
if (mapControl.ActiveView.FocusMap.MapScale < 2000)
{//需要在界面放置MapControl控件时,才有MapScale
mapControl.ActiveView.FocusMap.MapScale = 2000;
}
System.Threading.Thread.Sleep(delayTime);
//【1】hdc:输出设备,export.StartExporting()指定
//【2】DPI:会影响图片中矢量线的粗细,DPI越大矢量线越粗,但不会影响图片大小和输出范围,默认96
//【3】tagRECT exportRECT:在图片中地图所占的尺寸,像素单位,一般与图片尺寸相同
//【4】VisibleBounds:指定地图输出的地理内容,地理坐标,如果为空则为地图的当前视野
mapControl.ActiveView.Output(export.StartExporting(), 200, ref exportRECT, mapControl.ActiveView.Extent, null);
export.FinishExporting();
export.Cleanup();
}
注意两个参数:
export.PixelBounds = imgSize;和tagRECT exportRECT
分别表示图片尺寸和地图在图片上显示的尺寸(地图尺寸),都是像素为单位,一般这两个尺寸应相等,否则会出现白边或地图内容显示不全,如图所示:
举例:
案例一:如果地图的坐标单位是米, dpi为96
1英寸=2.54厘米;
1英寸=96像素;
最终换算的单位是米;
如果当前地图比例尺为1:125000000,则代表图上1米实地125000000米;
米和像素间的换算公式:
1英寸=0.0254米=96像素
1像素=0.0254/96米
则根据1:125000000比例尺,图上1像素代表实地距离是125000000*0.0254/96= 33072.9166666667米。我们这个换算结果和切片的结果略微有0.07米的误差。这个误差产生的原因是英寸换算厘米的参数决定的,server使用的换算参数1英寸约等于0.0254000508米。
案例二:如果地理坐标系是wgs84,地图的单位是度,dpi为96
Server中度和米之间的换算参数:
1度约等于 111194.872221777米,周长40030153.99983972米。
若比例尺为1: 1000000,则瓦片分辨率=瓦片单位像素的地理长度=瓦片单位像素的图片长度m*比例尺/1度长度m,
Resolution=(0.0254000508/96) * 1000000/111194.872221777=0.002379461,
与ArcGIS Server自动生成的切片方案高度一致
若瓦片宽度为256像素,则瓦片内影像的地理宽度为:256* Resolution=
256 * (0.0254000508/96) *1000000/111194.872221777=0.60914201度
瓦片宽度(像素)*单位像素长度m*比例尺/1度长度m