Jak wykonać wygładzanie linii SIA lub Beziera w PostGIS?

9

Czy ktoś może podać przykładowy SQL do wygładzania linii z tabeli postgis przy użyciu krzywych Beziera lub algorytmu iteracyjnego uśredniania ( SIA )?

nextstopsun
źródło

Odpowiedzi:

6

Stworzyłem mały, naiwny skrypt, który konwertuje wejściowe LineStrings na CompoundCurves na podstawie pewnych heurystyk.

Co to robi:

  • Skraca ostre rogi, aby uzyskać atrakcyjniejsze wizualnie wyniki niż oryginalne dane.
  • Wykorzystuje plpgsql. Nie są wymagane żadne dodatkowe rozszerzenia.
  • Akceptuje opcjonalny „współczynnik wygładzania” od 0 do 100 oprócz geometrii.

Czego nie robi:

  • Przetwarza MultiLineStrings. Dla każdego innego typu geometrii po prostu zwraca dane wejściowe.
  • Wykorzystuje wartości Z i M. Po prostu upuszcza je. Używaj tego tylko do celów kartograficznych 2D.
  • Tworzy matematycznie poprawne wyniki. Wyniki są dalekie od prawidłowych, aw niektórych przypadkach mogą być nawet nieestetyczne (np. Ostre rogi). Nie przetestowałem tego dokładnie. Zawsze przeglądaj wyniki!
  • Szybko biega. Jestem pewien, że można go przepisać w znacznie bardziej optymalną formę.
  • Naprawdę wygładza. Istnieją znacznie lepsze algorytmy (np. Chaiken lub te wymienione w pytaniu), które można wykorzystać do prawdziwego wygładzenia. Ta odpowiedź jest skierowana do osób takich jak ja, poszukujących czystego podejścia PostGIS, automatycznie tworzących zakrzywione linie z rzeczywistych danych.

Scenariusz:

CREATE OR REPLACE FUNCTION CreateCurve(geom geometry, percent int DEFAULT 40)
    RETURNS geometry AS
$$
DECLARE
    result text;
    p0 geometry;
    p1 geometry;
    p2 geometry;
    intp geometry;
    tempp geometry;
    geomtype text := ST_GeometryType(geom);
    factor double precision := percent::double precision / 200;
    i integer;
BEGIN
    IF percent < 0 OR percent > 100 THEN
        RAISE EXCEPTION 'Smoothing factor must be between 0 and 100';
    END IF;
    IF geomtype != 'ST_LineString' OR factor = 0 THEN
        RETURN geom;
    END IF;
    result := 'COMPOUNDCURVE((';
    p0 := ST_PointN(geom, 1);
    IF ST_NPoints(geom) = 2 THEN
        p1:= ST_PointN(geom, 2);
        result := result || ST_X(p0) || ' ' || ST_Y(p0) || ',' || ST_X(p1) || ' ' || ST_Y(p1) || '))';
    ELSE
        FOR i IN 2..(ST_NPoints(geom) - 1) LOOP
            p1 := ST_PointN(geom, i);
            p2 := ST_PointN(geom, i + 1);
            result := result || ST_X(p0) || ' ' || ST_Y(p0) || ',';
            tempp := ST_Line_Interpolate_Point(ST_MakeLine(p1, p0), factor);
            p0 := ST_Line_Interpolate_Point(ST_MakeLine(p1, p2), factor);
            intp := ST_Line_Interpolate_Point(
                ST_MakeLine(
                    ST_Line_Interpolate_Point(ST_MakeLine(p0, p1), 0.5),
                    ST_Line_Interpolate_Point(ST_MakeLine(tempp, p1), 0.5)
                ), 0.5);
            result := result || ST_X(tempp) || ' ' || ST_Y(tempp) || '),CIRCULARSTRING(' || ST_X(tempp) || ' ' || ST_Y(tempp) || ',' || ST_X(intp) || ' ' ||
            ST_Y(intp) || ',' || ST_X(p0) || ' ' || ST_Y(p0) || '),(';
        END LOOP;
        result := result || ST_X(p0) || ' ' || ST_Y(p0) || ',' || ST_X(p2) || ' ' || ST_Y(p2) || '))';
    END IF;
    RETURN ST_SetSRID(result::geometry, ST_SRID(geom));
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE;

Ponieważ zwraca krzywe w typie geometrii, jeśli chcesz użyć go w GIS, takim jak QGIS, musisz owinąć go w funkcje PostGIS, które je przekształcają. Składnia zamierzonego zastosowania to:

SELECT ST_AsText(ST_CurveToLine(CreateCurve(geom))) AS geom FROM linestringtable;
Gabor Farkas
źródło
To był ratownik! Dziękuję za scenariusz. Wygląda na to, że wygładzanie Chaikin będzie dostępne jako funkcja od wersji 2.5 postgis, na co czekam z niecierpliwością.
she_weeds
1

Jest to nadal kwestia otwarta w PostGIS (i innych narzędziach GIS), jak stwierdzono w książce „PostGIS w akcji” w rozdziale 2.2.6 „Zakrzywione geometrie”.

Oto kilka odniesień do algorytmów i kodu:

Stefan
źródło
I dodał postgis.17.x6 ... Linki
Marcina, F
0

Możesz spróbować przekonwertować swoje linie na krzywe za pomocą ST_LineToCurve, a następnie z powrotem na linie za pomocą ST_CurveToLine .

W ST_CurveToLine możesz ustawić liczbę segmentów na ćwierć koła.

FredB
źródło
LineToCurve służy do przekazywania danych wyjściowych CurveToLine, a nie do wyciągania krzywych z dowolnych danych wejściowych.
Paul Ramsey
@PaulRamsey zostałby dodany wygładzanie Beziera w kolejnych wersjach Postgis? Zastanawiałem się nad czymś takim, na przykład: webhelp.esri.com/arcgisdesktop/9.2/...
Gery,