Przyciąganie początkowych i końcowych węzłów linii do innych linii w PostGIS

9

Istnieje wiele przykładów pokazujących, jak przyciągać linie do punktów, ale nie znalazłem (szybkiego!) Sposobu przyciągania początkowych i końcowych węzłów ciągów linii do węzłów innych linii.

Zasadniczo chcę „wyczyścić” moją warstwę w postgis (2.0), przesuwając prawie podobne punkty razem i szyjąc małe otwory między strunami linii.

Nie miałoby to większego znaczenia, czy dodam kolejny węzeł, przesunę pierwszy / ostatni węzeł którejkolwiek linii, czy przesunę oba punkty na środek.

Znalazłem dwie opcje, ale nie jestem pewien, jak zacząć od jednej z nich:

Druga opcja wydaje się wykonalna, ale każda pomoc w stosowaniu tej metody byłaby bardzo mile widziana.

Jelmer Baas
źródło

Odpowiedzi:

6

Udało mi się to rozwiązać bez użycia wspomnianych narzędzi GRASS lub funkcji topologicznych.

Zasadniczo biorę wszystkie węzły początkowy i końcowy, umieszczam je w nowej, tymczasowej tabeli, umieszczam wokół nich bufor, łączę obiekty buforów i przenoszę wszystkie znalezione węzły w każdym buforze do środka ciężkości bufora.

Kiedy to się stanie, przeniosę oryginalne punkty początkowe i końcowe do nowej lokalizacji.

Łatwiej niż się spodziewałem i wciąż szybko, ale spodziewałem się, że PostGIS będzie miał do tego wbudowaną funkcję - będzie to jeszcze szybsze.

Edycja: w celu oddania społeczności, to na razie mój (dość gówniany) kod.

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;
Jelmer Baas
źródło
Ta odpowiedź wygląda trochę jak sugestia „nie topologiczna” z mojej odpowiedzi. Byłoby miło, gdybyś wyraził opinię lub wybrał odpowiedź. To one karmią społeczność tutaj :)
katahdin
Masz rację. Poparłem twoją odpowiedź i dokonam edycji mojej odpowiedzi, aby uwzględnić mój kod.
Jelmer Baas
4

Oto trzy opcje. Mam nadzieję, że ktoś pomoże.

v.clean

Za pomocą narzędzi GRASS w QGIS możesz wyczyścić topologię obiektu przestrzennego. Użytkownik @RK podaje dobry zestaw instrukcji, jak to zrobić, w odpowiedzi na inne pytanie . Zaletą GRASS jest to, że wywnioskuje topologię pliku kształtu. Wadą twojej sytuacji jest to, że twoich danych nie ma w pliku kształtu. Oczywiście możesz wyeksportować dane z Postgres do pliku kształtu za pomocą narzędzia „Dodaj warstwę PostGIS”, ale to dodatkowy krok.

Nie topologiczne funkcje PostGIS

W PostGIS możesz użyć funkcji ST_EndPoint i ST_StartPoint, aby uzyskać koniec i punkt początkowy dla linii. Następnie, używając kombinacji ST_DWithi n i ST_Distance , możesz znaleźć najbliższy punkt początkowy lub końcowy na pobliskiej geometrii. Jeśli masz dużo punktów, to ST_DWithin znacznie przyspieszy zapytanie - zakładając, że masz indeks. Następnie musisz ustalić regułę, która określa, które punkty mają zostać zmodyfikowane, a które stałe.

Zaletą jest to, że nie musisz wysyłać swoich danych do GRASS w celu wyczyszczenia, ale są pewne pułapki, na które należy uważać.

Topologiczne funkcje PostGIS

Pytanie dotyczyło funkcji topologicznych PostGIS. Działa to świetnie, ale jak opisuje wiki , musisz jawnie zdefiniować krawędzie, węzły i ściany. Oczywiście będzie to stanowić problem dla twojego zestawu danych, ponieważ znasz problemy z topologią.

katahdin
źródło
1

PostGIS ma funkcje przyciągania. Może pomogą?

ST_Snap: Przyciągaj segmenty i wierzchołki geometrii wejściowej do wierzchołków geometrii odniesienia.

ST_SnapToGrid: Przyciągnij wszystkie punkty geometrii wejściowej do zwykłej siatki.

Jordan Arseno
źródło
1
Dzięki, znam te funkcje. ST_Snap przyciąga WSZYSTKIE węzły, chcę tylko węzeł początkowy i końcowy. ST_SnapToGrid nie jest tak naprawdę odpowiedni, ponieważ modyfikuje całą istniejącą geometrię i ma szansę na przesunięcie węzłów, które są blisko, ponieważ ledwo wpadają w inny segment.
Jelmer Baas