java+postgis实现4490坐标系动态矢量瓦片并实现后端聚合

4 篇文章 5 订阅
4 篇文章 0 订阅

java+postgis实现4490坐标系动态矢量瓦片并实现后端聚合



前言

什么是矢量瓦片:现阶段,电子地图瓦片主要使用两种方式,一种是传统的栅格瓦片,另外一种是新出的矢量瓦片(Vector Tiles),前者是采用四叉树金字塔模型的分级方式,将地图切割成无数大小相等的矩形栅格图片,由这些矩形栅格图片按照一定规则拼接成不同层级的地图显示。后者是将矢量数据用多层次模型分割成矢量要素描述文件存储在服务器端,再到客户端根据指定样式进行渲染绘制地图,在单个矢量瓦片上存储着投影于一个矩形区域内的几何信息和属性信息。当客户端通过分布式网络获取矢量瓦片、地图标注字体、图标、样式文件等数据后,最终在客户端进行渲染输出地图。

简而言之:矢量瓦片存储的实际还是矢量数据优点数据不会丢失精度,同时在一定程度上也解决了矢量数据加载和渲染慢问题,是目前最流行的一种地图数据解决方案。

这里介绍下为什么要4490坐标系呢?

其实地理数据的坐标系是多种多样的,比如常见的全球常用的通用坐标系WGS84和百度的BD09和高德的GJC-02,随着国家技术发展日新月异,国产化潮流来袭,EPSG:4490坐标系成为了目前国内项目上逐渐的地图坐标系标准,CGCS2000(4490) : 国家大地坐标系。天地图采用的就是这个。可以提供高精度三维坐标,它是以地球质量中心为原点的地心坐标系,可以满足航天、海洋、气象、水利、建设、规划、地质调查、国土资源管理等领域的多种需求。所以后面地理信息系统使用4490坐标系的要求只会越来越严格。


一、postgis是什么?

postgis是基于postgresql数据库的一款空间插件,PostgreSQL目前使用量也是越来越多逐渐赶超主流的mysql等数据库,postgis在这块提供里非常丰富的空间数据处理函数和扩展,是目前gis开发人员使用最多的数据库和插件。

二、本文主要使用的postgis函数

ST_AsMVTGeom:将几何图形转换成MAPBOX矢量瓦片的坐标空间

参数介绍:
geom:指定需要变换的几何字段
bounds:不带缓冲区的几何边界
extent:按照规范定义的平铺坐标空间中的平铺范围。默认4096
buffer:平铺坐标空间中任意修剪几何图形的缓冲区距离,默认256
clip_geom:用于控制几何图形是否被裁剪活编码,默认true

ST_AsMVT:返回一个MapBox矢量瓦片的一组行(返回Byte数组)

参数介绍:
row:一个几何列的行数据
name:图层名称
extent:按照规范定义的平铺坐标空间中的平铺范围。默认4096 (非必填)
geom_name:指定行数据列里面的空间字段名称,默认是找到的第一个空间字段 (非必填)

ST_MakeEnvelope:从X和Y的最小值和最大值创建矩形。输入值必须在SRID指定的空间参考系中。如果未指定SRID,则使用未知空间参考系(SRID 0)。

参数介绍:
geometry ST_MakeEnvelope(float xmin, float ymin, float xmax, float ymax, integer srid=unknown);
这里就是数据的四至范围,最后一个参数为坐标系的srid,这里是4490

st_centroid:计算几何的几何中心,或等效地将几何的质心计算为POINT(后端聚合使用)

st_collect:从其他Geometry对象的collection返回一个具体的Geometry值(后端聚合使用)

width_bucket:将对应的经度、纬度范围值划分为多少份,参数就是地图四至范围和划分数量(后端聚合使用)

st_intersects:判断两个几个对象是否存在相交,返回布尔值。(数据过滤常用)

st_x:获取几何的x坐标值
st_y:获取几何的y坐标值

三、实现4490坐标系动态切片

1.核心代码

代码如下(示例):

        String tile = TileUtils4326.xyz2prj4326wkt(z, x, y);
        String sql = "select ST_AsMVT ( mvtgeom.*, '" + sourceName + "' )as data from ( " +
                "   SELECT " +
                "      ST_AsMVTGeom ( the_geom, ST_MakeEnvelope ( "+TileUtils4326.xyz2prj4326BBox(z, x, y)+", 4490 ),4096,0,true ) AS the_geom, " +
                "      * " +
                "   FROM " +
                "      \""+sourceName+"\" " +
                "   where st_intersects(the_geom,st_geomfromtext(?,4326))"+
                "    )mvtgeom";
        Map<String, Object> result = jdbcTemplate.queryForMap(sql, tile);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip;
        try {
            gzip = new GZIPOutputStream(out);
            gzip.write((byte[]) result.get("data"));
            gzip.close();
        } catch (IOException e) {
            logger.error("gzip compress error.", e);
        }
        return out.toByteArray();

