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

时间:2016-12-07 05:05:51

标签: postgresql postgis

使用Postgres 9.2

我有一个奇怪的问题。为了简化它:

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

在这种情况下,我有一个行点,其中start和end是相同的值。两个记录看似相同,起点和终点上的X,Y,Z分量是相同的。使用=〜比较两个点,它们是相等的。使用=,它们是平等的。使用st_equals,结果为false,但比较组成行的组件,值似乎都相等,包括通过目视检查比较二进制表示。

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

如果我将函数从st_intersects更改为可能更昂贵的st_3dintersects,它们都会按预期返回true,问题就会消失。被比较的多边形非常大,这会影响几个具有不同点的记录,因此我们不太可能遇到任何类型的一些条纹舍入误差。使用st_force2d也不起作用。

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

这里是线的EWKT,坐标已更改:

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

两个记录对于ST_AsEWKT具有完全相同的值,但是其中一个对于st_intersects(my_line,the_poly)返回false,而另一个对于st_intersects(my_line,the_poly)返回true。即使我硬编码EWKT值,我仍然看到这种差异:

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

似乎它总是影响结果集中的第一条记录而没有其他记录。如果我更改了查询中的所有其他内容,则第一条记录的返回值始终为false,所有后续记录的值都为true。

编辑: 更多的调查,似乎线串无效,start和end都是相同的值。转换st_makevalid通过使其成为一个点来修复它。显然,无效的线串被评估不一致。

2 个答案:

答案 0 :(得分:1)

最有可能的是,您只能通过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将返回false,因为这些谓词函数需要精确的编码。

通过测试距离是否在一个很小的距离内,可以看到一个更健壮的度量来查找基本上相交的几何图形,如最后一列所示。另一种解决方案是查看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)

答案 1 :(得分:0)

我不知道你在谈论什么。只是提供数据,因为您不擅长描述问题。

\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