11. 空间关系

目前我们仅使用了针对单一几何体的空间函数,包括测量类(如 :command:ST_Area、:command:ST_Length)、序列化(:command:ST_GeomFromText)及反序列化(:command:ST_AsGML)函数。这些函数的共同特点是每次仅能处理单个几何对象。

空间数据库的强大之处不仅在于存储几何数据,更在于其能够分析 几何体之间的空间关系

诸如"距离公园最近的自行车架在哪里?"或"地铁线路与街道的交叉点有哪些?"等问题,必须通过比对代表自行车架、街道和地铁线路的几何图形才能得出答案。

OGC 标准定义了下述几何图形比对方法集。

11.1. ST_Equals

ST_Equals(geometry A, geometry B) 用于检测两个几何图形的拓扑相等性。

_images/st_equals.png

当两个同类型几何图形的(x,y)坐标值完全一致时,:command:ST_Equals 将返回 TRUE,即判定两个图形拓扑相等(空间位置与形状完全重合)。

首先,我们从``nyc_subway_stations`` 表中提取 'Broad St' 站点的几何图形表示。

SELECT name, geom
FROM nyc_subway_stations
WHERE name = 'Broad St';
   name   |                      geom
----------+---------------------------------------------------
 Broad St | 0101000020266900000EEBD4CF27CF2141BC17D69516315141

随后,将几何图形表示重新代入 ST_Equals 函数进行测试:

SELECT name
FROM nyc_subway_stations
WHERE ST_Equals(
  geom,
  '0101000020266900000EEBD4CF27CF2141BC17D69516315141');
Broad St

注解

该点的几何表示(0101000020266900000EEBD4CF27CF2141BC17D69516315141)虽不易人工解读,但完整精确地记录了坐标值。在进行相等性测试时,必须使用此类精确坐标表示。

11.2. ST_Intersects, ST_Disjoint, ST_Crosses and ST_Overlaps

ST_IntersectsST_Crosses`和 :command:`ST_Overlaps 用于检测几何图形内部区域是否发生相交。

_images/st_intersects.png

ST_Intersects(geometry A, geometry B) 当两个图形存在任意空间交集时返回 t(TRUE),即边界或内部发生相交即视为满足条件。

_images/st_disjoint.png

与 :command:ST_Intersects 相对的是 ST_Disjoint(geometry A , geometry B)。若两个几何图形互不相交(disjoint),则它们不存在任何空间交集,反之亦然。实际上,测试"不相交"(not intersects)通常比直接测试"相离"(disjoint)更高效——因为相交测试可利用空间索引优化,而相离测试则无法利用索引。

_images/st_crosses.png

ST_Crosses(geometry A, geometry B) 用于以下几何类型组合的比对:多点/多边形、多点/线串、线串/线串、线串/多边形、线串/多多边形。当同时满足:(1) 交集结果的几何维度比两个源几何的最大维度小1;(2) 该交集同时位于两个源几何内部时,函数返回 TRUE。

_images/st_overlaps.png

ST_Overlaps(geometry A, geometry B) 用于比对两个同维度几何图形,当满足以下条件时返回 TRUE。

以下是通过 :command:`ST_Intersects`函数确定「Broad Street」地铁站所属行政辖区的示例:

SELECT name, ST_AsText(geom)
FROM nyc_subway_stations
WHERE name = 'Broad St';
POINT(583571 4506714)
SELECT name, boroname
FROM nyc_neighborhoods
WHERE ST_Intersects(geom, ST_GeomFromText('POINT(583571 4506714)',26918));
        name        | boroname
--------------------+-----------
 Financial District | Manhattan

11.3. ST_Touches

:command:`ST_Touches`用于检测两个几何图形是否边界接触但内部无交集

_images/st_touches.png

ST_Touches(geometry A, geometry B) 当满足以下任一条件时返回 TRUE:两个几何图形的边界存在交集;仅其中一个几何图形的内部与另一个图形的边界相交。

11.4. ST_Within 和 ST_Contains

ST_WithinST_Contains 用于检测两个几何图形之间的完全包含关系。

_images/st_within.png

ST_Within(geometry A , geometry B) 当第一个几何图形完全包含于第二个几何图形时返回 TRUE。该函数与 :command:ST_Contains 的检测结果互为逆反关系。

:command:`ST_Contains(geometry A, geometry B)`当第二个几何图形完全被包含于第一个几何图形内部时返回 TRUE。

11.5. ST_Distance 和 ST_DWithin

GIS 领域中一个极其常见的问题是:"找出与指定对象距离在 X 范围内的所有要素"。

ST_Distance(geometry A, geometry B) 用于计算两个几何图形之间的最短距离,并以浮点数形式返回结果。该函数特别适用于需要精确报告对象间距离的场景。

SELECT ST_Distance(
  ST_GeometryFromText('POINT(0 5)'),
  ST_GeometryFromText('LINESTRING(-2 2, 2 2)'));
3

ST_DWithin 函数提供基于索引加速的布尔距离检测,用于判断两个对象是否处于指定距离范围内。该函数特别适用于诸如"道路500米范围内有多少树木"这类空间分析场景——无需实际生成缓冲区,仅需测试距离关系即可获得结果。

_images/st_dwithin.png

以下是通过空间查询查找Broad Street地铁站周边10米范围内街道的SQL示例:

SELECT name
FROM nyc_streets
WHERE ST_DWithin(
        geom,
        ST_GeomFromText('POINT(583571 4506714)',26918),
        10
      );
     name
--------------
   Wall St
   Broad St
   Nassau St

我们可通过地图验证该结论:Broad St 地铁站实际位于 Wall Street、Broad Street 和 Nassau Street 三条道路的交汇处。

_images/broad_st.jpg

11.6. 函数列表

ST_Contains(geometry A, geometry B):当且仅当B的任何点都不位于A的外部,并且B的内部至少有一个点位于A的内部时,返回true。

ST_Crosses(geometry A, geometry B): 当两个几何图形存在部分(非全部)内部点重合时返回 TRUE。

ST_Disjoint(geometry A , geometry B): 若两个几何图形不存在任何空间交集(即完全不共享任何空间区域),则返回 TRUE。

ST_Distance(geometry A, geometry B):返回两个几何图形在二维笛卡尔坐标系下的最小投影距离(基于空间参考系统),单位为投影坐标单位。

ST_DWithin(geometry A, geometry B, radius):若两几何图形之间的最短距离小于等于指定半径值,则返回 true,否则返回 false。

ST_Equals(geometry A, geometry B):当两个几何图形几何等价时返回 true(忽略顶点顺序和方向)。

ST_Intersects(geometry A, geometry B):当几何图形/地理要素"存在空间交集"(即共享任意空间区域)时返回 TRUE,否则(两者相离时)返回 FALSE。

ST_Overlaps(geometry A, geometry B):当两个几何图形空间重叠(具有相同维度且互不完全包含)时返回 TRUE。

ST_Touches(geometry A, geometry B):如果两个geometry 至少有一个公共点,但它们的内部不相交,则返回 TRUE。

ST_Within(geometry A , geometry B):如果geometry A 完全位于 geometry B 内部,则返回 TRUE