基于 PostGIS 的矢量切片服務(wù)器

基于 PostGIS 的矢量切片服務(wù)器

矢量切片簡介

矢量切片是 MapBox 定義的一種開放的 矢量地圖標(biāo)準(zhǔn) , 已經(jīng)成為開放地理聯(lián)盟 (OGC) 的標(biāo)準(zhǔn)之一。

個人認(rèn)為矢量切片的主要優(yōu)點有:

服務(wù)端只關(guān)注數(shù)據(jù), 無需進(jìn)行繁瑣的配圖;

網(wǎng)絡(luò)傳輸快, 因為只有括矢量數(shù)據(jù);

客戶端渲染, 服務(wù)端的一套矢量數(shù)據(jù), 在客戶端可以有多種的表現(xiàn)形式;

充分利用客戶端硬件

適配客戶端屏幕, 根據(jù)屏幕解析度進(jìn)行高精度矢量渲染;

利用 OpenGL/WebGL 實現(xiàn)海量空間數(shù)據(jù)渲染;

目前制作矢量切片的方式主要有:

使用 ArcGIS Pro 生成矢量切片包, 上傳到 ArcGIS Portal 和 Server , 這套工具最完善, 但是也最貴;

使用開源的 GeoServer 來配置生成矢量切片, 配置比較繁瑣, 而且對于矢量切片標(biāo)準(zhǔn)的支持也也比較慢;

這兩種方式都能生成質(zhì)量比較高的矢量切片, 并提供可靠的矢量切片服務(wù), 但是都需要對數(shù)據(jù)做預(yù)處理, 如果修改了數(shù)據(jù), 往往不能及時響應(yīng)。

PostGIS 對矢量切片的支持

PostGIS 是關(guān)系數(shù)據(jù)庫 PostgreSQL 的空間擴(kuò)展, 提供了強(qiáng)大的空間數(shù)據(jù)查詢和處理能力, 對矢量切片也提供了支持, 相關(guān)的函數(shù)有:

ST_AsMVTGeom 將數(shù)據(jù)庫存儲的空間坐標(biāo)轉(zhuǎn)換為矢量切片坐標(biāo);

ST_AsMVT 將矢量空間坐標(biāo)聚合為符合矢量切片格式規(guī)范的二進(jìn)制數(shù)據(jù);

ST_TileEnvelope 在 Web墨卡托坐標(biāo)系 (SRID:3857) 下使用 xyz 切片架構(gòu) 計算切片切片坐標(biāo)范圍;

通過者上面這三個相關(guān)函數(shù), 可以將數(shù)據(jù)庫存儲的空間數(shù)據(jù)快速轉(zhuǎn)換成矢量切片標(biāo)準(zhǔn)的二進(jìn)制數(shù)據(jù)。

將單表輸出為單圖層矢量切片的 SQL 語句為:

with mvt_geom as (

? select

? ? ST_AsMVTGeom(

? ? ? geom,

? ? ? ST_TileEnvelope(15, 26696, 14219),

? ? ? extent => 4096, buffer => 64

? ? ) as geom,

? ? id, name, fclass, ref, oneway, maxspeed, bridge, tunnel, layer

? from public.sr3857_guangzhou_road

? where geom && ST_TileEnvelope(15, 26696, 14219, margin => (64.0 / 4096))

)

select ST_AsMVT(mvt_geom, 'guangzhou_road', 4096, 'geom', 'id')

from mvt_geom

也可以使用 || 算符將多個圖層生成矢量切片

select (

? (

? ? with mvt_geom as (

? ? ? select

? ? ? ? ST_AsMVTGeom(

? ? ? ? ? geom,

? ? ? ? ? ST_TileEnvelope(15, 26696, 14219),

? ? ? ? ? extent => 4096, buffer => 64

? ? ? ? ) as geom,

? ? ? ? id, name, fclass, ref, oneway, maxspeed, bridge, tunnel, layer

? ? ? from public.sr3857_guangzhou_road

? ? ? where geom && ST_TileEnvelope(15, 26696, 14219, margin => (64.0 / 4096))

? ? )

? ? select ST_AsMVT(mvt_geom, 'guangzhou_road', 4096, 'geom', 'id')

? ? from mvt_geom

? ) || (

? ? with mvt_geom as (

? ? ? select

? ? ? ? ST_AsMVTGeom(

? ? ? ? ? geom,

? ? ? ? ? ST_TileEnvelope(15, 26696, 14219),

? ? ? ? ? extent => 4096, buffer => 64

? ? ) as geom,

? ? ? ? objectid, name, height, flag, type, area_id

? ? ? from public.sr3857_guangzhou_building

? ? ? where geom && ST_TileEnvelope(15, 26696, 14219, margin => (64.0 / 4096))

? ? )

? ? select ST_AsMVT(mvt_geom, 'guangzhou_building', 4096, 'geom', 'objectid')

? ? from mvt_geom

? )

);

