Tentei fazer polígonos de recorte mesclando esse código com o código de dados "postGIS in action", mas apenas um polígono é criado ... Esqueci alguma coisa? CRIAR OU SUBSTITUIR FUNÇÃO makegrid (geometria, número inteiro, número inteiro) RETORNA a geometria AS 'SELECT st_intersection (g1.geom1, g2.geom2) AS geom FROM (SELECIONE $ 1 AS geom1) AS g1 INNER JOIN (Selecione st_setsrid (CAST (ST_Makeid2) (st_setsrid (CAST (ST_MakeBox2d (st_setsrid) ST_Point (x, y), $ 3), st_setsrid (ST_Point (x + $ 2, y + $ 2), $ 3)) como geometria), $ 3) como geom2 FROM generate_series (floor (st_xmin ($ 1)) :: int, ceiling ( st_xmax ($ 1)) :: int, $ 2) como x, generate_series (floor (st_ymin ($ 1)) :: int, teto (st_ymax (
aurel_nc
veja minha resposta detalhada.
Muhammad Imran Siddique 27/03
Respostas:
30
Você faz isso com generate_series.
Se você não deseja escrever manualmente onde a grade deve iniciar e parar, o mais fácil é criar uma função.
Não testei o abaixo corretamente, mas acho que deve funcionar:
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
Para usá-lo, você pode fazer:
SELECT makegrid(the_geom,1000)from mytable;
onde o primeiro argumento é o polígono em que você deseja inserir a grade e o segundo argumento é a distância entre os pontos na grade.
Se você quer um ponto por linha, basta usar ST_Dump como:
SELECT(ST_Dump(makegrid(the_geom,1000))).geom as the_geom from mytable;
Pode ser necessário adicionar st_setSRID () às funções st_point, caso contrário, st_intersects não funcionará.
JaakL
Adicionado minha versão testada como resposta separada.
JaakL
12
Eu peguei Nicklas Aven código de função makegrid e fez dele um pouco mais genérico, lendo e usando a srid da geometria de polígono. Caso contrário, usar um polígono com um srid definido causaria um erro.
A função:
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
Para usar a função é feito exatamente como Nicklas Avén escreveu:
SELECT makegrid(the_geom,1000)from mytable;
ou se você quiser um ponto por linha:
SELECT(ST_Dump(makegrid(the_geom,1000))).geom as the_geom from mytable;
A resposta aceita não funciona com meus dados devido a erros SRID. Essa modificação funciona melhor.
precisa
Você pode adicionar algo quando o polígono estiver cruzando o antimeridiano? Eu posso imaginar que causaria um problema com xmin / xmax.
Thomas
2
Não funcionou para mim. Usando o Postgres 9.6 e o PostGIS 2.3.3. Dentro da chamada generate_series, tive que colocar isso como o segundo parâmetro "ceiling (st_xmax ($ 1)) :: int" em vez de "ceiling (st_xmax ($ 1) -st_xmin ($ 1)) :: int" e "ceiling ( st_ymax ($ 1)) :: int "em vez de" teto (st_ymax ($ 1) -st_ymin ($ 1)) :: int "
Vitor Sapucaia
Eu aprovo o comentário anterior; o limite superior de generate_series deve ser o teto do máximo, e não o teto da diferença (max - min).
R. Bourgeon
10
Pessoas que usam uma geometria wgs84 provavelmente terão problemas com essa função, pois
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
retornam apenas números inteiros. Exceto por geometrias muito grandes, como países (que estão em vários graus de lat, lng), isso fará com que você colete apenas 1 ponto, que na maioria das vezes nem sequer cruza a própria geometria ... => resultado vazio!
Meu problema foi que parece que não consigo usar generate_series () com uma distância decimal em números flutuantes como os WSG84 ... É por isso que aprimorei a função para fazê-la funcionar de qualquer maneira:
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)))
Basicamente exatamente o mesmo. Apenas multiplicando e dividindo por 1000000 para obter as casas decimais no jogo quando eu precisar.
Certamente há uma solução melhor para conseguir isso. ++
Essa é uma solução inteligente. Você verificou os resultados? Eles são consistentes?
21413 Pablo
Oi. Sim Pablo. Estou feliz com os resultados até agora. Eu precisava construir um polígono com altitude relativa acima do solo. (Eu uso o SRTM para calcular a altitude desejada para cada ponto da grade). Agora estou perdendo apenas uma maneira de incluir os pontos que estão no perímetro do polígono também. Atualmente, a forma renderizada é um pouco truncada na borda.
Julien Garcia
funcionou, quando todas as soluções dos outros falharam, obrigado!
A abordagem simples e melhor, usando a distância real da terra das coordenadas da direção xey. O algoritmo funciona com qualquer SRID, internamente, funciona com o WGS 1984 (EPSG: 4326) e a transformação do resultado volta para a entrada do SRID.
Segunda função baseada no algoritmo Nicklas Avén . Eu o aprimorei para lidar com qualquer SRID.
atualize as seguintes alterações no algoritmo.
Variável separada para direção x e y para tamanho de pixel,
Nova variável para calcular a distância em esferóide ou elipsóide.
Insira qualquer SRID, função transforme Geom no ambiente de trabalho do Spheroid ou Ellipsoid Datum, aplique a distância em cada lado, obtenha o resultado e transforme na entrada 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
Uso:
SELECT(ST_Dump(makegrid(the_geom,1000,3857))).geom as the_geom from my_polygon_table
Oi, eu recebo resultado vazio com a função Makegrid. O shapefile foi importado para o PostGIS usando shp2pgsql. Não tem idéia do que pode estar causando problemas, o srs está definido como wgs84.
precisa
3
Aqui está outra abordagem que é certamente mais rápida e fácil de entender.
Por exemplo, para uma grade de 1000m por 1000m:
SELECT(ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0))).geom FROM the_polygon
Além disso, o SRID original é preservado.
Esse trecho converte a geometria do polígono em uma varredura vazia e, em seguida, converte cada pixel em um ponto. Vantagem: não precisamos verificar novamente se o polígono original cruza os pontos.
Opcional:
Você também pode adicionar o alinhamento da grade com o parâmetro gridx e gridy. Mas como usamos o centróide de cada pixel (e não um canto), precisamos usar um módulo para calcular o valor certo:
SELECT(ST_PixelAsCentroids(ST_AsRaster(the_geom,1000.0,1000.0,mod(1000/2,100),mod(1000/2,100)))).geom FROM the_polygon
Com mod(grid_size::integer/2,grid_precision)
Aqui está a função 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;
Canbe usado com:
SELECT makegrid(the_geom,1000.0,100)as geom from the_polygon -- makegrid(the_geom,grid_size,alignement)
Uma pequena atualização em potencial para as respostas anteriores - terceiro argumento como escala para wgs84 (ou use 1 para as normais) e também arredondando dentro do código para que os pontos dimensionados em várias formas estejam alinhados.
Espero que isso ajude, 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
Respostas:
Você faz isso com generate_series.
Se você não deseja escrever manualmente onde a grade deve iniciar e parar, o mais fácil é criar uma função.
Não testei o abaixo corretamente, mas acho que deve funcionar:
Para usá-lo, você pode fazer:
onde o primeiro argumento é o polígono em que você deseja inserir a grade e o segundo argumento é a distância entre os pontos na grade.
Se você quer um ponto por linha, basta usar ST_Dump como:
HTH
Nicklas
fonte
Eu peguei Nicklas Aven código de função makegrid e fez dele um pouco mais genérico, lendo e usando a srid da geometria de polígono. Caso contrário, usar um polígono com um srid definido causaria um erro.
A função:
Para usar a função é feito exatamente como Nicklas Avén escreveu:
ou se você quiser um ponto por linha:
Espero que isso seja útil para alguém.
Alex
fonte
Pessoas que usam uma geometria wgs84 provavelmente terão problemas com essa função, pois
retornam apenas números inteiros. Exceto por geometrias muito grandes, como países (que estão em vários graus de lat, lng), isso fará com que você colete apenas 1 ponto, que na maioria das vezes nem sequer cruza a própria geometria ... => resultado vazio!
Meu problema foi que parece que não consigo usar generate_series () com uma distância decimal em números flutuantes como os WSG84 ... É por isso que aprimorei a função para fazê-la funcionar de qualquer maneira:
Basicamente exatamente o mesmo. Apenas multiplicando e dividindo por 1000000 para obter as casas decimais no jogo quando eu precisar.
Certamente há uma solução melhor para conseguir isso. ++
fonte
Este algoritmo deve estar bem:
onde 'polígono' é o polígono e 'resolução' é a resolução de grade necessária.
Para implementá-lo no PostGIS, as seguintes funções podem ser necessárias:
Boa sorte!
fonte
Três algoritmos usando métodos diferentes.
Link para repositório do Github
Função =================================================== ==================
Use a função com uma consulta simples, a geometria deve ser válida e o tipo de polígono, multi-polígonos ou envelope
SELECT I_Grid_Point_Distance(geom, 50, 61) from polygons limit 1;
Resultado =================================================== =====================
Segunda função baseada no algoritmo Nicklas Avén . Eu o aprimorei para lidar com qualquer SRID.
atualize as seguintes alterações no algoritmo.
Função =================================================== ==================
Use-o com uma consulta simples.
SELECT I_Grid_Point(geom, 22, 15, false) from polygons;
Resultado =================================================== ==================
Função =================================================== =================
Use-o com uma consulta simples.
SELECT I_Grid_Point_Series(geom, 22, 15, false) from polygons;
Resultado =================================================== =========================fonte
Então, minha versão fixa:
Uso:
fonte
Aqui está outra abordagem que é certamente mais rápida e fácil de entender.
Por exemplo, para uma grade de 1000m por 1000m:
Além disso, o SRID original é preservado.
Esse trecho converte a geometria do polígono em uma varredura vazia e, em seguida, converte cada pixel em um ponto. Vantagem: não precisamos verificar novamente se o polígono original cruza os pontos.
Opcional:
Você também pode adicionar o alinhamento da grade com o parâmetro gridx e gridy. Mas como usamos o centróide de cada pixel (e não um canto), precisamos usar um módulo para calcular o valor certo:
Com
mod(grid_size::integer/2,grid_precision)
Aqui está a função postgres:
Canbe usado com:
fonte
Uma pequena atualização em potencial para as respostas anteriores - terceiro argumento como escala para wgs84 (ou use 1 para as normais) e também arredondando dentro do código para que os pontos dimensionados em várias formas estejam alinhados.
Espero que isso ajude, Martin
fonte