C#+AE切出與ArcGIS Server地圖服務緩存兼容的瓦片(180815更新)

最近在做個切片程序,切的瓦片可以和ArcGIS Server和GeoServer兼容,可以選擇ArcGIS Online、谷歌的切片方案,也可以自定義切片方案。切好的瓦片ArcGIS Server發佈的地圖服務可以作爲緩存直接調用。最近整理了下過程,本文將影像切片的原理、方法、程序思路進行介紹。先上效果圖。

目錄

1.效果圖

2.背景

2.1爲何應緩存地圖?

3.關鍵概念

4.設計思路

6.C#代碼講解


1.效果圖

圖1與ArcGIS Server兼容的瓦片圖

圖2使用ArcGIS Server打開的緩存服務

圖3編寫的切片工具

2.背景

使用ArcGIS Server做地圖發佈,爲了提升瀏覽性能,通常會使用現時比較流行的地圖緩存技術(通俗的說法爲“瓦片技術”)。如目前的MapABC和GoogleMap正是使用該技術。

所謂的地圖緩存技術,就是按照一定的數學規則,把地圖提前按照不同比例尺切成一定規格的圖片保存到計算機硬盤裏,當用戶通過客戶端瀏覽器訪問地圖服務時,服務器直接返回當前地圖座標區域所對應的“瓦片”,而不是由服務器動態創建出一幅圖片來送到客戶端,從而達到降低服務器負擔,提升地圖瀏覽速度的效果。

地圖緩存技術一般針對相對穩定的數據,因爲地圖切爲瓦片以後,以圖片的形式存在,對於數據的變化(這裏指的是數據的幾何形狀變化)不能及時的反應,這就是地圖緩存技術不足之處。要想地圖的變化得到及時的反映,那就必須重建地圖緩存。而重建地圖緩存要視地圖的區域範圍和緩存的比例尺而定,時間爲幾分鐘到幾十個小時不等。因此,緩存的管理是一件相對麻煩的事情。

2.1爲何應緩存地圖?

使用緩存時,您爲繪製地圖所造成的性能損失付出代價的唯一時間是在創建緩存時。因此,創建緩存可能要花費很長時間。然而,緩存的好處足可以彌補創建緩存所花費的時間。緩存的一些主要優勢如下:

性能:部署已緩存地圖時,用戶可以做更多的事情,因爲他們所花費的等待地圖繪製的時間更少。

質量:使用緩存時,性能不會受到地圖詳細程度的影響。無論是否使用暈渲地貌、透明度還是 Maplex 標註引擎創建地圖,性能都不會受到影響。緩存只是圖像的集合,服務器返回這些不同的緩存圖像所花費的時間大致相同。

行業標準:您是否去過某個流行的 Internet 製圖站點並觀看過平移和縮放時的小方形切片填充?顯示出所有的切片通常只需要幾分之一秒的時間。這是因爲它們使用的是緩存。使用 ArcGIS Server 地圖緩存,您可以讓地圖實現類似的性能。

參考:

http://enterprise.arcgis.com/zh-cn/server/latest/publish-services/windows/available-map-and-image-cache-properties.htm

https://blog.csdn.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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章