Blog Geo.NET Geoprocessamento, SIG e Sensoriamento Remoto

4ago/101

Construindo funcionalidades para o WKT Raster

No post anterior, falamos um pouquinho sobre como o WKT Raster funciona. Hoje gostaria de mostrar um pouquinho sobre as maquinações que ando desenvolvendo para o PostGIS e WKT Raster.

Em tese, se o raster está armazenado no banco e conseguimos determinar o valor de cada pixel, poderíamos usar a SQL para realizar álgebra de mapas? A resposta é sim, podemos. É claro, já existem softwares especializados em realizar álgebra de mapas, como o IDRISI, ENVI, SPRING, ArcGIS (com Spatial Analyst), o módulo Sextante do gvSIG, WhiteBox, entre outros.

A vantagem de fazermos isto no PostGIS é que podemos aproveitar de algumas funcionalidades do banco de dados para realizar atualizações automáticas (funciona, mas a perfomance não deve ser das melhores), controlar melhor o acesso aos rasters - centralizando tudo em uma única localização, backup, etc.

Existem diversas funções para análise espacial de rasters, incluindo as matemáticas, lógicas, entre outras. Hoje irei mostrar apenas algumas matemáticas, que são bem simples. O módulo WKT Raster já planeja construir em C (linguagem nativa do PostgreSQL) algumas funções para análise espacial, mas enquanto isto não acontece, vamos levando com estas aqui.

Importante: estas funções só operam com rasters de uma única banda. Todas as operações são realizadas na banda 1. Nenhuma operação é realizada na banda 2 ou 3 - se bem que o suporte para tal é simples de ser construído.

Cuidado ao utilizar estas funções. Caso você sobreescreva seu raster, não o conseguirá de volta - caso precise.

ST_Plus

Esta função adiciona um valor double precision ao nosso raster de interesse. Se o pixel tem valor 1 e nosso argumento é 1, o resultado daquele pixel será 2. Esta função tem como entrada um raster e um valor numérico. O retorno da função é um objeto raster completo.

CREATE OR REPLACE FUNCTION ST_Plus(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 + z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

A função é bem simples. Ela copia o raster original em memória e adiciona o valor à cada pixel. Sem segredos. Como usá-la? Recomendo primeiramente, duplicar sua coluna do tipo raster, pois a função de adição de colunas raster é bastante longa e com parâmetros meio obscuros. Procure o arquivo SQL gerado pelo gdal2wktraster e ache a linha que adiciona a coluna. Modifique o nome da coluna e execute este comando novamente. Depois disso popule a coluna com os novos valores.

SELECT AddRasterColumn('public','teste_raster','grid_stplus',-1, ARRAY['16BUI'], false,
       true, null, 0.000833, -0.000833, 9, 9,
           ST_Envelope(
               ST_SetSRID('POLYGON((-49.500416 -18.000416,-49.500416 -19.000416,-48.000416 -18.000416,-48.000416 -19.000416,-49.500416 -18.000416))'::geometry, -1)));

UPDATE teste_raster SET grid_stplus = ST_Plus('nome_da_coluna_raster_original',10);

Faça um teste com ST_Value para identificar se tudo correu bem. Neste teste, somamos 10 unidades ao valor de cada pixel da coluna original raster. Por que estamos criando uma coluna extra para armazenar nosso novo raster? Se alterarmos o raster original, não conseguiremos ele de volta, portanto, cuidado ao utilizar as funções.

ST_Minus

De forma similar à ST_Plus, ST_Minus vai subtrair determinado valor de cada pixel de nosso raster e nos trará como resultado o raster modificado.

CREATE OR REPLACE FUNCTION ST_Minus(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 - z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

Recomendo testar da mesma maneira que a função anterior. O uso é o mesmo - modificando o nome da função.

ST_Plus

Esta função realiza a multiplicação do valor do pixel. Simples e direta.

CREATE OR REPLACE FUNCTION ST_Times(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 * z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

Use-a do mesmo jeito que as anteriores.

ST_Divide

CREATE OR REPLACE FUNCTION ST_Divide(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN
	if (z = 0) then
		return p_grid;
	end if;

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			z1 := ST_Value(p_grid,i,j);
			grid := st_setvalue(grid,1,i,j,z1 / z);

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

ST_Power

Esta função eleva o valor da célula ao valor passado como parâmetro na função. Se temos uma célula de valor 2, e passamos 2 como parâmetro, teremos o 4 como resultado (2^2);

CREATE OR REPLACE FUNCTION ST_Power(p_grid raster, z double precision)
	RETURNS raster AS
$$
DECLARE
	w integer;
	h integer;
	z1 integer;

	grid raster;
BEGIN

	SELECT
		ST_Width(p_grid),
		ST_Height(p_grid)
	 into w,h;

	-- realizar cópia do raster original
	grid := p_grid;

	for i in 1..h loop
		for j in 1..w loop

			-- selecting cell value
			if z = 0 then
				grid := st_setvalue(grid,1,i,j,1);
			else
				z1 := st_value(p_grid,i,j);
				grid := st_setvalue(grid,1,i,j,z1 ^ z);
			end if;

		end loop;
	end loop;

	return grid;
END
$$
language 'plpgsql';

E assim podemos construir funções que alterem nossos rasters originais. São funções simples, praticamente demonstrativas. Na sequência demonstraremos algumas funções mais interessantes, como declividade, cálculo de fluxo de direção, identificação de depressões, eliminação de depressões, entre outras.

Um abraço,

George R. C. Silva

Compartilhe:
31jul/104

PostGIS WKT Raster

Buenas pessoal,

Como estão as coisas? Hoje vamos conversar um pouquinho sobre o WKT Raster.

O WKT Raster é um projeto para implementar suporte aos famosos grids, rasters, imagens ao PostGIS. WKT vem de Well Known Text (algo como "texto bem conhecido").

O projeto já tem código compilado e funcionando e tomei a semana para testá-lo de acordo. A implementação veio da especificação desenvolvida por Pierre Racine. O projeto tem como objetivo integrar-se perfeitamente ao engine do PostGIS já existente, sendo possível executar operações espaciais / álgebra de mapas, carregar rasters multi-bandas, entre outras coisas deliciosas.

Este projeto é muito interessante, pois podemos armazenar os rasters dentro do banco de dados, garantindo ou excluindo acesso à quem realmente precisa, ao invés de ficarmos com milhares de cópias por aí (imagine um escritório com 20 analistas GIS - qual é quantidade de informações duplicadas), sem saber ao certo qual é a mais atual ou com melhor qualidade - enfim, nos garante todas as vantagens do armazenamento centralizado em banco de dados. Não necessariamente precisamos armazenar os dados no PostgreSQL, podemos deixá-los em HD e adicionar somente os metadados e acessá-los da mesma forma, caso você esteja preocupado com disco ;) . Em suma, é demais!

Vamos comentar com instalar essa belezinha no seu PostgreSQL - em Windows XP. Linux users, sorry.

Pré-requisitos

Sempre existem né?

  • PostgreSQL/PostGIS instalado. O PostGIS deve 1.4 ou maior, determinando também a versão do PostgreSQL: 8.3 ou maior;
  • Python;
  • GDAL/python;
  • WKT Raster;

Instalação

1) Instale o Python, 2.5 ou 2.6. Estou usando o 2.5, que foi instalado junto com o ArcGIS. Portanto, se você tem esta instação específica, não se preocupe. Esta instalação é bem simples. Dois cliques, pá pum, está instalado.

2) Instale os GDAL bindings. Para fazer isso é só descompactar a pasta zipada e colocá-la no diretório que mais lhe agradar. Coloquei a minha pasta (gdalwin32-1.6) no diretório C:\.

2.1) Vá em Painel de Controle > Sistema > Avançado > Variáveis de Ambiente. Procure a variável PATH. Ela é composta de vários diretórios separados por um ponto-e-vírgula, correto? Adicione o diretório C:\gdalwin32-1.6\bin nesta listinha e adicione um ; no final. Claro, se você pos a pasta do gdal em outro diretório, faça as alterações pertinentes.

