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_YMin 및 ST_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.