OpenLayers:海量圖形渲染之矢量切片

最近由于在工作中涉及到了海量圖形渲染的問題,因此我開始研究相關的解決方案。在咨詢了許多朋友之后發現矢量切片似乎是行業內最常用的一種解決方案,于是我便開始研究它該如何使用。

一、什么是矢量切片

矢量切片按照我的理解就是用柵格切片的方式把矢量數據也切成金字塔,只不過切割的不是柵格圖片,而是矢量數據的描述性文件。

矢量切片的特點

因此矢量切片它就兼具矢量數據與柵格數據的優點,比如說:

  • 矢量瓦片相比于柵格圖片更加靈活,可以直接訪問矢量要素,因為矢量數據是以要素為單位的,而柵格數據它就是一個圖片那就難以直接訪問到具體的要素了。
  • 可直接在客戶端獲取請求指定地物的信息,無須再次請求服務器。因為空間數據和屬性數據一起被請求到客戶端了,無需再次請求了。
  • 樣式可改變和定制。因為我們拿到的只是矢量數據,因此就可以在客戶端自由的給它設置樣式。
  • 相比于原始矢量數據,矢量瓦片更小巧,進行了重新編碼并切分,在被請求時可以只返回請求區域和相應級別的數據。這個優點也就是我想使用它的理由,我期望矢量切片可以幫助我解決海量圖形渲染的問題。
  • 數據更新快,甚至可以說是實時的,當數據庫中的空間數據變化后,再次請求的數據是更新后的數據。

二、發布矢量切片服務

如何發布矢量瓦片服務,具體要看你使用的是什么WebGIS服務器,不同的WebGIS服務器操作的步驟可能都不一樣,需要專門去查閱相關資料。我在實驗的過程中是使用GeoServer來發布矢量切片的。

GeoServer中發布矢量切片

1.下載Vector Tiles 插件

GeoServer中無法直接實現矢量切片,需要下載對應的插件。

插件在官網中就可以下載(Download - GeoServer),但是注意要到自己所安裝的對應geoserver版本的下載頁面中去下載插件,如果下載了其它版本下的插件,可能會在啟動geoserver時導致報錯。

由于我安裝的是2.21.5版本的geoserver,因此就進入這個版本的下載頁面。

然后下滑到下面的 Extensions 部分就可以找到對應的插件。

2.安裝Vector Tiles插件

將下載的插件解壓之后得到如下的這些文件,復制其中的.jar文件(jar包)。

將復制好的文件放到geoserver的 WEB-INF/lib目錄下,這個目錄中都是各種.jar文件,比較好辨認。

3.檢查Vector Tiles插件是否安裝成功

安裝插件成功后重新啟動GeoServer,然后打開GeoServer的圖層頁面

然后隨便選擇一個矢量圖層

然后進入Tile Caching頁面

滾動頁面到 "Tile Image Formats" 部分,除了標準的GIF/PNG/JPEG格式之外,如果你好看到以下的內容就表示插件安裝成功了。

4.發布矢量切片

發布矢量切片的過程也很簡單,首先將自己準備的數據創建為一個矢量圖層(具體的步驟我就不多說了)。

這里我就隨便選擇了一個GeoServer中的美國人口的矢量面圖

點擊進入“圖層編輯”頁面,然后再進入“Tile Caching”選項卡

滾動頁面到 "Tile Image Formats" 部分,勾選application/json;type=geojsonapplication/json;type=topojsonapplication/vnd.mapbox-vector-tile這幾個選項(注意:這三個選項對應了三種不同格式的矢量切片數據,我們每勾選一種就會GeoServer就會制作發布一種對應格式的矢量切片)

最后點擊保存,一個帶有矢量切片的圖層就準備好了。

三、OpenLayers中加載矢量切片

1.加載TMS服務的矢量切片

網上絕大多數的文章中都是加載的TMS服務的矢量切片,這種加載方式看起來還是比較簡單的,但是我在實際使用的時候卻發現“困難重重”實際上用起來比較麻煩。

獲取TMS服務地址

首先第一步我們要搞清楚我們所發布的矢量瓦片的TMS服務的url地址是什么。可以打開Goeserver去查看。

點擊左上角的logo進入首頁

在首頁點擊TMS的鏈接

