Blog Geo.NET Geoprocessamento, SIG e Sensoriamento Remoto

29Jul/101

Desenvolvendo um SIG para Suporte de Decisões Municipais #2

Olá pessoal, boa noite.

No post anterior falamos sobre a modelagem de um sistema que atendesse as necessidades de uma prefeitura e mostramos como modelar a parte de sistema viário. O sistema viário foi modelado primeiro pois ele é de fato, o coração de uma cidade e muita coisa acontence "em torno" do sistema viário.

Estamos assumindo com nosso modelo, que construíremos um sistema de geocoding, capaz de localizar endereços em nossa base de logradouros. Através deste sistema construíremos localizadores de diversos tipos de feição, como acidentes de trânsito, pontos de ônibus, focos de dengue, entre outras.

Hoje iremos conversar sobre a modelagem do sistema de transportes. Obviamente é um modelo simples, que não atende todas as necessidades de uma empresa/prefeitura para administrar o sistema de transporte público, mas já ajuda. Bem, do que é feito um sistema de transporte público? Falaremos aqui somente de linhas, pontos de parada, sentidos (bairro-centro, centro-bairro) e horários. Poderíamos muito bem falar de localização em tempo real, relatórios de viagem, etc., mas foge um pouco do objetivo da série - de ser uma introdução à modelagem de um sistema completo.

2.2 - Sistema de Transporte Público

Vamos começar com a modelagem do nosso sistema de Transporte. Vamos modelar Pontos de Parada, Linhas, Sentidos, e Horários.

CREATE TABLE tp_ponto_parada
    (
        id_tp_ponto_parada serial not null,
        dc_tp_ponto_parada varchar(50) not null,
        constraint tp_ponto_parada_pk PRIMARY KEY (id_tp_ponto_parada),
        constraint tp_ponto_parada_un UNIQUE (dc_tp_ponto_parada)
    );

    CREATE TABLE ponto_parada
    (
        id_ponto_parada serial not null,
        dc_ponto_parada varchar(255) not null, -- descricao do ponto
        tp_ponto_parada integer not null references tp_ponto_parada (id_tp_ponto_parada),
        constraint ponto_parada_pk PRIMARY KEY (id_ponto)
    );

    -- vamos adicionar nossa coluna geométrica a ponto_parada
    SELECT * FROM AddGeometryColumn('public','ponto_parada','the_geom',-1,'POINT',2);

    CREATE TABLE linha
    (
        id_linha serial not null,
        nm_linha varchar(50) not null,
        dc_linha varchar(255) not null,
        constraint linha_pk PRIMARY KEY (id_linha),
        constraint linha_nm_linha_un UNIQUE (nm_linha) -- o nosso nome de linha deve ser único.
    );

Bem, modelos nossas entidades básicas, pontos e linhas. Mas como descobrir qual linha serve à cada ponto? Ou como dizer se um ponto de parada pertence à determinada linha? Temos neste momento, uma relação de muitos para muitos. Porque? Bem, um ponto pode servir à mais de uma linha. E uma linha, com certeza abrange vários pontos. Para isto ser feito de maneira correta, temos de criar uma entidade intermediária, decompondo nosso relacionamento em 1:M, de cada um dos lados.

    CREATE TABLE sentido
    (
        id_sentido serial not null,
        dc_sentido varchar(50) not null,
        constraint sentido_pk primary key (id_sentido)
    );

    -- vamos aproveitar e inserir os sentidos possíveis!

    INSERT INTO sentido(id_sentido,dc_sentido) VALUES (DEFAULT,'CENTRO - BAIRRO');
    INSERT INTO sentido(id_sentido,dc_sentido) VALUES (DEFAULT,'BAIRRO - CENTRO');

    CREATE TABLE linha_possui_ponto
    (
        id_linha integer not null references linha (id_linha),
        id_ponto_parada integer not null references ponto_parada (id_ponto_parada),
        id_sentido integer not null references sentido (id_sentido),
        constraint lpp_pk primary key (id_linha,id_ponto_parada,id_sentido)
    );

Através desta tabela intermediária, conseguimos modelar quem pertence à quem. Podem ver, que as chaves estrangeiras em linha_possui_ponto, não permite o cadastro de linhas inexistentes ou de pontos inexistentes, nem de pontos duplicados que partilhem do mesmo sentido. Desta forma, podemos construir um cadastro básico de linhas e pontos, bem como de quais pontos são servidos por quais linhas.

Agora, precisamos de uma maneira inteligente de desenhar as linhas de ônibus que operam na cidade fictícia. Precisamos criar algo com uma coluna geométrica, correto? Errado. Como temos uma tabela geométrica com nossos logradouros, podemos facilmente utilizá-la para construir nossos trajetos de linha.