2.2 ) Ainda em variáveis de ambiente, adicione uma nova variável, chamada GDAL_DATA e adicione o caminho C:\gdalwin32-1.6\data como caminho. Como esta variável de ambiente é usada somente pelo GDAL, não se preocupe em colocar o ;. Mas se colocar também não faz mal. Dê OK para salvar as variáveis de ambiente. Os bindings do GDAL para Python já estão instalados. Você pode acessá-los e utilizar o GDAL para um monte de coisas, como converter coordenadas de rasters, reprojetá-los, etc. tudo usando uma linha de comando.

3) Descompacte o pacote do WKT Raster.

3.1) Copie o arquivo rtpostgis.dll para a pasta lib do PostgreSQL. Geralmente é algo como C:\Program Files\PostgreSQL\8.x\lib;

3.2) Copie os arquivos gdal2wktraster.py e libgdal.dll para a pasta bin da sua instalação do PostgreSQL. Fácil né?

3.3) Vamos instalar os comandos e funções do Wkt Raster no nosso banco agora. Abra o PgAdmin3 ou o console sql do Postgres e conecte-se ao banco de dados alvo. Feito isso, rode os comandos que se encontram na pasta share\contrib\ do pacote WktRaster. Feito isso, teste se o WKT Raster está funcionando apropriadamente usando o comando SQL:

SELECT postgis_raster_lib_build_date(),postgis_raster_lib_version();

Caso o comando tenha sucesso, tudo foi instalado com sucesso.

A instalação termina aqui. Mas como carregar um raster para dentro de nosso banco de dados? Podemos utilizar a ferramenta em Python desenvolvida para este propósito, o script gdal2wktraster.py

Carregar um raster para o banco de dados

Esta ferramenta é uma aplicação em linha de comando, bastante fácil de utilizar. O resultado dela é um script .sql que você pode rodar pelo console sql ou pelo PgAdmin3.

Abra um console DOS e digite:

python "CaminhoParaOArquivo\gdal2wktraster.py" --help

Isto lhe deve dar todas as opções da ferramenta.

Algumas:

  • -t nome da tabela à ser criada no PostGIS, e.g. -t teste_raster;
  • -o nome do arquivo de saída, e.g. -o srtm.sql;
  • -k especifica o tamanho tile. Esta opção é muito importante, pois divide seu raster original em diversos registros cada um com este tamanho, em pixels. e.g. -k 90x90; Caso você não utilize esta opção, seu raster original ocupará apenas um único registro da tabela. Se você utilizá-la, você diz ao PostGIS: pegue este raster, fatie-o em pedaços de tal tamanho e insira-os nesta tabela!
  • -f especifica o nome da coluna do tipo raster. e.g. -f grid;
  • -r esta é a opção mais importante de todas, com ela especificamos o arquivo original à ser carregado. e.g. -r "CaminhoDoArquivoRaster\arquivo.tif";

Exemplo de um comando completo

C:\Python25\python.exe "C:\Program Files\PostgreSQL\8.3\bin\gdal2wktraster.py" - r "C:\srtm.tif" -k 90x90 -f grid -t srtm -o srtm.sql

Esta ferramenta é bem fácil de utilizar e gera um SQL limpinho, só faltando rodá-lo dentro do banco de dados.

Estou desenvolvendo algumas ferramentinhas de análise espacial, em especial ferramentas para extração automática de feições - algumas já estão prontas, outras ainda no forno, mas logo logo falo sobre elas! Esta é a página oficial do WKT Raster.

O que acharam?

Abraços!

George R. C. Silva

Compartilhe:
7jul/101

Usando Python e o geoprocessing framework #2

Boa tarde pessoal!

