行の開始ノードと終了ノードをPostGISの他の行にスナップする


9

ラインをポイントにスナップする方法を示す例はたくさんありますが、ラインストリングの開始ノードと終了ノードを他のラインのノードにスナップする(速い!)方法を見つけることができませんでした。

基本的に、私はpostgis(2.0)で自分のレイヤーを「クリーン」にし、ほぼ同様のポイントを一緒に移動し、ラインストリング間の小さな開口部を縫い合わせたいと考えています。

別のノードを追加するか、どちらかの線の最初/最後のノードを移動するか、両方のポイントを中央に移動するかは、それほど重要ではありません。

2つのオプションを見つけましたが、どちらから始めるかわかりません。

2番目のオプションは実現可能に聞こえますが、この方法を実行する方法についてのヘルプがあれば大歓迎です。

回答:


6

前述のGRASSツールやトポロジ関数を使用せずに、これを解決することができました。

基本的に、私はすべての開始ノードと終了ノードを取得し、それらを新しい一時テーブルに配置し、それらの周りにバッファーを配置し、バッファーオブジェクトを結合し、各バッファーで見つかったすべてのノードをバッファーの重心に移動します。

それが終わったら、元の始点と終点を新しい場所に移動します。

予想よりも簡単で、しかも高速ですが、PostGISにはこのための組み込み関数があると思っていました。

編集:コミュニティに還元するために、これは今のところ私の(かなりくだらない)コードです。

drop table if exists nodes;
drop table if exists nodes2;
drop table if exists buffers;

-- Get Start and End nodes
select ST_StartPoint(wkb_geometry) startnode,  ST_EndPoint(wkb_geometry) endnode,    ogc_fid into nodes  from sourceTable;
-- Combine all nodes into one table for easier queries
select startnode node, ogc_fid into nodes2 from nodes;
insert into nodes2 select endnode node, ogc_fid from nodes;

-- Some indexes to speed everything up
CREATE INDEX nodesstart_idx ON nodes USING gist  (startnode);
CREATE INDEX nodesend_idx ON nodes USING gist  (endnode);
CREATE INDEX nodes2_idx ON nodes2 USING gist  (node);
CREATE INDEX nodes_ogcfid_idx ON nodes USING btree (ogc_fid ASC NULLS LAST);

-- Create buffers, combine them, split combined objects again
select (ST_Dump(ST_Union(ST_Buffer(node, 1)))).geom geom into buffers from nodes2;
CREATE INDEX buffers_idx ON buffers USING gist  (geom);

-- Update start/end nodes table
UPDATE nodes SET startnode = ST_Centroid((select geom from buffers WHERE geom && startnode));
UPDATE nodes SET endnode = ST_Centroid((select geom from buffers WHERE geom && endnode));
-- Update original points
update sourceTable set wkb_geometry = ST_SetPoint(
ST_SetPoint(wkb_geometry, 0, (select startnode from nodes where ogc_fid=sourceTable.ogc_fid)), 
ST_NumPoints(wkb_geometry) - 1, (select endnode from nodes where ogc_fid=sourceTable.ogc_fid));

DROP TABLE nodes;
DROP TABLE nodes2;
DROP TABLE buffers;

この回答は、私の回答からの「非トポロジー」の提案にかなり似ています。あなたが賛成票を与えたか、答えを選択した場合、それは親切です。それらはここでコミュニティを養うものです:)
katahdin 2013年

あなたが正しい。私はあなたの回答に賛成しました。私のコードを含めるように私の回答を編集します。
Jelmer Baas

4

3つのオプションがあります。うまくいけば、1つは役立ちます。

v.clean

QGISのGRASSツールを使用して、空間オブジェクトのトポロジをクリーンアップできます。ユーザー@RKは、これを行う方法に関する一連の適切な指示を別の質問への回答で提供します。GRASSの利点は、シェープファイルのトポロジーを推測することです。状況の欠点は、データがシェープファイルにないことです。もちろん、「PostGISレイヤーの追加」ツールを使用してデータをPostgresからシェープファイルにエクスポートすることもできますが、それは追加の手順です。

非トポロジーPostGIS関数

PostGIS ではST_EndPoint関数とST_StartPoint関数を使用して、ラインストリングの終了点と開始点を取得できます。次に、ST_DWithi nとST_Distanceの組み合わせを使用して、近くのジオメトリ上の最も近い開始点または終了点を見つけることができます。ポイントが多い場合、ST_DWithinを使用するとクエリが大幅に高速化されます(インデックスが設定されている場合)。そこから、修正するポイントと修正するポイントを定義するルールを確立する必要があります。

ここでの利点は、データをクリーンアップのためにGRASSに送信する必要がないことですが、注意すべき落とし穴がいくつかあります。

トポロジーPostGIS関数

質問はPostGISトポロジ関数を参照していました。これらはうまく機能しますが、wikiで説明されているように、エッジ、ノード、およびフェースを明示的に定義する必要があります。トポロジに既知の問題があるため、これは明らかにデータセットの問題になります。


1

PostGISにはスナップ機能があります。

ST_Snap入力ジオメトリのセグメントと頂点を参照ジオメトリの頂点にスナップします。

ST_SnapToGrid入力ジオメトリのすべてのポイントを通常のグリッドにスナップします。


1
おかげで、私はこれらの機能を知っています。ST_Snapはすべてのノードをスナップします。開始ノードと終了ノードだけが必要です。ST_SnapToGridは、既存のすべてのジオメトリを変更し、別のセグメントにかろうじて落ちるだけなので、より近くにあるノードを移動する可能性があるため、あまり適していません。
Jelmer Baas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.