PostGIS에서 SIA 또는 베 지어 라인 스무딩을 수행하는 방법은 무엇입니까?


9

베 지어 곡선 또는 SIA (Iterative Averaging ) 알고리즘을 사용하여 postgis 테이블에서 라인 스트링을 매끄럽게하기 위해 SQL 예제를 제공 할 수 있습니까 ?

답변:


6

휴리스틱을 기반으로 입력 LineString을 CompoundCurves로 변환하는 작고 순진한 스크립트를 만들었습니다.

그것이하는 일 :

  • 날카로운 모서리를 줄여 원본 데이터보다 시각적으로 더 매력적인 결과를 만듭니다.
  • plpgsql을 사용합니다. 추가 확장이 필요하지 않습니다.
  • 지오메트리 외에 0과 100 사이의 선택적 "평활 계수"를 허용합니다.

하지 않는 것 :

  • MultiLineString을 처리합니다. 다른 지오메트리 유형의 경우 입력을 반환합니다.
  • Z 및 M 값을 사용합니다. 단순히 떨어 뜨립니다. 2D지도 제작 용도로만 사용하십시오.
  • 수학적으로 올바른 결과를 만듭니다. 결과는 정확하지 않으며 경우에 따라 시각적으로 미학적 일 수도 있습니다 (예 : 날카로운 모서리). 나는 그것을 철저히 테스트하지 않았다. 항상 결과를 검토하십시오!
  • 빨리 달린다. 훨씬 더 최적의 형태로 다시 쓸 수 있다고 확신합니다.
  • 실제 스무딩을 수행합니다. 실제 스무딩에 사용할 훨씬 더 나은 알고리즘 (예 : Chaiken 또는 질문에서 언급 한 알고리즘)이 있습니다. 이 답변은 실제 Post 데이터에서 자동으로 일종의 곡선을 생성하는 순수한 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"책에 명시된 PostGIS (및 기타 GIS 도구)에서 여전히 공개 된 문제입니다.

다음은 알고리즘 및 코드에 대한 참조입니다.


postgis.17.x6 ... 링크를 추가했습니다
Martin F

0

ST_LineToCurve 를 사용하여 선 스트링을 곡선으로 변환 한 다음 ST_CurveToLine을 사용 하여 선 스트링으로 다시 변환 할 수 있습니다 .

ST_CurveToLine에서 원하는 분기 원당 세그먼트 수를 설정할 수 있습니다.


LineToCurve는 임의의 입력에서 곡선을 추출하지 않고 CurveToLine의 출력을 처리하도록 설계되었습니다.
Paul Ramsey

@PaulRamsey는 다음 Postgis 버전에서 베 지어 스무딩을 추가합니까? 예를 들어 webhelp.esri.com/arcgisdesktop/9.2/…
Gery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.