【GISER && Painter】矢量切片(Vector tile) 矢量切片(Vector tile)番外一:Proj4js

說明:本月的主要工做都是圍繞製做矢量切片這一個核心問題進行的,因此2月的主題就以這個問題爲主,目前分支出來的一些內容主要包括了TMS(Tile map service),OpenLayers3中的ProjectionResolution以及proj4js在OpenLayers3中的應用,這些在這篇文章以後會繼續展開,做爲本月的番外內容。html

1、GIS數據與OGC標準地圖服務 前端

  本節主要是介紹一些基礎的數據概念以及基本的WebGIS地圖服務,如對這些內容已經熟知,可直接跳過本節。web

  1)GIS中的矢量與柵格數據算法

  熟悉GIS的人應該都知道,在GIS中的數據分類有不少種方式,其中最經常使用的一種是根據數據組織結構方式的不一樣而分類成矢量數據柵格數據的兩種類型。其中柵格數據以二維矩陣的形式來表示地理空間信息的數據結構,其中數據的最小存在單元是以像素的形式存在,能夠理解爲和圖片的組織結構相似,以分辨率等特徵做爲精度的定義標準。數據庫

                               

                 柵格數據                   矢量數據編程

  而矢量數據則是試圖利用點、線、面等幾何要素來表現這個世界,其數據結構緊湊精準,數據圖形質量好,有利於地理信息檢索與網絡傳輸等。其中矢量數據的最小單元是以點的形式存在,點構成線,線組成面,面構造出體。因此,我我的看來矢量數據應該更貼近於信息的精準分析與計算,而柵格數據則偏重於信息的表達(主要受制於當前圖像處理技術的瓶頸)。json

  2)OGC地圖服務數組

  在WebGIS中,訪問數據是經過訪問服務器端的數據庫來獲取數據,鑑於GIS數據的特殊性,在這一套標準的請求響應模型中引入了一套基於OGC標準的地圖服務標準,在這裏我只介紹幾個與本文有關的服務(若是你須要瞭解一個完整的內容,在這裏能夠找到不少資料:http://blog.csdn.net/wildboy2001/article/details/7743350):瀏覽器

  - WMS(Web Map Service)緩存

  Web地圖服務,利用地理空間信息的數據輸出地圖,地圖自己只是一張圖片,其中包括了圖片的寬高、座標系統、圖片格式以及渲染方式,也正是由於自己的簡潔性,讀取傳輸速度都比較快,要高於WFS

  //WMS請求實例

http://localhost:8080/geoserver/szdata/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=true
&LAYERS=szdata:DLZXX_2011_PL_10000_3857&SRS=EPSG:4326&STYLES=&WIDTH=1347&HEIGHT=336
&BBOX=113.68754425048829,22.5346435546875,114.61245574951172,22.7653564453125

  - WFS(Web Feature Service)

  Web要素服務,請求獲取要素,最小單元是以要素的形式存在的,用戶能夠經過與——請求得到的矢量數據——在前端渲染繪製的幾何圖形進行交互,從而達到對矢量要素的控制。

  //WFS請求實例

http://localhost:8080/geoserver/wfs?service=WFS&request=GetFeature&version=1.1.0&outputFormat=application/json
&typename=szdata:DLZXX_2011_PL_10000_new3857

  - TMS(Tile Map Service)

  (詳細內容見番外篇)

  因此,爲了帶來更好更快的用戶體驗,目前許多主流WebGIS應用都採用了柵格切片技術,經過緩存切片的形式使得地圖數據的瀏覽體驗更順暢。打開你的瀏覽器,F12出控制檯,進入任意一家地圖供應商提供的地圖應用,你會發現大部分的地圖數據都是以切片的形式請求得到的,我在這裏就不舉例了。柵格地圖的切片應用是很普遍,可在咱們的平常工做中遇到的需求每每要比這些功能需求較淺的商業性地圖複雜,有的時候用戶甚至會提出須要地圖配色的編輯修改功能這樣的需求,這是商業主流地圖所達不到的,由於柵格切片在完成切圖以後,你所能控制的最小單位是一張圖片,失去了對圖片上地理信息的交互能力。

 

  總結來看,柵格切片存在如下的幾個缺點:

  - 地圖數據一次渲染,沒法修改

  - 無交互能力

  那能否用WFS來替代呢?直接用WFS請求獲取矢量數據,這樣不就得到了交互能力嗎?固然,若是在你的應用中矢量數據量不大的狀況下,這樣作也是可行的,可是當一旦數據量大了起來,前端對於數據的請求和響應處理渲染會提升客戶端的硬件門檻,而頻繁的交互操做也會對服務器產生壓力。

  直接加載的矢量數據與對柵格地圖進行切片這兩種方式看起來好像有些互補,若是能將這兩者結合起來的話應該會很美好: 矢量+切片=矢量切片

2、矢量切片

  1)什麼是矢量切片?

   和柵格切片同樣的思路,以金字塔的方式切割矢量數據,只不過切割的不是柵格圖片,而是矢量數據的描述性文件,目前矢量切片主要有如下三種格式:GeoJSON,TopoJSON和MapbBox Vector Tile(MVT)。