Por que fazer desta maneira?

  • Não repita informação.
  • Não repita informação.
  • Não repita informação.

É um motivo forte o bastante. Imagine se temos milhares de linhas, com milhares de trechos servidos. Se alterarmos nossos logradouros, teremos de alterar também nossas linhas - configurando um problema em potencial. Por isso iremos utilizar as geometrias da tabela logradouros para desenharmos nossas linhas.

Esta tabela tomará a forma de uma tabela intermediária, informando ordem e sentido. Desta maneira, utilizando uma view construíremos nossa tabela virtual de linhas.

    CREATE TABLE linha_possui_trecho
    (
        id_lpt serial not null,
        id_linha integer not null references linha (id_linha),
        id_trecho_logradouro not null references trecho_logradouro (id_trecho_logradouro),
        id_sentido not null references sentido (id_sentido),
        ordem integer not null default 0,
        constraint lpt_pk primary key (id_lpt),
        constraint lpt_un_linha_lpt unique (id_linha,id_trecho_logradouro,id_sentido,ordem)
    );

Através desta tabela intermediária, conseguimos informar à nosso sistema quais são os trechos de logradouro que formam uma linha específica. Realmente é algo à mais para monitorarmos e inserir no banco de dados, mas atualmente é a única maneira. A idéia aqui é construir uma ferramenta específica, que seleciona trechos de logradouros, e em memória armazena estas informações, bem como sua ordem (de seleção). Após a seleção, o ideal é o usuário executar o comando de "inserir", e nosso sistema, cuide do restante para o mesmo. Nada de editar tabelas como esta na mão.

Já temos nosso modelo preliminar, mas como vamos mostrar as linhas em um cliente web? Necessitamos gerar as linhas em tempo de execução, com as informações pertinentes. Para isto, iremos utilizar uma view e adicionar os registros apropriados à tabela geometry_columns para que esta fique transparente para o usuário/serviço de mapas.

CREATE OR REPLACE VIEW linhas_transporte_publico AS
SELECT
	id_linha,
	nm_linha,
	ST_Collect((SELECT the_geom from logradouros where gid = id_trecho_logradouro)) as "the_geom"
FROM linha
	LEFT OUTER JOIN linha_possui_trecho
		ON (linha.id_linha = linha_possui_trecho.id_linha)
	LEFT OUTER JOIN trecho_logradouro
		ON (linha_possui_trecho.id_trecho_logradouro = trecho_logradouro.id_trecho_logradouro)
	GROUP BY id_linha,nm_linha

Esta view nos possibilitará disponibilizar as informações de linha como um todo, sem diversos registros. O segredo está na função ST_Collect, responsável por unir os trechos de logradouros em nossa tabela trecho_logradouro. Veja que não estamos duplicando informação, apenas reutilizando os dados já existentes em nosso modelo.

Existem outras tabelas interessantes em se disponibilizar, tais como pontos de táxi, linhas de metrô/trem, transportes marítimos, aeroportos, terminais de embarque, etc. Deixo este exercício para o leitor. O objetivo aqui é mostrar como a modelagem de dados preliminar do sistema viário é importante e como podemos simplificar nosso trabalho futuro.

No próximo artigo falaremos sobre setores administrativos, bairros, quadras, lotes, etc. Estes dados são muito importantes para a administração pública e com certeza devem estar presentes em nosso sisteminha.

O que acharam?

Abraços

George R. C. Silva

21Jul/102

Desenvolvendo um SIG para Suporte de Decisões Municipais

Atualmente temos no Brasil 5561 municípios, de diversos tamanhos. Gerenciar um município e todos os seus serviços é uma tarefa complicada, pela multiplicidade de usuários que devem ser atendidos (a população), e diversidade de serviços oferecidos (educação, saúde, segurança, lazer, moradia).

Como administrar tudo isso, de forma coesa e inteligente? Muito poucos municípios tem hoje a capacidade de construir um sistema de informações geográficas, por diversos motivos: preço do desenvolvimento de um sistema integrado, preço do software (licenças proprietárias), treinamento de mão-de-obra e manutenção deste centro de inteligência espacial.

Enfim, é muito caro coletar e organizar dados geográficos, mas é uma ação municipal que tem retorno imediato, não somente no caixa, mas em agilidade na prestação dos serviços e por conseguinte satisfação da população em geral.

Além disto, os custos para realizar diversas operações diminuem exponencialmente. Ordens de serviço são precisamente direcionadas ao problema, sem desperdícios ou prestando serviços desnecessários.

