PostGIS:如何将LineString与速度、时间字段合并为LineString ZM类型
嘿,这个需求其实用PostGIS的几个基础函数组合一下就能轻松搞定,不用绕复杂的弯子。我给你直接上最简的实现方案,顺便拆解下逻辑:
核心实现SQL
假设你的表名叫tracks,直接用这段SQL就能生成目标的LineString ZM:
SELECT id, ST_MakeLine( ST_MakePointZM( ST_X(point.geom), ST_Y(point.geom), speed_val, time_val ) ORDER BY point.path[2] ) AS linestring_zm FROM tracks, ST_DumpPoints(geometry) AS point, UNNEST(speed) WITH ORDINALITY AS s(speed_val, idx), UNNEST(time) WITH ORDINALITY AS t(time_val, idx) WHERE s.idx = point.path[2] AND t.idx = point.path[2] GROUP BY id;
逻辑拆解
我给你掰碎了说每个部分干了啥:
ST_DumpPoints(geometry):把原二维LineString拆成一个个独立的点,返回的path数组里的第二个元素(path[2])就是这个点在原线里的顺序位置(从1开始计数)。UNNEST(speed) WITH ORDINALITY:把speed这个整数数组拆成一行行的数值,同时带上对应的索引idx,确保每个速度值能对应到原线里的对应点。time数组也是同理。ST_MakePointZM(x, y, z, m):创建一个四维点,这里把原点的x/y作为前两维,speed作为Z值,time作为M值——要是你想调换Z和M的顺序,直接把后两个参数换位置就行。ST_MakeLine(...) ORDER BY point.path[2]:按原线的点顺序重新把四维点拼成LineString ZM,这个排序一定要加,不然点的顺序乱了线就错了。- 最后按
id分组,把每个轨迹的所有四维点重新组合成一条完整的ZM线。
关键注意事项
- 必须保证
speed、time数组的长度和原LineString的点数完全一致!不然会出现点和属性不匹配或者丢数据的情况。你可以在查询里加个校验条件,比如在WHERE里加上:
甚至可以给表加个CHECK约束从源头保证数据一致性。AND array_length(speed, 1) = ST_NPoints(geometry) AND array_length(time, 1) = ST_NPoints(geometry) - PostGIS的版本不用太担心,这些函数(
ST_DumpPoints、ST_MakePointZM、ST_MakeLine)在2.x及以上版本都支持,兼容性拉满。
内容的提问来源于stack exchange,提问作者SOK
相关产品推荐
相关产品推荐

