Как выполнить сглаживание линий SIA ​​или Безье в PostGIS?


9

Может ли кто-нибудь предоставить пример SQL для сглаживания линейных строк из таблицы Постгиса с использованием кривых Безье или алгоритма итеративного усреднения ( SIA )?

Ответы:


6

Я создал небольшой наивный скрипт, который на основе некоторой эвристики преобразует входные строки LineStrings в CompoundCurves.

Что оно делает:

  • Обрезает острые углы, чтобы создать визуально более привлекательные результаты, чем исходные данные.
  • Использует plpgsql. Никаких дополнительных расширений не требуется.
  • Принимает необязательный «коэффициент сглаживания» между 0 и 100 помимо геометрии.

Что он не делает:

  • Обрабатывает MultiLineStrings. Для любого другого типа геометрии он просто возвращает входные данные.
  • Использует значения Z и М. Это просто отбрасывает их. Используйте это только для 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, вы должны обернуть его в функции PostGIS, преобразовав их вокруг. Предполагаемый синтаксис использования:

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

Это был спасатель! Спасибо за сценарий. Похоже, что сглаживание Чайкина станет доступным как функция начиная с версии 2.5, что я с нетерпением жду.
she_weeds

1

Эта проблема все еще остается открытой в PostGIS (и других инструментах ГИС), как указано в книге «PostGIS in Action» в главе 2.2.6 «Кривые геометрии».

Вот некоторые ссылки на алгоритмы и код:


Я добавил postgis.17.x6 ... ссылки
Martin F

0

Вы можете попытаться преобразовать свои линии линий в кривые с помощью ST_LineToCurve, а затем вернуться к строкам линий с помощью ST_CurveToLine .

Вы можете установить желаемое количество сегментов на четверть круга в ST_CurveToLine.


LineToCurve создан для обработки выходных данных CurveToLine, а не для извлечения кривых из произвольного ввода.
Пол Рэмси

@PaulRamsey будет ли добавлено более гладкое сглаживание в следующих версиях Postgis? Я думал о чем-то вроде этого, например: webhelp.esri.com/arcgisdesktop/9.2/…
Gery
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.