SQL Server 地理测试点是不是在范围内 - STWithin() 做啥?

Posted

技术标签:

【中文标题】SQL Server 地理测试点是不是在范围内 - STWithin() 做啥?【英文标题】:SQL Server geography testing if a point is within a bounds - what does STWithin() do?SQL Server 地理测试点是否在范围内 - STWithin() 做什么? 【发布时间】:2020-05-02 02:30:16 【问题描述】:

我正在测试各种 SQL 地理类型的方法 - 具体来说,我想了解 STContains()STWithin() 之间的区别。

根据文档:

StWithin() - 如果地理实例在空间上位于另一个地理实例中,则返回 1;

STContains() - 指定调用 geography 实例是否在空间上包含传递给方法的 geography 实例。

我在微软总部周围创建了一个简单的 1 公里 x 1 公里 POLYGON(实际上是一个正方形),在视觉上看起来像这样:

使用的数据点如下:

Center point: 47.6423318, -122.1391189

Polygon (Square) corner points:

SE: 47.6378402235794, -122.13244353271
NE: 47.6468233764206, -122.13244353271
NW: 47.6468233764206, -122.14577646729
SW: 47.6378402235794, -122.14577646729

POLYGON 声明如下(使用左手规则),并检查是否有效:

DECLARE @bounds geography;
SET @bounds = geography::STPolyFromText('POLYGON((-122.13244353271 47.6378402235794, -122.13244353271 47.6468233764206, -122.14577646729 47.6468233764206, -122.14577646729 47.6378402235794, -122.13244353271 47.6378402235794))', 4326 );

SELECT @bounds.STIsValid() AS 'STIsValid', @bounds.STIsClosed() AS 'STIsClosed';

SQL 返回:

STIsValid   STIsClosed
True        True

接下来,我检查中心点是否在边界内(应该是),如下

DECLARE @point geography;
SET @point = geography::Point( 47.6423318, -122.1391189, 4326 );

SELECT @bounds.STContains( @point) AS 'STContains', 
       @bounds.STIntersects( @point ) AS 'STIntersects',
       @bounds.STOverlaps( @point ) AS 'STOverlaps',
       @bounds.STWithin( @point ) AS 'STWithin';

SQL 返回:

STContains  STIntersects    STOverlaps  STWithin
True        True            False       False

注意:我原以为STWithinTrue,但结果中心点不在“范围内”?

接下来,我检查 SW 角点是否被认为是“在”范围内,如下所示:

SET @point = geography::Point( 47.6378402235794, -122.14577646729, 4326 );

SELECT @bounds.STContains( @point) AS 'STContains', 
       @bounds.STIntersects( @point ) AS 'STIntersects',
       @bounds.STOverlaps( @point ) AS 'STOverlaps',
       @bounds.STWithin( @point ) AS 'STWithin';

SQL 返回:

STContains  STIntersects    STOverlaps  STWithin
False       True            False       False

注意:在这种情况下,STContains() 返回False(这是预期的),但STIntersects() 返回True;如果您需要将边缘点视为“在”范围内,这很有用。

最后一次测试 - 边界外的一点:

SET @point = geography::Point( 47.647, -122.13244353271, 4326 );

SELECT @bounds.STContains( @point) AS 'STContains', 
       @bounds.STIntersects( @point ) AS 'STIntersects',
       @bounds.STOverlaps( @point ) AS 'STOverlaps',
       @bounds.STWithin( @point ) AS 'STWithin';

SQL 返回:

STContains  STIntersects    STOverlaps  STWithin
False       False           False       False

在上述所有测试中,即测试边界内、边界边缘和边界外的点,STWithin() 返回 False - STWithin() 需要什么条件才能返回True? (或者,STWithin() 根本不起作用?)

另外,我期待 STOverlaps() 在某些情况下返回 true,但如果有人可以评论该方法,那也会有所帮助。

任何建议将不胜感激。

【问题讨论】:

【参考方案1】:

STWithin() 需要什么条件才能返回 True? (或者,确实 STWithin() 根本不起作用?)

STWithin, STContains : OGC 标准方法,返回 1 或 0,它们表示一个实例的所有点是否完全存在于另一个实例中。

对于您的示例,该点可以存在于多边形内,但该多边形不能存在于该点内。将 within 视为 contains 的“逆”:如果 x 在 y 内,则 y 包含 x。 --> 如果多边形包含点,则点在多边形内:

SELECT 
@bounds.STContains( @point) AS 'bounds contains point',  --if this is true...
@point.STWithin( @bounds ) AS 'point is within bounds'; --...then this is also true

另外,我期待 STOverlaps() 在某些情况下返回 true

这在the documentation 中有点模糊(适用于几何,但也适用于地理):

备注 如果表示它们的交集的区域与实例具有相同的维度并且区域不等于任一实例,则两个几何实例重叠。

点与多边形重叠 --> 重叠是点(==等于任一实例)--> 0。

您可以通过“克隆”相同的空间实例并检查它是否重叠来测试它:

DECLARE @bounds geography;
SET @bounds = geography::STPolyFromText('POLYGON((-122.13244353271 47.6378402235794, -122.13244353271 47.6468233764206, -122.14577646729 47.6468233764206, -122.14577646729 47.6378402235794, -122.13244353271 47.6378402235794))', 4326 );
DECLARE @boundsclone geography=@bounds;

select @bounds.STOverlaps(@boundsclone), @boundsclone.STOverlaps(@bounds);

【讨论】:

lptr - 谢谢 - 仍然有些困惑 - 可能是因为名称 (STWithin) - 如果它是 STContains 的倒数,人们会认为 STNotContains 之类的名称更合适。简而言之:a.STWithin(b) == b.STContains(a) -- 正确吗? 看起来像。使用您的样本点,我运行 select @point.STWithin( @bounds ) AS 'STWithin'; 并返回 true。【参考方案2】:

好的,看来以下是正确的:

@point.STWithin( @bounds ) == @bounds.STContains( @point );

例如以下查询(测试中心点是否在边界内):

DECLARE @point geography;
SET @point = geography::Point( 47.6423318, -122.1391189, 4326 );

SELECT @bounds.STContains( @point) AS 'STContains', 
       @point.STWithin( @bounds ) AS 'STWithin';

返回:

STContains  STWithin
True        True

【讨论】:

从简单的英语角度考虑。你把你的鞋子放在一个盒子里了。 shoes.within(box) -> yes, box.contains(shoes) -> yes, shoes.contains(box) -> no, box.within(shoes) -> no

以上是关于SQL Server 地理测试点是不是在范围内 - STWithin() 做啥?的主要内容,如果未能解决你的问题,请参考以下文章

使用 SQL Server 2008 地理类型的查询点

查询以将在特定地理距离内的行返回到给定行(使用 sql server 2008)

SQL Server:检查两个地理/几何的边界是不是相互交汇

如何检查地理位置是不是在半径范围内?

SQL - 地理计算

在Spark SQL作业中使用地理空间函数