meface/docs/article/db/vectorData.md

336 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: PostGIS 矢量瓦片
date: 2020-09-11
author: ac
tags:
- vector tile
categories:
- Database
---
![马丁](./images/logo.png)
### Martin - 基于PostGIS的矢量瓦片服务器
### 1. 简介
目前流行的矢量瓦片的切图方案:
- `mapbox gl` + [tippecanoe](https://github.com/mapbox/tippecanoe) v2收费tippecanoe是mapbox官方推荐的矢量瓦片静态生成工具 ,适用于大数据量场景,且不频繁更新的空间数据;
- `openlayers` + `geoserver` 开源使用geoserver的矢量瓦片扩展增加矢量瓦片的输出格式
- `maplibre`+ `Martin` +[postgis](https://www.postgis.net/docs/manual-dev/en/ST_AsMVT.html) 开源martin是矢量切片服务器通过postgis的函数动态生成矢量瓦片。
- `maptiler`:收费
> mapbox v2 必须使用 access token 才能初始化 Map 对象。进行token计算每月50000免费次数。
### 2. Martin
`Martin`是一个开源的PostGIS矢量切片服务器可以从任何PostGIS表或视图中创建`MVT`矢量切片,也可以从 PMTile 和MBTile文件中动态生成矢量瓦片是使用 `Rust`编写,针对切片速度和大流量进行了优化,是极快且轻量级的切片服务器。
#### 2.1 安装
> 如果将Martin和PostgreSQL一起使用PostGIS版本必须为v3.0+
Martin支持Linux、macOS、windows平台和docker环境本例采用windows环境。先从github上下载[martin-Windows-x86_64](https://github.com/maplibre/martin/releases/latest/download/martin-Windows-x86_64.zip) 。解压后会发现这两个exe:
```yaml
─martin-Windows-x86_64
├─martin.exe
└─mbtiles.exe
```
windows平台可以直接使用`martin.exe`来启动切片服务器,可以先在命令行查看一下参数:
```shell
D:\tools\vectorTileTool\martin-Windows-x86_64>martin.exe --help
Blazing fast and lightweight tile server with PostGIS, MBTiles, and PMTiles support
Usage: martin.exe [OPTIONS] [CONNECTION]...
Arguments:
[CONNECTION]... Connection strings, e.g. postgres://... or /path/to/files
Options:
-c, --config <CONFIG>
Path to config file. If set, no tile source-related parameters are allowed
--save-config <SAVE_CONFIG>
Save resulting config to a file or use "-" to print to stdout. By default, only print if sources are auto-detected
-s, --sprite <SPRITE>
Export a directory with SVG files as a sprite source. Can be specified multiple times
-k, --keep-alive <KEEP_ALIVE>
Connection keep alive timeout. [DEFAULT: 75]
-l, --listen-addresses <LISTEN_ADDRESSES>
The socket address to bind. [DEFAULT: 0.0.0.0:3000]
-W, --workers <WORKERS>
Number of web server workers
-b, --disable-bounds
Disable the automatic generation of bounds for spatial PG tables
--ca-root-file <CA_ROOT_FILE>
Loads trusted root certificates from a file. The file should contain a sequence of PEM-formatted CA certificates
-d, --default-srid <DEFAULT_SRID>
If a spatial PG table has SRID 0, then this default SRID will be used as a fallback
-p, --pool-size <POOL_SIZE>
Maximum connections pool size [DEFAULT: 20]
-m, --max-feature-count <MAX_FEATURE_COUNT>
Limit the number of features in a tile from a PG table source
-h, --help
Print help
-V, --version
Print version
```
#### 2.2 使用
> 本例pg安装postgis是v3.3.3.1
`martin`连接pg可以用`connection_string`(命令行参数)和配置文件两种形式。
PostgreSQL连接字符串的形式
```shell
# martin.exe postgresql://user:password@host/db
D:\tools\vectorTileTool\martin-Windows-x86_64>martin.exe postgresql://postgres:123@127.0.0.1:5433/postgres
[2023-08-08T03:50:11Z INFO martin] Starting Martin v0.8.7
[2023-08-08T03:50:11Z INFO martin] Config file is not specified, auto-detecting sources
[2023-08-08T03:50:11Z INFO martin::pg::pool] Connecting to postgresql://postgres:123@127.0.0.1:5433/postgres
[2023-08-08T03:50:11Z INFO martin::pg::configurator] Discovered source zhujiang_river from table public.zhujiang_river with geom column (MULTIPOLYGON, SRID=4326)
[2023-08-08T03:50:11Z INFO martin] Use --save-config to save or print Martin configuration.
[2023-08-08T03:50:11Z INFO martin] Martin has been started on 0.0.0.0:3000.
[2023-08-08T03:50:11Z INFO martin] Use http://0.0.0.0:3000/catalog to get the list of available sources.
```
配置文件的形式 config.yaml
```yaml
# Connection keep alive timeout [default: 75]
keep_alive: 75
# The socket address to bind [default: 0.0.0.0:3000]
listen_addresses: '127.0.0.1:3000'
# Number of web server workers
worker_processes: 8
# Database configuration. This can also be a list of PG configs.
postgres:
# Database connection string. You can use env vars too, for example:
# $DATABASE_URL
# ${DATABASE_URL:-postgresql://postgres@localhost/db}
connection_string: 'postgresql://postgres@localhost:5433/postgres?sslmode=disable&user=postgres&password=123'
# Same as PGSSLCERT for psql
#ssl_cert: './postgresql.crt'
# Same as PGSSLKEY for psql
#ssl_key: './postgresql.key'
# Same as PGSSLROOTCERT for psql
#ssl_root_cert: './root.crt'
# If a spatial table has SRID 0, then this SRID will be used as a fallback
default_srid: 4326
# Maximum connections pool size [default: 20]
pool_size: 20
# Limit the number of table geo features included in a tile. Unlimited by default.
max_feature_count: 1000
# Control the automatic generation of bounds for spatial tables [default: false]
# If enabled, it will spend some time on startup to compute geometry bounds.
disable_bounds: false
```
```shell
D:\tools\vectorTileTool\martin-Windows-x86_64>martin.exe -c config.yaml
[2023-08-08T03:54:43Z INFO martin] Starting Martin v0.8.7
[2023-08-08T03:54:43Z INFO martin] Using config.yaml
[2023-08-08T03:54:43Z INFO martin::pg::pool] Connecting to postgresql://postgres@localhost:5433/postgres?sslmode=disable&user=postgres&password=123
[2023-08-08T03:54:43Z INFO martin::pg::configurator] Discovered source zhujiang_river from table public.zhujiang_river with geom column (MULTIPOLYGON, SRID=4326)
[2023-08-08T03:54:44Z INFO martin] Use --save-config to save or print Martin configuration.
[2023-08-08T03:54:44Z INFO martin] Martin has been started on 127.0.0.1:3000.
[2023-08-08T03:54:44Z INFO martin] Use http://127.0.0.1:3000/catalog to get the list of available sources.
```
本例采用的是配置文件的形式启动服务器,服务地址是`http://127.0.0.1:3000`。
从启动的日志可以看到`Martin`将所连接的pg库中的`zhujiang_river`表发布为数据源。
> Martin 会将所有表发布为数据源(如果它们至少有一个几何列)。如果 SRID 为 0则必须设置默认 SRID否则该地理列/表将被忽略。所有非几何表列都将发布为矢量切片要素标签(属性)。
![image-20230808134430612](./images/image-20230808134430612.png)
打开目录可以看到已发布的数据源:
![image-20230808135027306](./images/image-20230808135027306.png)
![image-20230809094825559](./images/image-20230809094825559.png)
数据表的元数据是符合`TileJSON 3.0.0`标准的JSON文件。
`Martin`为每张要素表都提供一个`TileJSON` endpoint。
> TileJSON是表示地图元数据的开放标准endpoint这个词以前经常被用来描述进程间通信。
#### 2.3 mapbox
发布完数据源后使用mapbox gl 来调用一下:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/mapbox-gl@1.9.1/dist/mapbox-gl.js"></script>
<link href="https://unpkg.com/mapbox-gl@1.9.1/dist/mapbox-gl.css"/>
<style>
#map{
height: 100vh;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const TIANDITU_URL = 'http://t0.tianditu.gov.cn';
const tdtKey = "your_token";
const tdtConfig = {
code: 'tdt_img',
name: '天地图影像',
source: {
type: 'raster',
tiles: [
`${TIANDITU_URL}/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=${tdtKey}`
],
tileSize: 256,
minzoom: 0,
maxzoom: 22
},
layer: {
id: 'tdt-img-tiles',
type: 'raster',
minzoom: 0,
maxzoom: 22,
layout: { visibility: 'visible' }
}
}
let map = new mapboxgl.Map({
container:'map',
style:{
"version":8,
"sources":{},
"layers":[],
glyphs: "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
},
center: [112.39747, 22.908823], // 广东
zoom: 8, // starting zoom 地图初始的拉伸比例
pitch: 0, // 地图的角度不写默认是0取值是0-85度一般在3D中使用
bearing: 0, // 地图的初始方向值是北的逆时针度数默认是0即是正北
antialias: true, // 抗锯齿通过false关闭提升性能
minZoom: 3,
maxZoom: 17.36
});
map.on('load', () => {
// 天地图底图加载
addLayerConfig(tdtConfig);
addMvt();
});
function addLayerConfig(layerConfig){
const {code, source,layer} = layerConfig;
map.addSource(code, source);
const layerParams = {
...layer,
source: code
};
// 添加图层
map.addLayer(layerParams);
}
function addMvt(){
map.addLayer({
id: 'lines',
type: 'fill',
source: {
type: 'vector',
url: 'http://localhost:3000/zhujiang_river'
},
'source-layer': 'zhujiang_river',
paint: {
'fill-color': 'red'
}
});
}
</script>
</body>
</html>
```
加载效果:
![image-20230808141517572](./images/image-20230808141517572.png)
#### 2.4 openlayers
> **由于postgis 切片生成的是mvt格式图片,所以只能使用web墨卡托坐标系**
### 3.应用
#### 3.1 docker安装
```shell
[root@localhost martin]# pwd
/home/martin
# 下载martin镜像
[root@localhost martin]# docker pull ghcr.io/maplibre/martin:main
main: Pulling from maplibre/martin
7264a8db6415: Pull complete
8b9d286dcf48: Pull complete
ada398a88aa0: Pull complete
Digest: sha256:13b38133bc15fd1d8b9b9444ca28e0380146799f1faa4c1f418090f067d48474
Status: Downloaded newer image for ghcr.io/maplibre/martin:main
ghcr.io/maplibre/martin:main
```
### 4. 遇到的问题
局限性只能连接一个pg库。
对于有分库的系统可以使用Nginx来转发。
#### 4.1 表没有空间索引
`Table public.table_name has no spatial index on column geom`
```sql
CREATE INDEX table_name_geom_idx
ON table_name
USING GIST (geom);
```
### 参考文章
[1] Martin https://martin.maplibre.org/
[2] Martin Tile Server Documentation https://maplibre.org/martin/installation.html