柵格切圖後文件存儲形式  

  矢量切圖後文件存儲形式

切片中的數據結構

  從上面的兩張圖能夠看出,其實思路是一致的,所以,矢量切圖結合了矢量數據與柵格切圖的優點互補:

  - 前端緩存切片,提升地圖使用的體驗

  - 粒度上來看,矢量切圖繼承了矢量數據的特性,以要素爲單位進行管理,增強了細節上的把控能力

  - 在保證體驗的前提下,爲用戶提供地圖數據樣式動態修改的功能,增強了地圖定製化的程度

  - 數據的實時性

   2)如何生成矢量切片?

   目前就博主所知道的矢量切片生成方式共有如下幾種:1)ArcGIS 系列產品:利用ArcGIS Pro生成矢量切片,而後發佈在ArcGIS Online上;2)Mapbox,目前已經提出了一套開放的矢量切片標準,並被多個開源團隊所接受,但具體的產品使用我並不熟悉,因此還請自行搜索資料,若是後期有接觸到這方面,我會繼續補充;3)GeoServer,在2.11beta版中出現了對矢量切片的支持,主要依賴於開源插件geoserver-2.11-SNAPSHOT-vectortiles-plugin以及內嵌的GeoWebcahce完成切片工做。4)本身編寫切片工具,這主要針對於對這一套體系很是熟悉的GIS編程人員,我本人也屬於入門級別,因此在此也無法提供更多詳細的內容。本文主要採用的切片方式就是利用第3種方法,利用GeoServer做爲GIS應用服務器生成矢量切片:

  2-1)切片前須要確認的環境配置:

  a) JAVA環境:GeoServer是一套基於JAVA環境下的開源項目,所以須要配置好JAVA環境,博主採用的是JAVA1.8,由於最新版的GeoServer文檔中提出須要JAVA_8,低配版本(JAVA7)我也試過,但沒有成功,因此爲了穩妥起見,我推薦你使用JAVA8,特別要注意的是,GeoServer當前不支持JAVA9

  b) Tomcat:Web容器,沒有限制,按本身的技術方向選擇。

  c) GeoServer 2.11以及其插件geoserver-2.11-SNAPSHOT-vectortiles-plugin

  d) 矢量數據:我在此使用的是 深圳道路【EPSG:4326】的矢量數據,請特別注意括號中的座標系,在後面我會具體講到相關的問題。

  2-2)切片過程

  a) 首先,咱們將下載好的GeoServer2.11的war包直接放入/%TomcatHome%/WebAPP的文件夾中,啓動Tomcat完畢後,訪問如下連接: http://localhost:8080/geoserver, 若是出現如下頁面則說明部署成功。

  b) 而後,咱們將下載好的插件geoserver-2.11-SNAPSHOT-vectortiles-plugin 進行解壓,而後將其直接copy到tomcat中部署的GeoServer文件夾的WEB-INF的lib文件夾下,重啓tomcat;

  c) 啓動完成後,訪問GeoServer主頁中的數據菜單中的數據存儲,在頁面中選擇添加新的數據存儲,這些步驟和發佈普通數據的步驟一致,在此就不贅述了。

  可是在發佈過程當中有一個編輯圖層的步驟須要注意,在進入編輯圖層的頁面以後,記得點擊選中Tile caching選項卡,你會發現Tile Image Foramt屬性中多出了幾種數據格式,這就說明你的插件生效了。

 

  d) 按照你的需求選中須要切片的格式,若是第一次切的話,我建議能夠用GeoJSON做爲入門,由於GeoJSON格式的數據可讀性較強,可以給咱們一個比較直觀的認識。

  e) 從左邊菜單欄點擊進入Tile caching的Tile Layer子項,在Tile Layer列表中你能夠看到已經被你發佈成功的Tile Layer,經過preview的選擇下拉框中的選項你能夠發現,以前發佈時被選中的格式都出現了,這就說明你的切片數據已經發布成功了!

 

   3)調用矢量切片

  調用矢量切片的方式有不少種,OpenLayers3,Leaflet等等均可以達到目的(不過據說好像LeafLet目前僅支持WGS84投影座標系的矢量切片),所以在這裏使用的調用請求工具是OpenLayers3,具體代碼以下:

 var projection4326 = new ol.proj.Projection({
    code: 'EPSG:4326',
    units: 'degrees',
  });

 

 var defaultView = new ol.View({
    projection: projection4326,
    center: [114.15, 22.65],
        //new ol.proj.fromLonLat([114.15, 22.65]),
    zoom: 11
  });

 
