Comment effectuer un lissage de ligne SIA ou Bézier dans PostGIS?

9

Quelqu'un peut-il fournir un exemple SQL pour lisser les chaînes de lignes de la table postgis en utilisant des courbes de Bézier ou un algorithme de moyenne itérative ( SIA )?

nextstopsun
la source

Réponses:

6

J'ai créé un petit script naïf qui convertit les LineStrings d'entrée en CompoundCurves en fonction de certaines heuristiques.

Ce qu'il fait:

  • Réduit les angles vifs pour créer des résultats visuellement plus attrayants que les données d'origine.
  • Utilise plpgsql. Aucune extension supplémentaire requise.
  • Accepte un "facteur de lissage" optionnel entre 0 et 100 en plus d'une géométrie.

Ce qu'il ne fait pas:

  • Traite MultiLineStrings. Pour tout autre type de géométrie, il renvoie simplement l'entrée.
  • Utilise les valeurs Z et M. Il les laisse simplement tomber. Utilisez-le uniquement à des fins cartographiques 2D.
  • Crée des résultats mathématiquement corrects. Les résultats sont loin d'être corrects et peuvent même être visuellement inesthétiques dans certains cas (par exemple, les angles vifs). Je ne l'ai pas testé à fond. Examinez toujours les résultats!
  • Court vite. Je suis sûr qu'il peut être réécrit sous une forme beaucoup plus optimale.
  • Fait un vrai lissage. Il existe de bien meilleurs algorithmes (par exemple Chaiken ou ceux mentionnés dans la question) à utiliser pour un véritable lissage. Cette réponse cible les gens comme moi qui recherchent une approche PostGIS pure créant automatiquement une sorte de lignes courbes à partir de données réelles.

Le scénario:

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;

Comme il renvoie des courbes dans un type de géométrie, si vous souhaitez l'utiliser dans un SIG tel que QGIS, vous devez l'encapsuler dans des fonctions PostGIS en les convertissant. La syntaxe d'utilisation prévue est:

SELECT ST_AsText(ST_CurveToLine(CreateCurve(geom))) AS geom FROM linestringtable;
Gabor Farkas
la source
Ce fut une bouée de sauvetage! Merci pour le script. Il semble que le lissage Chaikin devienne disponible en tant que fonction à partir de postgis 2.5, ce que j'attends avec impatience.
she_weeds
1

Il s'agit toujours d'un problème ouvert dans PostGIS (et dans d'autres outils SIG), comme indiqué dans le livre "PostGIS in Action" du chapitre 2.2.6 "Géométries courbes".

Voici quelques références aux algorithmes et au code:

Stefan
la source
J'ai ajouté les liens postgis.17.x6 ...
Martin F
0

Vous pouvez essayer de convertir vos linestrings en courbes avec ST_LineToCurve , puis de nouveau en linestrings avec ST_CurveToLine .

Vous pouvez définir le nombre de segments par quart de cercle souhaité dans ST_CurveToLine.

FredB
la source
LineToCurve est conçu pour gérer les sorties de CurveToLine, et non pour extraire des courbes d'une entrée arbitraire.
Paul Ramsey
@PaulRamsey ajouterait-il du lissage dans les prochaines versions de Postgis? J'ai pensé à quelque chose comme ça par exemple: webhelp.esri.com/arcgisdesktop/9.2/…
Gery