PostGISの非ノード交差の問題を修正する最善の方法は?


38

PL/R関数を使用してPostGIS、一連のポイントの周りにボロノイポリゴンを生成しています。私が使用している関数は、ここで定義されています。特定のデータセットでこの関数を使用すると、次のエラーメッセージが表示されます。

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までのすべてのポイントを変換していることです。また、適切な翻訳量が必要かどうかもわかりません。たとえば、このデータセットで試行錯誤を繰り返してもa 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)最初にポイントをフィルタリングするために使用しています。
djq

回答:


30

私の経験では、この問題はほとんどの場合次の原因で発生します。

  1. 座標の高精度(43.231499999999996)と組み合わせて
  2. ほぼ一致しているが同一ではない線

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;

このアプローチのもう1つの利点は、実際に問題を引き起こしているジオメトリを特定できることです。ブロックにいくつかのRAISE NOTICEステートメントを追加して、EXCEPTIONWKTを出力するか、問題を追跡するのに役立つ他の何かを追加します。


それは賢いアイデアです。交差点の問題は、結合、差分、バッファなどの組み合わせ中に現れるラインストリングに起因することがよくあります。これは興味深いアプローチです。
ジョンパウエル14

ジオメトリを1e-6グリッドにスナップするとおっしゃいましたが、ここでは2のべき乗にスナップする方が良いのではないかと考えています。PostGIS(およびGEOS)は浮動小数点数を使用するため、10のべき乗にスナップしても、数値の長さが有限のバイナリ表現ではない可能性があるため、実際には座標があまり切り捨てられない場合があります。しかし、2 ^ -16と言えば、小数部分は必ず2バイトに切り捨てられることが保証されます。または私は間違って考えていますか?
jpmc26

12

多くの試行錯誤を通して、最終的に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]
        )
    )

私の問題を解決する唯一のアプローチであると思われるため、これを答えとしてマークしました。


11

私はこの同じ問題に遭遇しました(Postgres 9.1.4、PostGIS 2.1.1)、そして私のために働いた唯一のことは、非常に小さなバッファでジオメトリをラップすることでした。

SELECT ST_Intersection(
    (SELECT geom FROM table1), ST_Union(ST_Buffer(geom, 0.0000001))
) FROM table2

ST_MakeValid私にとってはうまくいかず、ST_Nodeとの組み合わせもうまくいきませんでしたST_Dump。バッファはパフォーマンスの低下をもたらさないように見えましたが、それを小さくしても、ノードなしの交差エラーを受け取りました。

glyいですが、動作します。

更新:

ST_Buffer戦略はうまく機能しているように見えますが、ジオメトリを地理にキャストするときにエラーが発生する問題に遭遇しました。たとえば、ポイントが元々-90.0にあり、0.0000001でバッファリングされている場合、現在は-90.0000001にあり、これは無効な地理です。

これST_IsValid(geom)t、多くの機能でST_Area(geom::geography)返さNaNれたにもかかわらず、返されたことを意味します。

有効な地理を維持しながら、非ノード交差の問題を回避するために、私はST_SnapToGridそのように使用することになりました

SELECT ST_Union(ST_MakeValid(ST_SnapToGrid(geom, 0.0001))) AS geom, common_id
    FROM table
    GROUP BY common_id;

6

たPostGISでST_Node非noded交差点の問題を解決すべき、交差点での一連の線を破る必要があります。これをST_Dumpラップすると、破線の複合配列が生成されます。

少し関連した、素晴らしいプレゼンテーションPostGIS:Power Users向けのヒントがあり、この種の問題と解決策を明確に概説しています。


これは素晴らしいプレゼンテーションです(@PaulRamseyに感謝)。どのように使用する必要がST_NodeありST_Dumpますか?関数のこの部分の近くでそれらを使用する必要があると思いますが、確かではありません: st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'')in
djq

うーん、2本の線の座標が同じであることに気付きませんでした。これらの座標をプロットすると、交差点は交差点から約18cm離れています。実際には解決策ではなく、単なる観察です。
ウルフオドラデ

st_nodeここでの使用方法が完全に明確ではありません-以前に使用できst_intersectionますか?
djq

1
プレゼンテーションは使用できなくなりました。ST_Clip(rast、polygon)
ジャッキー

1
@Jackie:回答のプレゼンテーションへのリンクを修正しました:PostGIS:パワーユーザー向けのヒント
ピート

1

私の経験では、多角形の頂点の座標の精度が高いという問題を解決する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';
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.