1. 程式人生 > >向量切片(Vector tile)

向量切片(Vector tile)

轉自:http://www.cnblogs.com/escage/p/6387529.html

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

一、GIS資料與OGC標準地圖服務 

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

  1)GIS中的向量與柵格資料

  熟悉GIS的人應該都知道,在GIS中的資料分類有很多種方式,其中最常用的一種是根據資料組織結構方式的不同而分類成向量資料柵格資料的兩種型別。其中柵格資料以二維矩陣的形式來表示地理空間資訊的資料結構,其中資料的最小存在單元是以畫素的形式存在,可以理解為和圖片的組織結構類似,以解析度等特徵作為精度的定義標準。

                               

                 柵格資料                   向量資料

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

  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請求獲取向量資料,這樣不就獲得了互動能力嗎?當然,如果在你的應用中向量資料量不大的情況下,這樣做也是可行的,但是當一旦資料量大了起來,前端對於資料的請求和響應處理渲染會提高客戶端的硬體門檻,而頻繁的互動操作也會對伺服器產生壓力。

  直接載入的向量資料與對柵格地圖進行切片這兩種方式看起來好像有些互補,如果能將這二者結合起來的話應該會很美好: 向量+切片=向量切片

二、向量切片

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容器,沒有限制,按自己的技術方向選擇。

  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/[email protected]:[email protected]/{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以及開源都有涉及,風格也比較接地氣,不過有些內容比較深入,不僅僅是停留在應用層面,所以讀這個部落格需要認真細緻的去思考。