進入的這個頁面中就記錄了目前我的這臺GeoServer服務器上發布的所有TMS服務的url。

找到之前設置了矢量切片的圖層的鏈接(例如我下面的這個美國人口的圖層)

這其中以geojsontopojsonpbf結尾的url就是矢量切片的url。

然后就可以拿到一個類似于http://localhost:8080/geoserver/gwc/service/tms/1.0.0/topp%3Astates@EPSG%3A4326@geojson這樣的url。這個url由幾個部分組成:

  1. http://localhost:8080/geoserver/gwc/service/tms/1.0.0 這部分在同一個GeoServer服務器上是固定的。
  2. /topp%3Astates 這部分表示圖層名,其中的%3A是冒號的URL編碼形式,所以我這里的圖層就叫做topp:states
  3. @EPSG%3A4326 這部分表示投影,我這使用的是 EPSG:4326
  4. @geojson 這部分表示數據的格式

一個完整的TMS的url還不止上面的這些,它應該還要包括切片的具體信息,例如:http://localhost:8080/geoserver/gwc/service/tms/1.0.0/topp%3Astates@EPSG%3A4326@geojson/3/2/1.geojson

后面的/3/2/1分別代表切片的層級、列號和行號。

加載TMS矢量切片的方式

OpenLayers中加載矢量切片都需要使用VectorTile 圖層 + VectorTile數據源的方式來實現。

創建VectorTile 圖層時可以通過style屬性給請求到的矢量瓦片數據設置樣式。

創建VectorTile數據源時則主要是要設置三個屬性:

  1. url,即矢量瓦片服務的地址,由于OpenLayers中不支持直接請求TMS服務,所以需要通過請求XYZ服務的方式請求TMS,因此url要寫成"http://localhost:8080/geoserver/gwc/service/tms/1.0.0/BeiJiang%3Abj@EPSG%3A4326@geojson/{z}/{x}/{-y}.geojson"的形式,也就是用占位符{z}{x}{y}來表示切片的層級、列號和行號。但是這里有一點特殊的地方在于使用的是{-y},之所以這樣寫是因為XYZ瓦片的y坐標從頂部開始向下遞增,TMS瓦片的y坐標從底部開始向上遞增,也就是說他們的y軸方向相反,所以url中要寫成{-y}進行轉換。
  2. format,這個屬性是用來將矢量數據轉換為Feature的,如果矢量切片的數據類型是geojson就使用GeoJSON轉換器,如果矢量切片的數據類型是pbf就使用MVT轉換器(這些轉換器都是OpenLayers封裝好的的都在ol/format目錄下面)。
  3. tileGrid,這個屬性應該用來定義切片規則的,具體怎么定義的我也搞不懂。這里由于我們使用的是加載XYZ服務的方式,所以可以直接使用OpenLayers內置的createXYZ函數來直接創建適合XYZ服務的tileGrid。但是在使用createXYZ函數時特別要注意,其中的extent屬性默認為 EPSG:3857 投影的范圍,如果你像我一樣使用的是其它的投影(例如 EPSG:4326),那就必需要手動將這個屬性設置為你所使用的投影的范圍,否則請求的url將會404(不要問我是怎么知道的😭)
import { VectorTile as VectorTileLayer } from "ol/layer";
import { VectorTile as VectorTileSource } from "ol/source";
import { Style, Stroke, Circle as CircleStyle } from "ol/style";
import { GeoJSON} from "ol/format";
import { createXYZ } from "ol/tilegrid";// 加載矢量切片
const riverVectorTileLayer = new VectorTileLayer({source: new VectorTileSource({url: "http://localhost:8080/geoserver/gwc/service/tms/1.0.0/BeiJiang%3Abj@EPSG%3A4326@geojson/{z}/{x}/{-y}.geojson",format: new GeoJSON(),tileGrid: new createXYZ({extent: getProjection("EPSG:4326").getExtent(),maxZoom: 18,}),}),style: function (feature) {const style = new Style({stroke: new Stroke({color: "blue",width: 1,}),});return style;},
});
map.addLayer(riverVectorTileLayer);

但是我使用上面的這套代碼進行加載卻失敗了,請求到的數據都是空的,這個就很奇怪,我看到很多的博客中都是這么寫的,他們都能加載出來,我卻加載不出來 ╭(╯^╰)╮。

