Funções PostGIS #3
Boa tarde pessoal!
Vamos falar um pouco hoje das funções de análise espacial e medições. Antes disso, o blog alcançou +50 postagens essa semana. Parabéns para nós!
ST_Area()
Esta função é bastante simples. Ela retorna a área de um polígono ou multipolígono.
-- assinatura
-- SELECT ST_Area(geometria)
SELECT ST_Area(
ST_GeomFromText(('POLYGON((0 0, 1 0,1 1,0 1,0 0))')))
ST_Perimeter()
Outra função bastante simples, de um único argumento. O argumento deve ser uma geometria do tipo polígono. Se você passar uma LINESTRING, o PostGIS irá retornar 0. Veja ST_Length() para LINESTRINGs.
-- assinatura
-- SELECT ST_Area(geometria)
SELECT ST_Perimeter(
ST_GeomFromText(('POLYGON((0 0, 1 0,1 1,0 1,0 0))')));
-- só funciona com polígonos. user ST_Length()
SELECT ST_Perimeter(
ST_GeomFromText('LINESTRING(0 0, 1 0, 2 1, 2 2, 3 2)'));
ST_Perimeter2D()
Calcula o perímetro considerando apenas as coordenadas X e Y de um polígono.
-- assinatura
-- SELECT ST_Perimeter2D(geometria)
-- note que nosso polígono é 3D, possui Z.
SELECT ST_Perimeter2D(
ST_GeomFromText(('POLYGON((0 0 1, 1 0 1,1 1 2,0 1 3,0 0 1))')));
ST_Perimeter3D()
Calcula o perímetro de um polígono levando em conta as coordenadas Z. Veja que nosso polígono anterior, com a coordenada Z, ST_Perimeter3D() nos dá um retorno diferente.
-- assinatura
-- SELECT ST_Perimeter3D(geometria)
-- note que o polígono é 3D, possui Z.
SELECT ST_Perimeter3d(
ST_GeomFromText(('POLYGON((0 0 1, 1 0 1,1 1 2,0 1 3,0 0 1))')));
ST_Length()
Calcula o comprimento de uma LINESTRING. Simples e direto
. Esta função calcula o comprimento de uma linha em duas dimensões.
-- assinatura
-- SELECT ST_Length(geometria)
SELECT ST_Length(
ST_GeomFromText('LINESTRING(0 0, 1 0, 2 1, 3 3)'));
ST_Length2D()
Exatamente igual à função acima. É apenas um apelido para ST_Length().
ST_Length3D()
Esta função funciona exatamente como ST_Perimeter3D. Mas para LINESTRINGs. Esta função leva em conta as coordenadas no eixo Z de uma geometria.
-- assinatura
-- SELECT ST_Length3D(geometria)
SELECT ST_Length3D(
ST_GeomFromText('LINESTRING(0 0 1, 0 0 0, 1 0 2, 2 3 1)'));
ST_Centroid()
Esta função calcula o centro de massa de uma geometria. Para pontos é apenas uma média aritmética de seus conjuntos de coordenadas. Para LINESTRINGS, é o resultado de uma média ponderada do comprimento de seus segmentos e para polígonos o centro de massa do mesmo.
É possível aplicar esta função em qualquer tipo de geometria e em coleções genéricas (GEOMETRY_COLLECTIONs - conjuntos de geometrias de diversos tipos), sendo o resultado equivalente ao centróide do conjunto de geometrias de maior dimensionalidade (pontos são 0-dimensionais, linhas unidimensionais, polígonos bidimensionais). Ou seja, se temos um conjunto de pontos, linhas e polígonos, o centróide será igual ao centróide do conjunto de polígonos.
Esta função é importante. Diversas vezes a maneira mais prática e fácil de se transformar dados é através do centróide e preparar dados para estatísticas espaciais.
-- assinatura
-- SELECT ST_Centroid(geometria)
SELECT ST_AsText(
ST_CENTROID(
ST_GeomFromText('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))')));
SELECT ST_AsText(
ST_CENTROID(
ST_GeomFromText('LINESTRING(0 0, 1 0, 1 1)')));
SELECT ST_AsText(
ST_CENTROID(
ST_GeomFromText('MULTIPOINT((0 0),(5 8),(10 1))')));
Aqui estão os resultados das chamadas acima.
ST_Intersects()
Outra função importante. Esta função simplesmente teste se geometria A interseciona geometria B. Esta função não retorna a real interseção das duas partes, mas somente se elas se intersecionam ou não, true ou false. ST_Intersects pode ser utilizado com qualquer par de geometrias.
-- assinatura
-- SELECT ST_Intersercts(geometria_A,geometria_B);
-- retorna true
SELECT ST_Intersects(
ST_GeomFromText('POLYGON((0 0, 1 1, 1 0, 0 1, 0 0))'),ST_GeomFromText('LINESTRING(0 0, 2 2, 1 1)'));
-- retorna false
SELECT ST_Intersects(
ST_GeomFromText('POLYGON((0 0, 1 1, 1 0, 0 1, 0 0))'),ST_GeomFromText('LINESTRING(10 10, 20 10)'));
ST_Intersection()
Esta função é parecida com a ST_Intersects, mas esta retorna de fato a interseção entre as duas geometrias. Ambas as funções são computacionalmente intensivas, portanto cuidado ao utilizá-la em um sistema em produção, em views e outras coisas deste tipo. Esta função tem uma particularidade: podemos usar como parametro qualquer tipo de geometria, mas o resultado sempre virá no formato de geometria com menor dimensionalidade.
Exemplo: se computarmos a interseção entre dois polígonos, teremos como resultado um polígono (ou nulo). Se computarmos a interseção entre um polígono e diversas linhas, o resultado será uma LINESTRING obrigatoriamente. Porque? É matemático, a interseção de um polígono com um ponto sempre terá como resultado um ponto. Os resultados estão em verde.
Veja:
Podemos ter como resultado da interseção entre duas LINESTRINGs um conjunto de pontos ou uma LINESTRING (quando dois segmentos são coincidentes).
Vamos à assinatura da função:
-- assinatura
-- SELECT ST_Intersection(geometria_A,geometria_B);
-- POLYGON e LINESTRING
SELECT ST_AsText(ST_Intersection(
ST_GeomFromText('POLYGON((0 0,1 0, 1 1,0 1,0 0))'),
ST_GeomFromText('LINESTRING(0 0,.5 .5,2 2,3 3)')));
-- POLYGON E PONTO
SELECT ST_AsText(ST_Intersection(
ST_GeomFromText('POLYGON((0 0,1 0, 1 1,0 1,0 0))'),
ST_GeomFromText('POINT(.2 .2)')))
-- POLYGON e POLYGON
SELECT ST_AsText(ST_Intersection(
ST_GeomFromText('POLYGON((0 0,1 0, 1 1,0 1,0 0))'),
ST_GeomFromText('POLYGON((.5 .5,1.5 .5,1.5 1.5,.5 1.5,.5 .5))')))
-- LINESTRING e LINESTRING
SELECT ST_AsText(ST_Intersection(
ST_GeomFromText('LINESTRING(0 0,1 1,3 2,6 6)'),
ST_GeomFromText('LINESTRING(-1 -1,.5 .5,3 4,5 6)')))
Os resultados em formato texto são os seguintes:
Uma nota importante: pontos não se intersecionam. Ou eles são coincidentes ou não.
ST_Overlaps
Esta função é parecida em funcionamento com a ST_Intersects. Na verdade ela realiza a mesma operação que ST_Intersects, mas leva em consideração se um objeto não está contido plenamente dentro do outro. Esta função opera com qualquer tipo de geometria, mas presta atenção na dimensionalidade de cada uma: uma geometria de menor dimensionalidade está sempre contida na geometria de maior dimensionalidade, portanto, não sobrepõe a de maior dimensionalidade.
Exemplo: geometria_a é um ponto e geometria_b é um polígono. Se perguntado se ST_Overlaps(geometria_a,geometria_b), o PostGIS vai retornar falso, pois não são da mesma dimensionalidade. Se geometria_a é um polígono e geometria_b também, a operação pode retornar verdadeiro, caso a sobreposição ocorra.
-- assinatura
-- SELECT ST_Overlaps(geometria_a,geometria_b)
-- [1]
-- mesma dimensionalidade: estas geometrias podem se sobrepor.
SELECT ST_Overlaps(
ST_GeomFromText('LINESTRING(0 0,1 1,3 2,6 6)'),
ST_GeomFromText('LINESTRING(-1 -1,.5 .5,3 4,5 6)'))
-- [2]
-- mesma dimensionalidade: estas geometrias podem se sobrepor.
SELECT ST_Overlaps(
ST_GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))'),
ST_GeomFromText('POLYGON((.5 .5,1.5 .5,1.5 1.5,.5 1.5,.5 .5))'))
-- [3]
-- dimensionalidade diferente: estas geometrias não podem se sobrepor (mesmo que se intersecionem)
SELECT ST_Overlaps(
ST_GeomFromText('LINESTRING(0 0,1 1,3 2,6 6)'),
ST_GeomFromText('POINT(0 0)'));
-- [4]
-- dimensionalidade diferente: estas geometrias não podem se sobrepor (mesmo que se intersecionem)
SELECT ST_Overlaps(
ST_GeomFromText('POLYGON((0 0,1 0,1 1,0 1,0 0))'),
ST_GeomFromText('POINT(0 0)'));
ST_Covers()
Esta função retorna verdadeiro caso nenhum ponto da geometria_b se encontre fora da geometria_a.
-- assinatura
-- SELECT ST_Covers(geometria_a,geomtria_b);
-- geometria_a cobre geometria_b? verdadeiro
SELECT ST_Covers(
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'),
ST_GeomFromText('POLYGON((.5 .5,1.5 .5,1.5 1.5,.5 1.5,.5 .5))'));
-- geometria_a cobre geometria_b? verdadeiro, todos os pontos de geometria_b estão contidos em a
SELECT ST_Covers(
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'),
ST_GeomFromText('POINT(1 1)'));
-- geometria_a cobre geometria_b? falso. geometria_a é menor que geometria_a.
SELECT ST_Covers(
ST_GeomFromText('POLYGON((.5 .5,1.5 .5,1.5 1.5,.5 1.5,.5 .5))'),
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'));
-- geometria_a cobre geometria_b? falso. geometria_a cobre geometria_b parcialmente (note o segundo ponto, em 100 100)
SELECT ST_Covers(
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'),
ST_GeomFromText('MULTIPOINT((1 1),(100 100))'));
ST_Within()
Esta função é similar em funcionamento à ST_Covers(). A diferença aqui é que esta retorna positivo se estiver completamente dentro de B.
-- assinatura
-- SELECT ST_Within(geometria_a,geometria_b)
-- [1]
-- geometria_a está completamente dentro de geometria_b? verdadeiro
SELECT ST_Within(
ST_GeomFromText('POINT(5 5)'),
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'));
-- [2]
-- geometria_a está completamente dentro de geometria_b? verdadeiro
SELECT ST_Within(
ST_GeomFromText('LINESTRING(5 5, 2 3, 1 0)'),
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'));
-- [3]
-- geometria_a está completamente dentro de geometria_b? verdadeiro
SELECT ST_Within(
ST_GeomFromText('POLYGON((1 1,2 1,2 2,1 2,1 1))'),
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'));
-- [4]
-- geometria_a está completamente dentro de geometria_b? falso. geometrias de dimensionalidade menor não contém geometrias de maior
-- dimensionalidade
SELECT ST_Within(
ST_GeomFromText('POLYGON((1 1,2 1,2 2,1 2,1 1))'),
ST_GeomFromText('MULTIPOINT((0 0),(10 0),(10 10),(0 10),(0 0))'));
-- [5]
-- geometria_a está completamente dentro de geometria_b? falso. A não está inteiramente dentro de B
SELECT ST_Within(
ST_GeomFromText('MULTIPOINT((5 5),(100 100))'),
ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'));
Por agora é só pessoal. No próximo post vou tentar explicar melhor sobre a dimensionalidade de cada tipo de geometria e os porquês estas funções se comportam desta maneira.
Espero que tenham gostado.
Abraços
Related posts:

















May 25th, 2010 - 23:04
Muito bom George, como sempre. Algumas dessas funções eu nem lembrava que existia
Abraço e parabéns.
[Translate]
May 26th, 2010 - 02:20
Obrigado Anderson,
Como sempre tentamos o melhor.
Obrigado pela visita e comentário.
[Translate]