Wie führe ich eine SIA- oder Bezier-Linienglättung in PostGIS durch?

9

Kann jemand ein Beispiel für SQL zum Glätten von Linestrings aus der Postgis-Tabelle mithilfe von Bezier-Kurven oder dem SIA- Algorithmus (Iterative Averaging ) bereitstellen ?

nextstopsun
quelle

Antworten:

6

Ich habe ein kleines, naives Skript erstellt, das eingegebene LineStrings basierend auf einigen Heuristiken in CompoundCurves konvertiert.

Was es macht:

  • Reduziert scharfe Ecken, um optisch ansprechendere Ergebnisse als die Originaldaten zu erzielen.
  • Verwendet plpgsql. Keine zusätzlichen Erweiterungen erforderlich.
  • Akzeptiert neben einer Geometrie einen optionalen "Glättungsfaktor" zwischen 0 und 100.

Was es nicht macht:

  • Verarbeitet MultiLineStrings. Für jeden anderen Geometrietyp wird einfach die Eingabe zurückgegeben.
  • Verwendet Z- und M-Werte. Es lässt sie einfach fallen. Verwenden Sie diese Option nur für kartografische 2D-Zwecke.
  • Erstellt mathematisch korrekte Ergebnisse. Die Ergebnisse sind alles andere als korrekt und können in einigen Fällen sogar visuell unästhetisch sein (z. B. scharfe Ecken). Ich habe es nicht gründlich getestet. Überprüfen Sie immer die Ergebnisse!
  • Rennt schnell. Ich bin sicher, dass es in eine weitaus optimalere Form umgeschrieben werden kann.
  • Macht echte Glättung. Es gibt viel bessere Algorithmen (z. B. Chaiken oder die in der Frage genannten), die für eine echte Glättung verwendet werden können. Diese Antwort richtet sich an Personen wie mich, die nach einem reinen PostGIS-Ansatz suchen und automatisch eine Art gekrümmte Linien aus realen Daten erstellen.

Das Skript:

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;

Wenn Sie Kurven in einem Geometrietyp zurückgeben und diese in einem GIS wie QGIS verwenden möchten, müssen Sie sie in PostGIS-Funktionen einbinden, um sie zu konvertieren. Die Syntax für den Verwendungszweck lautet:

SELECT ST_AsText(ST_CurveToLine(CreateCurve(geom))) AS geom FROM linestringtable;
Gabor Farkas
quelle
Das war ein Lebensretter! Danke für das Drehbuch. Es scheint, dass die Chaikin-Glättung ab Postgis 2.5 als Funktion verfügbar sein wird, worauf ich mich freue.
she_weeds
1

Dies ist in PostGIS (und anderen GIS-Tools) immer noch ein offenes Problem, wie im Buch "PostGIS in Aktion" in Kapitel 2.2.6 "Gebogene Geometrien" angegeben.

Hier einige Verweise auf Algorithmen und Code:

Stefan
quelle
Ich habe die postgis.17.x6 ... Links hinzugefügt
Martin F
0

Sie können versuchen, Ihre Linestrings mit ST_LineToCurve in Kurven und dann mit ST_CurveToLine wieder in Linestrings umzuwandeln .

Sie können die Anzahl der Segmente pro Viertelkreis in ST_CurveToLine festlegen.

FredB
quelle
LineToCurve dient dazu, die Ausgaben von CurveToLine zu übergeben und keine Kurven aus beliebigen Eingaben zu extrahieren.
Paul Ramsey
@PaulRamsey würde die Bezier-Glättung in den nächsten Postgis-Versionen hinzugefügt werden? Ich habe zum Beispiel über so etwas nachgedacht
Gery