在PostGIS中创建规则的多边形网格?


61

如何在Postgis中以多边形的形状创建给定大小的多边形/正方形的规则网格?

我已经考虑过类似如何在Postgis中的多边形内部创建规则点网格的功能仅适用于正方形,因此正方形可以为5m x 5m甚至10m x 10m。但是不知道以正确的方式更改它。


2
您寻求的概括尚不清楚。您是说要从一个(任意)单个多边形开始,并希望用其全等副本对平面进行平铺吗?通常,这是不可能的,但是此多边形可能具有特定的属性(例如,已知它是平行四边形,三角形或六边形)。
Whuber

Answers:


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;

其中nrowncol是行和列的数量,xsize以及ysize是单元尺寸的长度,以及可选的x0y0是用于左下角坐标。

结果是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 2011年

这非常有帮助。我有一个查询。如何在多边形/ bbox中创建网格?
Mohammed shafeek 2014年

尼斯工作麦克,这非常有帮助。
Mounaim

56

这是生成的一种特定变体,适用于需要以恒定度量级为地理地图创建网格的情况(单元可以用于对值进行分组,例如区域中的闪电密度)。

功能不是很好,但是我没有找到更好的解决方案(包括上面的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

因此,您可以看到由生成的多边形设置格式的线位于地理平行线和子午线上-这非常方便。

步距为50公里的网格示例

建议: 如果您计算密度之类的值(例如,按单元绘制的雷击图),并且动态生成了网格,则为提高性能,我建议使用临时表将单元存储为几何多边形,列上的空间索引表示细胞。


我希望我能再次投票赞成……这是一个完美的解决方案!而且自定义坐标系的能力真棒〜!
DPSSpatial

只是一个较小的建议,您可以使用并且仅指定该框的左下角和右上角坐标,而不是ST_GeomFromText在创建要添加的框时使用。sectorsST_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

我创建了@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;

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;

通过简单查询使用它;输入应为有效的多边形,Multipolygon或信封。

select I_Grid_Regular(st_setsrid(g.geom, 4326), .0001, .0001 ), geom from polygons limit 1
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.