Bagaimana cara melakukan smoothing garis SIA atau Bezier di PostGIS?


9

Adakah yang bisa memberikan contoh SQL untuk merapikan linestrings dari tabel postgis menggunakan kurva Bezier atau algoritma Iterative Averaging ( SIA )?

Jawaban:


6

Saya membuat skrip kecil dan naif yang mengubah input LineStrings ke CompoundCurves berdasarkan beberapa heuristik.

Apa fungsinya:

  • Memotong sudut tajam untuk membuat hasil yang secara visual lebih menarik daripada data asli.
  • Gunakan plpgsql. Tidak diperlukan ekstensi tambahan.
  • Menerima "faktor pemulusan" opsional antara 0 dan 100 selain geometri.

Apa yang tidak dilakukan:

  • Memproses MultiLineStrings. Untuk jenis geometri lainnya, ia hanya mengembalikan input.
  • Menggunakan nilai Z dan M. Itu hanya menjatuhkan mereka. Gunakan ini hanya untuk keperluan kartografi 2D.
  • Menciptakan hasil yang benar secara matematis. Hasilnya jauh dari benar, dan bahkan mungkin secara visual tidak estetis dalam beberapa kasus (misalnya sudut tajam). Saya tidak mengujinya secara menyeluruh. Selalu tinjau hasilnya!
  • Berlari cepat. Saya yakin itu dapat ditulis ulang ke bentuk yang jauh lebih optimal.
  • Apakah smoothing nyata. Ada banyak algoritma yang lebih baik (misalnya Chaiken atau yang disebutkan dalam pertanyaan) untuk digunakan untuk smoothing nyata. Jawaban ini menargetkan orang-orang seperti saya yang mencari pendekatan PostGIS murni secara otomatis membuat semacam garis lengkung dari data nyata.

Naskah:

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;

Ketika mengembalikan kurva dalam tipe geometri, jika Anda ingin menggunakannya dalam GIS seperti QGIS, Anda harus membungkusnya ke dalam fungsi PostGIS untuk mengubahnya. Sintaks penggunaan yang dimaksudkan adalah:

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

Ini adalah penyelamat! Terima kasih untuk skripnya. Sepertinya smoothing Chaikin akan tersedia sebagai fungsi dari postgis 2.5 dan seterusnya, yang saya tunggu-tunggu.
she_weeds

1

Ini masih merupakan masalah terbuka di PostGIS (dan perangkat GIS lainnya) sebagaimana dinyatakan dalam buku "PostGIS dalam Tindakan" di bab 2.2.6 "Geometri lengkung".

Berikut ini beberapa referensi untuk algoritma dan kode:


Saya menambahkan postgis.17.x6 ... tautan
Martin F

0

Anda dapat mencoba mengubah linestrings Anda menjadi kurva dengan ST_LineToCurve dan kemudian kembali ke linestrings dengan ST_CurveToLine .

Anda dapat mengatur jumlah segmen per kuartal lingkaran yang Anda inginkan di ST_CurveToLine.


LineToCurve dibangun untuk menyerahkan output CurveToLine, bukan untuk mengekstrak kurva dari input yang sewenang-wenang.
Paul Ramsey

@PaulRamsey akan lebih mulus ditambahkan dalam versi Postgis berikutnya? Saya telah memikirkan sesuatu seperti ini misalnya: webhelp.esri.com/arcgisdesktop/9.2/…
Gery
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.