2.xyz行列号转经纬度工具类

代码如下(示例):

public class TileUtils4326 {
    public static String xyz2prj4326wkt(int z, int x, int y) {
        StringBuilder sb = new StringBuilder("POLYGON ((");
        double n = Math.pow(2, z);
        double lon_min = (x / n) * 360.0 - 180.0;
        double lat_min = 90.0 - (((y + 1) / n) * 360.0);
        double lon_max = ((x + 1) / n) * 360.0 - 180.0;
        double lat_max = 90.0 - ((y / n) * 360.0);
        sb.append(lon_min +" "+lat_max+", ");
        sb.append(lon_max +" "+lat_max+", ");
        sb.append(lon_max +" "+lat_min+", ");
        sb.append(lon_min +" "+lat_min+", ");
        sb.append(lon_min +" "+lat_max+")) ");
        return sb.toString();
    }

    public static String xyz2prj4326BBox(int z, int x, int y) {
        String bbox = "";
        double n = Math.pow(2, z);
        double lon_min = (x / n) * 360.0 - 180.0;
        double lat_min = 90.0 - (((y + 1) / n) * 360.0);
        double lon_max = ((x + 1) / n) * 360.0 - 180.0;
        double lat_max = 90.0 - ((y / n) * 360.0);
        bbox = lon_min + ","+lat_min+","+lon_max+","+lat_max;
        return bbox;
    }
}

四、实现后端聚合4490坐标系动态切片

1.核心代码

bbox为数据的四至范围

String tile = TileUtils4326.xyz2prj4326wkt(z, x, y);
String sql = "select ST_AsMVT ( mvtgeom.*, '" + sourceName + "' )as data from (SELECT " +
        "width_bucket(st_x(the_geom), " + bbox[0] + " ," + bbox[2] + " ," + segmentedCount + ") grid_x," +
        "width_bucket(st_y(the_geom), " + bbox[1] + " ," + bbox[3] + " ," + segmentedCount + ") grid_y," +
        "count(*)," +
        "ST_AsMVTGeom (st_centroid(st_collect(the_geom)), ST_MakeEnvelope ( " + TileUtils4326.xyz2prj4326BBox(z, x, y) + ", 4490 ),4096,0,true ) as geom " +
        "from \"" + sourceName + "\" " +
        "where " +
        "st_x(the_geom) between " + bbox[0] + " and " + bbox[2] + " " +
        "and " +
        "st_y(the_geom) between " + bbox[1] + "  and " + bbox[3] + " " +
        "and " +
        "st_intersects(the_geom,st_geomfromtext(?,4326)) " +
        "GROUP BY grid_x,grid_y )mvtgeom";
Map<String, Object> result = jdbcTemplate.queryForMap(sql, tile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip;
try {
     gzip = new GZIPOutputStream(out);
     gzip.write((byte[]) result.get("data"));
     gzip.close();
} catch (IOException e) {
     logger.error("gzip compress error.", e);
}
return out.toByteArray();

2.效果图

在这里插入图片描述

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
PostgreSQL+PostGIS 相对于 Oracle Spatial 在以下几个方面具有优势: 1. 开源和免费:PostgreSQL+PostGIS 是开源的数据库系统,可以免费使用,并且在开源社区中有广泛的支持和贡献。相比之下,Oracle Spatial 是商业数据库产品,可能需要支付高额的许可费用。 2. 社区支持和生态系统:PostgreSQL+PostGIS 有庞大的开源社区支持,许多开发者和组织都在为其开发新功能、解决问题和提供支持。这意味着用户可以从活跃的社区中获取帮助、学习和分享经验。 3. 扩展性和灵活性:PostgreSQL 是一个高度可扩展的数据库系统,可以轻松处理大规模数据集。PostGIS 扩展为 PostgreSQL 提供了丰富的地理空间功能,包括拓扑关系查询、空间索引、几何运算等。用户可以根据自己的需求选择性地安装和配置 PostGIS 扩展,使其更适合特定的应用场景。 4. 标准兼容性:PostgreSQL+PostGIS 遵循 SQL 和 OGC(Open Geospatial Consortium)的标准,支持标准的地理空间数据模型和函数。这使得它与其他遵循相同标准的地理空间数据系统具有良好的互操作性。 5. 可定制性和开发灵活性:开源的 PostgreSQL+PostGIS 提供了许多扩展和插件,用户可以根据自己的需求进行定制和开发。这使得用户可以根据具体应用的要求,灵活地扩展和定制地理空间功能。 需要注意的是,选择使用 PostgreSQL+PostGIS 还是 Oracle Spatial 取决于具体的需求和环境。如果对性能、功能全面性和与商业软件集成有较高要求,以及有相应的预算支持,那么 Oracle Spatial 可能更适合。而如果希望免费使用、享受开源社区支持、具备灵活性和可定制性,那么 PostgreSQL+PostGIS 是一个更好的选择。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值