我正在使用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'');"


我已经读过什么是“非节点交叉点”?试图更好地理解此问题。

评论

如果您输入的内容开头无效,请对它们运行ST_MakeValid()。如果它们是有效的,那么您正在做的事情就是添加熵,这是下一个可用的技巧,也许是现在的最后一个技巧。

是的,我最初使用WHERE ST_IsValid(p.geom)过滤点。

#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_NodeST_Dump的组合也不起作用。缓冲区似乎并没有导致性能下降,但是如果将其减小,我仍然会收到非节点相交错误。

丑陋,但是可以。

更新:

ST_Buffer策略似乎运行良好,但是我遇到了一个问题,即在将几何体投射到地理位置时会产生错误。例如,如果一个点原先为-90.0,并且被0.0000001缓冲,则现在为-90.0000001,这是无效的地理位置。

这意味着即使ST_IsValid(geom)tST_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';