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;
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:
quelle
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.
quelle