PL/R
函数和PostGIS
围绕一组点生成voronoi多边形。我正在使用的功能在此处定义。当我在特定数据集上使用此函数时,会收到以下错误消息:Error : ERROR: R interpreter expression evaluation error
DETAIL: Error in pg.spi.exec(sprintf("SELECT %3$s AS id,
st_intersection('SRID='||st_srid(%2$s)||';%4$s'::text,'%5$s')
AS polygon FROM %1$s WHERE st_intersects(%2$s::text,'SRID='||st_srid(%2$s)||';%4$s');",
:error in SQL statement : Error performing intersection: TopologyException: found non-noded
intersection between LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465
264611, 594406 286813) at 568465.05533706467 264610.82749605528
CONTEXT: In R support function pg.spi.exec In PL/R function r_voronoi
通过检查错误消息的这一部分:
Error performing intersection: TopologyException: found non-noded intersection between
LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465 264611, 594406 286813)
at 568465.05533706467 264610.82749605528
上面列出的问题是这样的:
我最初认为此消息可能是由相同的消息引起的点,并尝试使用
st_translate()
函数解决此问题,该函数的使用方式如下:ST_Translate(geom, random()*20, random()*20) as geom
这确实解决了问题,但我担心的是我现在正在翻译所有点在x / y方向上的最大距离约为20m。我也不知道需要什么适当的翻译量。
例如,在通过反复试验的此数据集中,
20m * random number
是可以的,但是如何确定是否需要更大?基于上面的图片,我认为问题在于,当算法尝试将点与多边形相交时,该点与线相交。我不确定应该怎么做才能确保该点在多边形内,而不是与直线相交。错误发生在这条线上:
"SELECT
%3$s AS id,
st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'') AS polygon
FROM
%1$s
WHERE
st_intersects(%2$s::text,''SRID=''||st_srid(%2$s)||'';%4$s'');"
我已经读过什么是“非节点交叉点”?试图更好地理解此问题。
#1 楼
以我的经验,这个问题几乎总是由以下原因引起的:坐标中的高精度(43.231499999999996),与
几乎重合但不完全相同的线结合
ST_Buffer
解决方案的“微动”方法使您远离#2,但是您可以采取任何解决这些根本原因的措施,例如将几何图形捕捉到1e-6网格,将使您的生活变得更轻松。缓冲的几何形状通常适合重叠区域之类的中间计算,但是您要谨慎保留它们,因为它们会使长距离的但不是很严重的问题变得更糟。 > PostgreSQL的异常处理功能使您可以编写包装器函数来处理这些特殊情况,仅在需要时才进行缓冲。这是ST_Intersection
的示例;我对ST_Difference
使用了类似的功能。您需要确定空多边形的缓冲和潜在返回在您的情况下是否可接受。CREATE OR REPLACE FUNCTION safe_isect(geom_a geometry, geom_b geometry)
RETURNS geometry AS
$$
BEGIN
RETURN ST_Intersection(geom_a, geom_b);
EXCEPTION
WHEN OTHERS THEN
BEGIN
RETURN ST_Intersection(ST_Buffer(geom_a, 0.0000001), ST_Buffer(geom_b, 0.0000001));
EXCEPTION
WHEN OTHERS THEN
RETURN ST_GeomFromText('POLYGON EMPTY');
END;
END
$$
LANGUAGE 'plpgsql' STABLE STRICT;
这种方法的另一个好处是,您可以查明几何形状实际上造成您的问题的;只需在
RAISE NOTICE
块中添加一些EXCEPTION
语句以输出WKT或其他可以帮助您查找问题的内容。评论
这是一个聪明的主意。我经常发现,交集问题是由联合,差异,缓冲区等组合期间出现的线串引起的,可以通过缓冲所有内容或转储所有内容并仅选择多边形/多义线形来解决此问题。这是一种有趣的方法。
–约翰·鲍威尔(John Powell)
2014年12月2日在15:20
您提到了将几何捕捉到1e-6网格,但是我坐在这里想知道捕捉到2的幂是否更好。 PostGIS(和GEOS)使用浮点数,因此捕捉到10的幂实际上可能不会截断坐标,因为数字可能没有有限长度的二进制表示形式。但是,如果您说2 ^ -16,我相信可以保证将任何小数部分截断为2个字节。还是我想错了?
– jpmc26
19年1月17日在21:26
#2 楼
经过大量的反复试验,我最终意识到non-noded intersection
是由自相交问题引起的。我发现建议使用ST_buffer(geom, 0)
的线程可用于解决问题(尽管确实使它总体上变慢了很多)。然后,我尝试使用ST_MakeValid()
并将其直接应用于任何其他功能之前的几何图形。这似乎可以很好地解决问题。ipoint <- pg.spi.exec(
sprintf(
"SELECT
%3$s AS id,
st_intersection(ST_MakeValid(''SRID=''||st_srid(%2$s)||'';%4$s''::text), ST_MakeValid(''%5$s'', 0)) AS polygon
FROM %1$s
WHERE
ST_Intersects(ST_MakeValid(%2$s::text),ST_MakeValid(''SRID=''||st_srid(%2$s)||'';%4$s''));",
arg1,
arg2,
arg3,
curpoly,
buffer_set$ewkb[1]
)
)
我将其标记为答案,因为这似乎是解决我的问题的唯一方法。
#3 楼
我遇到了同样的问题(Postgres 9.1.4,PostGIS 2.1.1),对我来说唯一有效的方法是用很小的缓冲区包装几何体。ST_MakeValid
对我不起作用,ST_Node
和ST_Dump
的组合也不起作用。缓冲区似乎并没有导致性能下降,但是如果将其减小,我仍然会收到非节点相交错误。丑陋,但是可以。
更新:
ST_Buffer策略似乎运行良好,但是我遇到了一个问题,即在将几何体投射到地理位置时会产生错误。例如,如果一个点原先为-90.0,并且被0.0000001缓冲,则现在为-90.0000001,这是无效的地理位置。
这意味着即使
ST_IsValid(geom)
是t
,ST_Area(geom::geography)
仍返回NaN
的许多功能。 ST_SnapToGrid
像这样SELECT ST_Intersection(
(SELECT geom FROM table1), ST_Union(ST_Buffer(geom, 0.0000001))
) FROM table2
#4 楼
在postgis中,ST_Node应该在相交处断开一系列直线,这应该可以解决非节点相交问题。将其包装在ST_Dump中会生成由虚线组成的复合数组。有点相关,其中有一个很棒的演示PostGIS:给高级用户的提示,清楚地概述了这类问题和解决方案。
评论
这是一个很棒的演示文稿(感谢@PaulRamsey)。我应该如何使用ST_Node和ST_Dump?我想我需要在函数的此部分附近使用它们,但不确定:st_intersection(''SRID =''|| st_srid(%2 $ s)||'';%4 $ s''::文字,“%5 $ s”)
– djq
13年2月8日在19:07
嗯,我没有注意到这两条线具有相同的坐标,应该没问题。如果绘制这些坐标,则交点距交点约18cm。并不是真正的解决方案,只是一个观察。
–WolfOdrade
13年2月8日在20:00
我在这里如何使用st_node尚不完全清楚-我可以在st_intersection之前使用它吗?
– djq
13年2月8日在20:17
该演示文稿不再可用。我在尝试ST_Clip(rast,polygon)时遇到同样的问题
–杰基
2014年12月12日在9:36
@Jackie:我在答案中修复了演示文稿的链接:PostGIS:高级用户提示。
– Pete
17年7月17日在19:38
#5 楼
根据我的经验,我通过使用St_SnapToGrid函数解决了non-noded intersection
错误,该函数解决了多边形顶点坐标具有高精度的问题。SELECT dissolve.machine, dissolve.geom FROM (
SELECT machine, (ST_Dump(ST_Union(ST_MakeValid(ST_SnapToGrid(geom,0.000001))))).geom
FROM cutover_automatique
GROUP BY machine) as dissolve
WHERE ST_isvalid(dissolve.geom)='t' AND ST_GeometryType(dissolve.geom) = 'ST_Polygon';
评论
如果您输入的内容开头无效,请对它们运行ST_MakeValid()。如果它们是有效的,那么您正在做的事情就是添加熵,这是下一个可用的技巧,也许是现在的最后一个技巧。是的,我最初使用WHERE ST_IsValid(p.geom)过滤点。