Iremos abordar em uma série de artigos a construção de um sistema de apoio de decisões para um prefeitura municipal fictícia. Serão utilizados softwares livres para o desenvolvimento desta solução, mas isto não lhe impede de desenvolver este tipo de sistema utilizando um software proprietário - os resultados práticos são os mesmos.

O tema será abordado em paralelo, mostrando tanto o esboço de uma arquitetura sistêmica, o desenho de um pequeno banco de dados espacial e a construção de um ambiente WEB para visualização das informações espaciais no navegador de internet comum.

Os primeiros artigos serão bastante simples e conforme caminharmos, iremos adicionar complexidade ao sistema, com consultas, relatórios e regras de negócio avançadas. Iremos adicionar inteligência ao sistema aos poucos.

Portanto leitor, seja bem vindo à esta série de artigos que estamos escrevendo com o intuito de mostrar o que Geoprocessamento realmente é. Esqueça os "mapinhas", pense em inteligência geográfica. Como sempre, você são encorajados à participarem ativamente deste processo, pelo blog ou via email. Aguardmos ansiosos pelo seu feedback.

1 - Arquitetura do sistema

Primeiramente precisamos pensar o que nosso sistema irá fazer, quem irá atender e como irá atender. Não é possível dentro de um prazo e custos razoáveis, atender todas as demandas de desenvolvimento que uma prefeitura municipal de médio porte terá. Mas é possível limitar este escopo e prever como o sistema deverá crescer. Por isso devemos ter em mente uma arquitetura que possa escalar e seja robusta.

Existem milhares de estudos sobre arquitetura que devemos fazer ANTES de iniciarmos um projeto desse porte. Mas não iremos realizar os estudos. Porque? Vamos construir um sistema pequeno para uma prefeitura pequena e não temos em mente muitos usuários simultâneos. O que quero deixar claro é que esta etapa deve existir e não pode ser descartada em qualquer projeto real e deve ser feito inclusive, por um profissional COMPETENTE.

Bem, o que nosso sistema irá fazer? Irá cartografar alguns temas de nossa cidade fictícia como lotes, quadras, praças, logradouros, bairros entre outros e disponibilizar a consulta destes temas via internet. Inicialmente, este será nosso objetivo. É uma missão bem simples, mas que já pode ajudar um administrador a entender seu espaço, seu município e seus habitantes.

O que precisamos para fazer isto? Logo de início, precisamos ter em mãos os dados espaciais a serem manipulados. Pelo fato de requerer custos elevados, muitas vezes nos deparamos com a falta de informação espacial para manipulação. Isso ocorre por, na maioria das vezes, o orçamento do lugar, cidade, estado, não cobrir a necessidade dos gastos totais local, o que redireciona os investimentos do lugar para problemas mais urgentes, ficando o planejamento do espaço em segundo plano.

Tendo em mãos estes dados, precisamos de uma forma confiável de armazena-los e lê-los, portanto precisamos de um banco de dados, geográfico! Só um banco de dados pode possibilitar multiplos usuários leitores, multiplos usuarios editores sem que haja quebra na consistência de informações. Para isto, a maioria dos bancos de dados relacionais, utiliza alguns princípios chamados de ACID (Atomicidade, Consistência, Isolamento e Durabilidade) detalhar isto aqui, mas fica para um próximo artigo) e são eles que garantem que tudo o que tenho dentro daquele banco de dados é uma informação verdadeira, ou seja, consistente e íntegra.

Como iremos inserir os dados no banco? Utilizaremos um software SIG desktop para a tarefa. Este tipo de software suporta conversão de coordenadas, edição de geometrias, customização de simbologia, geração de mapas temáticas, consultas complexas, entre outras funções. O importante é que este software ficará a disposição, em nosso caso fictício, de uma pequena parcela de funcionários da prefeitura, treinados e compententes para operar um software com toda esta complexidade. Não que todos não pudessem aprender, mas é melhor dividir para conquistar. Com um número reduzido de usuários responsável pela inserção/deleção/atualização de registros, temos maior segurança e podemos prevenir desastres em nossas preciosas bases cartográficas.

Além disso precisaremos de um servidor de mapas. Precisamos publicar nossas informações na internet, através de mapas coloridos. Um servidor de mapas é o responsável por entender os pedidos do navegador de internet ("me dê aquela extensão geográfica ali, com as camadas de logradouros, quadras e hidrografia, para ontem!") e traduzir sua resposta em gráficos. Em alguns casos, o servidor de mapas entende o pedido e gera as imagens, em outros, manda as informações para o navegador interpretar e desenhar aquele lindo mapa em sua tela.

Figura 01 - Arquitetura simplificada do sistema

Figura 01 - Arquitetura simplificada do sistema

1.1 - Escolha de ferramentas