Continuando naquele nosso projetinho, hoje vamos falar sobre a classe em Python que atualiza nossos dados em um determinado banco de dados. Temos algumas particularidades quando trabalhamos com ArcSDE, (registro de camadas como versionadas/não versionadas), portanto mostrarei como trabalhar com um Geodatabase local. A alteração para ArcSDE não é tão grande, e com um cadinho de pesquisa vocês conseguem fazer.

Lembre-se das outras classes que precisamos, mostradas no post anterior.

Construiremos duas classes, uma chamada GeoprocessorWrapper, um "embrulho" do objeto geoprocessor da ESRI. Isto não necessário, mas facilita, já que facilitamos algumas operações através deste "embrulho". A outra será uma tarefa, que juntará todos os dados e resultados das classes anteriores para atualizar nosso banco de dados.

Vamos começar com a mais simples, geoprocessorWrapper:

import arcgisscripting, logHandler

__toolboxAliases = [
            "analysis",
            "management",
            "3d",
            "cartography",
            "arc",
            "interop",
            "geocoding",
            "ga",
            "lr",
            "md",
            "na",
            "samples",
            "sa",
            "stats"]

class geoprocessorWrapperClass():
    def __init__(self,workspace,toolboxList,overwriteOutput=False):
        self.logs = logHandler.logHandlerClass()
        # Startup logging object
        self.gp = arcgisscripting.create(9.3)
        # Startup ESRI geoprocessing object

        self.gp.Workspace = workspace
        self.gp.OverwriteOutput = overwriteOutput
        # Define overwrite output. Default is to FALSE.

        #lista de toolboxes disponiveis
        self.toolboxList = []
        self.toolboxList += toolboxList

        self.buildGeoprocessorOptions(toolboxList)

    def buildGeoprocessorOptions(self):
        for x in self.toolboxList:
            try:
                if x in __toolboxAliases:
                    self.gp.AddToolbox(x)
            except:
                self.logs.newLogMessage(self, "Error in adding " + x + " toolbox to geoprocessor object. Are you sure this toolbox exists?" + self.gp.GetMessages(), "Geoprocessing Error")
    # adds all toolboxes to current geoprocessing object.

    def changeWorkspace(self,workspace):
        self.gp.Workspace = workspace;
    # changes the current workspace in geoprocessing object

    def removeToolboxes(self,toolboxList):
        for x in self.toolboxList:
            try:
                self.gp.RemoveToolbox(x)
                self.toolboxList.remove(x)
                self.logs.newLogMessage(self,"Removed " + x + "toolbox from geoprocessing object.","Information")
            except:
                self.logs.newLogMessage(self,self.gp.GetMessages(),"Geoprocessing Error")
    # removes unneeded toolboxes from current geoprocessing object

Vamos começar com alguns detalhes desta classe:

Em primeiro lugar, temos os tradicionais import x. Eles são responsáveis por disponibilizar outras bibliotecas ao nosso código. Note que importamos o módulo arcgisscripting.

Logo depois, temos uma lista dos aliases que cada toolbox possui no Python. É necessário adicionar uma toolbox ao objeto geoprocessing para que se tenha acesso às ferramentas da mesma - o que pode ser feito de dois jeitos, pelo caminho da toolbox (C:\Program Files\...\ArcGis\Toolbox.tbx) ou pelo seu apelido. A primeira maneira é útil para adicionar toolboxes customizadas, que não tem apelido. A segunda maneira é mais prática para adicionar as toolboxes tradicionais.

O construtor da classe toma dois parâmetros obrigatórios e um opcional para inicializar a classe. O workspace é a pasta onde iremos trabalhar - ele poderia ser também um geodatabase, mas neste caso, uma pasta. toolboxList é uma lista com os apelidos das toolboxes que queremos adicionar ao nosso objeto de geoprocessing. O parâmetro adicional é se você deseja que os resultados do objeto geoprocessing sejam escritos por cima dos anteriores (caso tenham o mesmo nome) e é por default, falso.

O construtor é bastante simples. Ele cria um objeto geoprocessing, utilizando a versão 9.3 como opção (ajuste para sua versão caso necessário - mas não garanto que funcione na 9.2 - já que vários métodos como ListDatasets, têm uma resposta diferente do que
na versão 9.3), define qual é o workspace inicial e adiciona as toolboxes relevantes.

A forma de uso é a seguinte:

