PostGIS에서 일반 다각형 그리드를 생성 하시겠습니까?


61

postgis에서 다각형의 모양에 대해 주어진 크기의 다각형 / 사각형의 그리드를 만드는 방법은 무엇입니까?

Postgis에서 다각형 내부에 규칙적인 점 그리드를 만드는 방법 과 같은 기능에 대해 생각 했습니다. 사각형의 경우에만 사각형이 5m x 5m 또는 10m x 10m 일 수 있습니다. 그러나 이것을 올바른 방법으로 바꿀 생각은 없습니다.


2
원하는 일반화가 명확하지 않습니다. (임의의) 단일 다각형으로 시작하여 평면의 합동 사본을 타일링하려고합니까? 일반적으로 이것은 가능하지 않지만이 다각형에는 특정 속성이있을 수 있습니다 (예를 들어 평행 사변형, 삼각형 또는 육각형으로 알려져 있음).
whuber

답변:


60

다음은 ST_CreateFishnet다각형 형상의 2D 그리드를 만드는 집합 반환 함수 입니다.

CREATE OR REPLACE FUNCTION ST_CreateFishnet(
        nrow integer, ncol integer,
        xsize float8, ysize float8,
        x0 float8 DEFAULT 0, y0 float8 DEFAULT 0,
        OUT "row" integer, OUT col integer,
        OUT geom geometry)
    RETURNS SETOF record AS
$$
SELECT i + 1 AS row, j + 1 AS col, ST_Translate(cell, j * $3 + $5, i * $4 + $6) AS geom
FROM generate_series(0, $1 - 1) AS i,
     generate_series(0, $2 - 1) AS j,
(
SELECT ('POLYGON((0 0, 0 '||$4||', '||$3||' '||$4||', '||$3||' 0,0 0))')::geometry AS cell
) AS foo;
$$ LANGUAGE sql IMMUTABLE STRICT;

경우 nrow와는 ncol행과 열 수있는, xsize그리고 ysize셀 크기의 길이이며, 옵션 x0y0하단 왼쪽 모서리에 대한 좌표이다.

결과는 다음 rowcol번호는, 왼쪽 아래, 및 1로부터 geom셀마다 직사각형 다각형. 예를 들어 :

SELECT *
FROM ST_CreateFishnet(4, 6, 10, 10) AS cells;
 row | col |         geom
-----+-----+--------------------------------
   1 |   1 | 0103000000010000000500000000...
   2 |   1 | 0103000000010000000500000000...
   3 |   1 | 0103000000010000000500000000...
   4 |   1 | 0103000000010000000500000000...
   1 |   2 | 0103000000010000000500000000...
   2 |   2 | 0103000000010000000500000000...
   ...
   3 |   6 | 0103000000010000000500000000...
   4 |   6 | 0103000000010000000500000000...
(24 rows)

또는 전체 그리드에 대한 단일 지오메트리 컬렉션을 만들려면

SELECT ST_Collect(cells.geom)
FROM ST_CreateFishnet(4, 6, 10, 10) AS cells;

4x6 그리드

x0/ y0원점 오프셋을 추가 할 수 있습니다 (기본값은 0).


1
감사! 이제 망사를 다각형의 BBox에 바인딩해야합니다.
mk.archaeo

이것은 매우 도움이됩니다. 하나의 쿼리가 있습니다. 다각형 / 상자 안에 격자를 만들려면 어떻게해야합니까?
Mohammed shafeek

Nice Work Mike, 매우 도움이됩니다.
Mounaim 2016 년

56

다음 은 일정한 메트릭 단계를 사용하여 지리적지도에 대한 그리드만들어야 하는 상황에 대한 생성의 특정 변형입니다. 셀은 값을 그룹화하는 데 사용될 수 있습니다 (예 : 지역의 낙뢰 밀도).

기능은 매우 우아하지는 않지만 해당 작업에 대한 더 나은 해결책을 찾지 못했습니다 (위의 Mike Toews 기능 포함). 따라서 바운드 다각형 (예 : Google지도 인터페이스에서 도착)이 있고 미터 단위의 단계 값이 있습니다.