function loadVectorTile(){  
   //參數設置:圖層名稱 / 投影座標系 / 初始化樣式 
  var layerName = 'szdata:DLZXX_2011_PL_10000_4326';   var layerProjection = '4326';   var initStyle = new ol.style.Style({ stroke: new ol.style.Stroke({ color: 'rgb(163,204,25)', width: 5 }) });
//矢量切片圖層 var vectorTile = new ol.layer.VectorTile({ title:"深圳道路-VectorTile", style: initStyle, projection: projection4326,
     //矢量切片數據 source: new ol.source.VectorTile({
       projeciton: projection4326, format:
new ol.format.GeoJSON(),
tileGrid: ol.tilegrid.createXYZ({
          extent: ol.proj.get('EPSG:4326').getExtent(),
          maxZoom:
22 }),
       tilePixelRatio:1,
       
//發出獲取切片的請求
       
tileUrlFunction: function(tileCoord){
 return '/geoserver/gwc/service/tms/1.0.0/'
                +layerName+'@EPSG%3A'+layerProjection+'@geojson/'+(tileCoord[0]-1)
                + '/'+tileCoord[1] + '/' + (Math.pow(2,tileCoord[0]-1)+tileCoord[2]) + '.geojson';
}
      })
    });
   

   //構造Map對象

   //你須要在頁面中提供一個id='map'的div
    map = new ol.Map({
        target: 'map',
        layers: [

          new ol.layer.Tile({
            source: new ol.source.OSM();
          }),

        ],
        view:defaultView,
        controls:[
            new ol.control.ScaleLine(),
            new ol.control.ZoomSlider(),
            new ol.control.LayerSwitcher(),
            new ol.control.OverviewMap(),
            new ol.control.Zoom()
        ],
      });

    map.addLayer(vectorTile);

}

//千萬別忘記這是一個獨立的JS文件,你須要將這一段JS代碼以Onload的方式加載到頁面中

  上述代碼中,在vectorSource的屬性tileUrlFunction中,我對coordinate(一個存儲了XYZ參數的數組)進行了一些簡單的處理,從而使EPSG:4326請求下的XYZ可以與切圖結果相匹配,有一些拼湊的嫌疑,致使了這段代碼並不具備普適性,因此,請讀者根據本身的狀況進行調整,但整個大致思路基本一致,主要是切片行列號的匹配方面須要額外注意。

  最後切片頁面的效果以下(關於樣式的問題,在OL3中你能夠經過設置Layer的Style屬性進行修改樣式,和WFS請求獲取的矢量數據處理方式一致,這也就實現了在完成切片緩存的前提下,獲得了地圖要素樣式的控制權。):

矢量切片效果圖

 控制檯請求響應過程

 

   4)遇到的一些問題

  4-1)我想檢查一下個人切片數據,在哪裏可以找到呢?

  首先,你須要瞭解的是,完成切片工做的實際上是GeoWebCache,而GeoWebCache的數據存儲文件的默認路徑通常爲:

  C:\Users\%YOUR-PC-NAME%\AppData\Local\Temp\geowebcache

  你能夠在這裏面看到各個圖層的切片數據,當你打開你的目標圖層文件夾時,若是你發現是空的,千萬不要着急,由於GeoWebCache中切片的生成原本就是一個動態的過程,

  若實在是不放心,你能夠經過進入GeoServer的管理頁面-->左側菜單欄中的Tile caching-->子菜單Tile Layers-->圖層列表中選擇一個Preview的方式進行預覽,而後在預覽界面進行縮放,你會發現剛纔的文件夾裏多了不少數據文件,這下你就能夠放心的進行下面的調用工做了。但有一點須要提到的是:GeoServer目前還不提供矢量切片的預覽,你經過查看預覽頁面的源碼就能發現,當前預覽功能中的代碼仍是採用的OpenLayers2的老代碼,因此當你選擇預覽vector tile時,只能看到一個個的紅叉。

  4-2)個人切片數據調用不出來怎麼辦?

  在確認了你的數據是沒有問題以後,採用OpenLayers3代碼進行調用,但仍有可能會出現資源地址不存在(即404錯誤)或者請求響應都成功了但是矢量切片的圖層仍未加載到地圖上。這些問題都和一個很關鍵的屬性有關係,就是我上面提到的Projection——投影座標系。在OpenLayers3 中有這麼一些類是須要你提供投影參數的:

  ol.View / ol.layer.Vector / ol.source.Vector

  a)404資源不存在:最有可能的緣由就是,你在在建立vectorTileSource對象時,url中設置的請求參數Projection與你數據視圖的Projection不一致,舉個例子,若是你發出的請求是以900913(Web-mercator)爲切圖投影,而你發佈的數據所採用的投影是4326(WGS 84):

