使用PostgreSQL+PostGIS实现地图引擎(经历ArcGIS Server/GeoServer/MapServer后)

地图服务器方案探索

研究GIS服务器已经很长一段时间,最开始使用ArcGIS Server,后来由于费用问题公司基于nginx和lua自己做了一套矢量瓦片的地图服务器,再后来开始研究使用Geoserver,再后来由于性能问题改研究Mapserver,最近由于开发的灵活性和业务需求开始研究PostgreSQL+PostGIS的方案。

PostGIS官方方案

WITH mvtgeom AS
(
  SELECT ST_AsMVTGeom(geom, ST_TileEnvelope(12,513,412)) AS geom, name, description
  FROM points_of_interest
  WHERE ST_Intersects(geom, ST_TileEnvelope(12,513,412)
)
SELECT ST_AsMVT(mvtgeom.*)
FROM mvtgeom;

存在问题

ST_TileEnvelope只能生成3857坐标的边界,类似于:
POLYGON((11858134.820049 3561354.02186289,11858134.820049 3580921.90110389,11877702.69929 3580921.90110389,11877702.69929 3561354.02186289,11858134.820049 3561354.02186289))

我们数据库里的数据都是4490坐标的边界,即类似于:
POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))

如果直接使用ST_TileEnvelope生成的边界来计算就必须要求数据库里的数据转换为3857坐标系的样式。

解决办法有五个思路,一是修改源数据为3857的数据后再导入,二是4490坐标系的数据设置坐标系为3857,三是在计算过程中用st_transform强制投影转换,四是计算过程中采用::geography强制转换,五是放弃ST_TileEnvelope函数采用ST_MakeEnvelope并从代码中计算好4490下的瓦片边界后使用。

方案一:
不可取。由于国家要求和实际计算的需要,我们只能在库里存4490坐标系的数据。

方案二:

不可取。
update "DS_YJJBNT_5" set geom=st_setsrid(geom,4490)这一行语句只是修改了表里面的坐标系描述,即只改了元数据,并不会去动表中的任何一条数据,所以设置坐标系的方式是无法使用的。

SELECT st_srid(geom) FROM "DS_YJJBNT_5" limit 1;查询数据表的坐标系。

方案三:
不可取。
官方文档中提示说使用st_transform需要有proj4这个库编译进PostgreSQL库,但是重新编译又是一项大工程。
UPDATE “DS_YJJBNT_5” SET geom=st_transform(st_geomfromtext((st_astext(geom)),4490),3857);

方案四:
不可取。
还没试成功过,具体原理未知。

方案五:
可以成功。

方案五的实现

通过xyz生成任意瓦片矩形边界

python版

func tile2lon( x int,  z int)(a float64) {
	return float64(x) /math.Pow(2, float64(z)) * 360.0 - 180;
 }

 func tile2lat( y int,  z int)(a float64) {
   n := math.Pi - (2.0 * math.Pi * float64(y)) / math.Pow(2, float64(z));
   return math.Atan(math.Sinh(n))*180/math.Pi;
 }

ymax :=FloatToString(tile2lat(int(xyz.y), int(xyz.z)));
ymin := FloatToString(tile2lat(int(xyz.y+1), int(xyz.z)));
xmin := FloatToString(tile2lon(int(xyz.x), int(xyz.z)));
xmax := FloatToString(tile2lon(int(xyz.x+1), int(xyz.z)));

node.js版

let xmin = x/Math.pow(2,z)*360.0-180;

let n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2,z);
let ymax = Math.atan((Math.exp(n)-Math.exp(-n))/2)*180/Math.PI;

Sinh(n)与(Math.exp(n)-Math.exp(-n))/2等价

原版SQL

WITH mvtgeom AS (SELECT ST_AsMVTGeom(geom, ST_MakeEnvelope(106.5234375, 30.44867367928757, 106.69921875, 30.600093873550065, 4490)) AS geom, bsm, objectid 
FROM "DS_YJJBNT_5" WHERE ST_Intersects(geom, ST_MakeEnvelope(106.5234375, 30.44867367928757, 106.69921875, 30.600093873550065, 4490))) 
SELECT ST_AsMVT(mvtgeom.*,'points') FROM mvtgeom;

解决了地图缩放到任何层级切出来图片大小都会盖全图的问题

(设置extent=4096,buffer为0,裁剪为true)

WITH mvtgeom AS (SELECT ST_AsMVTGeom(geom, ST_MakeEnvelope(106.5234375, 30.44867367928757, 106.69921875, 30.600093873550065, 4490),4096, 0, true) AS geom, bsm, objectid 
FROM "DS_YJJBNT_5" WHERE ST_Intersects(geom, ST_MakeEnvelope(106.5234375, 30.44867367928757, 106.69921875, 30.600093873550065, 4490))) 
SELECT ST_AsMVT(mvtgeom.*,'points') FROM mvtgeom;

解决了放大到最大层级时相对geoserver部分数据丢失且偏移的问题

(去除where相交的条件)

在这里插入图片描述

WITH mvtgeom AS (SELECT ST_AsMVTGeom(geom, ST_MakeEnvelope(106.5234375, 30.44867367928757, 106.69921875, 30.600093873550065, 4490),4096, 0, true) AS geom, bsm, objectid 
FROM "DS_YJJBNT_5" ) 
SELECT ST_AsMVT(mvtgeom.*,'points') FROM mvtgeom;

重组美化SQL后

select ST_AsMVT ( mvtgeom.*, '${tableName}' )as data from (
   SELECT
      ST_AsMVTGeom ( geom, ST_MakeEnvelope ( #{xmin},#{ymin},#{xmax},#{ymax}, 4490 ),4096,0,true ) AS geom,
      bsm,
      objectid
   FROM
      "${tableName}"
    )mvtgeom

参考资料:

https://www.cnblogs.com/polong/p/9831106.html

http://postgis.net/docs/manual-3.0/ST_TileEnvelope.html

http://postgis.net/docs/manual-3.0/ST_AsMVT.html

http://postgis.net/docs/manual-3.0/ST_AsMVTGeom.html

我自己产品的官网:http://www.newgis.top

搭建PostgreSQL PostGIS空间数据引擎,需按照以下步骤进行操作。 首先,确保已经安装了PostgreSQL数据库服务器。可以从官方网站上下载并安装最新版本的PostgreSQL。 完成安装后,打开命令行终端并切换到PostgreSQL的安装目录下的bin文件夹。在命令行中输入以下命令来启动PostgreSQL: ``` pg_ctl -D 数据库存储路径 start ``` 数据库存储路径是指定数据库文件将保存的目录路径。将其替换为你想要使用的路径。 启动后,会在命令行中显示一些数据库连接信息,包括端口号和数据库用户名等。 接下来,需要创建一个新的数据库。在命令行中输入以下命令: ``` createdb -U 数据库用户名 -h localhost -p 端口号 新数据库名称 ``` 将数据库用户名、端口号和新数据库名称替换为真实值。 创建数据库后,需要在其中安装PostGIS扩展。在命令行中输入以下命令来连接到新数据库: ``` psql -U 数据库用户名 -h localhost -p 端口号 新数据库名称 ``` 进入数据库后,运行以下命令来创建PostGIS扩展: ``` CREATE EXTENSION postgis; ``` 该命令将在数据库中创建PostGIS所需的表和函数。安装完成后,就可以在数据库中存储和查询空间数据了。 最后,可以使用数据库管理工具,如pgAdmin等,连接到数据库进行操作和管理。可以使用这些工具来创建数据表、导入和导出空间数据,以及执行空间查询等操作。 总结一下,搭建PostgreSQL PostGIS空间数据引擎的主要步骤是:安装PostgreSQL,启动数据库服务器,创建新数据库,安装PostGIS扩展,然后使用数据库管理工具进行操作和管理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘久胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值