之后,我歷經了千辛萬苦終于找到了原因出在哪里,我發現只要將層級z減一就能夠請求到正確的矢量切片數據,這就說明XYZ的層級跟TMS的層級好像是不匹配的,有可能XYZ切片的層級是從1開始計數的,而TMS切片的層級是從0開始計數的。

想要將z減一,就需要使用tileUrlFunction屬性,這個屬性接收一個函數,然后XYZ切片的坐標就會作為參數傳入到函數中,之后就可以根據XYZ切片的坐標來換算出TMS切片的坐標。

要換算的地方有兩個,一是將z減一這個比較簡單,二是要將y進行轉換(因為它們的y軸是相反的)。

# 進行y軸轉換的公式
y_tms = 最大行號 - y_xyz
# 因為
最大行號 = 總行數 - 1
# 所以
y_tms = 總行數 - 1 - y_xyz
# 又因為
總行數 = 2 ^ z_tms  # 2的z次方
z_tms = z_xyz - 1
# 所以最終的公式為
y_tms = (2 ^ (z_xyz - 1)) - 1  - y_xyz
import { VectorTile as VectorTileLayer } from "ol/layer";
import { VectorTile as VectorTileSource } from "ol/source";
import { Style, Stroke, Circle as CircleStyle } from "ol/style";
import { GeoJSON} from "ol/format";
import { createXYZ } from "ol/tilegrid";// 加載矢量切片
const riverVectorTileLayer = new VectorTileLayer({source: new VectorTileSource({tileUrlFunction: function (tileCoord) {const [z, x, y] = tileCoord;const url ="http://localhost:8080/geoserver/gwc/service/tms/1.0.0/BeiJiang%3Abj@EPSG%3A4326@geojson/" +(z - 1) +"/" +x +"/" +(Math.pow(2, z - 1) - 1 - y) +".geojson";return url;},format: new GeoJSON(),tileGrid: new createXYZ({extent: getProjection("EPSG:4326").getExtent(),maxZoom: 18,}),}),style: function (feature) {const style = new Style({stroke: new Stroke({color: "blue",width: 1,}),});return style;},
});
map.addLayer(riverVectorTileLayer);

通過上面的方式我最終才將我自己的矢量切片加載出來了

2.加載WMTS服務的矢量切片

之后我又看到了另一種加載方式,通過WMTS進行加載。WMTS加載起來那就比TMS要復雜很多了,但是其實是有一條“捷徑”的。

在GeoServer中,進入切片圖層頁面。

選擇一個帶有矢量切片的矢量圖層,在預覽的下拉菜單中選擇帶有geojsontopojsonpbf的選項就可以預覽矢量切片

然后F12打開調試工具查看頁面的源代碼,在demo文件夾中就可以找到通過WMTS加載矢量切片的代碼,直接照抄就可以了。

