【问题标题】:Postgres PostGIS: st_intersects returns false but only for first record returned, even if hard codedPostgres PostGIS:st_intersects 返回 false,但仅适用于返回的第一条记录,即使是硬编码
【发布时间】:2016-12-07 05:05:51
【问题描述】:

使用 Postgres 9.2

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

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

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

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

如果我将函数从 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。

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

【问题讨论】:

  • 为您要发送到ST_Equals 的两个内容提供ST_AsEWKT()
  • 你说的是什么意思当我做st_intersects(my_line, some_polygon)时,一个返回true,另一个false还有什么?
  • 这对于gis.stackexchange.com 来说可能是一个更好的问题(如果需要,您可以标记它并要求将其移动)
  • 我做了更多的研究,发现带有这个特定行字符串的第一条记录如果返回第一条记录,则对于 st_intersects 总是返回 false,对于所有后续记录,总是返回 true。这似乎表明它是gis中的一个错误?
  • 不知道你在说什么不知道问题是什么,没有样本数据。

标签: postgresql postgis


【解决方案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)

【讨论】:

  • 情况并非如此,因为您可以对几何图形进行硬编码并通过简​​单地将其与任何表格交叉连接来重现问题。问题似乎在于 postgres 如何处理包含相同值的开头和结尾的无效行。
  • @JamesHutchison 好的,我看到您对无效几何的编辑,我可以让 PostGIS 显示您要解释的内容。我的建议是不要使用无效的几何图形。
  • 是的,我无法控制数据,因此我在可疑几何体上使用 st_makevalid 来修复它,从而解决了问题。遗憾的是,postgres 有这种行为并且默默地这样做。
【解决方案2】:

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

\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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-20
    • 2013-03-28
    • 2022-01-27
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    相关资源
    最近更新 更多