S2 单元函数¶
MatrixOne 提供了一系列 S2 单元函数,用于操作 Google S2 几何库的单元网格。这些函数将 POINT 几何值转换为以 BIGINT UNSIGNED 存储的 S2 CellID 值,并支持查询单元层级、计算父单元、获取单元中心点、以平方米为单位估算单元面积,以及检测邻接关系。S2 单元以分层四边形网格覆盖球面,级别从 0(粗粒度,一个立方体面)到 30(细粒度,边长约 1 厘米)。
Syntax¶
各 S2 单元函数遵循 S2_CellID*(...) 命名模式,接受 BIGINT UNSIGNED S2 CellID 值、POINT/POINT32 几何值以及可选的 INT 层级参数。具体语法参见下方各函数说明。
Arguments¶
所有 S2 单元函数均操作 BIGINT UNSIGNED S2 CellID 值和/或 POINT/POINT32 几何值。NULL 参数产生 NULL 结果。各函数的具体参数列表和返回类型请参见下方函数描述。
函数列表¶
函数 |
描述 |
|---|---|
|
返回 POINT 几何值对应的 S2 CellID。 |
|
返回单元所在层级(0-30)。 |
|
返回指定层级的父单元 CellID。 |
|
返回单元的中心点,类型为 POINT。 |
|
返回单元的近似面积,单位为 m²。 |
|
返回 4 个边相邻邻居 CellID 的 JSON 数组。 |
|
返回全部 8 个邻居 CellID 的 JSON 数组。 |
|
若两单元为邻居关系返回 1,否则返回 0。 |
英式拼写别名 S2_CellID_EdgeNeighbours、S2_CellID_AllNeighbours、S2_CellID_AreNeighbours 同样被接受,行为完全一致。
S2_CellID()¶
语法¶
S2_CellID(pt)
参数说明¶
pt:POINT 或 POINT32 几何值。
返回值¶
POINT 输入返回 BIGINT UNSIGNED;POINT32 输入返回 BIGINT UNSIGNED。返回的 CellID 始终为第 30 级的叶单元。若参数为 NULL 则返回 NULL。
使用说明¶
点的经度必须在
[-180, 180]范围内,纬度必须在[-90, 90]范围内。空点(
POINT EMPTY)会导致报错。该函数使用 S2 几何库将点的坐标转换为 S2 叶单元。
S2_CellID_Level()¶
语法¶
S2_CellID_Level(cell_id)
参数说明¶
cell_id:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。
返回值¶
返回 INT。层级为 0 到 30 之间的整数(含 0 和 30)。若参数为 NULL 则返回 NULL。
使用说明¶
传入
0作为 CellID 会导致”invalid S2 CellId”错误。
S2_CellID_Parent()¶
语法¶
S2_CellID_Parent(cell_id[, level])
参数说明¶
cell_id:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。level:可选 INT,指定期望的父单元层级。若省略,默认值为 cell_level - 1(粗一个层级)。
返回值¶
返回 BIGINT UNSIGNED,为指定层级的父单元 CellID。若任一参数为 NULL 则返回 NULL。
使用说明¶
父单元层级必须在
[0, 30]范围内。父单元层级必须比当前单元的层级更粗(数值上更小)。请求更细或相同层级会导致报错。
S2_CellID_Center()¶
语法¶
S2_CellID_Center(cell_id)
参数说明¶
cell_id:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。
返回值¶
返回 POINT,包含单元中心的经度和纬度。若参数为 NULL 则返回 NULL。
S2_CellID_Area()¶
语法¶
S2_CellID_Area(cell_id)
参数说明¶
cell_id:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。
返回值¶
返回 DOUBLE,为单元的近似面积,单位为平方米(m²)。较粗(层级较低)的单元面积更大。若参数为 NULL 则返回 NULL。
S2_CellID_EdgeNeighbors()¶
语法¶
S2_CellID_EdgeNeighbors(cell_id)
参数说明¶
cell_id:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。
返回值¶
返回 JSON 数组,包含恰好 4 个 BIGINT UNSIGNED 值,表示 4 个边相邻邻居的 CellID。若参数为 NULL 则返回 NULL。
使用说明¶
英式拼写别名
S2_CellID_EdgeNeighbours(cell_id)返回相同结果。
S2_CellID_AllNeighbors()¶
语法¶
S2_CellID_AllNeighbors(cell_id)
参数说明¶
cell_id:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。
返回值¶
返回 JSON 数组,包含 8 个 BIGINT UNSIGNED 值,表示所有邻居 CellID(4 个边邻居加 4 个顶点邻居)。若参数为 NULL 则返回 NULL。
使用说明¶
英式拼写别名
S2_CellID_AllNeighbours(cell_id)返回相同结果。
S2_CellID_AreNeighbors()¶
语法¶
S2_CellID_AreNeighbors(cell_a, cell_b)
参数说明¶
cell_a、cell_b:表示有效 S2 CellID 的 BIGINT UNSIGNED 值。
返回值¶
返回 TINYINT(1):若两单元为邻居关系(同层级下边相邻或顶点相邻)返回 1,否则返回 0。若任一参数为 NULL 则返回 NULL。
使用说明¶
一个单元不是自身的邻居(返回 0)。
不同层级的单元不被视为邻居(返回 0)。
该关系具有对称性:若 A 是 B 的邻居,则 B 也是 A 的邻居。
英式拼写别名
S2_CellID_AreNeighbours(cell_a, cell_b)返回相同结果。
错误场景¶
以下输入会导致运行时错误:
情形 |
错误消息 |
|---|---|
CellID 为 |
|
经度/纬度超出范围 |
|
空 POINT 几何值 |
|
父单元层级超出 [0, 30] |
|
父单元层级比当前单元层级更细 |
|
示例¶
DROP DATABASE IF EXISTS dbgeocell;
CREATE DATABASE dbgeocell;
USE dbgeocell;
SELECT S2_CellID_Level(S2_CellID(ST_GeomFromText('POINT(116.3975 39.9087)'))) AS leaf_level;
SELECT S2_CellID_Level(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(116.3975 39.9087)')), 10)) AS parent_level;
SELECT ST_AsText(S2_CellID_Center(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 5))) AS center_point;
SELECT S2_CellID_Area(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 5))
> S2_CellID_Area(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10)) AS coarser_is_larger;
SELECT JSON_LENGTH(S2_CellID_EdgeNeighbors(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10))) AS n_edge;
SELECT JSON_LENGTH(S2_CellID_AllNeighbors(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10))) AS n_all;
SELECT S2_CellID_AreNeighbors(
S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10),
S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10)) AS self_not_neighbor;
SELECT S2_CellID_AreNeighbors(
c,
CAST(JSON_UNQUOTE(JSON_EXTRACT(S2_CellID_EdgeNeighbors(c), '$[0]')) AS UNSIGNED)) AS edge_is_neighbor
FROM (SELECT S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10) AS c) t;
SELECT S2_CellID_AreNeighbors(
S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 10),
S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 5)) AS cross_level;
CREATE TABLE s2t(id INT, pt POINT, cell BIGINT UNSIGNED);
INSERT INTO s2t VALUES (1, ST_GeomFromText('POINT(116.3975 39.9087)'), 0);
INSERT INTO s2t VALUES (2, ST_GeomFromText('POINT(121.4737 31.2304)'), 0);
UPDATE s2t SET cell = S2_CellID(pt);
SELECT id, S2_CellID_Level(cell) AS lvl FROM s2t ORDER BY id;
DROP TABLE IF EXISTS s2t;
SELECT S2_CellID(NULL) AS a, S2_CellID_Level(NULL) AS b, S2_CellID_Center(NULL) AS c;
-- Expected-Success: false
SELECT S2_CellID_Level(0);
-- Expected-Success: false
SELECT S2_CellID(ST_GeomFromText('POINT(200 100)'));
-- Expected-Success: false
SELECT S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 40);
-- Expected-Success: false
SELECT S2_CellID_Parent(S2_CellID_Parent(S2_CellID(ST_GeomFromText('POINT(0 0)')), 5), 20);
DROP DATABASE dbgeocell;