如何在Postgis中的多边形内部创建规则点网格?


30

如何在Postgis中在多边形内创建点距x,y的规则网格?像例子:

替代文字


我试图制作将此代码与“ postGIS in action”切割代码合并的剪切多边形,但仅创建了一个多边形...我忘了什么吗?创建或替换功能makegrid(geometry,integer,integer)返回geometry AS'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)as geom2 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(
aurel_nc 2013年

看我详细的答案。
穆罕默德·伊姆兰·西迪克

Answers:


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;

高温超导

尼克拉斯


1
您可能需要将st_setSRID()添加到st_point函数,否则st_intersects不起作用。
JaakL 2012年

将我的测试版本添加为单独的答案。
2012年

12

我已经拿起尼克拉斯·阿芬(NicklasAvén) NicklasAvénmakegrid函数代码,并通过读取和使用多边形几何图形中的使其变得更加通用。否则,使用具有已定义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

完全按照NicklasAvén的说法来使用该功能:

SELECT makegrid(the_geom, 1000) from mytable;

或者,如果您希望每行一个点:

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

希望这对某人有用。

亚历克斯


由于SRID错误,接受的答案不适用于我的数据。此修改效果更好。
维塔利·伊萨耶夫

您可能要在多边形经过反子午线时添加一些东西吗?我可以想象会导致xmin / xmax出现问题。
托马斯

2
它对我不起作用。使用Postgres 9.6和PostGIS 2.3.3。在generate_series调用中,我必须将其作为第二个参数“ ceiling(st_xmax($ 1)):: int”而不是“ ceiling(st_xmax($ 1)-st_xmin($ 1)):: int”和“ ceiling( st_ymax($ 1)):: int”而不是“ ceiling(st_ymax($ 1)-st_ymin($ 1)):: int”
Vitor Sapucaia

我赞成先前的评论;generate_series的上限应该是最大值的上限,而不是差异的上限(max-min)。
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 

只返回整数。除了非常大的几何图形(例如国家/地区)(位于多个纬度,lng度上)之外,这将导致仅收集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计算每个网格点所需的高度)。我现在只缺少一种方法来包含放置在多边形外围的点。目前,渲染的形状在边缘处已被截断。
朱利安·加西亚

工作,其他所有人的解决方案都失败了,谢谢!
乔丹·阿塞诺

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);
       }
    }
}

其中“多边形”是多边形,“分辨率”是所需的网格分辨率。

要在PostGIS中实现它,可能需要以下功能:

祝好运!


1
请注意,如果您有较大的复杂多边形区域(例如,我有海岸线缓冲区),则此方法不是很理想。
JaakL 2012年

那么,您有什么建议呢?
2012年

4

三种算法使用不同的方法。

Github回购链接

  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. 第二功能基于NicklasAvén算法。我对其进行了增强以处理任何SRID。

    升级了以下算法更改。

    1. x和y方向的单独变量用于像素尺寸,
    2. 新变量以球体或椭圆体的距离计算。
    3. 输入任何SRID,对Geom进行功能变换到椭球形或椭球形基准面的工作环境,然后将距离应用于每一侧,获取结果并变换为输入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将shapefile导入到PostGIS。不知道是什么原因引起的麻烦,将srs设置为wgs84。
Michal Zimmermann

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

将几何图形转换为特定的SRID(例如EPSG:3857)会比仅乘以比例因子更好吗?
Nikolaus Krismer '17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.