g = geoprocessorWrapper.geoprocessorWrapperClass(r"C:\",["analysis","management","lr"])
#ou
g = geoprocessorWrapper.geoprocessorWrapperClass(r"C:\",["analysis","management","lr"],true)

# para acessar o geoprocessor do nosso wrapper, use:

listaDeFeatureClasses = g.gp.ListFeatureClasses()

for x in listaDeFeatureClasses:
    print x.FeatureType

Bem simples né? Temos um método também para mudar de workspace, sem necessitar de criarmos uma nova ferramenta. O outro método disponível é para remover toolboxes que não precisamos. Um método aqui poderia ser facilmente criado para adicionar novas toolboxes ao objeto. Alguém se arrisca?

Com esta classe podemos fazer quaisquer operações, mas utilizaremos uma outra classe para realizar todo o trabalho sujo. Lembra-se do código do post passado? Temos disponível em nossa máquina um arquivo .zip extraído em uma pasta qualquer, correto?

Vamos à classe geodatabaseUpdateTask.

import os, sys

class geodatabaseOperationClass():
    def __init__(self,geoprocessor,inputShapefile,outputGeodatabase,outputFeatureDataset,outputFeatureClass):

        self.geoprocessorWrapperClass = geoprocessor

        self.inputShapefile = inputShapefile

        self.outputGeodatabase = outputGeodatabase
        self.outputFeatureDataset = outputFeatureDataset
        self.outputFeatureClass = outputFeatureClass

        self.processStage = 0
        self.stages = ["Testes de conformidade",
                       "Deleçãoo de Feature Class",
                       "Cópia de Shapefile",
                       "Atualização Completa"]

    def getProcessStage(self):
        return self.stages[self.processStage]

    def testGeodatabase(self):
        #workspace definido pelo geoprocessor
        return self.outputGeodatabase in self.geoprocessorWrapperClass.gp.ListWorkspaces(self.outputGeodatabase,"ALL")

    def testFeatureDataset(self):
        #adaptando workspace
        self.geoprocessorWrapperClass.gp.Workspace += "\\" + self.outputGeodatabase
        return self.outputFeatureDataset in self.geoprocessorWrapperClass.gp.ListDatasets(self.outputFeatureDataset,"ALL")

    def testFeatureClass(self):
        #adaptando workpace
        self.geoprocessorWrapperClass.gp.Workspace += "\\" + self.outputFeatureDataset
        return self.outputFeatureClass.gp.Workspace in self.geoprocessorWrapperClass.gp.ListFeatureClasses(self.outputFeatureClass,"ALL")

    def testAllObjetcs(self):
        if self.testGeodatabase() and self.testFeatureDataset() and self.testFeatureClass():
            self.processStage = 1
            return True
        else:
            self.processStage = 0
            return False

    def deleteFeatureClass(self,featureClass):
        try:
            self.geoprocessorWrapperClass.gp.Delete_management(featureClass)
        except:
            print self.geoprocessorWrapperClass.gp.getmessages()

    def copyFeatures(self,inputShapefile,outputFeatureClass):
        try:
            self.geoprocessorWrapperClass.gp.CopyFeatures_management(inputShapefile,outputFeatureClass)
        except:
            print self.geoprocessorWrapperClass.gp.getmessages()

    def updateFeatureClass(self):
        try:
            if self.testAllObjects:
                self.processStage += 1
                print self.getProcessStage()

                self.deleteFeatureClass(self.outputFeatureClass)
                self.processStage += 1
                print self.getProcessStage()

                self.copyFeatures(self.inputShapefile,self.outputFeatureClass)
                self.processStage += 1
                print self.getProcessStage()
        except:
            print self.geoprocessorWrapperClass.gp.getmessages()

Temos os tradicionais import no cabeçalho de nosso arquivo e logo depois o construtor da classe.

Nosso construtor tem os seguintes parâmetros: geoprocessor (um objeto do tipo geoprocessorWrapper), o caminho para o shapefile à ser carregado no banco de dados, o geodatabase de destino, o featureDataset de destino e a FeatureClass de destino.

Você pode ver que construí uma lista de estágios que temos de passar antes de atualizar a FeatureClass. O estágio testes de conformidade vão garantir que os objetos existam no geodatabase e não ocorram erros. Esta etapa pode ser customizada, caso a FeatureClass não exista, crie a mesma, somente importando os dados - também deixo isto para o usuário interessado! Lembre-se que temos de passar um objeto geoprocessorWrapper com um workspace, uma pasta. Neste caso em específico, deve-se passar apenas pastas, pois definimos o geodatabase em outras áreas.

Os testes cuidam da mudança de workspace e asseguram que a featureClass exista. Perceba que todo o trabalho é realizado dentro desta classe, nas funções:

  • deleteFeatureClass()
  • copyFeatureClass()

Uma função resume todo o processo: updateFeatureClass(). Veja que ela não tem parâmetros, pois usa os parâmetros setados no construtor. À medida que a mesma progride, atualiza o status do processo e informa ao usuário.

Forma de uso:

gp = geoprocessorWrapper.geoprocessorWrapperClass(r"C:\",['management'])
geoOperation = geodatabaseOperation.geodatabaseOperationClass(gp,r"C:\shapefile.shp","teste.mdb","dnpm","dnpm_brasil")
geoOperation.updateFeatureClass()

Lembrem-se que o restante do código (buscar o arquivo na net, dezipar, etc) está no post anterior. Como prometi, aqui vai a classe LogHandler.

LogHandler Class

E ae pessoal? Dúvidas?

Podem ver que o Python dá muito poder ao framework de geoprocessing do ArcGIS e é muito simples.

Um abraço

George

Compartilhe:
25mai/102

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 :D . 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.

Resultado da função ST_Centroid utilizando um polígono como argumento

Resultado da função ST_Centroid utilizando um polígono como argumento

Resultado da função ST_Centroid utilizando uma linestring como argumento

Resultado da função ST_Centroid utilizando uma linestring como argumento

Resultado da função ST_Centroid utilizando um multipoint como argumento

Resultado da função ST_Centroid utilizando um multipoint como argumento

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:

Resultado gráfico da interseção de duas LINESTRINGs

Resultado gráfico da interseção de duas LINESTRINGs

Podemos ter como resultado da interseção entre duas LINESTRINGs um conjunto de pontos ou uma LINESTRING (quando dois segmentos são coincidentes).

Resultado gráfico da interseção de um conjunto de pontos e um polígono

Resultado gráfico da interseção de um conjunto de pontos e um polígono

Resultado gráfico de ST_Intersection entre um conjunto de LINESTRINGs e um polígono

Resultado gráfico de ST_Intersection entre um conjunto de LINESTRINGs e um polígono

Resultado gráfico de ST_Intersection entre dois polígonos

Resultado gráfico de ST_Intersection entre dois polígonos

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:

Resultado textual de ST_Intersection entre um polígono e uma linestring

Resultado textual de ST_Intersection entre um polígono e uma linestring

Resultado textual de ST_Intersection entre um polígono e um ponto

Resultado textual de ST_Intersection entre um polígono e um ponto

Resultado textual de ST_Intersection entre dois polígonos

Resultado textual de ST_Intersection entre dois polígonos

Resultado textual de ST_Intersection entre duas LINESTRINGs

Resultado textual de ST_Intersection entre duas LINESTRINGs

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)'));
Resultado da função ST_Overlaps nos exemplos 1 e 2 de ST_Overlaps

Resultado da função ST_Overlaps nos exemplos 1 e 2 de ST_Overlaps

Resultado da função ST_Overlaps nos exemplos 3 e 4 de ST_Overlaps

Resultado da função ST_Overlaps nos exemplos 3 e 4 de ST_Overlaps

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))'));
Resultado da função ST_Covers utilizando com dois polígonos

