如何在Postgis中以多边形的形状创建给定大小的多边形/正方形的规则网格?
我已经考虑过类似如何在Postgis中的多边形内部创建规则点网格的功能?仅适用于正方形,因此正方形可以为5m x 5m甚至10m x 10m。但是不知道以正确的方式更改它。
如何在Postgis中以多边形的形状创建给定大小的多边形/正方形的规则网格?
我已经考虑过类似如何在Postgis中的多边形内部创建规则点网格的功能?仅适用于正方形,因此正方形可以为5m x 5m甚至10m x 10m。但是不知道以正确的方式更改它。
Answers:
这是一个返回函数集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 Maps界面到达),并具有一个以米为单位的步长值:
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
我创建了@Alexander函数的变体,不需要我们转换为另一个SRID。这样避免了必须找到一个以米为特定区域单位的投影的问题。它用于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;
通过简单查询使用它;输入应为有效的多边形,Multipolygon或信封。
select I_Grid_Regular(st_setsrid(g.geom, 4326), .0001, .0001 ), geom from polygons limit 1