CREATE OR REPLACE FUNCTION public.makegrid_2d (
  bound_polygon public.geometry,
  grid_step integer,
  metric_srid integer = 28408 --metric SRID (this particular is optimal for the Western Russia)
)
RETURNS public.geometry AS
$body$
DECLARE
  BoundM public.geometry; --Bound polygon transformed to the metric projection (with metric_srid SRID)
  Xmin DOUBLE PRECISION;
  Xmax DOUBLE PRECISION;
  Ymax DOUBLE PRECISION;
  X DOUBLE PRECISION;
  Y DOUBLE PRECISION;
  sectors public.geometry[];
  i INTEGER;
BEGIN
  BoundM := ST_Transform($1, $3); --From WGS84 (SRID 4326) to the metric projection, to operate with step in meters
  Xmin := ST_XMin(BoundM);
  Xmax := ST_XMax(BoundM);
  Ymax := ST_YMax(BoundM);

  Y := ST_YMin(BoundM); --current sector's corner coordinate
  i := -1;
  <<yloop>>
  LOOP
    IF (Y > Ymax) THEN  --Better if generating polygons exceeds the bound for one step. You always can crop the result. But if not you may get not quite correct data for outbound polygons (e.g. if you calculate frequency per sector)
        EXIT;
    END IF;

    X := Xmin;
    <<xloop>>
    LOOP
      IF (X > Xmax) THEN
          EXIT;
      END IF;

      i := i + 1;
      sectors[i] := ST_GeomFromText('POLYGON(('||X||' '||Y||', '||(X+$2)||' '||Y||', '||(X+$2)||' '||(Y+$2)||', '||X||' '||(Y+$2)||', '||X||' '||Y||'))', $3);

      X := X + $2;
    END LOOP xloop;
    Y := Y + $2;
  END LOOP yloop;

  RETURN ST_Transform(ST_Collect(sectors), ST_SRID($1));
END;
$body$
LANGUAGE 'plpgsql';

사용 방법:

SELECT cell FROM 
(SELECT (
ST_Dump(makegrid_2d(ST_GeomFromText('Polygon((35.099577 45.183417,47.283415 45.183417,47.283415 49.640445,35.099577 49.640445,35.099577 45.183417))',
 4326), -- WGS84 SRID
 10000) -- cell step in meters
)).geom AS cell) AS q_grid

따라서 생성 된 다각형으로 서식이 지정된 선이 지리적 평행선과 자오선을 따라 놓여 있음을 알 수 있습니다. 매우 편리합니다.

50km 간격의 그리드 예

조언 : 밀도와 같은 것을 계산하고 (예 : 셀별 번개 획의 맵) 동적으로 그리드가 생성되는 경우 성능을 향상 시키려면 열에 공간 인덱스 가있는 셀을 형상 다각형으로 저장하기 위해 임시 테이블 을 사용하는 것이 좋습니다. 세포.


나는 이것을 다시 투표 할 수 있기를 바랍니다 ... 이것은 완벽한 해결책이었습니다! 좌표계를 커스터마이징하는 기능은 환상적입니다 ~!
DPSSpatial

ST_GeomFromText추가 할 상자를 만들 때 사용하는 대신 사소한 제안 만 사용 하면 상자의 왼쪽 및 오른쪽 위 좌표를 sectors사용 ST_MakeEnvelope하고 지정할 수 있습니다 .
Matt

이것은 잠재 제공
nickves

11

빈 래스터를 벡터화하는 정규 그리드를 만들 수 있습니다.

SELECT (ST_PixelAsPolygons(ST_AddBand(ST_MakeEmptyRaster(100, 100, 1.1, 1.1, 1.0), '8BSI'::text, 1, 0), 1, false)).geom

1
그것은 벡터 솔루션을 여러 번 수행 한 간단한 솔루션입니다.
존 파월

6

다른 SRID로 변환 할 필요가없는 @Alexander 기능의 변형을 만들었습니다. 이것은 미터를 특정 지역의 단위로 사용하는 투사를 찾아야하는 문제를 피합니다. ST_Project주어진 투영법을 사용 하여 올바르게 걸을 때 사용합니다. 사각형을 요구하는 대신 사각형 타일을 허용하기 위해 width_stepheight_step을 추가했습니다 .

CREATE OR REPLACE FUNCTION public.makegrid_2d (
  bound_polygon public.geometry,
  width_step integer,
  height_step integer
)
RETURNS public.geometry AS
$body$
DECLARE
  Xmin DOUBLE PRECISION;
  Xmax DOUBLE PRECISION;
  Ymax DOUBLE PRECISION;
  X DOUBLE PRECISION;
  Y DOUBLE PRECISION;
  NextX DOUBLE PRECISION;
  NextY DOUBLE PRECISION;
  CPoint public.geometry;
  sectors public.geometry[];
  i INTEGER;
  SRID INTEGER;