Resultado da função ST_Covers utilizando com dois polígonos

Resultado da função ST_Covers entre um polígono e multipontos

Resultado da função ST_Covers entre um polígono e multipontos

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))'));
Resultado da função ST_Within(), exemplos de 1 à 3

Resultado da função ST_Within(), exemplos de 1 à 3

Resultado da função ST_Within, exemplos 4 e 5

Resultado da função ST_Within, exemplos 4 e 5

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

George R. C. Silva

Compartilhe:
12mai/102

Funções PostGIS #2

Boa tarde senhores e senhoras,

Continuando nossa peregrinação pelas funções do PostGIS, irei começar explicar a que usamos no post anterior e não expliquei.

ST_AsText()

Esta função retorna o valor WKT (Well Known Text - especificação OGC) da geometria. Esta função é útil pois lhe mostra algo um pouco mais inteligível do que o WKB (Well Known Byte).

Ela tem como retorno o WKT sem o código SRID da geometria especificada. Se utilizada em um comando SELECT, ela irá realizar esta conversão em todos os objetos válidos da coluna especificada. Ela é uma função de output.

-- assinatura
-- SELECT ST_AsText(the_geom)

SELECT nm_equipamento_urbano, ST_AsText(the_geom);

Vamos falar um pouco das funções construtoras de geometria. Por que elas são importantes? É uma maneira de se converter dados de coordenadas, em objetos geográficos, representados no banco de dados por uma string com o valor WKB. Vamos começar pela mais simples: ST_Point()

ST_Point()

Esta é a mais simples das funções construtoras. Ela tem como entrada apenas um X e Y. Esta função esta de acordo com a norma OGC. Na verdade, o que ela faz é chamar a função ST_MakePoint() passando como entrada apenas os eixos X e Y.

-- assinatura
-- SELECT ST_Point(coordenada_x, coordenada_y);

SELECT ST_Point(-42.5,-19.2);

O resultado é retornado em WKB. Veja:

Função ST_Point() retornando o valor em WKB

Função ST_Point() retornando o valor em WKB

ST_MakePoint()

A função MakePoint é mais completa que a ST_Point, pois permite a utilização de até quatro eixos de coordenadas, X, Y, Z e M. Esta função não está de acordo com a norma OGC mas é uma forma de se trabalhar no PostGIS. O problema do uso da mesma é no momento de integração com outros softwares OGC compliant. Fique atento!

-- assinaturas
-- SELECT ST_MakePoint(x,y);
-- SELECT ST_MakePoint(x,y,z);
-- SELECT ST_MakePoint(x,y,z,m);

SELECT ST_MakePoint(-10,-1,300,1);

O resultado desta função também é trazido em WKB.

Função ST_MakePoint() retornando o valor em WKB

Função ST_MakePoint() retornando o valor em WKB

Existem funções deste tipo para todos os tipos de geometria. Vamos mostrar as outras:

ST_MakeLine()

Vamos complicar um pouquinho. Da mesma maneira que podemos construir pontos, podemos construir linhas. Existem três maneiras de se utilizar esta função: uma é com o resultado agregado de uma consulta, um array de pontos, ou dois pontos. Vou mostrar as três maneiras.

-- assinatura
-- SELECT ST_MakeLine(geometry_set);
-- SELECT ST_MakeLine(ponto1,ponto2);
-- SELECT ST_MakeLine(array_pontos);

-- resultado agregado de consulta
SELECT l.setor, ST_AsText(ST_MakeLine(l.the_geom)) FROM
	(SELECT codsetor as "setor", the_geom FROM equipamento_urbano) as l GROUP BY l.setor;

-- dois pontos
SELECT ST_AsText(ST_MakeLine(ST_MakePoint(-1,-1),ST_MakePoint(-2,-2)))

-- array de pontos
SELECT ST_AsText(ST_MakeLine(ARRAY[ST_MakePoint(-10,-1),ST_MakePoint(-5,0),ST_MakePoint(-10,2),ST_MakePoint(-19,-20),ST_MakePoint(-1,0)]));

-- note que a abertura do array se faz com os colchetes!

Vejamos os resultados, respectivamente: agregado, dois pontos e array de pontos. Uma nota: utilizei ST_AsText nas funções para facilitar a visualização do resultado. Todos os resultados podem ser facilmente testados, com exceção do agregado. Caso alguém tenha interesse, posso lhe enviar a tabela em formato .sql para conferência :P

Resultado de ST_MakeLine com pontos agregados

Resultado de ST_MakeLine com pontos agregados

Resultado de ST_MakeLine com dois pontos

Resultado de ST_MakeLine com dois pontos

Resultado da função ST_MakeLine com um array de pontos

Resultado da função ST_MakeLine com um array de pontos

Vamos complicar mais um pouquinho?

ST_MakePolygon()

Esta função constrói polígonos. Para um polígono ser um polígono ele deve ter uma clara distinção de seu interior com seu exterior. A única maneira de delimitarmos isto é tenho uma LINESTRING fechada, ou seja, o último vértico deve ser igual ao primeiro. Um polígono também pode ter holes ou seja, buracos. Eles também podem ser construídos aqui. Veja só:

-- assinatura
-- SELECT ST_MakePolygon(linestring_fechada);
-- SELECT ST_MakePolygon(linestring_fechada,array_poligonos_interiores);

SELECT ST_AsText(ST_MakePolygon(
	ST_MakeLine(ARRAY[
		ST_MakePoint(0,0),
		ST_MakePoint(1,0),
		ST_MakePoint(1,1),
		ST_MakePoint(0,1),
		ST_MakePoint(0,0)])))

