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ụ:
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ụ:
Câu trả lời:
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
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
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 đó. ++
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!
Ba thuật toán sử dụng các phương pháp khác nhau.
Liên kết Repith Github
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ả ================================================= =====================
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.
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ả ================================================= ==================
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ả ================================================= =========================
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
Đâ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)
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