Bem, escolhemos como banco de dados o PostgreSQL 8.4 com sua extensão espacial PostGIS 1.5. Porquê? Bem, conforme mencionamos no começo do artigo, iremos trabalhar com ferramentas livres, ao invés de proprietárias, mas existem algumas razões técnicas para isto:

  • É o mais completo banco de dados (livre) da atualidade;
  • O PostgreSQL é o banco de dados que faz menos extrapolações do padrão SQL. Portanto, desenvolver para PostgreSQL, quase sempre é estar de acordo com o padrão.
  • O PostGIS, sua extensão espacial, é a mais madura do mercado. Tem o maior número de funções, funciona muito bem e com certeza dá uma lavada em outras implementações espaciais.
  • O PostGIS segue o padrão aberto OGC (Open Geospatial Consortium), ou seja, informação dentro do PostGIS se comunica com todos os softwares de SIG/GIS que implementam o padrão.
  • O PostGIS é livre e gratuito.

O PostgreSQL ainda nos permite interação com diversas linguagens de programação, para aumentar sua capacidade de análise espacial, como a pl/R e como a pl/python que nos irá ajudar a criar futuramente um ambiente web completo.

O software SIG desktop escolhido foi o QGIS. A resposta para esta escolha, é que antes de tudo, o Quantum GIS é um software livre! É um projeto que faz parte da OSGeo, e que roda em diferentes plataformas (Unix, Linux, MacOSX e Windows), além de suportar dados vetoriais, raster e formatos de banco de dados. Atrevés do QGIS, é possivel gerenciar, manipular e analisar os dados trabalhados, bem como compor mapas para impressão.

Para o servidor de mapas, iremos utilizar o GeoServer. O GeoServer é um projeto bastante maduro, é utilizado mundo afora e suporta os principais protocolos especificados pela OGC - Web Map Services, Web Feature Services, entre outros. Em conjunto com o GeoServer, usaremos o OpenLayers para trabalhar como cliente do GeoServer e construir nosso mapa - dentro do navegador.

2 - Temas e Feições

Em suma, um SIG armazena informações de forma relacional, da mesma forma que um banco de dados tradicional. A diferença é que o SIG permite e lhe dá
ferramentas para armazenar de forma eficiente informações espaciais: pontos, linhas, polígonos e outras geometrias mais complexas, como coleções de
geometrias, geometrias em três dimensões, etc..

As ferramentas que o sistema lhe fornece são composta basicamente de operações matemáticas sobre objetos dispostos em um plano euclidiano (existem ferramentas
avançadas que se dão em uma esfera, como a superfície da Terra), tais como: intersecção, união, disjunção, soma, subtração, distância, área, entre outras.

Existem diversas operações que podemos realizar com as geometrias dos objetos, e chamamos isto de análise espacial. É através da análise espacial e pesquisa relacional em um banco de dados que conseguimos os fantásticos resultados, que não seriam obtidos de nenhuma outra maneira.

Em nosso pequeno sistema, vamos armazenar algumas informações cruciais para a administração pública: sistema viário, quadras, lotes, bairros, linhas e pontos de ônibus e pontos de táxi. A administração de nossa prefeitura fictícia quer uma atualização cartográfica geral e um controle maior sobre o transporte neste município.

A prefeitura fictícia nos forneceu estas informações e nos mostrou como são armazenadas hoje. À partir daí podemos começar com a modelagem de dados e a construção de nosso banco de dados espacial.

2.1 - Sistema Viário

A prefeitura quer um levantamento e organização completa de seu sistema viário. Atualmente eles não tem nada armazenado em forma digital, mas querem uma solução que seja compatível com geocodificação, roteamento e sirva para construção dos itinerários de linhas de ônibus.

Bem, como temos requisitos funcionais (geocodificação e roteamento) precisamos pensar em uma forma de construir esta base de logradouros de uma forma que nos permite posteriormente, implantar estas funcionalidades para a prefeitura.

Uma estrutura relacional comumente aceita para representar este tipo de informações é criar uma linha por logradouro, de seu ponto inicial ao seu ponto final, indicando as seguintes informações: Código Logradouro,Tipo Logradouro, Nome Logradouro, CEP Logradouro. Mas temos nosso requisitos. Nosso sistema quase nunca teria uma linha de ônibus que segue um logradouro de seu início ao seu final, sem nenhuma virada, por exemplo. Temos ainda a questão de preparar o sistema para o roteamento e geocodificação. É muito mais prático, dividir este elemento "logradouro" em partes atômicas, que nunca irão se alterar (com exceção, claro, de uma alteração do traçado viário) ou ser divididos em pedaços menores por alguma necessidade (como um ônibus virar a esquina, por exemplo).

