PostGIS'te düzenli çokgen ızgara oluşturma?


61

Bir çokgen biçiminde, belirli bir büyüklükte düzenli bir çokgen / kare ızgarası postgis'te nasıl oluşturulur?

Ben böyle bir işlevi hakkında düşündüm PostGIS bir çokgen içinde düzenli nokta ızgara nasıl oluşturulur? sadece kareler için, böylece kareler 5m x 5m veya hatta 10m x 10m olabilir. Ancak bunu doğru şekilde değiştirmek için hiçbir fikrim yok.


2
Aradığınız genelleme belli değil. (İsteğe bağlı) tek bir çokgenle başladığınızı ve düzlemin uyumlu kopyalarıyla döşenmesini istediğinizi mi söylüyorsunuz? Genelde bu mümkün değildir, ancak belki bu çokgen belirli özelliklere sahiptir (örneğin, bir paralelkenar, üçgen veya altıgen olduğu bilinmektedir).
whuber

Yanıtlar:


60

ST_CreateFishnet2B çokgen geometrileri ızgarası oluşturan bir set döndürme işlevi :

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;

burada nrowve ncolsatır ve sütun sayısıdır, xsizeve ysizehücre boyutu uzunlukları ve isteğe bağlı x0ve y0alt sol köşesinde koordinatları vardır.

Sonucudur rowve colsayılar, sol alt köşede, ve en 1'den başlayarak geom, her bir hücre için dikdörtgen çokgen. Yani örneğin:

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)

Veya tüm ızgara için tek bir geometri koleksiyonu yapmak için:

SELECT ST_Collect(cells.geom)
FROM ST_CreateFishnet(4, 6, 10, 10) AS cells;

4x6 ızgara

x0/ y0Origin ofsetlerini ekleyebilirsiniz (bunlar varsayılan olarak sıfırdır).


1
Teşekkürler! Şimdi sadece ağı çokgen BBox'a bağlamak zorundayım.
mk.archaeo

Bu çok yararlı .. Bir sorgu var. Bir çokgen / kutunun içinde ızgaraları nasıl oluşturabilirim?
Mohammed Shafeek

İyi İş Mike, Bu çok yardımcı olur.
Mounaim

56

İşte sabit bir metrik adım ile bir coğrafi harita için bir ızgara oluşturmanız gerektiğinde (hücreler bir bölgedeki yıldırım yoğunluğu, örneğin gruplama için kullanılabilir) , bir durum için belirli bir üretme varyantı .

İşlev çok zarif değil, ancak bu görev için daha iyi bir çözüm bulamadım (yukarıdaki Mike Toews'in işlevi dahil). Dolayısıyla, bağlı bir poligonunuz var (ör. Bir Google Haritalar arayüzünden gelmiş), metre cinsinden bir adım değerine sahip:

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';

Bu nasıl kullanılır:

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

Böylece üretilen poligonlarla biçimlendirilmiş çizgilerin coğrafi paralellikler ve meridyenler boyunca uzandığını görebilirsiniz - bu çok uygun.

50 km adımlı bir ızgara örneği

Tavsiye: Eğer yoğunluk gibi bir şey (hücreler tarafından yıldırım vuruş örneğin harita) hesaplamak ve ızgara dinamik kullanıyorum öneririm performansını artırmak için oluşturulan ise geçici tablolar bir ile, geometri çokgenler olarak hücrelerin saklanması için mekansal indeksi sütunu temsil üzerinde hücre.


Keşke bunu tekrar oylayabilseydim ... bu mükemmel bir çözümdü! ve koordinat sistemini kişiselleştirme yeteneği fantastik ~!
DPSSpatial

Sadece küçük bir öneri, ST_GeomFromTexteklemek için bir kutu oluştururken kullanmak yerine, kutunun sol alt ve sağ üst koordinatlarını sectorskullanabilir ST_MakeEnvelopeve belirleyebilirsiniz.
Matt

Bu potansiyel getiriyor
Ocak'ta

11

Düzenli bir ızgara oluşturarak sadece boş bir raster vektörleştiriyor olabilirsiniz:

SELECT (ST_PixelAsPolygons(ST_AddBand(ST_MakeEmptyRaster(100, 100, 1.1, 1.1, 1.0), '8BSI'::text, 1, 0), 1, false)).geom

1
Bu çok basit bir çözüm, vektörü birçok defa yapmış.
John Powell,

6

@ Alexander'ın başka bir SRID'ye dönüştürmemizi gerektirmeyen bir işlevi türünü oluşturdum. Bu, sayaçları belirli bir bölge için birim olarak kullanan bir çıkıntı bulmak zorunda kalmamaktan kaçınır. Bu kullanır ST_Projectdüzgün verilen projeksiyon kullanılarak uzun adımlarla yürümek. Ben de bir kare ekleyerek yerine dikdörtgen fayans izin vermek için bir width_stepve ekledim 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';

Bu şekilde kullanabilirsiniz:

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

Fileto, düzenli ızgara, çokgen ızgara, herhangi bir zarfın içinde çokgen ızgara, çokgen veya Çokgenler oluşturmak için optimize edilmiş ve etkili bir algoritma. neredeyse herhangi bir SRID ile başa çıkmak;

GitHub Repo Bağlantısı

görüntü tanımını buraya girin

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;

Basit bir sorgu ile kullanın; giriş geçerli bir çokgen, Çoklayıcı veya zarf olmalıdır.

select I_Grid_Regular(st_setsrid(g.geom, 4326), .0001, .0001 ), geom from polygons limit 1
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.