版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yh0503/article/details/84377133
MVT
MVT(Mapbox Vector Tile):传送门
本文中用到的PostGIS函数
矢量切片后端服务(基于PostGIS+Flask )
以下代码仅供参考!
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
import shutil
import math
import psycopg2
import psycopg2.pool
from flask import Flask, render_template, make_response
app = Flask(__name__)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CACHE_DIR = os.path.join(BASE_DIR, 'cache')
Dbpool = psycopg2.pool.PersistentConnectionPool(
1,
100,
dbname='osm',
user='postgres',
host='192.168.90.110',
password='postgres',
port='5432')
def tile_ul(x, y, z):
n = 2.0**z
lon_deg = x / n * 360.0 - 180.0
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * y / n)))
lat_deg = math.degrees(lat_rad)
return lon_deg, lat_deg
def get_tile(z, x, y):
xmin, ymin = tile_ul(x, y, z)
xmax, ymax = tile_ul(x + 1, y + 1, z)
tile = None
conn = Dbpool.getconn()
# cur = conn.cursor()
if (conn):
query = "SELECT ST_AsMVT(tile, 'polygons', 4096, 'geom') AS tile FROM ( SELECT w.gid , ST_AsMVTGeom(w.geom, Box2D(ST_MakeEnvelope(%s,%s,%s,%s, 4326)), 4096, 0, true) AS geom FROM gis_osm_buildings_a_free_1 w ) tile WHERE tile.geom IS NOT NULL"
cur = conn.cursor()
cur.execute(query, (xmin, ymin, xmax, ymax))
tile = str(cur.fetchone()[0])
cur.close()
Dbpool.putconn(conn)
return tile
@app.route('/')
def index():
return render_template('leaflet_map.html')
@app.route('/tiles')
@app.route('/tiles/<int:z>/<int:x>/<int:y>', methods=['GET'])
def tiles(z=0, x=0, y=0):
tile = get_tile(z, x, y)
response = make_response(tile)
response.headers['Content-Type'] = "application/x-protobuf"
response.headers['Access-Control-Allow-Origin'] = "*"
response.headers['Access-Control-Allow-Methods'] = "POST"
response.headers['Access-Control-Allow-Headers'] = "x-requested-with,content-type"
return response
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5000)
矢量切片前端展示(基于MapBox-GL.js )
以下代码仅供参考!
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Add a third party vector tile source</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='mapbox-gl.js'></script>
<link href='mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = '去Mapbox官网注册账号,申请你自己的Token';
var tileset = 'mapbox.streets';
var map = new mapboxgl.Map({
container: 'map',
//北京
zoom: 14,
center: [116.3900, 39.9209],
style: 'mapbox://styles/mapbox/light-v9',
hash: false
});
map.on('load', function loaded() {
map.addSource('custom-go-vector-tile-source1', {
type: 'vector',
tiles: ['http://192.168.90.110:5000/tiles/{z}/{x}/{y}']
});
map.addLayer({
"id": "custom-go-vector-tile-layer1",
"type": "fill",
"source": "custom-go-vector-tile-source1",
"source-layer": "polygons",
"paint": {
"fill-color": "#0000ff"
}
});
});
</script>
</body>
</html>
效果图:
测试结果
算不上是测试结果吧,说说用户体验吧:
900w 点数据(QGIS按照渔网随机填充生成点数据),实时渲染感觉速度还行。
600w 简单面数据(上面的点数据构建的泰森多边形),实时渲染感觉速度也可以,10级以上无压力。
具体测试数据,可以参考下面参考链接文章里的结果,这块我暂时没有做详细的测试,这块待我回头测试补充一篇文章。
快显优化策略
- 数据库建空间索引(GIST),这个当然了也是必须的。
- 简化节点 使用ST_RemoveRepeatedPoints 和 ST_SnapToGrid等函数。
- 确定查询的范围,在SQL中使用A&B,求取查询范围和geom字段的交集,减少无效的请求范围。
- SQL性能调优(这块本人不擅长,就不多说了)。
- 聚合数据(这块个人觉得看你的需求是啥了,一些太小的图形可以考虑聚合或者抽稀)。
- 升级到最新版本的Postgis。
- PG数据库这块集群(基于XL集群)。
- 服务器端PLpgSQL编程,看GeoHey就是这种搞的呐。
参考资料
本文主要参考资料: