postgis 矢量切片

文章主要来自于该篇文章,对博客中的内容进行了注释及部分修改,帮助理解。

https://www.jianshu.com/p/24f7363c05b9

#BBOX函数,该函数要先在数据库中运行才不会报错,将文中的注释去掉
CREATE OR REPLACE FUNCTION BBox(x integer, y integer, zoom integer)
    RETURNS geometry AS
$BODY$
DECLARE
    max numeric := 6378137 * pi();#墨卡托投影的最大范围
    res numeric := max * 2 / 2^zoom;#墨卡托投影下一个瓦片代表的实际距离
    bbox geometry;
BEGIN
    根据传入的行列号计算出该瓦片对应的墨卡托投影范围并转换到84坐标系下,
    返回的范围是84坐标系下的范围--经纬度
    return st_transform(ST_MakeEnvelope(
        -max + (x * res),
        max - (y * res),
        -max + (x * res) + res,
        max - (y * res) - res,
        3857),4326);
END;
$BODY$
  LANGUAGE plpgsql IMMUTABLE;

python执行代码

import psycopg2
#配置数据库字典
dbConfig={
    "database":"postgis_25_sample",
    "user":"postgres",
    "password":"123456",
    "host":"localhost",
    "port":"5432"
}

#该函数的作用就是根据表名,动态生成sql语句,在已知表结构的情况下,完全不需要这个函数。
def createSql(table_name,x,y,z):
    geoColumn = "(select f_geometry_column from geometry_columns where f_table_name= '" + table_name + "' )"
    #由于pg_attribute中没有与表名直接对应的字段,先从pg_class中选出c表,得到其c.oid。再用a.attrelid判断,即可得到c表
    #实际上第一句sql做的事情就是将空间字段列和属性字段列分开存储f_geometry_column,和name列中
    condition=" pg_class as c,pg_attribute as a  where c.relname = '" + table_name + "' and a.attrelid = c.oid and a.attnum>0"
    sql1 = "SELECT "+geoColumn+",replace(replace(string_agg(a.attname,','),"+geoColumn+"||',',''),"+geoColumn+"||'','') as name FROM" +condition

    print(sql1)
    conn = psycopg2.connect(database=dbConfig["database"], user=dbConfig["user"], password=dbConfig["password"], host=dbConfig["host"], port=dbConfig["port"])
    cur = conn.cursor()
    cur.execute(sql1)
    keyData = cur.fetchall()
    geom_column=keyData[0][0]
    other_fields=keyData[0][1]
    cur.close()
    conn.close()
    #select 前面就是正常的切片,from 后面的select在选择空间属性与普通属性列,where条件则是先判断是否相交,如果相交则返回交集
    sql2="SELECT ST_AsMVT(q, '"+table_name+"', 4096, 'geometry') from (SELECT "+other_fields+"ST_AsMvtGeom("+geom_column+",BBox("+str(x)+", "+str(y)+" ,"+str(z)+") , 4096,256, true) as geometry  FROM "+table_name+" WHERE "+geom_column+" && BBox("+str(x)+", "+str(y)+" ,"+str(z)+")  AND ST_Intersects("+geom_column+", BBox("+str(x)+", "+str(y)+" ,"+str(z)+") )) q;"
    return sql2;
#运行sql,获得mvt的16进制文件
def getPbfFile(table_name,x,y,z):
    sql=createSql(table_name,x,y,z)
    conn = psycopg2.connect(database=dbConfig["database"], user=dbConfig["user"], password=dbConfig["password"], host=dbConfig["host"], port=dbConfig["port"])
    cur = conn.cursor()
    cur.execute(sql)
    print(sql)
    keyData = cur.fetchall()
    cur.close()
    conn.close()
    with open(str(z)+"_"+str(x)+"_"+str(y)+'.pbf', 'wb') as f:
        f.write(keyData[0][0])
    return keyData[0][0]
#x,y,z对应的是矢量切片的行号,列号,级别
tile=getPbfFile("cs",54605,26956,16)
print(tile)

你可能感兴趣的:(postgis)