蜂巢的艺术与技术价值 - PostgreSQL PostGIS's hex-grid

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介:

标签

PostgreSQL , vector grid , polygon grid , square grid , Hexagon grid , 矢量网格 , 几何网格 , 线段网格 , 多边形网格 , 四边形网格 , 六边形网格 , 蜂巢 , PostGIS , 地图 , 转换


背景

人们为了更好的描述一个东西,有一种将大化小的思路,比如时钟被分为了12个区域,每个区域表示一个小时,然后每个小的区域又被划分为更小的区域表示分钟。

pic

在GIS系统中,也有类似的思想,比如将地图划分成网格。通过编码来简化地理位置的判断(比如相交,包含,距离计算等),但是请注意使用网格带来的问题,比如精度的问题,网格的大小决定了精度,又比如相对坐标的问题,可能无法描述清楚边界的归属。

PS:

1. 在PostGIS中虽然也支持网格对象的描述方式,但是并不是使用这种方法来进行几何运算(比如相交,包含,距离计算等),所以不存在类似的精度问题,个人建议没有强需求的话,不必做这样的网格转换。

PostgreSQL GIS索引的原理请参考

《从难缠的模糊查询聊开 - PostgreSQL独门绝招之一 GIN , GiST , SP-GiST , RUM 索引原理与技术背景》

2. 如果是多种精度地图的切换(比如多个图层,每个图层代表一种地图精度),建议使用辐射的方式逐渐展开更精细的图层,以点为中心,逐渐辐射。(很多专业的地图软件是这样做的)

回到主题,还记得最强大脑的蜂巢迷宫吗?

pic

还有勤劳的蜜蜂兄弟

pic

我们接下来要做的就是如何将几何图形转换为网格对象。

回忆一下六边形的几何特性

首先要了解一下六边形的几何特性,提供转换的计算基础。

六边形可以切分为6个等边三角形

pic

所以它的边长关系如下

pic

面积计算

pic

更多细节详见

https://hexnet.org/content/hexagonal-geometry

将几何图形(sharp)转换为六边形网格

比如要将澳大利亚的版图,转换为六边形网格,

pic

有两种方法,一种使用geotools的JAVA 类(在程序中转换),另一种是使用PostGIS插件的UDF(在数据库中转换)。

当然,如果PostgreSQL安装了pljava插件的话,那么也可以在PostgreSQL中调用geotools提供的java类进行转换。

下面是例子

1 geotools Vector grids class

http://docs.geotools.org/latest/userguide/extension/grid.html

使用geotools vector grids class生成网格,返回 SimpleFeatureSource 类型。

geotools Vector grids class支持将几何图形转换为 polygon网格 或者 line网格 。

1 Polygon grids

举几个例子

1. 将澳大利亚地图转换为10度边长的正方形网格

pic

输入澳大利亚的经纬度范围,转换

    ReferencedEnvelope gridBounds = new ReferencedEnvelope(  
            110.0, 150.0, -45.0, -5.0, DefaultGeographicCRS.WGS84);  

    SimpleFeatureSource grid = Grids.createSquareGrid(gridBounds, 10.0);  

2. 将澳大利亚地图转换为最大20度边长的扇形网格

pic

    ReferencedEnvelope gridBounds = new ReferencedEnvelope(  
            110, 160, -45, -8, DefaultGeographicCRS.WGS84);  

    double squareWidth = 20.0;  

    // max distance between vertices  
    double vertexSpacing = squareWidth / 20;  

    SimpleFeatureSource grid = Grids.createSquareGrid(gridBounds, squareWidth, vertexSpacing);  

3. 创建纵横宽100,变长为5.0的六边形网格

pic

    ReferencedEnvelope gridBounds = new ReferencedEnvelope(0, 100, 0, 100, null);  

    // length of each hexagon edge  
    double sideLen = 5.0;  
    SimpleFeatureSource grid = Grids.createHexagonalGrid(gridBounds, sideLen);  

4. 导入图形、将澳大利亚地图转换为边长1度的六边形网格

pic

自定义图形边界判断的类

