28. 3-D

28.1. 3-D 几何图形

到目前为止,我们一直在使用只有 X 和 Y 坐标的 2-D 几何图形。但 PostGIS 支持所有几何类型上的附加维度,一个“Z”维度用于添加高度信息,一个“M”维度用于每个坐标的附加维度信息(通常是时间、道路里程或上游距离信息)。

对于 3-D 和 4-D 几何图形,额外的维度作为几何图形中每个顶点的额外坐标添加,并且几何图形类型得到增强以指示如何解释额外的维度。添加额外的维度会导致每个几何图元有三个额外的可能的几何类型

  • 点(一种 2-D 类型)由 PointZ、PointM 和 PointZM 类型连接。

  • 线串(一种 2-D 类型)由 LinestringZ、LinestringM 和 LinestringZM 类型连接。

  • 多边形(一种 2-D 类型)由 PolygonZ、PolygonM 和 PolygonZM 类型连接。

  • 等等。

对于众所周知的文本 (WKT) 表示,更高维几何图形的格式由 ISO SQL/MM 规范给出。额外的维度信息只是在类型名称之后添加到文本字符串中,并且额外的坐标添加到 X/Y 信息之后。例如

  • POINT ZM (1 2 3 4)

  • LINESTRING M (1 1 0, 1 2 0, 1 3 1, 2 2 0)

  • POLYGON Z ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0))

当处理 3-D 和 4-D 几何图形时,ST_AsText() 函数将返回上述表示。

对于众所周知的二进制 (WKB) 表示,更高维几何图形的格式由 ISO SQL/MM 规范给出。该格式的 BNF 形式可从 https://git.osgeo.org/gitea/postgis/postgis/src/branch/master/doc/bnf-wkb.txt 获取。

除了标准类型的更高维形式之外,PostGIS 还包含一些在 3-D 空间中很有意义的新类型

  • TIN 类型允许您将三角形网格建模为数据库中的行。

  • POLYHEDRALSURFACE 允许您在数据库中对体积对象进行建模。

由于这两种类型都是用于对 3-D 对象进行建模,因此只有使用 Z 变体才有意义。POLYHEDRALSURFACE Z 的一个例子是 1 个单位立方体。

POLYHEDRALSURFACE Z (
  ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
  ((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)),
  ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
  ((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)),
  ((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)),
  ((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))
)

28.2. 3-D 函数

有许多函数被构建来计算 3-D 对象之间的关系。

  • ST_3DClosestPoint — 返回 g1 上最靠近 g2 的 3 维点。这是 3D 最短线的第一个点。

  • ST_3DDistance — 对于几何类型,返回两个几何体之间基于空间参考的 3 维笛卡尔最小距离(以投影单位表示)。

  • ST_3DDWithin — 对于 3d (z) 几何类型,如果两个几何体的 3d 距离在单位数范围内,则返回 true。

  • ST_3DDFullyWithin — 如果所有 3D 几何体都彼此之间的指定距离内,则返回 true。

  • ST_3DIntersects — 如果几何体在 3d 中“空间相交”,则返回 TRUE - 仅适用于点和线字符串。

  • ST_3DLongestLine — 返回两个几何体之间的 3 维最长线。

  • ST_3DMaxDistance — 对于几何类型,返回两个几何体之间基于空间参考的 3 维笛卡尔最大距离(以投影单位表示)。

  • ST_3DShortestLine — 返回两个几何体之间的 3 维最短线。

例如,我们可以使用 ST_3DDistance 函数计算单位立方体和一个点之间的距离。

-- This is really the distance between the top corner
-- and the point.
SELECT ST_3DDistance(
  'POLYHEDRALSURFACE Z (
    ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
    ((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)),
    ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
    ((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)),
    ((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)),
    ((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))
  )'::geometry,
  'POINT Z (2 2 2)'::geometry
);

-- So here's a shorter form.
SELECT ST_3DDistance(
  'POINT Z (1 1 1)'::geometry,
  'POINT Z (2 2 2)'::geometry
);

-- Both return 1.73205080756888 == sqrt(3) as expected

28.3. N-D 索引

一旦您拥有更高维度的數據,对它进行索引可能是有意义的。但是,在应用多维索引之前,您应该仔细考虑数据在所有维度上的分布。

索引只有在它们允许数据库大幅减少 WHERE 条件返回的行数时才有用。为了使更高维度的索引有用,数据必须覆盖该维度的大范围,相对于您正在构建的查询类型。

  • 一组 DEM 点可能不是 3-D 索引的良好候选者,因为查询通常会提取 2-D 点框,很少尝试选择 Z 切片点。

  • 一组 X/Y/T 空间中的 GPS 轨迹可能是 3-D 索引的良好候选者,如果 GPS 轨迹在所有维度上频繁地相互重叠(例如,在不同时间重复行驶相同的路线),因为数据集中所有维度都会存在很大的可变性。

您可以对任何维度的(甚至混合维度的)数据创建多维索引。例如,要创建对nyc_streets表的索引,

CREATE INDEX nyc_streets_gix_nd ON nyc_streets
USING GIST (geom gist_geometry_ops_nd);

gist_geometry_ops_nd参数告诉PostGIS使用N-D索引而不是标准的2-D索引。

建立索引后,您可以在查询中使用&&&索引运算符。 &&&&&具有相同的语义,“边界框交互”,但使用输入几何的所有维度应用这些语义。维度不匹配的几何体不会交互。

-- Returns true (both 3-D on the zero plane)
SELECT 'POINT Z (1 1 0)'::geometry &&&
       'POLYGON ((0 0 0, 0 2 0, 2 2 0, 2 0 0, 0 0 0))'::geometry;

-- Returns false (one 2-D one 3-D)
SELECT 'POINT Z (3 3 3)'::geometry &&&
       'POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0))'::geometry;

-- Returns true (the volume around the linestring interacts with the point)
SELECT 'LINESTRING Z(0 0 0, 1 1 1)'::geometry &&&
       'POINT(0 1 1)'::geometry;

要使用N-D索引搜索nyc_streets表,只需将通常的&& 2-D索引运算符替换为&&&运算符。

-- N-D index operator
SELECT gid, name
FROM nyc_streets
WHERE geom &&&
      ST_SetSRID('LINESTRING(586785 4492901,587561 4493037)'::geometry,26918);

-- 2-D index operator
SELECT gid, name
FROM nyc_streets
WHERE geom &&
      ST_SetSRID('LINESTRING(586785 4492901,587561 4493037)'::geometry,26918);

结果应该相同。一般来说,N-D索引比2-D索引略慢,因此只有在您确定N-D查询会提高查询选择性时才使用N-D索引。