Próbowałem zrobić wycinające się wielokąty łączące ten kod z kodem kostki „postGIS w akcji”, ale tworzony jest tylko jeden wielokąt… Czy coś zapomniałem? TWORZENIE LUB WYMIANA FUNKCJI makegrid (geometria, liczba całkowita, liczba całkowita) ZWRACA geometrię AS 'SELECT st_intersection (g1.geom1, g2.geom2) AS geom FROM (SELECT $ 1 AS geom1) AS g1 INNER JOIN (Wybierz st_setsrid (CAST (ST_MakeBox2d (ST_MakeBox2d ST_Point (x, y), 3 USD), st_setsrid (ST_Point (x + 2 USD, y + 2 USD), 3 USD)) jako geometria), 3 USD) jako geom2 FROM generator_series (floor (st_xmin (1 USD)) :: int, sufit ( st_xmax (1 $)) :: int, 2 $) jako x, generate_series (floor (st_ymin (1 $)) :: int, ceiling (st_ymax (
aurel_nc
spójrz na moją szczegółową odpowiedź.
Muhammad Imran Siddique
Odpowiedzi:
30
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ć:
CREATEOR 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;
Może być konieczne dodanie st_setSRID () do funkcji st_point, w przeciwnym razie st_intersects nie działa.
JaakL
Dodałem moją przetestowaną wersję jako osobną odpowiedź.
JaakL
12
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:
CREATEOR 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;
Akceptowana odpowiedź nie działa z moimi danymi z powodu błędów SRID. Ta modyfikacja działa lepiej.
Vitaly Isaev
Możesz coś dodać, gdy wielokąt przecina antimeridian? Mogę sobie wyobrazić, że spowodowałoby to problem z xmin / xmax.
Thomas
2
Nie działało to dla mnie. Korzystanie z Postgres 9.6 i PostGIS 2.3.3. Wewnątrz wywołania generate_series musiałem umieścić to jako drugi parametr „pułap (st_xmax (1 $)) :: int” zamiast „pułap (st_xmax (1 $) -st_xmin (1 $)) :: int” i „pułap ( st_ymax (1 $)) :: int "zamiast" sufit (st_ymax (1 $) -st_ymin (1 $)) :: int "
Vitor Sapucaia
Popieram poprzedni komentarz; górna granica generowania_series powinna być pułapem maksimum, a nie pułapem różnicy (max - min).
R. Bourgeon,
10
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ę.
To sprytne obejście. Czy sprawdziłeś wyniki? Czy są spójne?
Pablo
Cześć. Tak pablo. Jak dotąd jestem zadowolony z wyników. Potrzebowałem go do zbudowania wielokąta o względnej wysokości nad ziemią. (Używam SRTM do obliczenia wysokości, którą chcę dla każdego punktu siatki). Obecnie brakuje mi tylko sposobu na uwzględnienie punktów leżących na obwodzie wielokąta. Obecnie renderowany kształt jest nieco obcięty na krawędzi.
Julien Garcia
działało, gdy wszystkie inne rozwiązania zawiodły, dzięki!
Proste i najlepsze podejście, wykorzystujące rzeczywistą odległość współrzędnych od ziemi w kierunku xiy. Algorytm działa z dowolnym SRID, wewnętrznie działa z WGS 1984 (EPSG: 4326) i przekształca wynik z powrotem na wejściowy SRID.
CREATEOR REPLACE FUNCTIONpublic.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;BEGINCASE st_srid(geom)WHEN0THEN
geom := ST_SetSRID(geom, srid);----RAISE NOTICE 'No SRID Found.';ELSE----RAISE NOTICE 'SRID Found.';ENDCASE;
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>>
LOOPIF(y > y_max)THENEXIT;ENDIF;CASE i WHEN0THEN
y := ST_Y(returnGeom[0]);ELSE
y := ST_Y(ST_Project(st_setsrid(ST_MakePoint(x, y), srid), y_side, radians(0))::geometry);ENDCASE;
x := x_min;<<xloop>>
LOOPIF(x > x_max)THENEXIT;ENDIF;
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.
Oddzielna zmienna dla kierunku xiy dla rozmiaru piksela,
Nowa zmienna do obliczania odległości w sferoidie lub elipsoidzie.
Wprowadź dowolny SRID, przekształć funkcję Geom w środowisko pracy sferoidy lub elipsoidy Datum, następnie zastosuj odległość z każdej strony, uzyskaj wynik i przekształć na wejściowy SRID.
CREATEOR 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
Cześć, otrzymuję pusty wynik z funkcją makegrid. Plik shapefile został zaimportowany do PostGIS przy użyciu shp2pgsql. Nie mam pojęcia, co może powodować problemy, srs jest ustawiony na wgs84.
Michal Zimmermann
3
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:
CREATEOR 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
CREATEOR 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
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ć:
Aby go użyć, możesz:
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:
HTH
Nicklas
źródło
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:
Aby użyć tej funkcji, należy wykonać dokładnie tak, jak napisał Nicklas Avén :
lub jeśli chcesz jeden punkt na rząd:
Mam nadzieję, że będzie to przydatne dla kogoś.
Alex
źródło
Od tego czasu osoby używające geometrii wgs84 prawdopodobnie będą miały problemy z tą funkcją
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:
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. ++
źródło
Ten algorytm powinien być w porządku:
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!
źródło
Trzy algorytmy wykorzystujące różne metody.
Github Repo Link
Funkcja ================================================= ==================
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 ================================================= ==================
Użyj go za pomocą prostego zapytania.
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
Wynik ================================================= ==================
Funkcja ================================================= =================
Użyj go za pomocą prostego zapytania.
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
Wynik ================================================= =========================źródło
Więc moja stała wersja:
Stosowanie:
źródło
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:
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ść:
Z
mod(grid_size::integer/2,grid_precision)
Oto funkcja postgres:
Można stosować z:
źródło
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
źródło