Veja o resultado:

Resultado de ST_MakePolygon

Resultado de ST_MakePolygon

Todas estas funções são extremamente úteis, permitindo o usuário à manipular as geometrias de diversas tabelas para construir objetos temporários ou views para visualização em softwares de SIG. Lembrem-se que você não precisa utilizar ST_MakePoint() para construir polígonos ou linhas. Você pode utilizar a agregados e resultados de consultas como parâmetros de entrada para estas funções.

ST_GeomFromText

Esta é a rainha das funções construtoras de geometria. Com ela é possível construir qualquer geometria, desde que você tenha o WKT das mesmas. Mão na roda. A segunda assinatura lhe permite especificar um SRID.

-- assinatura
-- SELECT ST_GeomFromText('wkt');
-- SELECT ST_GeomFromText('wkt',srid);

SELECT ST_AsText(ST_GeomFromText('LINESTRING(0 0, 1 0, 2 1, 2 2, 3 1, 3 3, 0 1, 0 0)'))

SELECT ST_AsText(ST_GeomFromText('POLYGON((0 0, 1 0,1 1,0 1,0 0))'));
Resultado da função ST_GeomFromText, construindo uma linha.

Resultado da função ST_GeomFromText, construindo uma linha.

Resultado da função ST_GeomFromText, construindo um polígono.

Resultado da função ST_GeomFromText, construindo um polígono.

Agora vem a pergunta: porque utilizamos dois pares de parênteses quando construímos um polígono e apenas um quando construímos uma linestring? Lembra quando construímos um polígono, temos a opção de passar uma array de polígonos internos, os famosos holes? Então, o segundo set de parênteses corresponde à possibilidade de inserir este array de polígonos. Não se esqueça, para polígonos e geometrias multi*, dois sets de parênteses são necessários.

Hoje vimos um pouco sobre as funções construtoras de geometrias no PostGIS. O que acharam?

Abraços

George R. C. Silva

Compartilhe:
28abr/102

Agricultura Familiar e Geoprocessamento

Olá Pessoal!

Hoje gostaria de comentar com vocês sobre um trabalho elaborado pela também Tecnóloga em Geoprocessamento, Julie Eugênio.

Há algum tempo ela preparou um projeto de gerenciamento de atividades de agricultura familiar fazendo uso de técnicas de Geoprocessamento.

O objetivo principal da pesquisa dela foi o desenvolvimento de uma aplicação, com base em técnicas de Geoprocessamento, para apoiar as atividades de um projeto voltado à agricultura familiar sustentável denominado “Cinturão Verde”, inserido no programa de microcrédito “Empreender-JP”, no município de João Pessoa, capital do Estado da Paraíba.

O mapa abaixo mostra a localização da área de estudo.

Durante a construção da aplicação SIG integrada a um Banco de Dados Geográficos deu-se ênfase ao uso de tecnologias livres, com destaque para o Quantum Gis (QGis) e PostgreSQL/PostGis.

Na parte escrita do trabalho desenvolvido foi detalhada toda a metodologia empregada. A qual está resumida na figura abaixo.

O trabalho foi extremamente elogiado pelos responsáveis técnicos da prefeitura de João Pessoa. Você pode fazer o download do trabalho completo a partir do link abaixo, que traz o tema da monografia escrita com base nesse projeto.

Gerenciamento de Atividades de Agricultura Familiar Sustentável com Base em Técnicas de Geoprocessamento, no Município de João Pessoa - PB

Espero que tirem proveito de mais essa demonstração da potencialidade do uso de tecnologias livres para Geoprocessamento.

Abraços.

--

Anderson Medeiros

Tecnólogo em Geoprocessamento

Compartilhe:
23abr/102

Padrões Open Geospatial Consortium – Parte 2

Hoje vamos dar sequência à postagem sobre padrões da OGC. Na primeira postagem dessa série vimos o que é o OGC e alguns comentários sobre as especificações WMS, WFS e WCS.

Agora vamos tecer algumas considerações sobre os padrões GML, KML e SLD.

Geographic Markup Language (GML)

O objetivo da GML é oferecer um conjunto de regras com as quais um usuário pode definir sua própria linguagem para descrever seus dados, assim utilização do padrão GML permite a interoperabilidade entre dados geográficos.  Definindo como será o armazenamento e transporte de informações geográficas, incluindo propriedades espaciais e não espaciais das entidades geográficas.

O GML é usado também em serviços WFS para trocar feições entre clientes e servidores, servindo, portanto como suporte ao serviço WFS.

Keyhole Markup Language (KML)

A linguagem XML (eXtensible Markup Language), como o próprio nome já diz, pode ser extendida  ou ampliada. O próprio padrão  KML da OGC é uma extensão de um XML utilizado pelo Google para tornar possível a visualização de dados geográficos nos seus famosos programas: Google Earth e Google Maps.

A estrutura do KML é baseado em tags como ocorre com arquivos HTML e XML comuns. Estas tags do KML tem os nomes e atributos usados para objetivos de exibição específicas. Em termos simples, notamos que o Google Earth e e o Google Maps funcionam pra os arquivos KML como como navegadores.

O KML depende de outros padrões para gerar a visualização de dados geográficos, pois na sintaxe do KML proveniente de um serviço de internet existe uma requisição WMS.

Hoje, o OGC e o Google trabalham em conjunto para aprimorar a implementação do KML, além de manter a comunidade informada das atualizações e avanços em seu projeto.

Styled Layer Descriptor (SLD)

A especificação SLD se refere à um arquivo XML que representa graficamente entidades geográficas (textos, pontos, objetos lineares ou polígonos.). Na linguagem SLD podem ser definidas regras que agrupam objetos em diferentes categorias e definindo para cada grupo um estilo diferente, por exemplo a simbologia de um WMS (estabelecer cores e rótulos) a partir de regras a serem definidas.

