Postgres PostGIS:st_intersects returns false 但仅针对返回的第一条记录,即使是硬编码

Postgres PostGIS: st_intersects returns false but only for first record returned, even if hard coded

使用 Postgres 9.2

我有一个奇怪的问题。简化一下:

我有一些带有线点的数据。有问题的查询使用 st_intersects 来确定线点是否与多边形重叠。线和多边形都存储在 3d 表示中,z 轴为 0。这是用于地理空间数据。

在这种情况下,我有一个起点和终点是相同值的线点。两条记录的值看似相同,起点和终点的X、Y、Z分量相同。用=~比较两点,它们是相等的。使用=,它们是相等的。使用st_equals,结果为false,但是比较组成线条的分量,数值似乎都相等,包括通过目测比较二进制表示。

当我做st_intersects(my_line,some_polygon)时,一条记录returns为真,另一条为假,即使这两条线的值记录看起来相同。我没有创建原始值,所以我不知道它们最初是如何创建的。每条记录都对应一辆车,无论出于何种原因,其中一辆车的多条记录都存在这个问题。

如果我将函数从 st_intersects 更改为可能更昂贵的 st_3dintersects,它们都如预期的那样 return 为真,问题就消失了。所比较的多边形非常大,这会影响具有不同点的多个记录,因此我们不太可能遇到任何类型的边缘舍入错误。使用 st_force2d 也不起作用。

为什么我可能会看到我所看到的行为?

这是该行的 EWKT,坐标已更改:

SRID=4326;LINESTRING(-85.6600021 30.7976979 0,-85.6600021 30.7976979 0)

两条记录对于 ST_AsEWKT 的值完全相同,但其中一条记录对于 st_intersects(my_line, the_poly) return 是错误的其他 return 对 st_intersects(my_line、the_poly)为真。即使我对 EWKT 值进行硬编码,我仍然会看到这种差异:

ST_Intersects(
  ST_GeomFromEWKT('SRID=4326;LINESTRING(-85.6600021 30.7976979 0,-85.6600021 30.7976979 0)')),
  x.geom
)

它似乎总是影响结果集中的第一条记录,而不影响其他记录。如果我更改查询中的所有其他内容,则第一个记录始终 return 为假,所有后续记录始终为真。

编辑: 更多调查,似乎线串无效,开始和结束都是相同的值。施法 st_makevalid 通过使它成为一个点来修复它。显然,无效线串的评估不一致。

我不知道你在说什么。只是提供数据,因为你不善于描述问题。

\set linestring ST_GeomFromEWKT($$SRID=4326;LINESTRING(-85.6600021 30.7976979 0,-80.6600021 30.7976979 0)$$)
\set point ST_GeomFromEWKT($$SRID=4326;POINT(-85.6600021 30.7976979 0)$$)

SELECT ST_Intersects( :linestring, :point ) AS linestringPoint
  , ST_Intersects( :linestring, :linestring ) AS linestringLinestring

很可能只有 WKB 格式才能看到坐标的小数点差异,这意味着 WKT 格式看不到小的差异。这是一个例子:

SELECT ST_AsEWKT(A) AS wkt_a, ST_AsEWKT(B) AS wkt_b,
    ST_AsEWKT(A) = ST_AsEWKT(B) AS wkt_are_equal,
    A::text = B::text AS wkb_are_equal,
    ST_Intersects(A, B), ST_Distance(A, B),
    ST_Distance(A, B) < 1e-12 AS pretty_much_intersect
FROM (
    SELECT
       '01010000A0E6100000A5B272793D6A55C07E96F8ED35CC3E400000000000000000'::geometry AS A,
       '01010000A0E6100000A5B272793D6A55C07F96F8ED35CC3E400000000000000000'::geometry AS B
) f;
-[ RECORD 1 ]---------+------------------------------------------
wkt_a                 | SRID=4326;POINT(-85.6600021 30.7976979 0)
wkt_b                 | SRID=4326;POINT(-85.6600021 30.7976979 0)
wkt_are_equal         | t
wkb_are_equal         | f
st_intersects         | f
st_distance           | 3.5527136788005e-015
pretty_much_intersect | t

所以你可以看到WKT是相等的,但是WKB不是。两者之间的距离很小,因此 ST_Intersects 将 return 为假,因为这些谓词函数需要精确的点数。

如最后一列所示,通过测试距离是否在很小的距离内,可以找到一个更可靠的指标来查找基本相交的几何图形。另一种解决方法是看ST_Snap.


现在看到问题中的无效几何,我的答案是不要使用无效几何!

行为转载于此:

DROP TABLE IF EXISTS invalid;

CREATE TEMP TABLE invalid(id integer primary key, geom geometry);
INSERT INTO invalid(id, geom) VALUES
(1, 'LINESTRING(-85.6600021 30.7976979,-85.6600021 30.7976979)'),
(2, 'LINESTRING(-85.6600021 30.7976979,-85.6600021 30.7976979)'),
(3, 'LINESTRING(-85.6600021 30.7976979,-85.6600021 30.7976979)');

SELECT id, ST_Intersects(
  ST_GeomFromEWKT('LINESTRING(-85.6600021 30.7976979,-85.6600021 30.7976979)'), x.geom)
    FROM invalid x;

 id | st_intersects
----+---------------
  1 | f
  2 | t
  3 | t
(3 rows)