Jak stworzyć wewnątrz wielokąta regularną siatkę punktów x, y rozmieszczonych w punktach postgis? Podobnie jak w przykładzie:
Jak stworzyć wewnątrz wielokąta regularną siatkę punktów x, y rozmieszczonych w punktach postgis? Podobnie jak w przykładzie:
Odpowiedzi:
Robisz to za pomocą generowania_serwisów.
Jeśli nie chcesz ręcznie pisać w miejscu, w którym siatka ma się uruchamiać i zatrzymywać, najłatwiej jest utworzyć funkcję.
Nie przetestowałem poprawnie poniższych elementów, ale myślę, że powinno to działać:
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
Aby go użyć, możesz:
SELECT makegrid(the_geom, 1000) from mytable;
gdzie pierwszym argumentem jest wielokąt, w którym chcesz siatkę, a drugim argumentem jest odległość między punktami na siatce.
Jeśli chcesz jednego punktu na wiersz, po prostu użyj ST_Dump, takiego jak:
SELECT (ST_Dump(makegrid(the_geom, 1000))).geom as the_geom from mytable;
HTH
Nicklas
Wziąłem kod funkcji makegrid Nicklasa Avéna i uczyniłem go nieco bardziej ogólnym, czytając i używając okienka z geometrii wielokąta. W przeciwnym razie użycie wielokąta ze zdefiniowanym oknem spowoduje błąd.
Funkcja:
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
Aby użyć tej funkcji, należy wykonać dokładnie tak, jak napisał Nicklas Avén :
SELECT makegrid(the_geom, 1000) from mytable;
lub jeśli chcesz jeden punkt na rząd:
SELECT (ST_Dump(makegrid(the_geom, 1000))).geom as the_geom from mytable;
Mam nadzieję, że będzie to przydatne dla kogoś.
Alex
Od tego czasu osoby używające geometrii wgs84 prawdopodobnie będą miały problemy z tą funkcją
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
zwracają tylko liczby całkowite. Z wyjątkiem bardzo dużych geometrii, takich jak kraje (które leżą na wielu stopniach lng, lng), spowoduje to zebranie tylko 1 punktu, który przez większość czasu nawet nie przecina samej geometrii ... => pusty wynik!
Mój problem polegał na tym, że nie mogę użyć generowania_serwerów () z dziesiętną odległością od liczb zmiennoprzecinkowych, takich jak te WSG84 ... Właśnie dlatego poprawiłem funkcję, aby i tak działała:
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)))
Zasadniczo dokładnie tak samo. Wystarczy pomnożyć i podzielić przez 1000000, aby wprowadzić liczby dziesiętne do gry, gdy jej potrzebuję.
Z pewnością jest na to lepsze rozwiązanie. ++
Ten algorytm powinien być w porządku:
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);
}
}
}
gdzie „wielokąt” jest wielokątem, a „rozdzielczość” jest wymaganą rozdzielczością siatki.
Aby zaimplementować go w PostGIS, mogą być potrzebne następujące funkcje:
Powodzenia!
Trzy algorytmy wykorzystujące różne metody.
Github Repo Link
Funkcja ================================================= ==================
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;
Użyj funkcji z prostym zapytaniem, geometria musi być poprawna, a typ wielokąta, wielokąta lub obwiedni
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
Wynik ================================================= =====================
Druga funkcja oparta na algorytmie Nicklas Avén . Ulepszyłem go, aby obsługiwał dowolny SRID.
zaktualizuj następujące zmiany w algorytmie.
Funkcja ================================================= ==================
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;
Użyj go za pomocą prostego zapytania.
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
Wynik ================================================= ==================
Funkcja ================================================= =================
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;
Użyj go za pomocą prostego zapytania.
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
Wynik ================================================= =========================
Więc moja stała wersja:
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
Stosowanie:
SELECT (ST_Dump(makegrid(the_geom, 1000, 3857))).geom as the_geom from my_polygon_table
Oto inne podejście, które z pewnością jest szybsze i łatwiejsze do zrozumienia.
Na przykład dla siatki o wymiarach 1000 na 1000 m:
SELECT (ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0))).geom
FROM the_polygon
Zachowany jest również oryginalny SRID.
Ten fragment przekształca geometrię wielokąta w pusty raster, a następnie przekształca każdy piksel w punkt. Zaleta: nie musimy ponownie sprawdzać, czy oryginalny wielokąt przecina punkty.
Opcjonalny:
Możesz także dodać wyrównanie siatki za pomocą parametru gridx i gridy. Ale ponieważ używamy środka ciężkości każdego piksela (a nie rogu), musimy użyć modulo, aby obliczyć właściwą wartość:
SELECT (ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0,mod(1000/2,100),mod(1000/2,100)))).geom
FROM the_polygon
Z mod(grid_size::integer/2,grid_precision)
Oto funkcja 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;
Można stosować z:
SELECT makegrid(the_geom,1000.0,100) as geom from the_polygon
-- makegrid(the_geom,grid_size,alignement)
Mała potencjalna aktualizacja poprzednich odpowiedzi - trzeci argument jako skala dla wgs84 (lub użyj 1 dla normalnych), a także zaokrąglenie wewnątrz kodu, aby wyskalowane punkty na wielu kształtach były wyrównane.
Mam nadzieję, że to pomaga, 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