Programas de SIG, como o Udig, geram arquivos SLD de forma automática. Para executar este processo, basta adicionar uma camada WFS à uma visualização do Udig, fazer uma requisição ao servidor através de uma URL adequada e depois criar temas e rótulos de acordo com as necessidades da aplicação.

Enfim, esta foi uma breve consideração sobre alguns dos principais padrões da OGC (WMS, WFS, WCS, GML, KML e SLD). Espero que tenham gostado. Qualquer dúvida, entre em contato deixando um comentário.

Um Abraço e até a próxima postagem

--

Anderson Medeiros

Tecnólogo em Geoprocessamento

Consultor em Geotecnologias Livres

Compartilhe:
16abr/101

Criação de Templates para PostGIS

Olá a todos, muito bom está por aqui novamente.

Hoje vou falar para vocês de um assunto que na minha graduação o Prof. Marcello Benigno[1] sempre "enchia o saco" repetindo e repetindo e repetindo... a criação de templates para o banco de dados (no nosso caso, PostgreSQL[2]). Templates nada mais são que modelos pré-definidos de banco de dados, que aumentam a produtividade na criação de novos bancos. Neles nós colocamos características comuns aos bancos de dados que serão criados e só associamos os novos bancos a eles.

Como exemplo, hoje a tarde precisei recriar um template_postgis para que pudesse sincronizar uma aplicação geodjango a ele (A aplicação poderá ser vista em breve na edição número 1 da revista Geo.NET), então fiz da seguinte forma:

Como root chamei o postgres:

# su postgres

Após entrar no root postgres, mandei criar um novo banco de dados chamado template_postgis:

$ createdb -U postgres template_postgis

A opção "-U" do comando createdb se refere ao usuário que será dono do banco, ou do template, como é nosso caso (Para maiores informações sobre outras opções do comando createdb digite $ man createdb). Para esta versão, o root postgres é por default o dono das tabelas, bancos e templates criados, por tanto, não faz necessário informá-lo como usuário.

Para que seja possível rodar as funções da extensão espacial postgis, é necessário a criação da linguagem procedural plpgsql. Por meio desta, é possível rodar as funções contidas nos arquivos lwpostgis.sql e ref_spatial_sys.sql, arquivos estes que contem funções que resolvem referência espacial, tipos de geometrias, sistemas de coordenadas e etc. Para criar a linguagem, basta usar o comando:

$ createlang -d template_postgis -U postgres plpgsql

A opção "-d" informa para qual banco de dados, ou template será criada a nova linguagem procedural (Para maiores informações, consulte $ man createlang).

Depois de ter criado a linguagem, basta importar os arquivos lwpostgis.sql, lwpostgis_upgrade.sql e spatial_ref_sys.sql. Para isso usaremos o terminal interativo do pgsql através do comando:

$ psql -d template_postgis -f lwpostgis.sql
$ psql -d template_postgis -f lwpostgis_upgrde.sql
$ psql -d template_postgis -f spatial_ref_sys.sql

Neste ponto é importante tomar nota de que, se o usuário não estiver no path onde estão os arquivos acima, lhe será retornado um erro. Para evitar tal erro, consulte a documentação para a sua distribuição.

Para confirmar se tudo correu bem, entre no template e faça uma consulta às tabelas da seguinte forma:

$ psql -d template_postgis
template_postgis=# \dt
Lista de relações
Esquema |       Nome       |  Tipo  |   Dono
---------+------------------+--------+----------
public  | geometry_columns | tabela | postgres
public  | spatial_ref_sys  | tabela | postgres
(2 registros)

Observe que dentro do template_postgis foram criadas as tabelas espaciais, e que por default o dono das mesmas é o root postgres. Agora ficou simples, pois sempre que for preciso criar um db com extensão espacial, basta rodar o comando:

$ psql -T template_postgis <nome_novo_db>

Este novo db será criado, e dentro dele já estarão inseridas as tabelas espaciais.

Fácil não é? ;)

Abraço a todos.

Referencias:

[1] Prof. Marcello

[2] PostgreSQL

Vicente Martins.

Compartilhe:
30mar/102

Padrões Open Geospatial Consortium – Parte 1

Olá Pessoal!

Hoje vou abordar um tema de extremo interesse para quem trabalha com Geotecnologias, livres ou não: Os padrões do Open Geospatial Consortium (OGC). Nesta primeira parte da série vamos entender o que é o OGC e os padrões WMS, WFS e WCS.

O Open Geospatial Consortium (OGC)

Desde seus primórdios em 1994 a instituição, que se chamava OpenGis Consortium, tem o com o objetivo de criar especificações de interfaces e padrões de intercâmbio de dados geoespaciais.

O OGC é hoje uma entidade internacional com mais de 350 companhias, agências governamentais e universidades, que tem o intuito de promover o desenvolvimento de tecnologias que facilitem a interoperabilidade entre diferentes sistemas que trabalhem com informação e  localização espacial.

Asim, o OGC define especificações, ou padrões (como o WMS, WFS, WCS, etc) aos quais produtos e serviços precisam se adequar para que a interação entre diversas fontes de dados e informações espaciais seja facilitada, independente de fatores como a plataforma utilizada. A partir de agora vamos começar a compreender três das especificações do OGC.

Web Map Service (WMS)

O padrão WMS define um serviço para a produção de mapas que serão apenas uma representação visual dos dados espaciais e não os dados em si. Estas representações serão geradas no formato de imagem, como JPEG, PNG e GIF ou em formato vetorial, como o Scalable Vector Graphics (SVG).

Este padrão especifica como o cliente deve requisitar as informações para o servidor e como este deve responder ao cliente. As operações WMS podem ser realizadas a partir de um navegador comum que fará a submissão das requisições sob a forma de uma URL.

É importante destacarmos que o conteúdo da URL dependerá da operação solicitada. Em outras palavras, através da URL, indica-se qual a informação que deve ser exibida (região geográfica e dado de interesse), bem como o sistema de referência espacial, além das características da imagem de saída (altura e largura).