import com.vividsolutions.jts.geom.Coordinate;  
import com.vividsolutions.jts.geom.Geometry;  
import com.vividsolutions.jts.geom.GeometryFactory;  
import java.io.IOException;  
import java.util.Map;  
import org.geotools.data.simple.SimpleFeatureSource;  
import org.geotools.factory.CommonFactoryFinder;  
import org.geotools.geometry.jts.JTSFactoryFinder;  
import org.opengis.feature.simple.SimpleFeatureType;  
import org.opengis.filter.Filter;  
import org.opengis.filter.FilterFactory2;  


public class IntersectionBuilder extends GridFeatureBuilder {  
    final FilterFactory2 ff2 = CommonFactoryFinder.getFilterFactory2();  
    final GeometryFactory gf = JTSFactoryFinder.getGeometryFactory();  

    final SimpleFeatureSource source;  
    int id = 0;  

    public IntersectionBuilder(SimpleFeatureType type, SimpleFeatureSource source) {  
        super(type);  
        this.source = source;  
    }  

    public void setAttributes(GridElement el, Map<String, Object> attributes) {  
        attributes.put("id", ++id);  
    }  

    @Override  
    public boolean getCreateFeature(GridElement el) {  
        Coordinate c = ((PolygonElement) el).getCenter();  
        Geometry p = gf.createPoint(c);  
        Filter filter = ff2.intersects(ff2.property("the_geom"), ff2.literal(p));  
        boolean result = false;  

        try {  
            result = !source.getFeatures(filter).isEmpty();  
        } catch (IOException ex) {  
            throw new IllegalStateException(ex);  
        }  

        return result;  
    }  
}  

导入地图,在createHexagonalGrid中使用边界判断的类,生成六边形网格

    // Load the outline of Australia from a shapefile  
    URL url = getClass().getResource("oz.shp");  
    FileDataStore dataStore = FileDataStoreFinder.getDataStore(url);  
    SimpleFeatureSource ozMapSource = dataStore.getFeatureSource();  

    // Set the grid size (1 degree) and create a bounding envelope  
    // that is neatly aligned with the grid size  
    double sideLen = 1.0;  
    ReferencedEnvelope gridBounds =  
            Envelopes.expandToInclude(ozMapSource.getBounds(), sideLen);  

    // Create a feature type  
    SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();  
    tb.setName("grid");  
    tb.add(GridFeatureBuilder.DEFAULT_GEOMETRY_ATTRIBUTE_NAME,  
            Polygon.class, gridBounds.getCoordinateReferenceSystem());  
    tb.add("id", Integer.class);  
    SimpleFeatureType TYPE = tb.buildFeatureType();  

    // Build the grid the custom feature builder class  
    GridFeatureBuilder builder = new IntersectionBuilder(TYPE, ozMapSource);  
    SimpleFeatureSource grid = Grids.createHexagonalGrid(gridBounds, sideLen, -1, builder);  

5. 生成的六边形网格的摆放参数,横(flat)的还是竖(angled)的?

pic

默认为flat网格,如果要生成angled网格,如下

    ReferencedEnvelope gridBounds = new ReferencedEnvelope(0, 100, 0, 100, null);  
    double sideLen = 5.0;  
    GridFeatureBuilder builder = new DefaultGridFeatureBuilder();  
    SimpleFeatureSource grid = Hexagons.createGrid(  
            gridBounds, sideLen, HexagonOrientation.ANGLED, builder);  

pic

2 line grids

转换为line 网格

例子

    ReferencedEnvelope gridBounds = new ReferencedEnvelope(  
            110.0, 150.0, -45.0, -5.0, DefaultGeographicCRS.WGS84);  

    /*  
     * Line definitions:   
     * major lines at 10 degree spacing are indicated by level = 2  
     * minor lines at 2 degree spacing are indicated by level = 1  
     * (level values are arbitrary; only rank order matters)  
     */  
    List<OrthoLineDef> lineDefs = Arrays.asList(  
            // vertical (longitude) lines  
            new OrthoLineDef(LineOrientation.VERTICAL, 2, 10.0),  
            new OrthoLineDef(LineOrientation.VERTICAL, 1, 2.0),  

            // horizontal (latitude) lines  
            new OrthoLineDef(LineOrientation.HORIZONTAL, 2, 10.0),  
            new OrthoLineDef(LineOrientation.HORIZONTAL, 1, 2.0));  

    // Specify vertex spacing to get "densified" polygons  
    double vertexSpacing = 0.1;  
    SimpleFeatureSource grid = Lines.createOrthoLines(gridBounds, lineDefs, vertexSpacing);  

