Zapytanie rekurencyjne PostGIS na podstawie łączności liniowej

9

Mam problem z zapytaniem. Mam sieć łączników, każdy z wartością w kolumnie n_type. Może to być jedna z kilku opcji. Chciałbym wygenerować nową tabelę, która grupuje wszystkie linie tego samego typu i tworzące linię ciągłą.

Przed:

wprowadź opis zdjęcia tutaj

Po:

wprowadź opis zdjęcia tutaj

Oto co mam do tej pory. Zwraca wyniki, ale nie mają one sensu - typy nie pasują do siebie i zwraca zbyt wiele funkcji.

Należy również pamiętać, że zdefiniowałem „ciągły” jako każdą linię w odległości 5 stóp od swojego sąsiada i spotykającą się pod kątem mniejszym niż 30 stopni.

WITH RECURSIVE all_links (i, pk_uid, n_type, geom) AS (
    SELECT  1 AS i,
            pk_uid,
            n_type,
            geom
    FROM    network
    WHERE   n_type != 'none'

    UNION ALL

    SELECT  a.i + 1,
            b.pk_uid,
            b.n_type,
            b.geom
    FROM    network b, all_links a
    WHERE   b.n_type = a.n_type
    AND     b.geom <#> a.geom <= 5  --lines are continuous if within 5 feet of neighbor
    AND     ABS( DEGREES( 3*pi() - st_azimuth(st_startpoint(a.geom),st_endpoint(a.geom)) + st_azimuth(st_startpoint(b.geom),st_endpoint(b.geom)))::int % 360 - 180) <= 30 )  --only take links within 30 degrees of the same angle

SELECT i, n_type, ST_Union(the_geom) FROM all_links GROUP BY i, n_type

Założyłem, że właściwym rozwiązaniem jest zapytanie rekurencyjne, ale cieszę się, że udowodniono mi błąd. Rekursywne są trochę trudne do zdobycia.

Edycja: Powinienem również dodać, że próbowałem już agregować przy użyciu ST_Union i ST_Linemerge, a następnie zrzucić wynik. Ten rodzaj działa, ale nie uwzględnia przecięć> 30 stopni, a także nie może honorować tolerancji pięciu stóp dla łączności.

spencerrecneps
źródło
Bez wnikania w to, kilka spostrzeżeń. Będziesz musiał połączyć a.geom i b.geom w klauzuli select. Prawdopodobnie powinieneś upewnić się, że nie spróbujesz również dołączyć do linii z samym sobąa.pk_uid != b.pk_uid
MickyT
@MickyT dzięki. Powinienem wspomnieć, że mogę wykonać połączenie w ostatniej klauzuli SELECT, ale na razie właśnie wybrałem *, aby zobaczyć wszystkie wyniki. Zmodyfikuję fragment kodu, aby pokazać, jak powinien on ostatecznie wyglądać.
spencerrecneps
Trudno jest wywoływać zapytania rekurencyjne. Lol i +1
John Powell,
Szybkie spojrzenie sugeruje, że możesz mieć problemy z zapytaniem bazowym / zakotwiczonym. Musisz wybrać punkt początkowy dla każdej linii, A, B, C itp., Które następnie budujesz w części rekurencyjnej. Być może musisz dodać jakiś porządek do zapytania zakotwiczenia (być może w kierunku x lub y, kierunek - trudny do zrozumienia bez zobaczenia danych). Rozbiłbym to i upewniłem się, że najpierw dostaję rozsądne punkty początkowe, zanim przejdę do części rekurencyjnej. Niedawno użyłem zapytania rekurencyjnego, aby znaleźć smugi w szeregach czasowych, a po prawidłowym zidentyfikowaniu punktów kontrolnych reszta była łatwa (ish)
John Powell
@dbaston. Dobra uwaga, ale możesz to zrobić również za pomocą zapytania rekurencyjnego, ale nie wszyscy jeszcze go zainstalowali.
John Powell,

Odpowiedzi:

1

W swoim rozwiązaniu brakuje przynajmniej wstępnego zamówienia komponentów linii, jak powiedział John Barça.

Powiedziałbym, że zapytania rekurencyjne są bardzo, bardzo trudne.

Musisz spróbować zreplikować zachowanie ST_Linemerge w nowej funkcji bazy danych. Najpierw spróbuję spojrzeć na źródło implementacji ST_Linemerge i zreplikować go, zmieniając go, aby uzyskać drganie pod kątem 30 stopni.

Aby odrzucić z agregacji segmenty, które nie są ustawione pod kątem <30 °, musisz porównać je WEWNĄTRZ pętli agregacji.

rpcavaco
źródło