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セルサイズの長さであり、そして任意x0及びy0左下隅の座標です。

結果は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原点オフセットを追加できます(デフォルトはゼロです)。


1
ありがとう!ここで、フィッシュネットをポリゴンのBBoxにバインドするだけです。
mk.archaeo

これは非常に役立ちます。ポリゴン/ bbox内にグリッドを作成するにはどうすればよいですか?
モハメッドシャフィーク14

Nice Work Mike、これは非常に役立ちます。
Mounaim

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

そのため、生成されたポリゴンによってフォーマットされた線が地理的な緯線と子午線に沿っていることがわかります。これは非常に便利です。

50 kmステップのグリッドの例

アドバイス: 密度などの計算(セルによる稲妻のストロークのマップなど)を行い、グリッドを動的に生成する場合パフォーマンスを向上させるために、列の空間インデックスを表すジオメトリポリゴンとしてセルを格納する一時テーブルを使用することをお勧めしますセル。


もう一度これに賛成票を投じることができるといいのですが...これは完璧な解決策でした!座標系をカスタマイズする機能は素晴らしいです!
DPSS16年

ST_GeomFromText追加するボックスを作成するときに使用する代わりに、ボックスの左下と右上の座標をsectors使用ST_MakeEnvelopeして指定することができます。
マット

これは可能性をもたらします
ニックス

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.