PostGISでSIAまたはベジェラインスムージングを実行する方法


回答:


6

入力LineStringをいくつかのヒューリスティックに基づいてCompoundCurvesに変換する小さな素朴なスクリプトを作成しました。

それがすること:

  • 鋭い角を切り取り、元のデータよりも視覚的に魅力的な結果を作成します。
  • plpgsqlを使用します。追加の拡張は必要ありません。
  • ジオメトリの他に、0〜100のオプションの「平滑化係数」を受け入れます。

それがしないこと:

  • MultiLineStringを処理します。その他のジオメトリタイプの場合は、単に入力を返します。
  • Z値とM値を使用します。単にそれらを落とします。これは、2Dカートグラフィックの目的にのみ使用してください。
  • 数学的に正しい結果を作成します。結果は正しいとはほど遠く、場合によっては視覚的に美しくないこともあります(鋭い角など)。私はそれを徹底的にテストしませんでした。常に結果を確認してください!
  • 速く走る。きっともっと最適な形に書き直すことができると思います。
  • 実際の平滑化を行います。実際の平滑化に使用できるはるかに優れたアルゴリズム(たとえば、Chaikenまたは質問で言及されたアルゴリズム)があります。この答えは、実際のデータからある種の曲線を自動的に作成する純粋なPostGISアプローチを探している私のような人々を対象としています。

スクリプト:

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;

ジオメトリタイプでカーブを返すため、QGISなどのGISでカーブを使用する場合は、PostGIS関数にラップして、カーブを変換する必要があります。使用目的の構文は次のとおりです。

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

これは命の恩人でした!台本ありがとうございます。Chaikinのスムージングがpostgis 2.5以降の機能として利用できるようになると思われます。
she_weeds

1

これは、第2.2.6章「湾曲したジオメトリ」の「PostGIS in Action」という本で述べられているように、PostGIS(および他のGISツール)で未解決の問題です。

次に、アルゴリズムとコードへの参照をいくつか示します。


postgis.17.x6 ...リンクを追加しました
Martin F

0

あなたがカーブにあなたのラインストリングを変換しようとすることができますST_LineToCurveでラインストリングに当時とST_CurveToLine

ST_CurveToLineで、必要な四分の一円あたりのセグメント数を設定できます。


LineToCurveは、任意の入力から曲線を抽出するためではなく、CurveToLineの出力を処理するために構築されています。
ポールラムジー

@PaulRamseyは次のPostgisバージョンでベジエスムージングを追加しますか?たとえば、次のようなものを考えています。webhelp.esri.com
9.2
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.