矢量切片服務(wù)器

有了上面的 SQL 語句, 開發(fā)矢量切片服務(wù)器就是非常簡單的了, 任何開發(fā)語言都可以實現(xiàn), 下面以 C# 代碼為例:

[HttpGet("{source}/{z:int}/{y:int}/{x:int}")]

public async Task<ActionResult> GetTile(string source, int z, int y, int x) {

? ? try {

? ? ? ? var buffer = await provider.GetTileContentAsync(source, z, y, x);

? ? ? ? if (buffer == null || buffer.Length == 0) {

? ? ? ? ? ? return NotFound();

? ? ? ? }

? ? ? ? return File(buffer, "application/vnd.mapbox-vector-tile");

? ? }

? ? catch (Exception ex) {

? ? ? ? logger.LogError(ex.Message);

? ? ? ? return StatusCode(500);

? ? }

}

通過 appsettings.json 配置兩個矢量切片源:

{

? "connectionStrings": {

? ? "geo_db": "server=127.0.0.1;port=5432;database=geo_db;user id=geo_db_user;password=********;"

? },

? "vectors": {

? ? "guangzhou": {

? ? ? "connectionString": "geo_db",

? ? ? "layers": [

? ? ? ? {

? ? ? ? ? "name": "road",

? ? ? ? ? "minzoom": 9,

? ? ? ? ? "maxzoom": 15,

? ? ? ? ? "srid": 3857,

? ? ? ? ? "schema": "public",

? ? ? ? ? "tableName": "sr3857_guangzhou_road",

? ? ? ? ? "idColumn": "id",

? ? ? ? ? "geometryColumn": "geom",

? ? ? ? ? "attributeColumns": "name, fclass, ref, oneway, maxspeed, bridge, tunnel, layer"

? ? ? ? },

? ? ? ? {

? ? ? ? ? "name": "building",

? ? ? ? ? "minzoom": 13,

? ? ? ? ? "maxzoom": 17,

? ? ? ? ? "srid": 3857,

? ? ? ? ? "schema": "public",

? ? ? ? ? "tableName": "sr3857_guangzhou_building",

? ? ? ? ? "idColumn": "objectid",

? ? ? ? ? "geometryColumn": "geom",

? ? ? ? ? "attributeColumns": "name, height, flag, type, area_id"

? ? ? ? }

? ? ? ]

? ? }

? }

}

這樣生成的矢量切片服務(wù)的地址是: http://127.0.0.1:5000/api/vector/guangzhou/{z}/{y}/{x} , 包含了 road 和 building 兩個圖層。

使用矢量切片服務(wù)

生成的是基于 Web 墨卡托坐標(biāo)系的 xyz 切片架構(gòu)的標(biāo)準(zhǔn)的矢量切片服務(wù), 可以直接任意支持矢量切片的客戶端中使用 (mapboxgl, openlayers, arcgis js api 等), 配置參照下面的矢量切片樣式:

{

? "version": 8,

? "sources": {

? ? "guangzhou": {

? ? ? "type": "vector",

? ? ? "scheme": "xyz",

? ? ? "tiles": ["http://127.0.0.1:5000/api/vectortiles/guangzhou/{z}/{y}/{x}"],

? ? ? "minzoom": 9,

? ? ? "maxzoom": 17

? ? }

? },

? "layers": [

? ? {

? ? ? "id": "road",

? ? ? "source": "guangzhou",

? ? ? "source-layer": "road",

? ? ? "type": "line",

? ? ? "minzoom": 9,

? ? ? "maxzoom": 15,

? ? ? "paint": {

? ? ? ? "line-color": "#00FF00",

? ? ? ? "line-width": 2

? ? ? }

? ? },

? ? {

? ? ? "id": "building",

? ? ? "source": "guangzhou",

? ? ? "source-layer": "guangzhou_building",

? ? ? "type": "fill",

? ? ? "minzoom": 13,

? ? ? "maxzoom": 17,

? ? ? "paint": {

? ? ? ? "fill-opacity": 0.8,

? ? ? ? "fill-color": "#8c2d04"

? ? ? }

? ? }

? ]

}

注意問題

PostGIS 版本要求最新的 3.1.x ;

雖然 PostGIS 3.x 最低支持 PostgreSQL 9.6.x , 但是建議使用高版本的 PostgreSQL (12+), 因為 PostgreSQL 12 以上的版本提供了更好的查詢性能;

雖然 PostGIS 提供了坐標(biāo)系轉(zhuǎn)換函數(shù) ST_Transform , 但是進(jìn)行實時轉(zhuǎn)換會消耗一些性能, 建議將空間數(shù)據(jù)轉(zhuǎn)換為 Web墨卡托坐標(biāo)系 (SRID:3857) 存儲在數(shù)據(jù)庫, 這樣在運行時就無需進(jìn)行坐標(biāo)系轉(zhuǎn)換, 效率最高;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容