Definido isto, temos a seguinte estrutura: Código Logradouro, Código Trecho Logradouro, Tipo de Logradouro, Nome Logradouro, CEP Logradouro. Estamos apenas preparando a base para demandas futuras, então lembrem-se, não iremos implementar tudo de uma vez. Esta estrutura será suficiente. O importante é entender a divisão de informações que iremos realizar. Também vamos assumir que todo o traçado dos eixos serão realizados no sentido do tráfego, ou seja, o ponto inicial flui para o ponto final do logradouro ou trecho.

Neste esquema a tabela não está apropriadamente normalizada. Precisamos normalizá-la para um funcionamento eficiente de informações. Mas porque? Note que um logradouro terá um ou mais trechos, e estamos repetindo à cada trecho as informações Tipo de Logradouro e Nome de Logradouro. A normalização permitirá que entremos com esta informação apenas uma vez e referenciemos esta à uma outra tabela.

Em SQL, ficaria assim:

 	CREATE TABLE tp_logradouro
	(
		cd_tp_logradouro SERIAL NOT NULL, -- nossa chave primária
		dc_tp_logradouro VARCHAR(30) NOT NULL, -- a descrição do tipo de logradouro
		CONSTRAINT tp_logradouro_pk PRIMARY KEY (cd_tp_logradouro)
	);

        CREATE TABLE logradouro
	(
		cd_logradouro SERIAL NOT NULL, -- nossa chave primária
		tp_logradouro INTEGER NOT NULL REFERENCES tp_logradouro (cd_tp_logradouro),
		nm_logradouro VARCHAR(75) NOT NULL,
		CONSTRAINT logradouro_pk PRIMARY KEY (cd_logradouro)
	);

	CREATE TABLE trecho_logradouro
	(
		cd_trecho SERIAL NOT NULL, -- nossa chave primária
		cd_logradouro integer NOT NULL REFERENCES logradouro (cd_logradouro), -- aqui estamos referenciando a tabela logradouros.
		no_vias integer NOT NULL,
		no_faixas integer NOT NULL,
		cep_trecho VARCHAR(9) NOT NULL DEFAULT '00000-000',
		CONSTRAINT trecho_logradouro_pk PRIMARY KEY (cd_trecho)
	);

	CREATE TABLE numeracao_trecho_logradouro
	(
		cd_trecho INTEGER NOT NULL REFERENCES trecho_logradouro (cd_trecho),
		no_inicial_esq INTEGER NOT NULL DEFAULT 0,
		no_inicial_dir INTEGER NOT NULL DEFAULT 0,
		no_final_esq INTEGER NOT NULL DEFAULT 0,
		no_final_dir INTEGER NOT NULL DEFAULT 0,
		-- já estamos dizendo que só podemos ter um trecho com estas informações.
		-- não é possível repetir cd_trecho com numerações diferentes
		CONSTRAINT numeracao_trecho_logradouro PRIMARY KEY(cd_trecho)
	);

	CREATE TABLE sentido_trecho_logradouro
	(
		cd_trecho INTEGER NOT NULL REFERENCES trecho_logradouro (cd_trecho),
		dc_sentido VARCHAR(2) NOT NULL DEFAULT 'FT',
                -- os valores possíves de sentido são FT (From To), TF (To From) e FF (From From - duas mãos)
		CONSTRAINT sentido_trecho_logradouro_pk PRIMAKEY KEY (cd_trecho)
	);

	-- vamos adicionar uma coluna geométrica à trecho_logradouro

	SELECT * FROM AddGeometryColumn('public','trecho_logradouro','the_geom',-1,'LINESTRING',2);

Com estas tabelas, modelamos toda a parte de sistema viário para nossa prefeitura. Não foi complicado né? Com estas tabelas, temos informações suficientes para estabelecer rotinas de geocodificação e roteamento parcial. Para estabelecermos um roteamento completo temos ainda de ter tabelas sobre as "viradas" possíves, também chamadas de turn tables.

Modelo Entidade Relacionamento do Sistema Viário

Modelo Entidade Relacionamento do Sistema Viário

Ainda vamos adicionar suporte para as turn-tables e quem sabe mais para frente, adicionamos em nossa aplicação o pgRouting, extensão do PostGIS responsável para realizar roteamento.

Por que modelar o sistema viário em primeiro lugar? Bem, o sistema viário, é de vital importância para qualquer cidade média do mundo e com uma sólida representação do SV podemos apoiar outras partes de nosso sistema no mesmo. Uma parte que dependerá completamente do "módulo" sistema viário será o módulo de transporte público, pois utilizaremos muito geocoding para construir automáticamente as rotas de ônibus, entre outras coisinhas.

