PostGIS:查询 z 和 m 维度 (linestringzm)
PostGIS: Query z and m dimensions (linestringzm)
问题
我有一个包含多个 linestringzm
的系统,其中数据的结构如下:[x, y, speed:int, time:int]
。数据以这种方式构建,以便能够在 x
、y
和 z
维度上使用 ST_SimplifyVW
,但我仍然希望能够基于m
维度,例如获取时间间隔之间的所有线串。
这是否可以通过 PostGIS 实现,或者我是否针对我的用例错误地构建了数据?
例子
z
= 速度 例如km/h
m
= Unix 纪元时间
CREATE TABLE t (id int NOT NULL, geom geometry(LineStringZM,4326), CONSTRAINT t_pkey PRIMARY KEY (id));
INSERT INTO t VALUES (1, 'SRID=4326;LINESTRING ZM(30 10 5 1620980688, 30 15 10 1618388688, 30 20 15 1615710288, 30 25 20 1620980688)'::geometry);
INSERT INTO t VALUES (2, 'SRID=4326;LINESTRING ZM(50 10 5 1620980688, 50 15 10 1618388688, 50 20 15 1615710288, 50 25 20 1620980688)'::geometry);
INSERT INTO t VALUES (3, 'SRID=4326;LINESTRING ZM(20 10 5 1620980688, 20 15 10 1618388688, 20 20 15 1615710288, 20 25 20 1620980688)'::geometry);
用例A:基于x
、y
和z
[=31=简化几何]
这可以通过例如ST_SimplifyVW
简化后保持 m
维度。
用例 B:根据 m
维度查询几何图形
我有一组linestringzm
,我想根据我的时间维度(m
)进行查询。如果所有 m
都在例如 1618388000
和 1618388700
之间,则结果是完整的几何图形,或者是满足谓词的几何图形的一部分。查询数据最有效的方法是什么?
如果您想检查 LineString 的每个点,您可以 ST_DumpPoints
它们并使用 ST_M
获得 M
维度。之后将子集提取为包含重叠 M
值的 LineString 并应用 ST_MakeLine
和 GROUP BY
:
WITH j AS (
SELECT id,geom,(ST_DumpPoints(geom)).geom AS p
FROM t
)
SELECT id,ST_AsText(ST_MakeLine(p))
FROM j
WHERE ST_M(p) BETWEEN 1618388000 AND 1618388700
GROUP BY id;
演示:db<>fiddle
注意:根据您的 table 和 LineString 大小,此查询可能会变得非常慢,因为值在查询时被解析,因此没有被索引。恕我直言,一个更优雅的选择是..
.. 1) 创建一个tstzrange
列
ALTER TABLE t ADD COLUMN line_interval tstzrange;
.. 2) 正确索引它
CREATE INDEX idx_t_line_interval ON t USING gist (line_interval);
.. 和 3) 用 geom
的 first 和 last 点的时间填充它:
UPDATE t SET line_interval =
tstzrange(
to_timestamp(ST_M(ST_PointN(geom,1))),
to_timestamp(ST_M(ST_PointN(geom,ST_NPoints(geom)))));
之后,您可以通过检查索引列是否与给定间隔重叠来加快速度。这将显着缩短查询时间:
SELECT * FROM t
WHERE line_interval && tstzrange(
to_timestamp(1618138148),
to_timestamp(1618388700));
演示:db<>fiddle
延伸阅读:
问题
我有一个包含多个 linestringzm
的系统,其中数据的结构如下:[x, y, speed:int, time:int]
。数据以这种方式构建,以便能够在 x
、y
和 z
维度上使用 ST_SimplifyVW
,但我仍然希望能够基于m
维度,例如获取时间间隔之间的所有线串。
这是否可以通过 PostGIS 实现,或者我是否针对我的用例错误地构建了数据?
例子
z
= 速度 例如km/hm
= Unix 纪元时间
CREATE TABLE t (id int NOT NULL, geom geometry(LineStringZM,4326), CONSTRAINT t_pkey PRIMARY KEY (id));
INSERT INTO t VALUES (1, 'SRID=4326;LINESTRING ZM(30 10 5 1620980688, 30 15 10 1618388688, 30 20 15 1615710288, 30 25 20 1620980688)'::geometry);
INSERT INTO t VALUES (2, 'SRID=4326;LINESTRING ZM(50 10 5 1620980688, 50 15 10 1618388688, 50 20 15 1615710288, 50 25 20 1620980688)'::geometry);
INSERT INTO t VALUES (3, 'SRID=4326;LINESTRING ZM(20 10 5 1620980688, 20 15 10 1618388688, 20 20 15 1615710288, 20 25 20 1620980688)'::geometry);
用例A:基于
x
、y
和z
[=31=简化几何]这可以通过例如
ST_SimplifyVW
简化后保持m
维度。用例 B:根据
m
维度查询几何图形我有一组
linestringzm
,我想根据我的时间维度(m
)进行查询。如果所有m
都在例如1618388000
和1618388700
之间,则结果是完整的几何图形,或者是满足谓词的几何图形的一部分。查询数据最有效的方法是什么?
如果您想检查 LineString 的每个点,您可以 ST_DumpPoints
它们并使用 ST_M
获得 M
维度。之后将子集提取为包含重叠 M
值的 LineString 并应用 ST_MakeLine
和 GROUP BY
:
WITH j AS (
SELECT id,geom,(ST_DumpPoints(geom)).geom AS p
FROM t
)
SELECT id,ST_AsText(ST_MakeLine(p))
FROM j
WHERE ST_M(p) BETWEEN 1618388000 AND 1618388700
GROUP BY id;
演示:db<>fiddle
注意:根据您的 table 和 LineString 大小,此查询可能会变得非常慢,因为值在查询时被解析,因此没有被索引。恕我直言,一个更优雅的选择是..
.. 1) 创建一个tstzrange
列
ALTER TABLE t ADD COLUMN line_interval tstzrange;
.. 2) 正确索引它
CREATE INDEX idx_t_line_interval ON t USING gist (line_interval);
.. 和 3) 用 geom
的 first 和 last 点的时间填充它:
UPDATE t SET line_interval =
tstzrange(
to_timestamp(ST_M(ST_PointN(geom,1))),
to_timestamp(ST_M(ST_PointN(geom,ST_NPoints(geom)))));
之后,您可以通过检查索引列是否与给定间隔重叠来加快速度。这将显着缩短查询时间:
SELECT * FROM t
WHERE line_interval && tstzrange(
to_timestamp(1618138148),
to_timestamp(1618388700));
演示:db<>fiddle
延伸阅读: