Postgis에서 다각형 안에 규칙적인 점 그리드를 만드는 방법은 무엇입니까?


30

postgis에서 x, y 간격의 점 그리드를 다각형으로 만드는 방법은 무엇입니까? 예를 들면 다음과 같습니다.

대체 텍스트


"postGIS in action"다이 싱 코드와 함께이 코드를 병합하는 클리핑 다각형을 만들려고했지만 하나의 다각형 만 만들어졌습니다. 함수 작성 또는 교체 makegrid (형상, 정수, 정수)는 형상을 'SELECT st_intersection (g1.geom1, g2.geom2) AS Geom FROM (SELECT $ 1 AS geom1) AS g1 INNER JOIN (st_setsrid (CAST (ST_MakeBox2d (st_setsrid ( ST_Point (x, y), $ 3), st_setsrid (ST_Point (x + $ 2, y + $ 2), $ 3)) 형상으로), $ 3) geom2로 FROM generate_series (floor (st_xmin ($ 1)) :: int, ceiling ( st_xmax ($ 1)) :: int, $ 2) x, generate_series (floor (st_ymin ($ 1)) :: int, ceiling (st_ymax (
aurel_nc)

자세한 답변을보십시오.
Muhammad Imran Siddique

답변:


29

generate_series로이를 수행하십시오.

그리드를 시작하고 중지 할 위치를 수동으로 작성하지 않으려면 가장 쉬운 방법으로 함수를 작성하십시오.

아래를 제대로 테스트하지 않았지만 제대로 작동한다고 생각합니다.

CREATE OR REPLACE FUNCTION makegrid(geometry, integer)
RETURNS geometry AS
'SELECT ST_Collect(ST_POINT(x,y)) FROM 
generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1)-st_xmin($1))::int, $2) as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1)-st_ymin($1))::int,$2) as y 
where st_intersects($1,ST_POINT(x,y))'
LANGUAGE sql

그것을 사용하려면 다음을 수행하십시오.

SELECT makegrid(the_geom, 1000) from mytable;

여기서 첫 번째 인수는 그리드에 원하는 다각형이고 두 번째 인수는 그리드의 점 사이의 거리입니다.

행당 하나의 포인트를 원하면 ST_Dump를 다음과 같이 사용하십시오.

SELECT (ST_Dump(makegrid(the_geom, 1000))).geom as the_geom from mytable;

HTH

니클라스


1
st_point 함수에 st_setSRID ()를 추가해야 할 수 있습니다. 그렇지 않으면 st_intersects가 작동하지 않습니다.
JaakL

테스트 된 버전을 별도의 답변으로 추가했습니다.
JaakL

12

내가 포착 한 니클라스 따방 makegrid 기능 코드와 만들어 그것을 좀 더 일반적인 읽기 및 다각형 형상의 SRID를 사용하여. 그렇지 않으면 srid가 정의 된 다각형을 사용하면 오류가 발생합니다.

함수:

CREATE OR REPLACE FUNCTION makegrid(geometry, integer)
RETURNS geometry AS
'SELECT ST_Collect(ST_SetSRID(ST_POINT(x,y),ST_SRID($1))) FROM 
generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1)-st_xmin($1))::int, $2) as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1)-st_ymin($1))::int,$2) as y 
where st_intersects($1,ST_SetSRID(ST_POINT(x,y),ST_SRID($1)))'
LANGUAGE sql

이 기능을 사용하려면 Nicklas Avén이 작성한 것과 정확히 동일합니다 .

SELECT makegrid(the_geom, 1000) from mytable;

또는 행당 하나의 포인트를 원할 경우 :

SELECT (ST_Dump(makegrid(the_geom, 1000))).geom as the_geom from mytable;

이것이 누군가에게 유용하기를 바랍니다.

알렉스


SRID 오류로 인해 허용 된 답변이 내 데이터와 작동하지 않습니다. 이 수정은 더 잘 작동합니다.
Vitaly Isaev

다각형이 자오선을 가로 지르는 경우 무언가를 추가하고 싶습니까? xmin / xmax에 문제가 발생할 것이라고 상상할 수 있습니다.
토마스

2
그것은 나를 위해 작동하지 않았다. Postgres 9.6 및 PostGIS 2.3.3 사용. generate_series 호출 내에서 "ceiling (st_xmax ($ 1) -st_xmin ($ 1)) :: int"및 "ceiling ( "ceiling (st_ymax ($ 1) -st_ymin ($ 1)) :: int"대신 st_ymax ($ 1)) :: int "
Vitor Sapucaia

이전 의견을 승인합니다. generate_series의 상한은 최대 값의 상한이어야하며 차이의 상한이 아니어야합니다 (최대-최소).
R. Bourgeon

10

wgs84 지오메트리를 사용하는 사람들은 아마도이 기능에 문제가있을 것입니다.

generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1))::int,$2) as x
,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1))::int,$2) as y 

정수만 반환합니다. 여러 위도, 경도로 배치 된 국가와 같은 매우 큰 지오메트리를 제외하고는 지오메트리 자체와 교차하지 않는 대부분의 시간 인 1 포인트 만 수집합니다.

내 문제는 WSG84와 같은 부동 숫자에서 소수 거리로 generate_series ()를 사용할 수없는 것 같습니다 ... 그래서 어쨌든 작동하도록 함수를 조정했습니다.

SELECT ST_Collect(st_setsrid(ST_POINT(x/1000000::float,y/1000000::float),st_srid($1))) FROM 
  generate_series(floor(st_xmin($1)*1000000)::int, ceiling(st_xmax($1)*1000000)::int,$2) as x ,
  generate_series(floor(st_ymin($1)*1000000)::int, ceiling(st_ymax($1)*1000000)::int,$2) as y 
WHERE st_intersects($1,ST_SetSRID(ST_POINT(x/1000000::float,y/1000000::float),ST_SRID($1)))

기본적으로 동일합니다. 필요할 때 게임에 소수점을 얻기 위해 1000000을 곱하고 나눕니다.

그것을 달성하는 더 좋은 해결책이 반드시 있습니다. ++


그것은 현명한 해결 방법입니다. 결과를 확인 했습니까? 일관성이 있습니까?
Pablo

안녕. 네 파블로 나는 지금까지 결과에 만족합니다. 지상 위의 상대 고도로 다각형을 만들려면 필요했습니다. (SRTM을 사용하여 모든 그리드 포인트에 대해 원하는 고도를 계산합니다). 이제 다각형의 둘레에 놓인 점을 포함시키는 방법 만 누락되었습니다. 현재 렌더링 된 모양이 가장자리에서 약간 잘립니다.
Julien Garcia

다른 모든 솔루션이 실패했을 때 감사했습니다!
Jordan Arseno

7

이 알고리즘은 괜찮을 것입니다 :

createGridInPolygon(polygon, resolution) {
    for(x=polygon.xmin; x<polygon.xmax; x+=resolution) {
       for(y=polygon.ymin; y<polygon.ymax; y+=resolution) {
          if(polygon.contains(x,y)) createPoint(x,y);
       }
    }
}

여기서 'polygon'은 다각형이고 'resolution'은 필요한 그리드 해상도입니다.

PostGIS에서이를 구현하려면 다음 기능이 필요할 수 있습니다.

  • ST_XMin , ST_XMax , ST_YMinST_YMax 는 다각형의 최소 및 최대 좌표를 가져옵니다.
  • ST_ 다각형에 점이 있는지 테스트하기 위해 포함됩니다.
  • ST_Point를이 점을 만들 수 있습니다.

행운을 빕니다!


1
복잡한 다각형 영역이 큰 경우 (예 : 해안선 버퍼가있는 경우)이 방법은 최적이 아닙니다.
JaakL

그러면 대신 무엇을 제안합니까?
julien

4

다른 방법을 사용하는 세 가지 알고리즘.

Github Repo 링크

  1. x와 y 방향에서 좌표의 실제 지구 거리를 사용하는 간단하고 가장 좋은 방법입니다. 이 알고리즘은 모든 SRID와 작동하며 내부적으로 WGS 1984 (EPSG : 4326)와 작동하며 결과는 입력 SRID로 다시 변환됩니다.

기능 ==================================================== ==================

CREATE OR REPLACE FUNCTION public.I_Grid_Point_Distance(geom public.geometry, x_side decimal, y_side decimal)
RETURNS public.geometry AS $BODY$
DECLARE
x_min decimal;
x_max decimal;
y_max decimal;
x decimal;
y decimal;
returnGeom public.geometry[];
i integer := -1;
srid integer := 4326;
input_srid integer;
BEGIN
CASE st_srid(geom) WHEN 0 THEN
    geom := ST_SetSRID(geom, srid);
        ----RAISE NOTICE 'No SRID Found.';
    ELSE
        ----RAISE NOTICE 'SRID Found.';
END CASE;
    input_srid:=st_srid(geom);
    geom := st_transform(geom, srid);
    x_min := ST_XMin(geom);
    x_max := ST_XMax(geom);
    y_max := ST_YMax(geom);
    y := ST_YMin(geom);
    x := x_min;
    i := i + 1;
    returnGeom[i] := st_setsrid(ST_MakePoint(x, y), srid);
<<yloop>>
LOOP
IF (y > y_max) THEN
    EXIT;
END IF;

CASE i WHEN 0 THEN 
    y := ST_Y(returnGeom[0]);
ELSE 
    y := ST_Y(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), y_side, radians(0))::geometry);
END CASE;

x := x_min;
<<xloop>>
LOOP
  IF (x > x_max) THEN
      EXIT;
  END IF;
    i := i + 1;
    returnGeom[i] := st_setsrid(ST_MakePoint(x, y), srid);
    x := ST_X(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), x_side, radians(90))::geometry);
END LOOP xloop;
END LOOP yloop;
RETURN
ST_CollectionExtract(st_transform(ST_Intersection(st_collect(returnGeom), geom), input_srid), 1);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;

간단한 쿼리로 함수를 사용하십시오. 기하학은 유효하고 다각형, 다중 다각형 또는 엔벨로프 유형이어야합니다.

SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;

결과 ================================================== =====================

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

  1. Nicklas Avén 알고리즘 에 기반한 두 번째 기능 . 모든 SRID를 처리하도록 개선했습니다.

    알고리즘에서 다음 변경 사항을 업그레이드하십시오.

    1. 픽셀 크기의 x 및 y 방향에 대한 개별 변수
    2. 구상 또는 타원체의 거리를 계산하는 새로운 변수.
    3. SRID를 입력하고 Geom을 Spheroid 또는 Ellipsoid Datum의 작업 환경에 변환 한 다음 각면에 거리를 적용하고 결과를 얻고 입력 SRID로 변환하십시오.

기능 ==================================================== ==================

CREATE OR REPLACE FUNCTION I_Grid_Point(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
RETURNS SETOF geometry AS $BODY$ 
DECLARE
x_max decimal; 
y_max decimal;
x_min decimal;
y_min decimal;
srid integer := 4326;
input_srid integer; 
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;

    CASE spheroid WHEN false THEN
        RAISE NOTICE 'Spheroid False';
        srid := 4326;
        x_side := x_side / 100000;
        y_side := y_side / 100000;
    else
        srid := 900913;
        RAISE NOTICE 'Spheroid True';
    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);
RETURN QUERY
WITH res as (SELECT ST_SetSRID(ST_MakePoint(x, y), srid) point FROM
generate_series(x_min, x_max, x_side) as x,
generate_series(y_min, y_max, y_side) as y
WHERE st_intersects(geom, ST_SetSRID(ST_MakePoint(x, y), srid))
) select ST_TRANSFORM(ST_COLLECT(point), input_srid) from res;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;

간단한 쿼리로 사용하십시오.

SELECT I_Grid_Point(geom, 22, 15, false) from polygons;

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

  1. 직렬 발생기 기반 기능.

기능 ==================================================== =================

CREATE OR REPLACE FUNCTION I_Grid_Point_Series(geom geometry, x_side decimal, y_side decimal, spheroid boolean default false)
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;
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;

    CASE spheroid WHEN false THEN
        RAISE NOTICE 'Spheroid False';
    else
        srid := 900913;
        RAISE NOTICE 'Spheroid True';
    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
SELECT st_collect(st_setsrid(ST_MakePoint(x * x_side + x_min, y*y_side + y_min), srid)) FROM
generate_series(0, x_series) as x,
generate_series(0, y_series) as y
WHERE st_intersects(st_setsrid(ST_MakePoint(x*x_side + x_min, y*y_side + y_min), srid), geom);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;

