本文将逐一介绍空间关系的定义及使用。
空间关系
PostGIS的强大功能是能够计算Geometry之间的空间关系。
通过比较代表自行车位置,街道和地铁线的Geometry 形状,可以回答诸如“距公园最近的自行车架在哪里?”或“地铁线与街道的交叉点在哪里?”之类的问题。
PostGIS提供了Open Geospatial Consortium / SQL-MM标准中定义的全套空间关系功能。这些功能允许测试空间(拓扑)关系和基于Geometry 之间的距离的关系。
大多数关系函数接受两个Geometry 作为输入,并以布尔值形式返回指定关系的值。 您可以使用以下查询尝试此操作:
SELECT ST_Intersects('POINT(1 1)', 'LINESTRING(1 1, 2 2)');
通常,布尔关系函数在SQL查询的“ WHERE”子句中使用(称为“空间过滤器”)。您将在本课程的稍后部分看到使用NYC示例数据集的示例。
它们还用于“ JOIN … ON”子句中,以指定“空间连接”。
ST_Equals
ST_Equals(geometry A,geometry B) 测试两个Geometry 的空间相等性。如果两个相同类型的Geometry 具有相同的形状,则 *返回TRUE。通常仅当它们具有相同的x,y坐标值时才如此。
例如,让我们使用“ nyc_subway_stations
”表中的点Geometry 。我们将查询Broad St站点的特征,并使用精确的数据表示形式(称为WKB)和更具可读性的文本格式(称为WKT)来显示它。 ):
SELECT name, geom, ST_AsText(geom) From nyc_subway_stations WHERE name = 'Broad St'; ----------------------------------- name | geom | st_astext ----------+----------------------------------------------------+----------------------- Broad St | 0EEBD4CF27CF2141BC17D | POINT( )
Geometry 值可以与“ ST_Equals”测试一起使用以检索原始记录:
SELECT name From nyc_subway_stations WHERE ST_Equals(geom, '0EEBD4CF27CF2141BC17D'); ---------------------------------- Broad St
注意:点的WKB数据格式不是可读的,但是它是坐标值的精确表示。 对于相等性之类的测试,必须使用确切的值。
ST_Intersects, ST_Disjoint
ST_Intersects(geometry A,geometry B)
如果两个形状有共同的空间,即它们的边界或内部相交,则 *返回t(TRUE)。
让我们乘坐Broad Street地铁站,并使用 ST_Intersects 函数确定其附近地区:
SELECT name, ST_AsText(geom) From nyc_subway_stations WHERE name = 'Broad St'; --------------------------------------- POINT( )
SELECT name, boroname From nyc_neighborhoods WHERE ST_Intersects(geom, ST_Geom FromText('POINT( )',26918)); ------------------------------ name | boroname-------------------+-----------Financial District | Manhattan
ST_Disjoint
ST_Disjoint(geometry A,geometry B) 与 ST_Intersects
相反。如果两个Geometry 不相交,则 *它们不相交,反之亦然。实际上,测试“ not_nots”通常更有效 “相交”而不是“不相交”,因为相交测试可以在空间上建立索引,而相交测试则 *不能。
ST_Within, ST_Contains
ST_Within 和 ST_Contains
是一对具有相关但相反含义的函数。
如果第一个Geometry 完全在第二个Geometry 内,并且它们具有至少一个共同的内部点,则 * ST_Within(geometry A,geometry B) 返回TRUE。
如果第一个Geometry 完全包含第二个Geometry ,并且它们具有至少一个共同的内部点,则 ST_Contains(geometry A,geometry B) 返回TRUE。
ST_Contains 测试 ST_Within 的相反关系,这意味着
ST_Contains(A,B) = ST_Within(B, A)
ST_Covers, ST_CoveredBy
PostGIS提供了另一对用于测试密闭度的功能,即 ST_Covers 和 T_CoveredBy 。
这些函数不是SQL / MM标准的一部分,但是它们解决了 ST_Contains 和 ST_Within 的微妙之处,这有时会引起问题。ST_Contains 的标准定义有一个怪异,即多边形不包含沿其边界(在边界内)的线串。
SELECT ST_Contains('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))'::geometry,'LINESTRING (0 0, 1 0)'::geometry ); --------------------------------- f
定义了 ST_Covers(geometry A,geometry B) ,以便不会发生此异常,该异常通常更符合您的期望。
SELECT ST_Covers('POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))'::geometry,'LINESTRING (0 0, 1 0)'::geometry ); --------------------------------- t
ST_CoveredBy(Geometry A,Geometry B) 与 ST_Covers 具有相反的含义,因此:
ST_Covers(A,B) = ST_CoveredBy(B, A)
SELECT ST_CoveredBy('LINESTRING (0 0, 1 0)'::geometry,'POLYGON ((0 1, 1 1, 1 0, 0 0, 0 1))'::geometry ); --------------------------------- t
ST_Crosses, ST_Overlaps, ST_Touches
ST_Crosses,ST_Overlaps 和 ST_Touches 是较少使用的函数,用于测试Geometry 之间空间关系的特定方面。
ST_Crosses(geometry A,geometry B) 测试交集是否产生尺寸小于两个源Geometry 的最大维且交集位于两个源Geometry 内部的Geometry ,仅适用于点/多边形, 点/线串,线串/线串和线串/多边形比较。
例如,这测试一条线是否穿过多边形:
SELECT ST_Crosses('POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))','LINESTRING (50 150, 150 150)'); --------------------------------- t
ST_Overlaps(Geometry A,Geometry B) 比较相同维度的两个Geometry ,如果它们的交集导致二者的年龄测量结果不同但尺寸相同,则 *返回true。
ST_Touches(Geometry A,Geometry B) 测试两个Geometry 的边界是否相交,或者仅Geometry 的一个内部与另一个Geometry 的边界相交。
ST_Relate
前几节中的空间关系函数是更通用的函数 ST_Relate 的特例。它使用维数扩展的9交点模型(DE-9IM)计算两个Geometry 之间的完整拓扑关系。 表示为文本代码,用于指定每个输入Geometry 的内部,边界和外部的交点的尺寸。由于有九种组合,因此代码具有符号,每个符号具有交集尺寸的值(0
,1
或2
)或F
(如果没有交叉点)。
例如,与多边形相交的线的交点的代码为“ 1020F1102”:
SELECT ST_Relate('POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))','LINESTRING (50 150, 150 150)'); --------------------------------- 1020F1102
特定的空间关系是通过将DE-9IM代码与指定所需关系的“图案遮罩”进行比较来确定的。除DE-9IM符号外,遮罩还可以包含“ T”(表示任何尺寸的交集)和“ *”(表示一个维)。 通配符或“无关”值。例如,多边形/线格“ Crosses”的图案遮罩为“ T T”。
对于上述情况,可以通过在掩码中使用 T_Relate 来确认这一点:
SELECT ST_Relate('POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))','LINESTRING (50 150, 150 150)','T* *T' ); --------------------------------- t
通常使用命名关系函数会更方便,但是在某些情况下,不需要提供关系的函数,例如GIS数据结构称为``多边形覆盖率’’(polygonal coverage *)是多边形的集合,其中没有多边形 有相交的内部。 这由矩阵模式“ F”表示。在这种情况下,没有命名空间关系函数测试,因此必须使用“ ST_Relate”进行测试。
这是两个内部相交的多边形,因此不会形成多边形覆盖范围:
SELECT ST_Relate('POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))','POLYGON ((250 250, 250 150, 150 150, 150 250, 250 250))','F' ); --------------------------------- f
这是两个确实形成有效多边形覆盖率的多边形:
SELECT ST_Relate('POLYGON ((100 100, 100 200, 200 200, 200 100, 100 100))','POLYGON ((300 100, 200 100, 200 200, 300 200, 300 100))','F' ); --------------------------------- t
ST_Distance, ST_DWithin
常见的GIS问题是“在其他物料的distanceX范围内找到所有物料”。
T_Distance(geometry A,geometry B) 函数计算两个Geometry 之间的最短距离,并将其作为浮点数返回。 这对于报告对象之间的实际距离很有用。
SELECT ST_Distance(ST_Geometry FromText('POINT(0 5)'),ST_Geometry FromText('LINESTRING(-2 2, 2 2)')); --------------------------------- 3
注意:返回的距离值以输入Geometry 的空间参考系为单位
ST_DWithin
为了测试两个物体是否在给定的距离内, T_DWithin 函数提供了索引加速的真/假测试。这对于诸如“在道路的500米缓冲区内有几棵树? ”。 您不必计算实际的缓冲区,只需要测试距离关系即可。
再次使用Broad Street地铁站,我们可以找到地铁站附近(10米以内)的街道:
SELECT name From nyc_streets WHERE ST_DWithin(geom,ST_Geom FromText('POINT( )',26918),10); --------------------------------- name -------------- Wall StBroad StNassau St
我们可以在地图上验证答案。 宽街站实际上位于华尔街,宽街和拿骚街的交汇处。
Exercises
以下是使用NYC数据集表的其他一些查询:
nyc_census_blocks
- blkid, popn_total, boroname, geom
nyc_streets
- name, type, geom
nyc_subway_stations
- name, geom
nyc_neighborhoods
- name, boroname, geom
名为“ Atlantic Commons”的街道的Geometry 值是多少?
SELECT ST_AsText(geom) From nyc_streets WHERE name = 'Atlantic Commons'; --------------------------------- MULTILINESTRING((. .,. .))
大西洋公域位于哪个街区和自治市镇?
SELECT name, boroname From nyc_neighborhoods WHERE ST_Intersects(geom,ST_Geom FromText('LINESTRING( , )', 26918)); --------------------------------- name | boroname- -----------+---------- Fort Green | Brooklyn
“嘿,您为什么从’MULTILINESTRING’变为’LINESTRING’?” 它们在空间上描述的形状相同,因此从单项多Geometry 到单例可以节省一些击键。
更重要的是,我们还对坐标进行了四舍五入,以使其更易于阅读,这实际上改变了结果:我们无法使用
ST_Touches()
谓词来确定哪些道路加入了Atlantic Commons,因为坐标不再完全相同 。
大西洋共同体与哪些街道相连?
SELECT name From nyc_streets WHERE ST_DWithin(geom,ST_Geom FromText('LINESTRING( , )', 26918),0.1); --------------------------------- name ------------------ Cumberland StAtlantic Commons
大约有多少人生活在(大西洋公地50米以内)
SELECT Sum(popn_total) From nyc_census_blocks WHERE ST_DWithin(geom,ST_Geom FromText('LINESTRING( , )', 26918),50); --------------------------------- 1438
总结
现在,您已经了解了PostGIS如何支持全套标准空间和距离关系功能。
有关空间关系和“尺寸扩展的9交叉模型”(DE-9IM)的更多技术细节,请访问[这里](https://en.wikipedia.org/wiki/DE-9IM)。
关系函数及其定义总结如下:
空间关系函数
ST_Contains(geometry A,geometry B)
当且仅当B的点不位于A的外部且B的内部的至少一个点位于A的内部时,才返回true。
ST_CoveredBy(geometryA,geometryB)
当且仅当A的点不位于B的外部时,才返回true。换句话说,A完全位于B的内部。 T_Covers 的相反。
ST_Covers(geometryA,geometryB)
当且仅当B的点不位于A的外部时,才返回true。换句话说,B完全位于A的内部。 T_CoveredBy 的反面。
ST_Crosses(geometry A,geometry B)
如果提供的Geometry 具有一些但不是全部内部点,则 *返回true。
ST_Disjoint(geometry A,geometry B)
如果Geometry 在空间上不相交-即它们不共享任何点,则 *返回true。ST_Intersects 的反函数。
ST_Equals(geometry A,geometry B)
如果Geometry 形状完全相同,则 *返回true。不考虑方向性。
ST_Intersects(geometryA,geometryB)
如果geometry“空间相交”,即,如果它们至少有一个共同的空间点,则 *返回true。ST_Disjoint 的反函数。
ST_Overlaps(geometry A,geometry B)
如果Geometry 共享空间,具有相同尺寸但彼此之间不完全包含,则 *返回true。
ST_Touches(geometryA,geometryB)
如果geometry至少有一个公共点,但它们的内部不相交,则 *返回true。
ST_Within(geometry A,geometry B)
如果Geometry A完全在Geometry B之内,则 *返回true。 T_Contains 的反之。
相关功能
ST_Relate(Geometry A,Geometry B)
返回DE-9IM代码,指示A和B之间的完整拓扑关系。
ST_Relate(Geometry A,Geometry B,文本蒙版)
测试Geometry A和B是否具有与给定蒙版匹配的DE-9IM代码。
距离关系功能
ST_Distance(geometryA,geometryB)
返回两个geometry之间的二维笛卡尔最小距离,以空间参考系统为单位。
ST_DWithin(Geometry A,Geometry B,半径)
如果两个Geometry 在彼此的指定距离(半径)之内,则 *返回true。