'http://localhost:8080/geoserver/gwc/service/tms/1.0.0/shenzhenDL_4326@EPSG:900913@geojson/{z}/{x}/{-y}.geojson'

致使了切出來的矢量切片的行列號是在EPSG:900913下產生的,因爲EPSG:4326和EPSG:900913之間的不匹配,致使了你用4326的行列號參數XY去請求實際生成的900913的行列號切片,致使了沒法準確的訪問資源。固然還有一個須要提到的小細節:在建立vectorTileSource對象時,有一個很是重要的屬性——tileGrid【ol.tilegrid】,這是用來建立切片的,若是你所切的圖層資源的投影座標系不是默認的EPSG:3857(也就是EPSG:900913),你須要額外的爲你的tilegrid限制一個範圍Extent,如上述代碼中所寫道的同樣。由於在OpenLayers3中的源碼中能夠看出(ol.source.XYZ),全部的默認的投影座標都是EPSG:3857,因此當你使用其餘座標系的數據時,須要將默認的參數所有按照你的投影座標系進行從新聲明,而OL3中也提供了一系列的Projection的轉換方法。

  b)請求響應都沒有問題,可是圖層並未加載出來:其實這個問題我暫時尚未徹底解決,個人初步設想是由於我在GeoServer上發佈數據時,原始數據的Projection並未被識別出來,致使了最終圖層的沒法加載,這可能與投影座標的轉換有關係,在後續我將繼續完成這個問題的探索。

  4-3) 若是我發佈的數據採用的座標系既不是EPSG:4326(WGS84),又不是EPSG:900913(Web Mercator),而是其餘座標系該怎麼辦呢?

  之因此把這個問題列出來是由於在GeoServer中,默認的Tile grid切片格網只定義了4326和900913這兩種類型,若是你須要更多其餘投影座標系下的切片,你須要在Geoserver的Tile Caching選項卡下的子選項tile grid中定義屬於本身的切片格網,固然,OL3中也沒有太多的投影可供你使用,與之相對應的,你須要利用Proj4js去定義你所須要的投影座標系,而後在你的OL3代碼中調用便可,具體關於Proj4js的內容,我會單列一篇文章進行介紹:矢量切片(Vector tile)番外一:Proj4js

   5)總結

  在這篇博客中,主要是簡單地介紹了關於矢量切片的製做與使用方法,沒有深刻的去探索矢量切片的實現原理與算法,若是之後有時間,我會接着這篇博客繼續學習關於切片算法以及實現過程的相關內容。

   其實第一次接觸矢量切片的時候,我並無太多的直觀認識,而網絡上的資料也十分有限,可以找到的博客也是寥寥無幾,一來是由於GIS開發較少,二來矢量切片的技術還處於一個初步發展的階段,基本上都是在開源上使用,ArcGIS系列產品雖有涉及,但也處於一個探索的過程當中,因此我寫這篇博客既是爲了總結以前的學習,也是爲了讓更多的人可以少走一些彎路。

  如下附上我在學習過程當中找到的比較有價值的資料:

  矢量切片的製做過程:http://blog.csdn.net/qingyafan/article/details/53367204,這個博客主要生產的內容是關於WebGIS這一塊的,應該是爲數很少的GIS技術博主,並保持着必定的更新頻率,若你對WebGIS有興趣的話能夠follow一下。

  切片數據的初步研究: http://www.cnblogs.com/naaoveGIS/p/4982549.html,這個博客比較全面,GIS算法、數據庫、中間件、Web以及開源都有涉及,風格也比較接地氣,不過有些內容比較深刻,不只僅是停留在應用層面,因此讀這個博客須要認真細緻的去思考。

相關文章
相關標籤/搜索