간단한 쿼리로 사용하십시오.

SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons; 결과 ================================================== ==========================

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


3

더 빠르고 이해하기 쉬운 다른 방법이 있습니다.

예를 들어 1000m x 1000m 그리드의 경우 :

SELECT (ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0))).geom 
FROM the_polygon

또한 원래 SRID가 유지됩니다.

이 스 니펫은 다각형의 지오메트리를 빈 래스터로 변환 한 다음 각 픽셀을 점으로 변환합니다. 장점 : 원래 다각형이 점과 교차하는지 다시 확인할 필요가 없습니다.

선택 과목:

매개 변수 gridx 및 gridy를 사용하여 격자 정렬을 추가 할 수도 있습니다. 그러나 각 픽셀의 중심을 사용하기 때문에 (모퉁이 아님) 올바른 값을 계산하려면 모듈러스를 사용해야합니다.

SELECT (ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0,mod(1000/2,100),mod(1000/2,100)))).geom 
FROM the_polygon

mod(grid_size::integer/2,grid_precision)

postgres 함수는 다음과 같습니다.

CREATE OR REPLACE FUNCTION st_makegrid(geometry, float, integer)
RETURNS SETOF geometry AS
'SELECT (ST_PixelAsCentroids(ST_AsRaster($1,$2::float,$2::float,mod($2::int/2,$3),mod($2::int/2,$3)))).geom'
LANGUAGE sql;

다음과 함께 사용 가능 :

SELECT makegrid(the_geom,1000.0,100) as geom from the_polygon  
-- makegrid(the_geom,grid_size,alignement)

2

그래서 내 고정 버전 :

CREATE OR REPLACE FUNCTION makegrid(geometry, integer, integer)
RETURNS geometry AS
'SELECT ST_Collect(st_setsrid(ST_POINT(x,y),$3)) FROM 
  generate_series(floor(st_xmin($1))::int, ceiling(st_xmax($1))::int,$2) as x
  ,generate_series(floor(st_ymin($1))::int, ceiling(st_ymax($1))::int,$2) as y 
where st_intersects($1,st_setsrid(ST_POINT(x,y),$3))'
LANGUAGE sql

용법:

SELECT (ST_Dump(makegrid(the_geom, 1000, 3857))).geom as the_geom from my_polygon_table

1
안녕하세요, makegrid 기능으로 빈 결과가 나타납니다. 셰이프 파일은 shp2pgsql을 사용하여 PostGIS로 가져 왔습니다. 무엇이 문제를 일으킬 수 있는지 모릅니다. srs는 wgs84로 설정되어 있습니다.
Michal Zimmermann 2016 년

1

이전 답변에 대한 약간의 잠재적 인 업데이트-wgs84의 스케일로 세 번째 인수 (또는 일반적인 것에는 1을 사용) 및 여러 모양의 스케일 포인트가 정렬되도록 코드 내에서 반올림.

이것이 도움이되기를 바랍니다, 마틴

CREATE OR REPLACE FUNCTION makegrid(geometry, integer, integer)
RETURNS geometry AS



/*geometry column , integer: distance between points, integer: scale factor for distance (useful for wgs84, e.g. use there 50000 as distance and 1000000 as scale factor*/

'
SELECT ST_Collect(st_setsrid(ST_POINT(x/$3::float,y/$3::float),st_srid($1))) FROM 
  generate_series(
                (round(floor(st_xmin($1)*$3)::int/$2)*$2)::int, 
                (round(ceiling(st_xmax($1)*$3)::int/$2)*$2)::int,
                $2) as x ,
  generate_series(
                (round(floor(st_ymin($1)*$3)::int/$2)*$2)::int, 
                (round(ceiling(st_ymax($1)*$3)::int/$2)*$2)::int,
                $2) as y 
WHERE st_intersects($1,ST_SetSRID(ST_POINT(x/$3::float,y/$3::float),ST_SRID($1)))
'

LANGUAGE sql

EPSG : 3857과 같은 지오메트리를 특정 SRID로 변환하는 것만으로 스케일 팩터를 곱하는 것보다 낫지 않습니까?
Nikolaus Krismer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.