多角形の形状で、特定のサイズの多角形/正方形の規則的なグリッドをPostgisで作成するにはどうすればよいですか?
Postgisのポリゴン内に通常のポイントグリッドを作成する方法のような機能について考えましたか?正方形のみの場合、正方形は5m x 5mまたは10m x 10mにもなります。しかし、これを正しい方法で変更する考えはありません。
多角形の形状で、特定のサイズの多角形/正方形の規則的なグリッドをPostgisで作成するにはどうすればよいですか?
Postgisのポリゴン内に通常のポイントグリッドを作成する方法のような機能について考えましたか?正方形のみの場合、正方形は5m x 5mまたは10m x 10mにもなります。しかし、これを正しい方法で変更する考えはありません。
回答:
以下は、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
左下隅の座標です。
結果はrow
、col
左下隅の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;
x0
/ y0
原点オフセットを追加できます(デフォルトはゼロです)。
一定のメトリックステップで地理マップのグリッドを作成する必要がある場合の生成の特定のバリアントを次に示します(セルは、値をグループ化するために使用される場合があります。たとえば、地域の稲妻密度)。
関数はそれほどエレガントではありませんが、そのタスク(上記の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
そのため、生成されたポリゴンによってフォーマットされた線が地理的な緯線と子午線に沿っていることがわかります。これは非常に便利です。
アドバイス: 密度などの計算(セルによる稲妻のストロークのマップなど)を行い、グリッドを動的に生成する場合パフォーマンスを向上させるために、列の空間インデックスを表すジオメトリポリゴンとしてセルを格納する一時テーブルを使用することをお勧めしますセル。
ST_GeomFromText
追加するボックスを作成するときに使用する代わりに、ボックスの左下と右上の座標をsectors
使用ST_MakeEnvelope
して指定することができます。
別のSRIDに変換する必要のない@Alexanderの関数のバリアントを作成しました。これにより、特定の地域の単位としてメートルを使用する投影法を見つける必要がなくなります。ST_Project
与えられた投影法を使用して適切に歩きます。また、正方形を要求する代わりに長方形のタイルを許可するためにwidth_step
とheight_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;
以下は、フィッシュネット、通常のグリッド、ポリゴングリッド、エンベロープ内の長方形グリッド、ポリゴン、またはマルチポリゴンを作成するための最適化された効率的なアルゴリズムです。ほとんどすべてのSRIDを処理します。
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