Làm cách nào để tạo lưới điểm thông thường bên trong một đa giác trong Postgis?


31

Làm thế nào để tạo, bên trong một đa giác, một lưới thông thường của các điểm cách nhau x, y trong postgis? Giống như ví dụ:

văn bản thay thế


Tôi đã cố gắng thực hiện cắt các đa giác hợp nhất mã này với mã cắt "postGIS in action" nhưng chỉ có một đa giác được tạo ... Tôi có quên điều gì không? TẠO HOẶC THAY THẾ CHỨC NĂNG makegrid (hình học, số nguyên, số nguyên) RETURNS hình học AS 'SELECT st_intersection (g1.geom1, g2.geom2) NHƯ geom TỪ (CHỌN $ 1 AS geom1) NHƯ g1 INNER THAM GIA (Chọn st_setsrid (Chọn ST_Point (x, y), $ 3), st_setsrid (ST_Point (x + $ 2, y + $ 2), $ 3)) dưới dạng hình học), $ 3) dưới dạng geom2 TỪ Gener_series (sàn (st_xmin ($ 1)) :: int, trần ( st_xmax ($ 1)) :: int, $ 2) dưới dạng x, Gener_series (sàn (st_ymin ($ 1)) :: int, trần (st_ymax (
aurel_nc

nhìn vào câu trả lời chi tiết của tôi
Muhammad Imran Siddique

Câu trả lời:


30

Bạn làm điều đó với Gener_series.

Nếu bạn không muốn viết thủ công nơi bắt đầu và dừng lưới, cách dễ nhất là tạo một hàm.

Tôi chưa thử nghiệm đúng cách dưới đây, nhưng tôi nghĩ nó nên hoạt động:

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

Để sử dụng nó bạn có thể làm:

SELECT makegrid(the_geom, 1000) from mytable;

trong đó đối số thứ nhất là đa giác bạn muốn lưới và đối số thứ hai là khoảng cách giữa các điểm trong lưới.

Nếu bạn muốn một điểm trên mỗi hàng, bạn chỉ cần sử dụng ST_Dump như:

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

HTH

Nicklas


2
Bạn có thể cần thêm st_setSRID () vào các hàm st_point, nếu không st_intersects không hoạt động.
JaakL

Đã thêm phiên bản thử nghiệm của tôi dưới dạng câu trả lời riêng biệt.
JaakL

12

Tôi đã chọn mã chức năng của Nicklas Avén makegrid và làm cho nó chung chung hơn một chút bằng cách đọc và sử dụng srid từ hình dạng đa giác. Nếu không, sử dụng một đa giác với một srid được xác định, sẽ gây ra lỗi.

Chức năng:

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

Để sử dụng chức năng được thực hiện chính xác như Nicklas Avén đã viết:

SELECT makegrid(the_geom, 1000) from mytable;

hoặc nếu bạn muốn một điểm trên mỗi hàng:

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

Hy vọng điều này sẽ hữu ích cho một ai đó.

Alex


Câu trả lời được chấp nhận không hoạt động với dữ liệu của tôi do Lỗi SRID. Sửa đổi này hoạt động tốt hơn.
Vitaly Isaev

Bạn có thể muốn thêm một cái gì đó khi đa giác đang vượt qua phản âm? Tôi có thể tưởng tượng nó sẽ gây ra vấn đề với xmin / xmax.
Thomas

2
Nó không làm việc cho tôi. Sử dụng Postgres 9.6 và PostGIS 2.3.3. Bên trong lệnh gọi_s_s_s st_ymax ($ 1)) :: int "thay vì" trần (st_ymax ($ 1) -st_ymin ($ 1)) :: int "
Vitor Sapucaia

Tôi tán thành ý kiến ​​trước đó; giới hạn trên của Gener_series phải là trần của max và không phải là trần của chênh lệch (max - min).
R. Bourgeon

10

Những người sử dụng hình học wss84 có thể sẽ gặp rắc rối với chức năng này kể từ khi

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 

chỉ trả về số nguyên. Ngoại trừ những hình học rất lớn như các quốc gia (đang đặt trên nhiều độ trễ, độ lng), điều này sẽ chỉ thu được 1 điểm, phần lớn thời gian thậm chí không giao nhau với hình học ... => kết quả trống!

Vấn đề của tôi là dường như tôi không thể sử dụng Gener_series () với khoảng cách thập phân trên các số trôi nổi như WSG84 ... Đây là lý do tại sao tôi điều chỉnh hàm để nó hoạt động:

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

Về cơ bản chính xác như nhau. Chỉ cần nhân và chia cho 1000000 để có được số thập phân vào trò chơi khi tôi cần.

Chắc chắn có một giải pháp tốt hơn để đạt được điều đó. ++


Đó là một cách giải quyết thông minh. Bạn đã kiểm tra kết quả chưa? Họ có nhất quán không?
Pablo