Web Feature Service (WFS) e Web Coverage Service (WCS)

A especificação de serviço WFS define um serviço para que clientes possam recuperar feições especiais em formato GML (você terá mais detalhes sobre GML na segunda parte desta série sobre o OGC).  O WFS pode ser implementado pelo servidor em duas versões:

  • Básica - Neste caso, basicamente funções de consulta ficam disponíveis, ou
  • Transacional - Implementa o serviço completo, incluindo operações de inserção, deleção, edição e, claro, consulta à objetos espaciais.

Assim, podemos afirmar que o WFS apresenta maior interatividade que o WMS, pois este primeiro possibilita não apenas a visualização das feições geográficas, mas também sua manipulação.

o padrão WCS define o acesso aos dados que representam fenômenos com variação contínua no espaço. Este serviço é especificado para
tratamento de dados modelados como geocampos.

Breves Comparações entre WMS, WFS e WCS

Uma diferença marcante entre o WMS e o WCS é que este último retorna ao usuário dados sobre a semântica original dos fenômenos representados, ao invés de imagens. Em outras palavras, o WCS fornece os dados disponíveis de imagens, juntamente com detalhes descritivos sobre as mesmas, como a grade.

Já em uma comparação entre o WFS e o WCS notamos que o primeiro retorna os chamados geo-objetos, já no caso do WCS retorna geocampos, conforme mencionado anteriormente.

Assim, chegamos a conclusão de que o serviço WCS pode ser utilizada para enquadrar aplicações do Sensoriamento Remoto (pois em geral o SR está relacionado com geocampos) no contexto da interoperabilidade.

Conclusão e o que vem por ai

Dessa nossa breve análise sobre estes três dos diversos padrões do OGC podemos notar que cada um terá sua aplicabilidade, sendo interpretado e explorado de maneira diferente dependendo dos objetivos de seu projeto.

Programas como o gvSIG e o Udig permitem interações com webservices que sigam as especificações WMS, WFS e WCS.

Na segunda parte desse post veremos mais sobre as padrões da OGC, com ênfase nas especificações GML, SLD e KML.

Fiquem na expectativa...

--

Anderson Maciel Lima de Medeiros

Tecnólogo em Geoprocessamento

Compartilhe:
18mar/101

shp2pgsql: Você conhece esta fantástica ferramenta?

Olá pessoal, boa noite.

É tempo de retomar a implementação de antigos projetos no trabalho (isso soa estranho né?), para poder mostrar que existem ferramentas livres, super-poderosas e que trazem respostas a várias perguntas de "onde" estão os problemas.

Neste trabalho que estou reiniciando na Companhia, estamos implementando um DB (Data Base) que guardará um monte de informações que estavam soltas nas mãos de todos os seus "donos".

Com estas informações, será possível fazer várias análises, inclusive espaciais, e diponibilizá-las em um ambiente interno [intranet] a partir de uma aplicação WebGIS, o que facilitará o acesso a informação de interesse comum, bem como facilitará o planejamento das decisões a serem tomadas. É sim um projeto extravagante, uma vez que um "novato" vai mexer com o lugar e "poder" de muita gente lá dentro, mas em contra-partida, tenho certeza que isso trará melhorias para a Companhia, o que é na verdade o objetivo do mesmo.

Para vocês hoje, trago uma ferramenta que a muito tempo não utilizava, mas que é extremamente importante quando falamos de PostGIS: shp2pgsql. O Anderson a um tempo atrás disponibilizou um mini-tutorial no ClickGeo[1], que inclusive serviu de fonte de pesquisa para mim, e que recomendo para quem quer utilizar shp2pgsql. Algumas outras pesquisas na documentação oficial da extensão[2], mais algumas conversas com o próprio Anderson e outros amigos da área, me vi "obrigado" a compartilhar mais um pouco de conhecimento.

A shp2pgsql, como o prórpio nome sugere, é um aplicativo que transforma arquivos shapefile da ESRI em sql, em que os antigos dados em formato shapefile são inseridos dentro das tabelas de um Data Base em PostgeSQL/PostGIS da maneira correta.

Para tanto, é necessário conhecer alguns parametros que precisamos informar ao aplicativo. De maneira geral, a utilização do shp2pgsql se dá da seguinte forma:

# shp2pgsql /path/do/shape/dado.shp nome_tabela > nome_arquivo.sql
# psql -d nome_DB -f nome_arquivo.sql

Convenções:

  • "#" você precisa estar logado como super-usuário para utilizar esta ferramenta;
  • "/path/do/shape/dado.shp" é o caminho onde está guardado o dado em shapefile;
  • "psql -d" define o Data Base utilizado;
  • "psql - f" executa o arquivo .sql indicado. Talvez seja necessário informar o caminho total do arquivo ".sql", caso não se esteja dentro do path indicado.

Porém, é possível informar alguns parametros para o aplicativo shp2pgsql que facilita a inserção dos dados desejados. Dentre os principais (ao menos para mim, foram os mais utilizados) cito:

-s: Este parametro define o SRID (Spatial Reference System Identifier)que será utilizado.

# shp2pgsql -s <SRID> dado.shp nome_tabela > nome_arquivo.sql

-W: Este parametro informa a codificação em que está o seu Data Base, inserindo os dados na mesma codificação.

# shp2pgsql -s <SRID> -W <encoding> dado.shp nome_tabela > nome_arquivo.sql

Bem, fora estes, o carregador de dados shp2pgsql traz outros parametros de inserção de dados que vale a pena ser consultado. De qualquer forma, é interessante consultar a documentação.

Vou ficando por aqui.

Abraço a todos.

Vicente Martins.

Referências:

[1] ClickGeo - Importando Arquivos Shapefile para PostGIS 8.1 via prompt do DOS

[2] Documentação PostGIS

Compartilhe:
Get Adobe Flash playerPlugin by wpburn.com wordpress themes