A explicação do código:

A tabela logradouro irá armazenar toda nossa informação estática sobre um conjunto de trechos de mesmo nome. A tabela trecho irá conter as informações que variam de trecho para trecho, mesmo que aqueles dois trechos distintos pertençam ao mesmo logradouro.

O relacionamento descrito pelo código na tabela trecho_logradouro "REFERENCES...", indica que um trecho deve pertencer a apenas um logradouro válido na tabela logradouro. Evitamos assim erros e duplicação de informação. Por enquanto, nossa cidade e base de dados é pequena, mas imagine daqui alguns anos? Seria uma complicação manter isto organizado, caso não utilizassemos este formato.

Por último, adicionamos uma coluna geométrica do tipo LINESTRING à tabela trecho_logradouro. Agora podemos começar inserir informações geográficas nesta tabela.

Nota: o SRID (Spatial Reference ID) -1 foi utilizado pois estamos trabalhando com um município fictício. Aqui deve aparecer o código do seu sistema de referência / datum. Lembre-se disto durante toda série de artigos ;) .

No próximo artigo iremos trabalhar com o transporte público. Iremos modelar toda a parte de linhas, pontos de parada, sentidos de transporte (bairro - centro; centro - bairro), táxis, etc.

O que acharam?

Abraços,

George R. C. Silva

25May/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

12May/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

11May/100

Funções PostGIS #1

Boa tarde pessoal,

Me desculpem o tempo parado, mas é que a correria está grande!

Gostaria de mostrar um pouco as funções do PostGIS e as maravilhas que podemos fazer com elas. Vamos começar devagar, com as básicas e ir aumentando o grau de complexidade destes posts. Algumas idéias aqui surgirão, como a criação de indíces específicos com o uso destas funções, uma prática comum para aumentar a perfomance do banco de dados. Espero que gostem. O PostGIS utilizado é o 1.4.0.

PostGIS_Full_Version()

Esta função não faz muita coisa, ela apenas te diz a versão do PostGIS instalada, bem como quais as versões das bibliotecas das quais o PostGIS depende (Proj4 e GEOS). Ela é importante pois é uma das primeiras perguntas que irão lhe fazer quando você encontrar dificuldades ou bugs. Guarde-a num cantinho da sua mente :P .

SELECT * FROM PostGis_Full_Version()

AddGeometryColumn()

Esta sim é importante. Aprenda-a usar logo.  Ela é responsável por adicionar corretamente as colunas geométricas à uma tabela. Ela não só adiciona a coluna à tabela, como cria as constraints definidas e popula a tabela geometry_columns. Se você adicionar uma coluna geométrica e não popular a tabela geometry_columns diversos softwares SIG podem não reconhecer aquela tabela como espacial. Portanto atenção nas duas.

CREATE TABLE teste(
id serial not nuLl,
atributo1 varchar(20) not null default 'abc',
constraint teste_pk primary key (id)
);

-- assinaturas
-- SELECT * FROM AddGeometryColumn('tabela','nome_da_coluna_a_ser_criada',srid,'TIPO_DE_GEOMETRIA',dimensao);
-- SELECT * FROM AddGeometryColumn('esquema','tabela','nome_da_coluna_a_ser_criada',srid,'TIPO_DE_GEOMETRIA',dimensao);

SELECT * FROM AddGeometryColumn('teste','the_geom',29192,'POINT',2);
-- QUALQUER UM DESSES FORMATOS FUNCIONAM

Qualquer um das assinaturas é válida.

DropGeometryColumn()

Esta função faz o inverso da AddGeometryColumn(). Ela remove a coluna espacial e limpa o registro na tabela geometry_columns.

-- assinaturas
-- SELECT * FROM DropGeometryColumn('tabela','nome_da_coluna');
-- SELECT * FROM DropGeometryColumn('esquema','tabela','nome_da_coluna');

SELECT * FROM DropGeometryColumn('teste','the_geom');

Populate_Geometry_Columns()

Esta função escaneia todas as tabelas que contenham colunas do tipo geometry e as popula com as constraints apropriadas: tipo de geometria, número de dimensões e SRID especificado.

-- assinaturas
-- SELECT * FROM Populate_Geometry_Columns();
-- SELECT * FROM Populate_Geometry_Columns(oid_tabela);

SELECT * FROM Populate_Geometry_Columns();

Esta função sem argumentos, irá escanear todas as tabelas do banco e tentar criar as constraints para cada uma. Se você especificar um oid a função tentará fazer isto somente para a tabela especificada.

Probe_Geometry_Columns()