Chào. Có pablo. Tôi hài lòng với kết quả cho đến nay. Tôi cần nó để xây dựng một số đa giác với độ cao tương đối trên mặt đất. (Tôi sử dụng SRTM để tính độ cao tôi muốn cho mọi điểm lưới). Bây giờ tôi chỉ thiếu một cách để bao gồm các điểm nằm trên chu vi của đa giác. Hiện tại hình dạng kết xuất có phần bị cắt bớt ở cạnh.
Julien Garcia

làm việc, khi tất cả các giải pháp của người khác không thành công, cảm ơn!
Jordan Arseno

7

Thuật toán này sẽ ổn:

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

trong đó 'đa giác' là đa giác và 'độ phân giải' là độ phân giải lưới cần thiết.

Để triển khai nó trong PostGIS, có thể cần các chức năng sau:

Chúc may mắn!


1
Lưu ý rằng nếu bạn có các khu vực đa giác phức tạp lớn (ví dụ: tôi có bộ đệm đường bờ biển), thì phương pháp này không hoàn toàn tối ưu.
JaakL

Sau đó, những gì bạn đề xuất thay thế?
bảy

4

Ba thuật toán sử dụng các phương pháp khác nhau.

Liên kết Repith Github

  1. Cách tiếp cận đơn giản và tốt nhất, sử dụng khoảng cách trái đất thực tế của tọa độ từ hướng x và y. Thuật toán hoạt động với bất kỳ SRID nào, bên trong nó hoạt động với WGS 1984 (EPSG: 4326) và chuyển đổi kết quả trở lại SRID đầu vào.

Hàm ================================================= ==================

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;

Sử dụng hàm với một truy vấn đơn giản, hình học phải hợp lệ và đa giác, đa giác hoặc loại phong bì

SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;

Kết quả ================================================= =====================

nhập mô tả hình ảnh ở đây

  1. Hàm thứ hai dựa trên thuật toán Nicklas Avén . Tôi đã tăng cường nó để xử lý bất kỳ SRID nào.

    đã nâng cấp các thay đổi sau đây trong thuật toán.

    1. Biến riêng cho hướng x và y cho kích thước pixel,
    2. Biến mới để tính khoảng cách trong hình cầu hoặc ellipsoid.
    3. Nhập bất kỳ SRID nào, chuyển đổi hàm Geom sang môi trường làm việc của Spheroid hoặc Ellipsoid Datum, sau đó áp dụng khoảng cách cho mỗi bên, nhận kết quả và chuyển đổi sang SRID đầu vào.

Hàm ================================================= ==================

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;

Sử dụng nó với một truy vấn đơn giản.

SELECT I_Grid_Point(geom, 22, 15, false) from polygons;

Kết quả ================================================= ==================nhập mô tả hình ảnh ở đây

  1. Chức năng dựa trên bộ tạo loạt.

Hàm ================================================= =================

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;

Sử dụng nó với một truy vấn đơn giản.

SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons; Kết quả ================================================= =========================

nhập mô tả hình ảnh ở đây


3

Vì vậy, phiên bản cố định của tôi:

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

Sử dụng:

SELECT (ST_Dump(makegrid(the_geom, 1000, 3857))).geom as the_geom from my_polygon_table

1
Xin chào, tôi nhận được kết quả trống với chức năng makegrid. Các shapefile đã được nhập vào PostGIS bằng cách sử dụng shp2pgsql. Không biết điều gì có thể gây rắc rối, srs được đặt thành wss84.
Michal Zimmermann

3

Đây là một cách tiếp cận khác chắc chắn nhanh hơn và dễ hiểu hơn.

Ví dụ cho lưới 1000m x 1000m:

SELECT (ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0))).geom 
FROM the_polygon

Ngoài ra SRID ban đầu được bảo tồn.

Đoạn mã này chuyển đổi hình dạng của đa giác thành một raster trống, sau đó chuyển đổi từng pixel thành một điểm. Ưu điểm: chúng tôi không phải kiểm tra lại nếu đa giác ban đầu giao nhau với các điểm.

Không bắt buộc:

Bạn cũng có thể thêm sự sắp xếp lưới với tham số Gridx và lưới. Nhưng vì chúng ta sử dụng trọng tâm của từng pixel (chứ không phải một góc), chúng ta cần sử dụng một modulo để tính giá trị đúng:

SELECT (ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0,mod(1000/2,100),mod(1000/2,100)))).geom 
FROM the_polygon

Với mod(grid_size::integer/2,grid_precision)

Đây là chức năng 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;

Có thể được sử dụng với:

SELECT makegrid(the_geom,1000.0,100) as geom from the_polygon  
-- makegrid(the_geom,grid_size,alignement)

1

Một bản cập nhật tiềm năng nhỏ cho các câu trả lời trước - đối số thứ ba là thang đo cho wss84 (hoặc sử dụng 1 cho các câu hỏi bình thường) và cũng làm tròn bên trong mã để các điểm được chia tỷ lệ trên nhiều hình được căn chỉnh.

Hy vọng điều này sẽ giúp, Martin

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

Sẽ không chuyển đổi hình học thành SRID cụ thể (như EPSG: 3857) sẽ tốt hơn là chỉ nhân với một hệ số tỷ lệ?
Nikolaus Krismer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.