BEGIN
  Xmin := ST_XMin(bound_polygon);
  Xmax := ST_XMax(bound_polygon);
  Ymax := ST_YMax(bound_polygon);
  SRID := ST_SRID(bound_polygon);

  Y := ST_YMin(bound_polygon); --current sector's corner coordinate
  i := -1;
  <<yloop>>
  LOOP
    IF (Y > Ymax) THEN  
        EXIT;
    END IF;

    X := Xmin;
    <<xloop>>
    LOOP
      IF (X > Xmax) THEN
          EXIT;
      END IF;

      CPoint := ST_SetSRID(ST_MakePoint(X, Y), SRID);
      NextX := ST_X(ST_Project(CPoint, $2, radians(90))::geometry);
      NextY := ST_Y(ST_Project(CPoint, $3, radians(0))::geometry);

      i := i + 1;
      sectors[i] := ST_MakeEnvelope(X, Y, NextX, NextY, SRID);

      X := NextX;
    END LOOP xloop;
    CPoint := ST_SetSRID(ST_MakePoint(X, Y), SRID);
    NextY := ST_Y(ST_Project(CPoint, $3, radians(0))::geometry);
    Y := NextY;
  END LOOP yloop;

  RETURN ST_Collect(sectors);
END;
$body$
LANGUAGE 'plpgsql';

다음과 같이 사용할 수 있습니다.

SELECT ST_AsGeoJSON(cell) FROM (
  SELECT (
    ST_Dump(
      makegrid_2d(
        ST_GeomFromText(
          'Polygon((35.099577 45.183417,47.283415 45.183417,47.283415 49.640445,35.099577 49.640445,35.099577 45.183417))',
          4326
        ),
         10000, -- width step in meters
         10000  -- height step in meters
       ) 
    )
  ) .geom AS cell
)q;

5

엔벨로프, 다각형 또는 다중 다각형 내부에 망 사망, 일반 격자 선, 다각형 격자 선, 직사각형 격자 선을 만드는 최적화되고 효율적인 알고리즘이 있습니다. 거의 모든 SRID를 처리합니다.

GitHub 리포 링크

여기에 이미지 설명을 입력하십시오

DROP FUNCTION IF EXISTS PUBLIC.I_Grid_Regular(geometry, float8, float8);
CREATE OR REPLACE FUNCTION PUBLIC.I_Grid_Regular
( geom geometry, x_side float8, y_side float8, OUT geometry )
RETURNS SETOF geometry AS $BODY$ DECLARE
x_max DECIMAL;
y_max DECIMAL;
x_min DECIMAL;
y_min DECIMAL;
srid INTEGER := 4326;
input_srid INTEGER;
x_series DECIMAL;
y_series DECIMAL;
geom_cell geometry := ST_GeomFromText(FORMAT('POLYGON((0 0, 0 %s, %s %s, %s 0,0 0))',
                                        $3, $2, $3, $2), srid);
BEGIN
CASE ST_SRID (geom) WHEN 0 THEN
    geom := ST_SetSRID (geom, srid);
    RAISE NOTICE'SRID Not Found.';
ELSE
    RAISE NOTICE'SRID Found.';
END CASE;
input_srid := ST_srid ( geom );
geom := ST_Transform ( geom, srid );
x_max := ST_XMax ( geom );
y_max := ST_YMax ( geom );
x_min := ST_XMin ( geom );
y_min := ST_YMin ( geom );
x_series := CEIL ( @( x_max - x_min ) / x_side );
y_series := CEIL ( @( y_max - y_min ) / y_side );

RETURN QUERY With foo AS (
    SELECT
    ST_Translate( geom_cell, j * $2 + x_min, i * $3 + y_min ) AS cell
    FROM
        generate_series ( 0, x_series ) AS j,
        generate_series ( 0, y_series ) AS i
    ) SELECT ST_CollectionExtract(ST_Collect(ST_Transform ( ST_Intersection(cell, geom), input_srid)), 3)
    FROM foo where ST_intersects (cell, geom);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;

간단한 쿼리로 사용하십시오. 입력은 유효한 다각형, 다중 다각형 또는 봉투 여야합니다.

select I_Grid_Regular(st_setsrid(g.geom, 4326), .0001, .0001 ), geom from polygons limit 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.