Esta função escaneia todas as tabelas do banco com constraints espaciais e as adiciona à tabela geometry_columns. Mão na roda para garantir que todas suas tabelas estejam de acordo para uso em softwares de SIG. Esta função não escaneia views que têm de ser populadas na tabela geometry_columns na mão.

-- assinatura
-- SELECT * FROM Probe_Geometry_Columns();

SELECT * FROM Probe_Geometry_Columns();

UpdateGeometrySRID

Esta belezinha aqui realiza o trabalho de atualizar as constraints e as geometrias para determinado SRID. Cuidado, esta função não converte coordenadas. Apenas atualiza a tabela geometry_columns e as constraints correspondentes!

-- assinatura
-- SELECT * FROM UpdateGeometryColumn('nome_tabela','nome_coluna_espacial',novo_srid);
-- SELECT * FROM UpdateGeometryColumn('esquema','nome_tabela','nome_coluna_espacial',novo_srid);

SELECT * FROM UpdateGeometryColumn('public','teste','the_geom',-1);

ST_Transform

Iniciando nas funções realmente espaciais, temos a função ST_Transform. Você notará que todas as funções espaciais contém o prefixo ST. As anteriores não possuem o prefixo pois são funções administrativas. Esta função, realmente converte as coordenadas de um SRID para outro.

-- assinatura
-- ST_Transform(geometria,novo_srid);

-- sem transformacao
SELECT cd_equipamento_urbano, ST_AsText(the_geom) FROM equipamento_urbano;

-- transformada
SELECT cd_equipamento_urbano, ST_AsText(ST_Transform(the_geom,4618)) FROM equipamento_urbano;

Nesta seção vemos duas funções. ST_AsText que será explicada mais tarde, e a ST_Transform. Veja como podemos embrulhar funções dentro de funções, que são avaliadas de dentro para fora. Os resultados das queires acima são.

Tabela de pontos original em UTM Zona 22S

Tabela de pontos original em UTM Zona 22S

Esta é o resultado transformado:

Tabela de pontos transformada em SAD69 Lat/Long

Tabela de pontos transformada em SAD69 Lat/Long

Existem muiiiitas funções úteis no PostGIS que são realmente uma mão na roda. Próximo post falaremos de funções modificadoras de geometria e construção de geometrias.

Espero que tenham gostado.

Abraços

George R. C. Silva

28Apr/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

16Apr/100

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.

18Mar/100

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

11Mar/100

Monografia

Boa noite pessoal,

Muita gente já me pediu e estava sem tempo de colocar online, mas agora vai.

A Construção de um Sistema Geocodificado de Acidentes de Trânsito

Defendi a monografia ano passado e fica como referência para quem tiver interesse.

Tenho certeza que não é perfeita, portanto, se tiverem algumas dúvidas ou enxergarem alguns erros, por favor, entre em contato ;)

Abraços

George

31Jan/106

O Geoprocessamento e Suas Tecnologias – Parte 2

Olá!

Conforme vimos na primeira parte deste post, o Geoprocessamento é um conjunto de tecnologias dinâmicas com alto potencial de aplicação.

Até aqui vimos que Geoprocessamento e SIG não são as mesma coisa. O SIG é apenas uma importante tecnologia dentre as diversas incluídas no Geoprocessamento.

Vimos também que programas como o gvSIG e ArcGis não são "SIGs" mas softwares para SIG. Assim como o Geoprocessamento possui várias ramificações tecnológicas o SIG é um sistema composto por softwares, hardwares, metodologias, recursos humanos e dados.

Ficamos de ver o que são e pra servem tecnologias como o Banco de Dados Geográfico e o WebMapping.

Banco de Dados Geográficos

Bom, vamos por partes. O que é um Banco de Dados (BD)?

Todo local, físico ou virtual onde estão armazenados dados, pode em certo sentido, ser chamado de banco de dados. Por exemplo, uma enciclopédia pode ser considerada um banco de dados. Mas para nós aqui da área de Geoprocessamento é mais importante o conceito especial de banco ou base de dados relacional. Ou seja um banco onde dados são armazenados na forma de tabelas relacionáveis entre si através campos chaves.

As mais diversas facetas de atividades, desde locadoras de DVD até grandes indústrias metalúrgicas usam-se deste tipo de base para ter um maior controle sobre fatores como cadastro de clientes e sua condição em relação à empresa (Inadimplência, por exemplo).

Neste ponto, é importante evitar confundir o BD em sí (conjunto de tabelas relacionáveis) com o programa que o gerenciará, o Sistema Gerenciador de Banco de Dados (SGBD). EM outras palavras, softwares como Access, MySQL, Oracle, PostgreSQL não são BD, mas sim SGBD.

Mas ainda não falamos no assunto deste tópico. O que é e para que serve um Banco de Dados Geográfico (BDG)?

