与 ST_DWithin 的奇怪差异 - 地理与几何

Strange difference with ST_DWithin - Geography vs Geometry

(编辑:抱歉。忘了提及。Postgresql 13,PostGIS:3.1 USE_GEOS=1 USE_PROJ=1 USE_STATS=1。抱歉)。

在我看来,以下 2 个查询在这两种情况下都应该 return "true"。 该点显然位于多边形(正方形)内。显示两者肯定表明如此。 我开始想知道我在这里缺少什么基本的东西。

老实说,多年来我一直在围绕这个问题徘徊,因为我一直无法找到“最终”的东西来理解正在发生的事情。在这种情况下,该点有点靠近多边形的边缘,但有时我会遇到完全位于多边形内的点的相同问题。

这两个查询之间的唯一区别是一个使用几何,另一个使用地理。如您所见,我们使用 0.0 作为距离值。这就像一个相交。

OH,顺便说一句,使用相交会产生相同的结果。我对此很困惑。

select 
ST_Dwithin(
St_GeometryFromText(
  'POLYGON((-95.979486 41.676556,-81.432269 41.676556,-81.432269 30.196043,-95.979486 30.196043,-95.979486 41.676556))', 4326),
ST_GeometryFromText('POINT (-87.70551 30.24481)', 4326),
  0
)
select 
ST_Dwithin(
St_GeographyFromText(
  'POLYGON((-95.979486 41.676556,-81.432269 41.676556,-81.432269 30.196043,-95.979486 30.196043,-95.979486 41.676556))'),
St_GeographyFromText('POINT (-87.70551 30.24481)'),
  0
)

编辑。 抱歉,不确定正确的礼仪。在获得好评后,我添加了更多上下文,以防有人觉得有趣。

我正在处理包含国家/地区多边形的“世界”数据集。由于其中一些很大,我选择 st_subdivide 它们。

![st_subdivide 美国] https://imgur.com/IQRz8vg

并且在缩放时我们可以清楚地看到下面答案中解释的内容:

![缩放 st_subdivide 美国] https://imgur.com/fgmpBx0

太棒了,完美的解释,非常感谢。

我知道我不应该用地理,嗯,“不应该”。然而,我还需要在距离和扩展方面做很多工作,而 geom(4326) 对于我找到的单位来说非常烦人。

首先,你需要了解几何学和地理学的区别。

  1. Geometry,它假定您的所有数据都位于笛卡尔平面上。
  2. 地理,它假定您的数据由地球表面的点组成。

问题如下。当您投影几何体时,PostGIS 假设几何体的边缘不是平面的(因为地球表面不是平面的)并将它们转换为球面(此过程称为曲面细分)。因此,当您尝试与它们相交时,该点不在多边形内部。

如果地理区域足够小,球面边缘和平面边缘之间的差异可以忽略,但在您的情况下,多边形是一个巨大的多边形。

您将几何图形投影到 EPSG 4326 上,以便将其投影到地球表面,但是尽管该点在平面坐标系中位于正方形内部,但它不在球形坐标系中。

总而言之,您需要了解哪种类型、几何形状或地理位置适用于您的用例。

您可以通过强制边缘为平面来解决此问题(在 PostGIS 的某些实现中作为 BigQuery):

St_GeogFromText(
    'POLYGON((-95.979486 41.676556,-81.432269 41.676556,-81.432269 30.196043,-95.979486 30.196043,-95.979486 41.676556))',
     planar => True)

除了@sergiomahi 的回答(应该被接受)之外,我还想添加一些示例来使他的观点更清楚。问题不在于类型 geography 本身,而是特征投影到哪个表面。

给定你的多边形和点,如果我们 ST_Distance 使用 geometry 距离为零,因为它将使用笛卡尔平面,但使用 geography 它 returns 16524.35577956 米,因为球形边缘和多边形的大小,正如@sergiomahi 所指出的。因此,它们不再重叠。

WITH j (pol,poi) AS (
  VALUES
   ('SRID=4326;POLYGON((-95.979486 41.676556,-81.432269 41.676556,-81.432269 30.196043,-95.979486 30.196043,-95.979486 41.676556))',
    'SRID=4326;POINT (-87.70551 30.24481)')
)
SELECT 
  ST_Distance(poi::geometry,pol::geometry) AS geom_dist, 
  ST_Distance(poi::geography,pol::geography) AS geog_dist 
FROM j;



geom_dist |   geog_dist    
-----------+----------------
         0 | 16524.35577956

但是,如果您坚持 geometry 并告诉 PostGIS 应该使用球体计算距离,您会得到与 geography:

类似的结果
WITH j (pol,poi) AS (
 VALUES
   ('SRID=4326;POLYGON((-95.979486 41.676556,-81.432269 41.676556,-81.432269 30.196043,-95.979486 30.196043,-95.979486 41.676556))',
    'SRID=4326;POINT(-87.70551 30.24481)'))
SELECT 
  ST_Distance(poi::geography,pol::geography) AS geog_dist, 
  ST_DistanceSphere(poi::geometry,pol::geometry) AS geom_dist_sphere
FROM j;

   geog_dist    | geom_dist_sphere 
----------------+------------------
 16524.35577956 |   16574.61755546
(1 Zeile)