PostGIS'te SIA veya Bezier çizgi yumuşatma nasıl yapılır?


9

Herkes Bezier eğrileri veya Yinelemeli Ortalama Alma ( SIA ) algoritması kullanarak postgis tablosundaki çizgileri düzeltmek için örnek bir SQL sağlayabilir mi?

Yanıtlar:


6

Bazı sezgisel tarama dayalı LineStrings giriş CompoundCurves dönüştüren küçük, naif bir komut dosyası oluşturdum.

Bu ne yapar:

  • Orijinal verilere göre görsel olarak daha çekici sonuçlar elde etmek için keskin köşeleri keser.
  • Plpgsql kullanır. Ek uzantı gerekmez.
  • Bir geometrinin yanı sıra, 0 ile 100 arasında isteğe bağlı bir "düzeltme faktörü" kabul eder.

Ne yapmaz:

  • MultiLineStrings'i işler. Diğer herhangi bir geometri türü için, girdiyi döndürür.
  • Z ve M değerlerini kullanır. Sadece onları düşürüyor. Bunu sadece 2B kartografik amaçlar için kullanın.
  • Matematiksel olarak doğru sonuçlar oluşturur. Sonuçlar doğru olmaktan uzaktır ve bazı durumlarda görsel olarak estetik olmayabilir (örneğin keskin köşeler). Ben iyice test etmedim. Her zaman sonuçları gözden geçirin!
  • Hızlı koşar. Eminim çok daha uygun bir forma yeniden yazılabilir.
  • Gerçek yumuşatma yapar. Gerçek yumuşatma için kullanmak için çok daha iyi algoritmalar (örn. Chaiken veya soruda belirtilenler) vardır. Bu cevap, benim gibi insanların gerçek verilerden otomatik olarak bir tür eğri çizgiler oluşturarak saf bir PostGIS yaklaşımı aramasını hedefliyor.

Senaryo:

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;

Bir geometri türünde eğriler döndürdüğü için, QGIS gibi bir CBS'de kullanmak isterseniz, bunları dönüştüren PostGIS işlevlerine sarmanız gerekir. Kullanım amacı sözdizimi:

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

Bu bir cankurtaran! Senaryo için teşekkürler. Görünüşe göre Chaikin yumuşatma postgis 2.5'ten itibaren bir işlev olarak sunulacak gibi görünüyor.
she_weeds

1

Bu, 2.2.6 "Eğri geometriler" bölümündeki "PostGIS in Action" kitabında belirtildiği gibi PostGIS'de (ve diğer CBS araçlarında) açık bir konudur.

İşte algoritmalara ve koda yapılan bazı referanslar:


Postgis.17.x6 ... linklerini ekledim
Martin F

0

ST_LineToCurve ile çizgi dizelerinizi eğrilere ve sonra da ST_CurveToLine ile çizgi dizilerine dönüştürmeyi deneyebilirsiniz .

ST_CurveToLine içinde istediğiniz çeyrek daire başına segment sayısını ayarlayabilirsiniz.


LineToCurve, CurveToLine çıktılarını teslim etmek için oluşturulmuştur, eğrileri rastgele girdilerden çıkarmak için değildir.
Paul Ramsey

@PaulRamsey sonraki Postgis sürümlerinde bezier yumuşatma eklenir mi? Mesela şöyle bir şey düşünüyordum: webhelp.esri.com/arcgisdesktop/9.2/…
Gery
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.