O BDG, também chamado de Banco de Dados Espacial (BDE), é semelhante ao descrito acima (relacional), com a grande e importante diferença de suportar feições geométricas em suas tabelas.

Este tipo de base com geometria oferece a possibilidade de análise e consultas espaciais. É possível calcular nestes casos, por exemplo, áreas, distâncias e centróides, além de realizar a geração de buffers e outras operações entre as geometrias.

Como dica de estudos para você obter uma boa base conceitual sobre BDG, indico o livro "Banco de Dados Geográficos" do INPE, que está disponível para download em PDF aqui.

Atualmente, alguns programas de SGBD desenvolveram extensões que inserem no software características de Sistemas Gerenciadores de Banco de Dados Geográficos (SGBDG) o PostgreSQL, MySQL, e Oracle, sendo os dois primeiros softwares livres e o último proprietário.

Vamos falar um pouco mais do PostgreSQL e como ele passa a agir como SGBDG. O PostgreSQL é desenvolvido atualmente pela PostgreSQL Global Development Group. Quando se percebeu a necessidade de extender este SBGD para suportar dados espaciais desenvolveu-se a extensão conhecida como PostGis.

Sendo assim, vamos entender que o PostGis não é um BDG ou um SGBDG, ele é apenas uma extensão, um plugin, do PostgreSQL que lhe confere funções para armazenamento e manipulação de dados geográficos.

A figura abaixo procura mostrar a diferença entre o PostgreSQL e "seu filho". Note que para termos um BDG no PostgreSQL faz-se necessária a devida instalação da extensão PostGis.

Você pode importar arquivos vetoriais shapefile (*.shp) para dentro de um "Banco PostGis" utilizando recursos oferecidos pelo próprio programa ou utilizando algum software de SIG com essa funcionalidade. O shapefile será convertido em uma tabela espacial que pode ser integrada com as convencionais contidas na base, além de poder ser visualizada e manipulada através de programas como o gvSIG, Kosmo, Quantum Gis, Udig e muitos outros desta safra. Para baixar tutoriais sobre como realizar esta operação com alguns destes softwares, clique aqui.

Para baixar a versão mais recente do PostgreSQL e sua extensão espacial PostGis, acesse os links abaixo.

Para finalizar este post vamos considerar outra tecnologia do Geoprocessamento, a saber, WebMapping.

WebMapping (WebGis)

A internet vem se destacando nos últimos anos como uma excelente ferramenta para disponibilização e interligação de dados das mais diversas fontes e naturezas.

A geomática, como área do conhecimento, também encontrou na internet um nicho para suas atividades. A disponibilização de mapas digitais, os chamados WebGis ou WebMapping, tem-se tornado comum, permitindo que um maior número de usuários tenha acesso a dados espacializados, de forma hábil e atraente.

Talvez o estopim para o crescimento das aplicações SIG para internet tenha sido a popularização de serviços online gratuitos de localização como o Google Earth e Google Maps.

Os mapas na web se apresentam de três formas princiapais:

1) Mapas Estáticos - Mapas no formato de imagem (*.jpg, *.gif, *.png, etc) integrados à páginas da internet.

2) Mapas Gerados à partir de formulários - Fornece-se parâmetros para geração de mapas na forma de imagem.

3) Mapas Dinâmicos - O usuário seleciona uma área de seu interesse em um mapa geral, gerando uma navegação para outro mapa ou imagem mais específico com informações mais detalhadas desta região. Em geral apresentam interface atraente com ícones para consulta espacial calculo de distância e etc.

Para mais detalhes sobre tipos de mapas veja a publicação disponibilizada neste link.

Há muitos softwares e frameworks livres para o desenvolvimento de aplicações WebGis. Podemos destacar alguns: MapServer, GeoServer, i3Geo, Alov Map, Time Map, Open Layers e P.Mapper.

Diversos órgãos públicos fazem uso destas ferramentas para divulgação dos resultados de seus trabalhos.

A imagem abaixo mostra um exemplo de aplicação desenvolvida com MapServer e o framework P.Mapper. Clique aqui para acessar a página da aplicação (Este é um exemplo de mapa dinâmico).

Nesta visão geral sobre algumas das tecnologias do Geoprocessamento, pudemos dissipar alguns falsos conceitos em torno de termos como SIG, BDG, SGBDG, WebGis, etc. Espero que tenham gostado do que leram.

Fiquem à vontade para deixar sua sugestão de tema, críticas e impressões através do e-mail anderson[@]geoprocessamento.net

Anderson Medeiros

Tecnólogo em Geoprocessamento

Get Adobe Flash playerPlugin by wpburn.com wordpress themes