Come eseguire il livellamento delle linee SIA o Bezier in PostGIS?


9

Qualcuno può fornire un esempio di SQL per smussare i linestring dalla tabella postgis usando le curve di Bezier o l'algoritmo di Iterative Averaging ( SIA )?

Risposte:


6

Ho creato un piccolo script ingenuo che converte input LineStrings in CompoundCurves sulla base di alcune euristiche.

Cosa fa:

  • Riduce gli angoli acuti per creare risultati visivamente più accattivanti rispetto ai dati originali.
  • Usa plpgsql. Non sono richieste estensioni aggiuntive.
  • Accetta un "fattore di livellamento" opzionale compreso tra 0 e 100 oltre a una geometria.

Cosa non fa:

  • Elabora MultiLineStrings. Per qualsiasi altro tipo di geometria, restituisce semplicemente l'input.
  • Utilizza i valori Z e M. Li lascia semplicemente cadere. Usalo solo per scopi cartografici 2D.
  • Crea risultati matematicamente corretti. I risultati sono tutt'altro che corretti e in alcuni casi potrebbero anche essere visivamente antiestetici (ad es. Angoli acuti). Non l'ho provato a fondo. Rivedi sempre i risultati!
  • Corre veloce. Sono sicuro che può essere riscritto in una forma molto più ottimale.
  • Fa davvero levigare. Esistono algoritmi molto migliori (ad esempio Chaiken o quelli citati nella domanda) da utilizzare per il livellamento reale. Questa risposta si rivolge a persone come me che cercano un approccio PostGIS puro creando automaticamente una sorta di linee curve da dati reali.

Il copione:

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;

Poiché restituisce curve in un tipo di geometria, se si desidera utilizzarlo in un GIS come QGIS, è necessario avvolgerlo nelle funzioni PostGIS convertendole. La sintassi dell'uso previsto è:

SELECT ST_AsText(ST_CurveToLine(CreateCurve(geom))) AS geom FROM linestringtable;

Questo è stato un vero toccasana! Grazie per la sceneggiatura. Sembra che il livellamento Chaikin diventerà disponibile come funzione da Postgis 2.5 in poi, che non vedo l'ora.
she_weeds,

1

Questo è ancora un problema aperto in PostGIS (e altri strumenti GIS) come indicato nel libro "PostGIS in azione" nel capitolo 2.2.6 "Geometrie curve".

Ecco alcuni riferimenti ad algoritmi e codice:


Ho aggiunto i link postgis.17.x6 ...
Martin F

0

Puoi provare a convertire le stringhe di linea in curve con ST_LineToCurve e quindi di nuovo in stringhe di linea con ST_CurveToLine .

È possibile impostare il numero di segmenti per ogni quarto di cerchio desiderato in ST_CurveToLine.


LineToCurve è costruito per gestire le uscite di CurveToLine, non per estrarre curve da input arbitrario.
Paul Ramsey,

@PaulRamsey verrebbe aggiunto un livellamento più bello nelle prossime versioni di Postgis? Ho pensato a qualcosa del genere, ad esempio: webhelp.esri.com/arcgisdesktop/9.2/…
Gery
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.