// 通過WMTS加載矢量切片
function addRiver_vectorTileWMTS() {const baseUrl = "http://localhost:8080/geoserver/gwc/service/wmts";const layerName = "BeiJiang:bj";const style = "";const gridsetName = "EPSG:4326";const format = "application/json;type=geojson";const resolutions = [0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625,0.010986328125, 0.0054931640625, 0.00274658203125, 0.001373291015625,6.866455078125e-4, 3.4332275390625e-4, 1.71661376953125e-4,8.58306884765625e-5, 4.291534423828125e-5, 2.1457672119140625e-5,1.0728836059570312e-5, 5.364418029785156e-6, 2.682209014892578e-6,1.341104507446289e-6, 6.705522537231445e-7, 3.3527612686157227e-7,];const params = {REQUEST: "GetTile",SERVICE: "WMTS",VERSION: "1.0.0",LAYER: layerName,STYLE: style,TILEMATRIX: gridsetName + ":{z}",TILEMATRIXSET: gridsetName,FORMAT: format,TILECOL: "{x}",TILEROW: "{y}",};let url = baseUrl + "?";for (var param in params) {url = url + param + "=" + params[param] + "&";}url = url.slice(0, -1);riverVectorTileLayer = new VectorTileLayer({source: new VectorTileSource({url,format: new GeoJSON(),projection: "EPSG:4326",tileGrid: new WMTSTileGrid({extent: [-180, -90, 180, 90],resolutions: resolutions,matrixIds: ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21",],}),}),style: function (feature) {const style = new Style({stroke: new Stroke({color: "blue",width: 1,}),});return style;},});map.addLayer(riverVectorTileLayer);
}

參考資料

  1. 矢量切片(Vector tile)_a vectortile source can only be rendered if it has-CSDN博客
  2. Openlayer加載geoserver發布的矢量切片_openlayers 加載geoserver xyz-CSDN博客
  3. QGIS加載Geoserver發布的矢量瓦片服務 - 槑孒 - 博客園
  4. 10openlayers加載矢量瓦片圖層-CSDN博客
  5. GeoServer官方教程:矢量切片
  6. OpenLayers教程十:多源數據加載之瓦片地圖原理二
  7. 【webgis】地圖切片|矢量地圖切片|柵格地圖切片-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76139.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76139.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76139.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

神經網絡入門—自定義網絡

網絡模型 定義一個兩層網絡 import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F# 定義神經網絡模型 class Net(nn.Module):def __init__(self, init_x0.0):super().__init__()self.fc1 nn.Linear(1, 10)self.fc2 nn.Linear(…

無人機裝調與測試

文章目錄 前言一、無人機基本常識/預備知識(一)無人機飛行原理無人機硬件組成/各組件作用1.飛控2.GPS3.接收機4.電流計5.電調6.電機7.電池8.螺旋槳9.UBEC(穩壓模塊) (二)飛控硬件簡介(三&#x…

2024年-全國大學生數學建模競賽(CUMCM)試題速瀏、分類及淺析

2024年-全國大學生數學建模競賽(CUMCM)試題速瀏、分類及淺析 全國大學生數學建模競賽(China Undergraduate Mathematical Contest in Modeling)是國家教委高教司和中國工業與應用數學學會共同主辦的面向全國大學生的群眾性科技活動,目的在于激…

Linux入門指南:從零開始探索開源世界

🚀 前言 大家好!今天我們來聊一聊Linux這個神奇的操作系統~ 🤖 很多小伙伴可能覺得Linux是程序員專屬,其實它早已滲透到我們生活的各個角落!本文將帶你了解Linux的誕生故事、發行版選擇攻略、應用領域,還有…

記錄vscode連接不上wsl子系統下ubuntu18.04問題解決方法

記錄vscode連接不上wsl子系統下ubuntu18.04問題解決方法 報錯內容嘗試第一次解決方法嘗試第二次解決方法注意事項參考連接 報錯內容 Unable to download server on client side: Error: Request downloadRequest failed unexpectedly without providing any details… Will tr…

Cursor+MCP學習記錄

參考視頻 Cursor MCP 王炸!徹底顛覆我的Cursor工作流,效率直接起飛_嗶哩嗶哩_bilibili 感覺這個博主講的還不錯 所使用到的網址 Smithery - Model Context Protocol Registry Introduction - Model Context Protocol 學習過程 Smithery - Model …

testflight上架ipa包-只有ipa包的情況下如何修改簽名信息為蘋果開發者賬戶對應的信息-ipa蘋果包如何手動改簽或者第三方工具改簽-優雅草卓伊凡

testflight上架ipa包-只有ipa包的情況下如何修改簽名信息為蘋果開發者賬戶對應的信息-ipa蘋果包如何手動改簽或者第三方工具改簽-優雅草卓伊凡 直接修改蘋果IPA包的簽名和打包信息并不是一個推薦的常規做法,因為這可能違反蘋果的開發者條款,并且可能導致…

深入解析Java內存與緩存:從原理到實踐優化

一、Java內存管理:JVM的核心機制 1. JVM內存模型全景圖 ┌───────────────────────────────┐ │ JVM Memory │ ├─────────────┬─────────────────┤ │ Thread │ 共享…

紫光展銳5G SoC T8300:影像升級,「定格」美好世界

影像能力已成為當今衡量智能手機性能的重要標尺之一。隨著消費者對手機攝影需求日益提升,手機廠商紛紛在影像硬件和算法上展開激烈競爭,力求為用戶帶來更加出色的拍攝體驗。 紫光展銳專為全球主流用戶打造的暢享影音和游戲體驗的5G SoC——T8300&#x…

【Java設計模式】第6章 抽象工廠模式講解

6. 抽象工廠模式 6.1 抽象工廠講解 定義:提供一個接口創建一系列相關或依賴對象,無需指定具體類。核心概念: 產品等級結構:同一類型的不同產品(如Java視頻、Python視頻)。產品族:同一工廠生產的多個產品(如Java視頻 + Java手記)。適用場景: 需要創建多個相關聯的產品…

Dify教程01-Dify是什么、應用場景、如何安裝

Dify教程01-Dify是什么、應用場景、如何安裝 大家好,我是星哥,上篇文章講了Coze、Dify、FastGPT、MaxKB 對比,今天就來學習如何搭建Dify。 Dify是什么 **Dify 是一款開源的大語言模型(LLM) 應用開發平臺。**它融合了后端即服務&#xff08…

Java后端開發-面試總結(集結版)

第一個問題,在 Java 集合框架中,ArrayList和LinkedList有什么區別?在實際應用場景中,應該如何選擇使用它們? ArrayList 基于數組,LinkedList 基于雙向鏈表。 在查詢方面 ArrayList 效率高,添加…

nslookup、dig、traceroute、ping 這些工具在解析域名時是否查詢 DNS 服務器 或 本地 hosts 文件 的詳細對比

host配置解析 127.0.0.1 example.comdig 測試,查詢 DNS 服務器 nslookup測試,查詢 DNS 服務器 traceroute測試,先讀取本地 hosts 文件,再查詢 DNS 服務器 ping測試,先讀取本地 hosts 文件,再查詢 DNS 服務…

文件上傳、讀取與包含漏洞解析及防御實戰

一、漏洞概述 文件上傳、讀取和包含漏洞是Web安全中常見的高危風險點,攻擊者可通過此類漏洞執行惡意代碼、竊取敏感數據或直接控制服務器。其核心成因在于開發者未對用戶輸入內容進行充分驗證或過濾,導致攻擊者能夠繞過安全機制,上傳或執行…

STM32 的編程方式總結

🧱 按照“是否可獨立工作”來分: 庫/方式是否可獨立使用是否依賴其他庫說明寄存器裸寫? 是? 無完全自主控制,無庫依賴標準庫(StdPeriph)? 是? 只依賴 CMSIS自成體系(F1專屬),只…

Flutter命令行打包打不出ipa報錯

Flutter打包ipa報錯解決方案 在Flutter開發中,打包iOS應用時可能會遇到以下錯誤: error: exportArchive: The data couldn’t be read because it isn’ in the correct format. 或者 Encountered error while creating the IPA: error: exportArchive…

SQL Server常見問題的分類解析(一)

以下是SQL Server常見問題的分類解析,涵蓋安裝配置、性能優化、備份恢復、高可用性等核心場景,結合微軟官方文檔和社區實踐整理而成(編號對應搜索結果來源): 一、安裝與配置問題 安裝失敗:.NET Framework缺失解決方案:手動安裝所需版本.NET Framework,以管理員身份運行…

Spring Boot 3.x 下 Spring Security 的執行流程、核心類和原理詳解,結合用戶描述的關鍵點展開說明,并以表格總結

以下是 Spring Boot 3.x 下 Spring Security 的執行流程、核心類和原理詳解,結合用戶描述的關鍵點展開說明,并以表格總結: 1. Spring Security 核心原理 Spring Security 通過 Filter 鏈 實現安全控制,其核心流程如下&#xff1a…

Vue:路由切換表格塌陷

目錄 一、 出現場景二、 解決方案 一、 出現場景 當路由切換時&#xff0c;表格操作欄會出現行錯亂、塌陷的問題 二、 解決方案 在組件重新被激活的時候刷新表格 <el-table ref"table"></el-table>activated(){this.$nextTick(() > {this.$refs[t…

文件上傳漏洞原理學習

什么是文件上傳漏洞 文件上傳漏洞是指用戶上傳了一個可執行的腳本文件&#xff0c;并通過此腳本文件獲得了執行服務器端命令的能力。“文件上傳” 本身沒有問題&#xff0c;有問題的是文件上傳后&#xff0c;服務器怎么處理、解釋文件。如果服務器的處理邏輯做的不夠安全&#…