2 PostGIS UDF hex-grid

https://github.com/minus34/postgis-scripts/tree/master/hex-grid

PostGIS不需要多介绍了,几十年的老牌GIS插件,在军方、科研、民用等各个领域有着非常广泛对应用。

如果你使用了PostGIS插件的话,在里面存储了不管是geometry, polygon还是其他的地图类型,都可以转换为六边形网格。

转换时使用这些定义好的UDF即可。

UDF使用方法

See the 2 sample usage scripts to see how to create a national hex grid, using the function.

UDF输入参数

Parameter Description
areakm2 Area of each hexagon in square km. Note: output hexagon sizes can be off slightly due to coordinate rounding in the calcs.
xmin,ymin Minimum coordinates of the grid extents (i.e. bottom, left).
xmax,ymax Maximum coordinates of the grid extents (i.e. top, right).
inputsrid The coordinate system (SRID) of the min/max coordinates.
workingsrid The SRID used to process the hexagons:
- SRID must be a projected coord sys (i.e. in metres) as the calcs require ints. Degrees are out.
- Should be an equal area SRID - i.e. Albers or Lambert Azimuthal (e.g. Australia = 3577, US = 2163).
- Using a Mercator projection will NOT return hexagons of equal area (don't try it in Greenland).
ouputsrid The SRID of the output hexagons.

输出

A set of hexagonal polygons as PostGIS geometries

pic

转换基础,参考如下

https://trac.osgeo.org/postgis/wiki/UsersWikiGenerateHexagonalGrid

小结

1. 在PostGIS中虽然也支持网格对象的描述方式,但是并不是使用网格编码的方法来进行几何运算(比如相交,包含,距离计算等),而是类似矢量的计算方法,因此不存在网格的精度问题,个人建议没有强需求的话,不必将几何图形转换为网格。

PostgreSQL GIS索引的原理请参考

《从难缠的模糊查询聊开 - PostgreSQL独门绝招之一 GIN , GiST , SP-GiST , RUM 索引原理与技术背景》

2. 如果是多种精度地图的切换(比如多个图层,每个图层代表一种地图精度),建议使用辐射的方式逐渐展开更精细的图层,以点为中心,逐渐辐射。(很多专业的地图软件是这样做的)

3. 如果要将图形转换为网格,可以使用geotools提供的java class来转换,也可以使用PostGIS的UDF来转换,当然PostgreSQL如果安装了pljava过程语言的话,可以直接在数据库中调用geotools提供的java class对图形进行转换。

4. pljava

https://tada.github.io/pljava/ 

参考

1. geotools vector grid包

http://docs.geotools.org/latest/userguide/extension/grid.html

2. PostGIS 生成六边形网格的UDF

https://github.com/minus34/postgis-scripts/tree/master/hex-grid

3. PostGIS 生成六边形网格的算法基础

https://trac.osgeo.org/postgis/wiki/UsersWikiGenerateHexagonalGrid

4. 六边形几何公式

https://hexnet.org/content/hexagonal-geometry

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
2月前
|
关系型数据库 分布式数据库 数据库
阿里云PolarDB登顶2024中国数据库流行榜:技术实力与开发者影响力
近日,阿里云旗下的自研云原生数据库PolarDB在2024年中国数据库流行度排行榜中夺冠,并刷新了榜单总分纪录,这一成就引起了技术圈的广泛关注。这一成就源于PolarDB在数据库技术上的突破与创新,以及对开发者和用户的实际需求的深入了解体会。那么本文就来分享一下关于数据库流行度排行榜的影响力以及对数据库选型的影响,讨论PolarDB登顶的关键因素,以及PolarDB“三层分离”新版本对开发者使用数据库的影响。
396 3
阿里云PolarDB登顶2024中国数据库流行榜:技术实力与开发者影响力
|
2月前
|
Cloud Native 关系型数据库 分布式数据库
开发者视角看云原生数据库一体化技术趋势
随着云原生数据库技术的不断发展,一体化数据库解决方案成为技术圈的热点,云原生数据库一体化技术是当前数据库领域的重要趋势,对于开发者而言,学习理解和应对这一趋势,对于业务开发的成功实施非常重要。比如,阿里云瑶池数据库和PolarDB-X等产品通过离在线一体化、处理分析一体化和集中分布一体化等创新理念,引领了数据库领域的新变革。那么本文就来从开发者的角度探讨云原生数据库一体化技术趋势,并分析在业务处理分析一体化、集中式与分布式数据库边界模糊和云原生一体化数据库的选择等方面的影响。
464 4
|
2月前
|
存储 关系型数据库 MySQL
PolarDB-X 存储引擎核心技术 | 索引回表优化
数据库系统为了高效地存储、检索和维护数据,采用了多种不同的数据组织结构。不同的组织结构有其特定的用途和优化点,比如提高查询速度、优化写入性能、减少存储空间等,目前 PolarDB-X 采用了 B-Tree 的索引组织结构。
|
2月前
|
关系型数据库 分布式数据库 数据库
【PolarDB开源】PolarDB资源隔离技术:在多租户环境中的应用与优化
【5月更文挑战第29天】PolarDB,阿里云的云原生数据库,在多租户环境中通过逻辑(Schema/Partition隔离)和物理(分布式存储计算节点)隔离保障数据安全和资源独占。它支持动态资源分配,适应不同租户需求,处理大规模并发,提供租户管理及数据访问控制功能。通过优化资源分配算法、提升事务处理能力和强化监控告警,PolarDB确保性能和稳定性,满足多租户的高效数据库服务需求。
82 1
|
10天前
|
存储 SQL 关系型数据库
PolarDB-X 存储引擎核心技术 | Lizard 无锁备份
本文重点要介绍全量备份的设计,作为承担在线数据存储的 DN 节点,按照数据保护和容灾的需求,DN 需要支持灵活定制周期策略的备份策略。同时,PolarDB-X 能够处理和存储庞大的数据规模,备份这些数据量(例如高达 20TB 大小的数据集),如果想在更短的时间内完成备份(比如 3~4 小时),这样的备份 SLA 需要在在线业务影响、并行策略上有更多的优化。
PolarDB-X 存储引擎核心技术 | Lizard 无锁备份
|
1月前
|
存储 算法 数据处理
惊人!PolarDB-X 存储引擎核心技术的索引回表优化如此神奇!
【6月更文挑战第11天】PolarDB-X存储引擎以其索引回表优化技术引领数据库发展,提升数据检索速度,优化磁盘I/O,确保系统在高并发场景下的稳定与快速响应。通过示例代码展示了在查询操作中如何利用该技术高效获取结果。索引回表优化具备出色性能、高度可扩展性和适应性,为应对大数据量和复杂业务提供保障,助力企业与开发者实现更高效的数据处理。
|
2月前
|
存储 关系型数据库 分布式数据库
数据库索引回表困难?揭秘PolarDB存储引擎优化技术
PolarDB分布式版存储引擎采用CSM方案均衡资源开销与可用性。
数据库索引回表困难?揭秘PolarDB存储引擎优化技术
|
27天前
|
自然语言处理 关系型数据库 数据库
技术经验解读:【转】PostgreSQL的FTI(TSearch)与中文全文索引的实践
技术经验解读:【转】PostgreSQL的FTI(TSearch)与中文全文索引的实践
13 0
|
2月前
|
Cloud Native 关系型数据库 分布式数据库
【PolarDB开源】PolarDB开源项目未来展望:技术趋势与社区发展方向
【5月更文挑战第29天】PolarDB,阿里云的云原生分布式数据库,正聚焦于云原生、容器化、HTAP与实时分析、智能化运维等技术趋势,旨在提升资源利用率、扩展性及数据分析能力。未来,项目将深化全球开源社区合作,拓宽应用场景,构建开发者生态,以创新技术驱动数据库领域发展,目标成为领先的云数据库服务。
95 1
|
2月前
|
Cloud Native OLAP OLTP
如何看待云原生数据库一体化的技术趋势?
【4月更文挑战第12天】如何看待云原生数据库一体化的技术趋势?

相关产品

  • 云原生数据库 PolarDB