Publicando uma mapa dinâmico com Django e OpenLayers

Na postagem anterior eu demonstrei como publicar um mapa usando Django e OpenLayers. Agora vou demonstrar como publicar um mapa com conteúdo dinâmico usando Django e OpenLayers. A aplicação completa utiliza os softwares Postgres, PostGIS, apache, MapServer e as bibliotecas Django, OpenLayers e jQuery, nesta outra postagem eu demonstro como configurá-la.

Partindo da postagem anterior, vou incluir naquele mapa uma camada WFS que será publicada utiliza dados armazenados no servidor da aplicação. Para que estes dados sejam disponibilizados na internet é necessário ter um servidor de mapas instalado e configurado. Neste caso estamos utilizando o MapServer com o seguinte arquivo de mapa (.map):

MAP
 # configuracoes gerais
    NAME "Cidade de São Paulo"
    STATUS ON
    EXTENT -46.8258 -24.0077 -46.3648 -23.3563
    SIZE 600 400
    IMAGECOLOR 255 255 255
    PROJECTION 
        "init=epsg:4291" # obrigatorio em minusculo
    END #PROJECTION
    WEB
        IMAGEPATH "/home/marcos/mapserver/ms_tmp"
        IMAGEURL "/ms_tmp/"
        METADATA
            # WMS
            "wms_title" "Cidade de São Paulo"
            #wms_onlineresorce ""
            "wms_srs" "EPSG:4291 EPSG:4674 EPSG:4326"
            "wms_enable_request" "*"
            # WFS
            "wfs_title" "Dados da Cidade de São Paulo"
            "wfs_srs" "EPSG:4291 EPSG: 4674 EPSG:4326"
            "wfs_abstract" "Este servico disponibiliza distritos da Cidade de São Paulo"
            "wfs_enable_request" "*"
        END  # METADATA
    END #WEB
Ver arquivo completo no final da postagem

Para publicar dados nos protocolos WFS e WMS no MapServer é necessário que o arquivo de mapa, no escopo global, contenha o marcador “METADATA” e com os marcadores iniciados com “wms_” e “wfs_” conforme indicado no arquivo. No âmbito de cada camada é necessário também um marcador de “METADATA” com os marcadores “wfs_title” e “wfs_srs” que indicam, respectivamente, o nome da camada e o código da projeção do EPSG. Uma vez configurado, os serviços estarão disponíveis em:

http://localhost/cgi-bin/mapserv?map=/home/marcos/sites/sisgeo/static/mapas/distritos.map

Note que o arquivo de mapa está dentro da pasta “static” da aplicação. Esta é uma pasta que o Django utilizada para arquivos que não possuem conteúdo manuseado por ele. Este arquivo pode estar em qualquer pasta desde que o usuário “www-data” utilizado pelo servidor HTTP (Apache) tenha acesso a ela.
Num servidor de produção deve-se utilizar outra estratégia para publicar e acessar o arquivo de mapa. Maiores detalhes de como configurar um servidor WFS/WMS com MapServer estão disponíveis em mapserver.org.

Uma vez configurado o servidor as camadas estão disponíveis para software que consomem serviços WFS e WMS. Para consumo destes serviços utilizamos aqui a biblioteca OpenLayers, para isso incluímos uma camada assim definida:

var vetor = new OpenLayers.Layer.Vector('Vetor básico',{
	 strategies: [new OpenLayers.Strategy.BBOX()],
	 protocol: new OpenLayers.Protocol.WFS({
	 	//version: "1.0.0",
		url: “http://localhost/cgi-bin/mapserv?map=/home/marcos/sites/sisgeo/static/mapas/distritos.map”,
		featureType: "fatos"
	 })
});

Uma vez criada a camada para adiciona-la ao mapa criado no OpenLayers utiliza-se o seguinte comando:

mapa.addLayer(vetor);

Como haverá edição nesta camada, é necessário indicar isso com o seguinte comando:

mapa.addControl(new OpenLayers.Control.EditingToolbar(vetor));

Agora vamos controlar os eventos associados a edição. Primeiro vamos pegar a barra de editar com o seguinte comando:

barraEditar = mapa.getControlsByClass('OpenLayers.Control.EditingToolbar')[0];

Depois vamos verificar quando ocorrem eventos de edição e acionar as funções apropriadas. A cada objeto inserido na camada de vetor a função abaixo é acionada e por padrão o OpenLayers envia para ela o objeto inserido que neste caso esta sendo armazenado temporariamente pela variável “fato”.

vetor.onFeatureInsert = function(fato){ 
	//controls[0]= pan; controls[1] = ponto; controls[2] = linha; controls[3] = poligono 
	if (barraEditar.controls[0].active == false){ 
		 
		// popup para atributos 
		fato.popup = new OpenLayers.Popup.FramedCloud( 
			"formulario",//identificador 
			fato.geometry.getBounds().getCenterLonLat(),//posicao 
			null, // tamanho 
			formFato.replace('%geom%', fato.geometry),// conteudo html 
			null,//ancora 
			true, //botao de fechar o popup 
			null // funcao acionada quando e acionado o botao fechar 
		); 

		// inclui o popup no mapa 
		mapa.addPopup(fato.popup); 
    } 
}

Esta função é acionada quando ocorre inclusão de objetos na camada vetor. Primeiramente ela verifica a inclusão foi feita com algum controle de edição (ponto, linha, polígono) isso é feito verificando se o controle de movimento (pan) não está ativo (barraEditar.controls[0].active == false) isso funciona porque o primeiro controle desta barra, indicado por controls[0], é o de movimento. Esta verificação é necessária porque quando o mapa é carregado na camada “vetor” ocorre a inclusão de objetos via WFS e estes não devem passar por nenhuma ação. Uma vez verificado que a inclusão esta sendo feita por um controle de edição inclui-se uma janela sobre o mapa (popup) com os campos a serem preenchidos, que nada mais é que um formulário html. Isto é feito pela função FrameCloud do OpenLayers e ela requer os seguintes parâmetros: identificador, posição, tamanho, conteúdo html, ancora, botão de fechar e função de retorno ao acionar fechar. Uma vez criada, a janela é incluída no mapa do OpenLayers com o comando mapa.addPopup(feature.popup).

O conteúdo html da janela está na variável formFato que nada mais é que um formulário html com o seguinte conteúdo:

<form action="" method="">
<input type="hidden" name="csrf" value="{{ csrf_token }}"/>
<p>Nome: <input type="text" name="nome" size="20"/></p>
<p>Tipo: <select name="tipo"><option value="Escolha">Escolha</option>
<option value="cultura">Cultural</option>
<option value="esporte">Esportivo</otption>
<option value="historia">Histórico</option>
<option value="curiosidade">Curiosidade</option></select></p>
<p>Descricao:<textarea name="descricao" rows="2" cols="50"></textarea></p>
Geom: <input type="text" name="geom" value="%geom%" readonly="true" size="30" />
<p><input type=submit name="Enviar" value="Salvar"
onClick=""/></p>
</form>

Importante notar neste formulário os campos “csrf” e “geom”. O primeiro armazena um token do Django que é responsável evitar que sejam enviados ao servidor dados que não sejam originados de formulários gerados pelo Django e será preenchido pelo mecanismo de template do Django cada vez que o formulário for chamado. O segundo possui a sequencia “%geom%” que é substituída pelas coordenadas do dado inserido no memento em que o formulário é aberto, note na criação do popup o comando: formFato.replace(‘%geom%’, fato.geometry).

A variável formFato foi colocada logo no começo do scrip, abaixo da variável mapa e foi preenchida dinamicamente por meio de uma chamada Ajax com o comando:

var formFato = $.get('mapa/formfato');

Como o servidor http usa Dajngo ao passar a url “mapa/formfato” o servidor procura por esta URL na configuração de URL (urls.py) e ao encontrar aciona a view indicada (formFato), esta por sua vez retorna o template (msp/formFato.html) com os marcadores de template ({{variavel}} ) substituídos por seus respectivos valores. Abaixo a configuração de URL:

from django.conf.urls import patterns, url

from msp import views

urlpatterns = patterns('',
    url(r'^mapa$', views.mapa, name='mapa'),
    url(r'^teste', views.teste, name='teste'),
    url(r'^mapa/inserefato', views.insereFato, name='inserefato'),
    url(r'^mapa/formfato', views.formFato, name='formfato'),
)

A view formFato possui o seguinte conteudo:

def formFato(request):
    return render(request, 'msp/formFato.html')

Optou-se aqui por usar um par url/view para alimentar a variável formFato para demonstrar uma das possibilidade de integração entre o Django e o OpenLayers, porém a variável pode ser alimentada na mesma view que carrega o mapa principal.

Uma vez disponibilizado o formulário é necessário tratar o seu comportamento ao ser aciona a opção “Salvar”. Isto é feito via Ajax com a biblioteca jQuery e a função encarregada disso está a seguir:

$(document).ready(function() { 
	$(':submit').click(function(evt) { 
		evt.preventDefault(); // nao submete o formulario 
		var nome = $(':text[name="nome"]').val(); 
		var tipo = $(':input[name="tipo"] option:selected').val(); 
		var desc = $(':input[name="descricao"]').val(); 
		var geom = $(':text[name="geom"]').val(); 
		var csrf = $(':input[name="csrf"]').val(); 

		// submete os dados via ajax post 
		$.ajax({ 
			type : 'POST', 
			url : 'mapa/inserefato', 
			data : { 
				nome : nome, 
				tipo : tipo, 
				descricao : desc, 
				geom : geom, 
				csrfmiddlewaretoken: csrf 
			} 
		}) 
			// recebe a resposta do servidor e inclui no popup 
			.done(function(resposta) { 
				$('#formulario form').html(resposta); 
			}); 
	}); 
});

Esta função deve estar imediatamente abaixo do comando mapa.addPopup(fato.Popup). Com ela a aplicação trata o envio de dados ao servidor com Ajax, isso significa que ao ser acionado o botão “Salvar” a aplicação enviara os dados ao servidor com a função $.ajax() sem alterar nada na janela popup, somente após a resposta do servidor é que o conteúdo desta janela será alterado, por meio da função done(), que recebe como parâmetro o conteúdo do servidor e o armazena na variável “resposta”. Em seguida esta função seleciona o formulário da janela popup via jQuery, utilizando o identificador definido no momento da criação da janela (#formulario) e o marcador de formulário html (form), e o substitui ( $(‘#formulario form’).html(resposta); )pelo conteúdo recebido e armazenado na variável “resposta”.

A função $.ajax() do jQuery recebe como parâmetros uma matriz com três objetos JavaScript: type, url e data. O primeiro é método de envio, o segundo a URL de destino encarregada de tratar o recebimento dos dados e o terceiro outro objeto JavaScript contendo os dados do formalário. Note que para criar este objeto foram utilizadas as variáveis nome, tipo, desc, geom e csrf definidas previamente e preenchidas por meio de jQuery. Notar também que as funções $.ajax() e done() estão encadeadas num único comando, ou seja, elas devem ser vistas desta forma: $.ajax().done(); e dentro delas seus respectivos conteúdos. Para melhor compreensão de jQuery recomendo a consulta da documentação desta biblioteca.

Do lado do servidor há uma configuração de URL para receber o endereço “mapa/inserefato”. Ao receber uma chamada para este endereço o Django aciona a view formFato que vai receber e tratar os dados do formulário, ela possui o seguinte conteúdo:

# insere um registro no banco de dados
def insereFato(request):
    
    if request.method == 'POST':
        try:
            nome = request.POST['nome']
            tipo = request.POST['tipo']
            descricao = request.POST['descricao']
            geom = request.POST['geom']
            
            # cria o objeto fato
            fato = Fato(nome=nome,tipo=tipo,descricao=descricao,geom=geom)
            # salva o objeto fato
            fato.save()
            
            return render(request, 'msp/insereFato.html')
        
        except:
            return render(request, 'msp/erroSalvar.html',
                          {'fato': fato, 'geom': geom}

Após verificar que os dados foram verificados via POST, num servidor de produção ao invés dessa configuração deve-se usar Django Forms que, entre outras coisas, valida o formulário por completo e é mais seguro. A seguir são criadas variáveis colocais para cada campo do formulário, é criado um objeto fato da classe Fato, com este objeto é acionado o comando para salvar os dados. Se não ocorrer nenhum erro em nenhum destes passos é retornado o template “insereFato.html” que informa que os dados foram inseridos com sucesso, caso contrario retorna uma mensagem de erro e os dados submetidos.

Com essa postagem eu encerro essa série de como colocar no ar uma aplicação de geoprocessamento, logicamente que o que foi demostrado aqui não é uma aplicação completa mas, acredito eu, cobre um de seus aspectos mais nebulosos. A partir deste ponto a construção da aplicação consiste em criar todos os formulários, visualizações e relatórios que atendam sua necessidade.

Veja aqui a aplicação funcionando.

Map file completo.

MAP
 # configuracoes gerais
    NAME "Cidade de São Paulo"
    STATUS ON
    EXTENT -46.8258 -24.0077 -46.3648 -23.3563
    SIZE 600 400
    IMAGECOLOR 255 255 255
    PROJECTION 
        "init=epsg:4291" # obrigatorio em minusculo
    END #PROJECTION
 Leia mais...

Criar e publicar um mapa no Django

No Django, para exibir qualquer informação é necessário criar uma view sendo que esta view pode possuir qualquer tipo de conteúdo seja estático, dinâmico ou ambos, sendo mais comum possuir ambos.
A parte estática do conteúdo fica em arquivos html denominados templates. Um template pode ser utilizado tanto para definir o aspecto visual de determinado conteúdo a ser exibido na página, bem como simplesmente ser exibido como uma página html estática, isto é, sem conteúdo dinâmico. Dito isto, vou mostrar aqui como exibir uma página html estática que possui um mapa criado com OpenLayers.
Note que apesar de o mapa possuir controles de zoom e movimento o conteúdo desta página é considerado estático pelo servidor da aplicação pois não há nenhuma informação, decorrente de alguma ação do usuário ou do momento em que foi acessada a página, que tenha sido gerada instantaneamente pela aplicação. Será simplesmente exibida uma página html que ao ser acessada exibirá sempre o mesmo conteúdo.

 

Criar APP no Django

Na postagem anterior foi criado e configurado o sistema ou site, “project” no Django, mas não foi incluído nenhum conteúdo. O passo seguinte àquele ponto, é a criação de um módulo ou “app” na terminologia do Django. Recomendo a leitura do tutorial do Django para que você obtenha uma visão detalhada de como criar projetos e app ‘s.
Dito isto, na pasta raiz do projeto – onde esta o arquivo manage.py, digite o seguinte comando:

python manage.py startapp msp

Este comando irá criar um pasta de nome ‘msp’ e incluirá nela os arquivos que compõem o app. Agora vamos criar uma view para exibir o mapa e depois configurar a url que conterá o endereço de acesso a view.

 

Criar a View

Para criar uma view dentro de um app, basta abrir o arquivo views.py e inserir, abaixo do conteúdo existente, as seguintes linhas:

def teste(request):
    return render(request, 'msp/teste.html')

Esta função cria a view “teste” que recebe uma requisição de entrada e retorna a requisição e um template (arquivo html). O conteúdo final da view é este:

from django.shortcuts import render
# Create your views here.

def teste(request):
    return render(request, 'msp/teste.html')

A função render é responsável por passar conteúdo dinâmico ao template, mas neste caso isso não ocorre e não precisamos nos preocupar com isso agora, esse processo será explicado na próxima postagem.

Criar o template

Na raiz do projeto, deve-se criar uma pasta chamada “templates” e dentro dela a pasta da aplicação, “msp”, neste local criaremos o template teste.html que será utilizado pela view “teste”. Insira nele o conteúdo abaixo :

<!DOCTYPE html>

<html>

<head>

<meta charset='utf-8' />

<title>SP Distritos</title>

http://dev.openlayers.org/OpenLayers.js

var mapa;

function inicializar(){

mapa = new OpenLayers.Map('mapa',{});

var wms = new OpenLayers.Layer.WMS(

'Densidade Pop 2000',

'http://sedac.ciesin.columbia.edu/geoserver/wms',

{layers:'gpw-v3:gpw-v3-population-density_2000'},

{}

);

mapa.addLayer(wms);

mapa.zoomToMaxExtent();

}

</head>

<body onload="inicializar()" >

</body>

</html>

Este arquivo cria um mapa do OpenLayers e exibe numa página html. Apesar de ser possível movimentar a aplicar zoom neste mapa, o seu conteúdo é estático, ele mostra a densidade populacional do mundo no ano 2000. Como este arquivo não possui nenhuma tag de template do Django ele não é um template de fato, é apenas um arquivo html e não fosse pelo mapa, ele poderia ser chamado de “arquivo html simples”. Para que este template possa ser acessado pela view é necessário configurar uma diretiva no arquivo settings.py do projeto. Este arquivo está na pasta de configuração do projeto /sisgeo/sisgeo/ . Ao abrir o arquivo, procurar a diretiva TEMPLATE_DIRS e verifique se ela está como a esta:

TEMPLATE_DIRS = [os.path.join(BASE_DIR,'templates')]

Com isso o Django irá encontrar e tratar qualquer arquivo neste diretório e subdiretórios como um template.

Configurar URL

Uma vez criada a view e o template o último passo é configurar a url. O Django possui um mecanismo de configuração de url que, além de possibilitar nomes amigáveis de urls, permite também a criação dinâmica de urls e é modular.
Para criar urls que dão acesso ao conteúdo de determinado app, deve-se criar o arquivo urls.py dentro da pasta do app. Neste arquivo ficam todas as urls do módulo, dentro deste arquivo, incluir o seguinte conteúdo:

from django.conf.urls import patterns, url
from msp import views

urlpatterns = patterns('',
    url(r'^teste', views.teste, name='teste'),
)

A primeira linha do arquivo contém a chamada para duas funções Django que são responsáveis por interpretar e definir os padrões de url. A segunda linha importa as views criadas na aplicação, no nosso caso, apenas a view “teste”. A quarta linha cria uma variável (urlpatterns) que será interpretada pelo Django e nela define a url que será criada.
Os três parâmetros da quinta linha “ r’^teste’, views.teste, name=’teste’ ” definem, respectivamente, o padrão que será procurado “teste”, a view acionada ao encontrar o padrão e o nome da url que pode ser usado em templates e em outras partes da aplicação.
Feita a configuração da url e da view no âmbito do app, agora é necessário conectar o app a url principal do sistema. Para isso, deve-se acessar o arquivo urls.py dentro da pasta principal do projeto e incluir, abaixo do exemplos dados, a seguinte linha:

url(r'^msp/', include('msp.urls', namespace='msp')),

Esta linha conecta a url da aplicação “msp” a url geral do sistema. Primeiro ela define o nome “msp” que será parte da url para acessar as views do app “msp” e depois inclui as urls configuradas no arquivo msp/urls.py. Assim, o caminho completo da view teste será: sisgeo/msp/teste
O arquivo sisgeo/sigeo/urls.py ficou assim:

from django.conf.urls import patterns, include, url
from django.contrib.gis import admin

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'sisgeo.views.home', name='home'),
    # url(r'^blog/', include('blog.urls')),
    url(r'^msp/', include('msp.urls', namespace='msp')),
)

Uma vez feito isso a view está pronta para ser exibida, digite localhost/sisgeo/msp/teste no navegador e a seguinte imagem deve aparecer:

densidade populacional

densidade populacional

Esta página está disponível neste link: http://52.67.51.226/sisgeo/msp/mapa

Esta postagem é apenas para mostrar como criar e publicar uma pagina html num servidor web com Django. Como o propósito de Django é acelerar o desenvolvimento de sites com conteúdo dinâmico, não faz sentido usá-lo apenas para exibir páginas com conteúdo estático. Sendo assim, na próxima postagem mostrarei como publicar uma página com conteúdo dinâmico e georreferenciado usando Django.

Configurando um servidor para aplicação de geoprocessamento

A uma semana atrás publiquei aqui uma uma proposta de configuração de servidor para atender uma aplicação web com geoprocessamento. Continuando aquela publicação, publico agora como instalar e configurar os softwares indicados. A mesma configuração foi instalada num servidor com Ubuntu 64 14.04 LTS e também numa maquina virtual com Ubuntu 32 14.04 LTS.

Os passos descritos aqui são baseados na documentação oficial do Django  e do GeoDjango porém, diferente de lá, onde a instalação das bibliotecas de geoprocessamento estão separadas da instalação padrão do framework, aqui a instalação e configuração é justamente para atender um servidor com capacidade de processar dados geográficos.

Instalação e configuração

Todos os comandos indicados aqui devem ser executados no terminal do Ubuntu. Para quem não está acostumado a instalar bibliotecas a partir do código fonte, recomendo a leitura do artigo http://ubuntuforum-br.org/index.php?topic=28774.0 ao final dele há também um link para outras formas de instalação de bibliotecas no Ubuntu.

Instalar bibliotecas com o comando checkinstall permite e desinstalação da mesma com o comando dpkg -r <nome da biblioteca>. Assim ao invés de usar o comando make install por make checkinstall. Normalmente nos roteiros originais de instalação está apenas o comando make install.
Quando instalar uma biblioteca a partir dos arquivos fonte (sequencia de instalação iniciada com wget), execute o comando sudo ldconfig ao final da instalação.
Após a instalação de cada biblioteca limpe o diretório de instalação com o comando make clean.

A primeira instalação a ser feita é da ferramenta para construção de pacotes build-essential e para gerenciamento de pacotes checkinstall. Para isso execute o comando:

sudo apt-get install build-essential checkinstall

Em seguida vamos instalar duas bibliotecas python:

sudo apt-get install python-dev python-numpy

Feito isso passamos a instalação dos softwares específicos.

Bibliotecas Espaciais
GEOS

GEOS é uma implementação em C++ da especificação Simple Feature for SQL do OpenGIS e também aprimoramentos da bibliteca JTS da qual é derivada. Ela contém funções para criar, analisar e processar dados vetoriais. Aqui está sendo instalada a versão 3.4.2.

cd downloads
wget http://download.osgeo.org/geos/geos-3.4.2.tar.bz2
tar xjf geos-3.4.2.tar.bz2 -C ../install/
cd ../install/geos-3.4.2/
sudo ./configure
sudo make
sudo checkinstall
sudo ldconfig
make clean

GDAL/OGR

GDAL é uma biblioteca para conversão de dados geográficos no formato matricial e OGR e responsável pelo processamento (leitura, gravação e conversão) de dados no formato vetorial. Ambas são distribuídas juntas pela OSGEO sob o nome de GDAL. A versão instalada aqui é a 1.11.0.

Para instalação a partir do código fonte, acione o comando wget numa pasta de sua preferência e execute os comandos abaixo:

cd downloads
wget http://download.osgeo.org/gdal/1.11.0/gdal-1.11.0.tar.gz
tar xzf gdal-1.11.0.tar.gz -C ../install/
cd ../install/gdal-1.11.0
./configure && make clean && make
sudo checkinstall #uninstall with: sudo dpkg -r  gdal
sudo ldconfig
make clean

Note que a instalação foi feita no diretório “install”. É recomendado que você defina um diretório de instalação para suas bibliotecas diferente do local onde foram baixados os arquivos, pode-se criar qualquer diretório e instalar nele.

Proj 4

Proj 4 é uma biblioteca de projeções cartográficas utilizada para conversão de dados. A versão a ser instalada é a 4.8.0.

wget http://download.osgeo.org/proj/proj-4.8.0.tar.gz
wget http://download.osgeo.org/proj/proj-datumgrid-1.5.tar.gz
tar xzf proj-4.8.0.tar.gz -C ../install/
tar xzf proj-datumgrid-1.5.tar.gz -C ../install/proj-4.8.0/nad/
cd ../install/proj-4.8.0/
sudo ./configure --with-geos=yes --with-python=yes
sudo make clean && make
sudo checkinstall 
sudo ldconfig
make clean

PyProj
Pyproj

sudo apt-get install python-pyproj

PostgreSQL e PostGIS: instalação

Será instalado aqui a versão 9.3 do Postgres e a 2.1 do PostGIS. Se estiver usando o Ubuntu 14.04 execute os comandos abaixo:

sudo apt-get install postgresql-9.3 postgresql-9.3-postgis-2.1 pgadmin3

Com eles você instala o postgres, postgis e pgadmin pois os repositórios destes softwares já estão nos repositórios do Ubuntu 14.04. Numa instalação em servidor, provavelmente não será instalada a biblioteca pgadmin3, ela será instalada apenas na máquina de desenvolvimento.

Se estiver utilizando outra versão do Ubuntu, 12.04 por exemplo, será necessário adicionar os repositórios no arquivos de fontes.

Criar o arquivo de fontes de instalação do postgresql com o comando:

sudo sh –c ‘echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" >> /etc/apt/sources.list.d/pgdg.list’

ou, fazendo em etapas:

sudo vim /etc/apt/sources.list.d/pgdg.list

Incluir esta linha no final do arquivo:

deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main

Note que “precise” é o nome da distribuição 12.04 de Ubuntu LTS. Caso esteja usando outra distribuição, para saber seu nome digite o comando: lsb_release –c.
A seguir importe a chave do repositório de https://www.postgresql.org/media/keys/ACCC4CF8.asc, atualize a lista de pacotes e inicie a instalação. Isto é feito em sequencia com os comando abaixo:

sudo apt-get install wget ca-certificates postgre	

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install postgresql-9.3 postgresql-9.3-postgis pgadmin3 postgresql-contrib

Postgres e PosGIS: configuração
Após a instalação, defina a senha do usuário administrador (postgres) para que se possa acessar o banco de dados através do pgAdmin3 e do psql, para isso digite:

sudo –u postgres psql postgres

Em seguida digite:

\password postgres

Será solicitado a digitação da senha duas vezes.
Então digite a nova senha para o usuário e confirme quando for solicitado. Por questões de segurança a senha não é exibida no console. Digite Ctrl+D para sair do console psql.

Criar um banco de dados:

sudo –u postgres createdb template_postgis

Criar a extensão espacial:

sudo –u postgres psql –d template_postgis –c “CREATE EXTENSION postgis;”

Criar a extensão topológica:

sudo –u postgres psql –d template_postgis –c “CREATE EXTENSION postgis_topology;”

Teste a instalação via PgAdmin3 ou via psql. A acessar o servidor será possível encontrar os bancos de dados postgres e template_postgis, o primeiro é o bando de dados de manutenção do SGBD e o segundo o banco de dados criado que deve servir de template para a criação de novos banco de dados já com a extensão espacial habilitada.

Fontes de consulta para instalação do PostgreSQL:
http://trac.osgeo.org/postgis/wiki/UsersWikiPostGIS21UbuntuPGSQL93Apt
https://wiki.postgresql.org/wiki/Apt
https://help.ubuntu.com/community/PostgreSQL

Psycopg2
Biblioteca para conexão ao postgres com python. Instalar com o comando abaixo:

sudo apt-get install python-psycopg2

Apache
Para instalação do servidor HTTP Apache, executar o seguinte comando no terminal:

sudo apt-get install apache2

Para testar a instalação abra um navegador de internet e digite: localhost . Se a instalação estiver correta poderá ser vista a frase: “It works!”. Configurações adicionais do apache.

Referencia:
https://help.ubuntu.com/14.04/serverguide/httpd.html

Mod WSGI
Instalação manual.
Via navegador, verificar versões disponíveis em:
http://code.google.com/p/modwsgi/downloads/list
Selecionar uma versão e executar os comandos:

wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.4.8.tar.gz 
tar xvfz 4.4.8.tar.gz

Antes de instalar, baixar duas bibliotecas:

sudo apt-get install python-dev apache2-prefork-dev

Depois de completado este processo configurar e instalar o mod_wsgi:

cd mod_wsgi-4.4.8
./configure
sudo make
sudo make checkinstall
make clean

Uma mensagem indicará onde o modulo foi instalado “Libraries have been instaled in: …”, não é preciso guardar esta informação, é apenas para saber que a instalação foi feita com sucesso.

Habilitar o módulo mod_wsgi no Apache
Criar o arquivo wsgi.load nos módulos disponíveis do apache com o seguinte comando:

sudo sh –c ‘echo “LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so” >> /etc/apache2/mods-available/wsgi.load’

ou

sudo vim /etc/apache2/mods-available/wsgi.load

Este comando cria o arquivo wsgi.load na pasta /etc/apache2/mods-available/. Agora incluia o seguinte conteúdo no arquivo: “LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so” sem as aspas. Salve e feche o arquivo

Ativar o módulo com o comando:

sudo a2enmod wsgi

Reiniciar o apache:

sudo service apache2 restart

Para verificar se o modulo está carregado, executar o comando:

apache2ctl –M | sort

Será possível ver o wsgi na lista de módulos carregados.

Referencias
http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide
https://www.digitalocean.com/community/articles/installing-mod_wsgi-on-ubuntu-12-04
http://www.lennu.net/2012/05/14/django-deployement-installation-to-ubuntu-12-dot-04-server/

Django
Django é uma framework para desenvolvimento de aplicações web utilizando Python, veja mais detalhes em https://www.djangoproject.com/.

Primeiro instalar o pip, que é uma ferramenta para instalação e manutenção de bibliotecas Python

sudo apt-get install python-pip

Após instalar o pip, instalar o Django 1.7.4 com o comando abaixo:

sudo pip install Django==1.7.4

Aparecerá uma mensagem indicando o sucesso da instalação.
Para testar a instalação digite:

python
import django
print(django.get_version())

Você verá o número da versão instalada.
Referencias:
https://pypi.python.org/pypi/pip
https://www.djangoproject.com/download/

Smart Selects
É uma biblioteca para criar botões de seleção em Django de modo que o valor de um é dependente de uma valor previamente informado, por exemplo, ao selecionar o estado, o sistema mostra apenas os municipios pertencentes aquele estado.
Fazer o download da biblioteca em https://pypi.python.org/pypi/django-smart-selects/1.0.9 e no local onde foi salvo, executar os comandos:

wget https://pypi.python.org/packages/source/d/django-smart-selects/django-smart-selects-1.0.9.tar.gz
tar xvfz django-smart-selects-1.0.9.tar.gz -C ../install
cd ../install/django-smart-selects-1.0.9
sudo python setup.py install

Criar aplicação Django e configurar no Apache
Criar uma pasta no diretório home do usuário e dentro dela criar um projeto Django (veja o tutorial aqui) com os comandos abaixo:

mkdir sites
cd sites/
django-admin.py startproject sisgeo

Dentro da pasta /etc/apache2/sites-available/ criar o arquivo sisgeo.conf ou outro com qualquer nome. O importante é que este é o arquivo de configuração do sistema no Apache. É a partir da leitura deste arquivo que o sistema será disponibilizado no servidor http. Nas versões mais recentes do Apache, para não misturar a configuração do servidor com as configurações de módulos e de sites, durante a instalação são criadas as pastas mods-available, mods-enabled, sites-available e sites-enabled. Dito isto, crie o arquivo sisgeo.conf na pasta sites-available do Apache:

sudo vim /etc/apache2/sites-available/sisgeo.conf

e inclua o seguinte conteúdo:

WSGIScriptAlias /sisgeo /home/ubuntu/sites/sisgeo/sisgeo/wsgi.py
WSGIPythonPath /home/ubuntu/sites/sisgeo

<Directory /home/ubuntu/sites/sisgeo/sisgeo>
<Files wsgi.py>
	Require all granted
</Files>
</Directory>

Para habilitar o sistema executar os comandos abaixo:

sudo a2ensite sisgeo.conf
sudo service apache2 reload
sudo service apache2 restart

Feito isso é só testar, abra um navegador e digite localhost/sisgeo/ na barra de endereço, deverá ser exibida uma pagina semelhante a esta:

Sucesso na instalação

Se for possível ver esta tela (ver aqui), significa que a aplicação Django está configurada corretamente no Apache, agora é colocar o conteúdo específico e configurar a url principal no Django.
Se falhar, verifique as configurações e se ainda persistir o erro dê permissão para o usuário apache do servidor (www-data) acessar o arquivo wsgi.py como dono:

sudo chown www-data:www-data sites/sisgeo/sisgeo/wsgi.py

Se continuar falhando de permissão de leitura e execução ao arquivo

sudo chmod 755 sites/sisgeo/sisgeo/wsgi.py

Se continuar falhando verifique os logs do apache (access.log e error.log, procure estes arquivos em seu servidor pois a localização deles varia conforme o sistema operacional) e procure ajuda na web. Os comandos abaixo exibem as ultimas linhas de erro destes arquivos no Ubuntu Server 14.04 LTS:

tail /var/log/apache2/error.log
tail /var/log/apache2/access.log

Esta é apenas a configuração básica, para o sistema entrar no ar, dependendo dos recursos a serem disponibilizados, será necessário incluir outras configurações no arquivo sisgeo.conf, principalmente no caso de arquivos remotos, para mais detalhes, consultar a seção em “Serving Files” na documentação oficial do Django.

Na próxima semana mostrarei como desenvolver uma pagina (view na denominação do Django) com recursos de geoprocessamento.

Referências:
https://docs.djangoproject.com/en/1.7/topics/install/
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/modwsgi/
https://docs.djangoproject.com/en/1.7/ref/contrib/gis/install/
https://docs.djangoproject.com/en/1.7/intro/tutorial01/

Aplicação WEB com geoprocessamento

Introdução

Atualmente diante da existência de um grande volume de dados, em diversos formatos e com pouca padronização, sempre que há a necessidade de uma visão integrada de uma determinada situação em um determinado momento, há uma dificuldade de encontrar a informação necessária e também uma tarefa considerável para atualizar todas as informações para o estado desejado. Evidentemente para se chegar ao estado desejado, quando se chega, é necessário um esforço extra dos envolvidos que envolvem a interrupção das atividades normais e, não raro, trabalho além dos limites de horário.
Diante desta situação é desejável que todas as informações de empresas e órgãos estejam padronizadas, organizadas, atualizadas, armazenadas com segurança e disponíveis a qualquer instante para aqueles que necessitam da informação para a tomada de decisão ou para realizar um procedimento rotineiro.
Felizmente, apesar de toda esta situação, estão disponíveis e acessíveis a qualquer pessoa ou organização, a baixíssimo custo, ferramentas que permitem lidar com situações como esta de modo organizado e, indo além, disponibilizando novas funções que permitem novas analises que não eram possíveis na situação anterior.

Objetivo
Construir uma aplicação web que permita a consulta e visualização de mapas e informações georreferenciadas em ambiente internet.

Justificativa
Orgãos públicos de diversas esferas são detentores de uma gama considerável de informações que geralmente não estão facilmente à disposição dos cidadãos. Ao mesmo tempo a sociedade demanda estas informações por diversas razões e na busca das mesmas se depara com a dificuldade de acessá-las. Finalmente ao acessarem, se dão conta que a informação não está em formato adequado, o que gera mais trabalho para se chegar onde se deseja.
Ao mesmo tempo órgãos públicos necessitam disponibilizar a informação e por não disporem de meios adequados, disponibilizam como esta. Numa tentativa de disponibilizar informações em formatos mais apropriados, o Governo Federal criou a Infraestrutura Nacional de Dados Espaciais – INDE uma plataforma na internet que, entre outras coisas, visa catalogar, integrar e harmonizar dados geoespaciais existentes nas instituições do governo brasileiro.
Informações georreferenciadas e informações alfanuméricas quando disponíveis de modo integrado e com fácil acesso permitem uma melhor compreensão de uma determinada situação. Não raro, a simples disponibilização e visualização da informação pelo usuário, leva a rápida tomada de atitudes e ações desejáveis que levariam um maior tempo para serem tomadas. Assim, a construção desta aplicação como esta visa disponibilizar e facilitar o acesso as informações.

Ferramentas

Hardware

Para este teste iremos utilizar uma instancia AWS EC2 na nuvem da Amazon com Ubuntu 14.04 LTS, com 1 GB de RAM e 30 GB de espaco em disco. Para maiores detalhes do Amazon EC2 consultar http://aws.amazon.com/pt/documentation/ec2/.

Softwares
PostgreSQL: sistema gerenciador de banco de dados – SGBD, objeto-relacional, que implementa o padrão SQL. É gratuito e de código aberto e está disponível em: http://www.postgresql.org

PostGIS: é uma extensão que prove um suporte para objetos geográficos no PostgreSQL, isto é, implementa um conjunto de funções para armazenamento e análise de informações georreferenciadas nos formatos vetorial e matricial neste SGBD. Ele implementa os padrões OpenGIS/OGC, é gratuito, código aberto e está disponível em http://postgis.refractions.net.

Python: é uma linguagem de programação orientada a objeto, de alto nível, isto é, com sintaxe e comandos que abstraem detalhes relacionados ao hardware. É uma linguagem para uso geral e está disponível em diversos sistemas operacionais (Linux, Windows, Mac). Em ambiente Linux e disponível por padrão, já em Windows é necessária a instalação. Está disponível em: http://www.python.org

Django: é um framework para a linguagem Python para desenvolvimento de aplicações web. Essencialmente o que ele prove é uma biblioteca de classes e funções que simplificam o desenvolvimento e manutenção de sistema e aplicações em ambiente web. Esta disponível em http://www.djangoproject.com.

Apache HTTP Server: é um servidor de paginas web, multiplataforma. É o servidor HTTP mais utilizado no mundo, é gratuito e está disponível em httpd.apache.org.

MapServer: é um servidor de mapas para internet que permite a disponibilização de mapas através dos protocolos WFS e WMS. É gratuito, de código aberto e está disponível em http://www.mapserver.org .

OpenLayers: é uma biblioteca (framework) de classes e funções em JavaScript para visualização, edição e análise de informações georreferenciadas através da internet. Ele permite a visualização de dados nos formatos vetorial e matricial e aceita os padrões WMS e WFS. É gratuito, de código aberto e está disponível em http://www.openlayers.org.

Navegador de Internet: qualquer navegador de internet para acessar a aplicação.

Arquitetura da aplicação

arquitetura aplicacao web

Funcionamento da aplicação

O usuário interage com a aplicação por meio de um navegador de internet. Ao digitar o endereço da aplicação na barra de endereço do navegador, este se conectara ao servidor de internet (Servidor HTTP) onde a mesma está hospedada. Neste momento o servidor HTTP, procura pelos arquivos de inicialização da aplicação, ao encontrar, exibe a pagina inicial ao usuário. A aplicação é conjunto de funções, desenvolvida na linguagem de programação Python com o framework Django. A partir do momento que o usuário se conecta a aplicação, todas as requisições que ele fizer serão controladas pelo framework que fica encarregado de processar as funções que irão buscar os dados no sistema gerenciador de banco de dados – SGBD ou no sistema de arquivos – FS e devolver ao usuário, numa pagina html, em forma de tabela, gráfico ou mapa.

A aplicação dispõe de um visualizador de mapas que possui a capacidade de exibir informações georreferenciadas e ler dados de diversos formatos. Quando o usuário acessa o visualizador de mapas este se conecta ao servidor da aplicação para buscar dados no formato WMS ou WFS. É possível que o visualizador de mapas exiba dados não só do servidor do sistema, mas também de outras fontes desde que estejam num dos formatos do padrão OGC (WMS, WFS, GML, KML). Assim é possível exibir imagem de diversos provedores tais como, Yahoo, Google e Microsoft Bing e muitos outros.

Em breve, até a próxima semana, farei um nova postagem com a configuração da arquitetura no Ubuntu 14.04 LTS.

Criando memorial descritivo com PostGIS e Python

Uma tarefa muito comum em geoprocessamento é criar memorial descritivo de uma área, apesar disso os SIG’s disponíveis não possuem uma ferramenta para gerar estes documentos. O que normalmente se encontra nestes softwares são funções que retornam os valores das coordenadas, o azimute e a distância. A elaboração do documento em si fica por conta do usuário. Visando ajudar nesta tarefa elaborei um script em Python que juntamente com o PostGIS gera estes documentos.

Com a tabela (layer) da(s) área(s) no Postgres  (veja como aqui) a primeira etapa é obter uma tabela com os vértices de cada área que terá memorial descritivo, para isso utilizou-se a instrução SQL abaixo:

CREATE TABLE vertices As
SELECT id,
    (ST_DumpPoints(geom)).path[3] As vertice,
    ST_X((ST_DumpPoints(geom)).geom),
    ST_Y((ST_DumpPoints(geom)).geom),
    (ST_DumpPoints(geom)).geom As geom
FROM servidao_lotes
ORDER BY id, vertice</i>

A instrução acima gera uma tabela com os vértices de cada lote. Esta tabela possui os seguintes campos: identificador do lote, vértice, coordenada x, coordenada y, e geometria do lote. Esta tabela foi criada apenas para facilitar o entendimento do script, mas estes vértices poderiam ser obtidos em tempo de execução. Ter uma tabela de vértices é útil também nos casos onde é necessário identificar os vértices com nomes que não sejam números sequenciais.

Os campos “vértice”, “x” e “y”, foram obtidos com o auxilio da função ST_DumpPoints do PostGIS, esta função retorna o conjunto de pontos que forma uma determinada geometria, ver documentação oficial para mais detalhes. Note o uso dos componentes geom e path da função, eles são os responsáveis por fornecer o ponto e o índice(vértice) de cada geometria.

Uma vez obtida a tabela acima os script Python a seguir é responsável por gerar o memorial descritivo de cada lote da tabela. Sua lógica é a seguinte:

Para cada lote da tabela de lotes:

  1. Cria-se o identificador do memorial;
  2. Em seguida, para este lote, selecionam-se seus vértices;
  3. Depois, se é o primeiro vértice da poligonal, inicia-se a descrição do memorial;
  4. A partir dai, para cada vértice e com o subsequente, obtêm-se o azimute e a distância entre os dois vértices e verifica-se se há lote adjacente ao lote em questão:
    • i.      Se existir é feita a descrição do confrontante;
    • ii.      Se não existir descreve como confrontante a próprio lote. Isto porque neste o memorial é para uma faixa de servidão dentro do lote;
  5. Finalizado o giro por todos os vértices do lote, faz-se a ligação do último vértice com o primeiro e aplica-se a descrição padrão final de cada memorial e, por fim, o script cria um arquivo txt com o memorial gerado.

Dentro do script são realizadas três instruções SQL. A primeira (strCadastros) seleciona os lotes para os quais serão gerados os memoriais. O importante a observar nesta instrução é a ordem dos campos que entram na descrição do memorial. Observada esta sequencia qualquer modificação na instrução é valida. Esta instrução origina o conjunto de lotes  para os quais serão gerados memoriais.  A segunda instrução (strVertices) seleciona os vértices que fazem parte do lote em questão e para cada um destes vértices é feita uma consulta que retorna entre ostras coisas, a distância e o azimute até o próximo vértice. Esta é principal consulta do script.

SELECT lote, denominaca, proprietario,
    to_char(ST_Distance(ST_setSRID(ST_MakePoint( 764975.11518, 9697768.20104), 31983),
        ST_SetSRID(ST_MakePoint(764974.070324, 9697767.45146), 31983)),'9G999D99'),
    degrees(ST_Azimuth(ST_setSRID(ST_MakePoint(764975.11518, 9697768.20104), 31983),
        ST_setSRID(ST_MakePoint(764974.070324, 9697767.45146), 31983))) azimute
FROM servidao_lotes
WHERE ST_Intersects(cad.geom, ST_MakeLine(
    ST_SetSRID(ST_MakePoint(764975.11518, 9697768.20104), 31983),
    ST_SetSRID(ST_MakePoint(764974.070324, 9697767.45146), 31983)))
ORDER BY lote DESC limit 2;</i>

Esta terceira instrução (strAdjacente) além da verificação dos lotes que estão contíguos ao lote atual, são obtidos também dois dos quatro principais valores que descrevem os vértices em memoriais descritivos modernos: azimute e distancia. Os outros dois são as coordenadas X e Y. Esses valores são obtidos a partir das funções ST_Distance e ST_Azimuth do PostGIS. A primeira retorna a distância entre dois pontos e a segunda retorna o ângulo, em radianos, azimute entre dois pontos. Como num memorial descritivo o azimute é indicado em graus, foi feita a conversão para esta unidade.

Há ainda nesta consulta algumas funções adicionais, ST_MakePoint() retorna uma geometria tipo ponto a partir das coordenadas;  ST_MakeLine() retorna uma geometria tipo linha a partir das coordenadas;  ST_SetSRID() define o código da projeção segundo o EPSG; to_char() converte um numero decimal para uma sequencia de caracteres definida pela formatação “9G999D99”, sendo “G” separador de grupo e “D” separador de decimal .

Com a substituição de algumas variáveis, acredito eu,  o script será muito útil, gero 100 memoriais em 1 minuto. Segue o código fonte:

# -*- encoding: utf-8 -*-
# Este script gera memoriais descritivos para um ou mais poligonos em uma
# tabela SQL. É necessário ter o PostGIS isntalado e o conector Psycopg.
# Autor: Antonio Marcos
# E-mail: marcosgeo#yahoo.com

import psycopg2
import math

# ALTERE ESTAS VARIVEIS
#conecta ao banco de dados
geodados = psycopg2.connect("dbname=geodados user=usuario password=senha")
geodados.set_client_encoding('latin-1')

# cria um cursor para realizar as operações
cadastros = geodados.cursor()
vertices = geodados.cursor()
adjacente = geodados.cursor()
atualiza = geodados.cursor()

# ALTERE ESTAS VARIAVEIS
# codigo da projeção e datum. neste caso é sirgas 2000 f 23
srid = '31983'
# tabela de áreas
tabCadastro = "servidao_lotes"
# tabela de vértices
tabVertices = "vertices"
# pasta onde os arquivos são salvos
pasta ="C:\Users\marcos\Temp\memoriais\Lote_"

# início do memorial
cabecalho = "MEMORIAL DESCRITIVO\n\n\n"

# realiza uma instrução SQL
strCadastros = """SELECT lote, denominaca, proprietario, municipio, comarca, cartorio, 
       matricula, area, incra, hectares, perimetro
  FROM %s;""" % tabCadastro

strVertices = """select id, to_char(st_x,'999G999D99') x,
        to_char(st_y,'9G999G999D99') y, to_char(min(vertice),'000'),
        st_x, st_y, min(vertice)
    from %s
    where id = '%s'
    group by  id, st_x, st_y, vertice
    order by id, vertice;"""

strAdjacente = """SELECT lote, denominaca, proprietario,
        to_char(ST_Distance(ST_setSRID(ST_MakePoint( %s), %s),
            ST_SetSRID(ST_MakePoint(%s), %s)),'9G990D99'),
        degrees(ST_Azimuth(ST_setSRID(ST_MakePoint(%s), %s),
            ST_setSRID(ST_MakePoint(%s), %s))) azimute
    FROM %s cad 
    WHERE ST_Intersects(cad.geom, ST_MakeLine(
        ST_SetSRID(ST_MakePoint(%s), %s),ST_SetSRID(ST_MakePoint(%s), %s)))  
    ORDER BY lote DESC limit 2;"""

cadastros.execute(strCadastros)

# coverte de graus decimais para grau, min e segundo.
def dec2gms(dec):
    separa = math.modf(dec)
    grau = int(separa[1])
    mindec = separa[0]*60
    min = int(math.modf(mindec)[1])
    seg = math.modf(mindec)[0]*60
    return str(grau) + "º " + str(min) + "' " + format(seg,'.2f').replace('.',',') +"''"

id = 0
# para cada área da tabela, elabora um memorial descritivo
for cadastro in cadastros:
    memorial = ""

    id = cadastro[0]
    memorial += cabecalho
 
    identificacao = """\n\nImóvel: Faixa de Servidão da LT de 500 kV Paulino Neves - SE Miranda II %s
        Comarca: %s
        Propreitario: %s
        Municipio: %s \t\t U.F.: SP
        Matrícula: %s \t\tIdentificador: %s
        Área: %s ha \t\tPerímetro: %s m
        DESCRIÇÃO""" % (str(cadastro[0]), str(cadastro[4]),
                        str(cadastro[2]), str(cadastro[3]), str(cadastro[6]),
                        str(cadastro[0]),str(cadastro[9]),str(cadastro[10]))

    memorial += identificacao  

    # seleciona os vértices que pertencem ao lote definido por 'id'
    vertices.execute(strVertices % (tabVertices, id))

    # variaveis de controle dos vértices
    ponto2 = ""
    ponto1 = ""
    v1 = ""
    # faz um giro pelos vertices seguindo  de p1 para p2     
    for vertice in vertices:
        if vertices.rownumber < vertices.rowcount: # pula o último ponto
            # se vértice 2 esta definido passa o valor para 1
            if vertices.rownumber == 1:
                ponto1 = str(vertice[4]) + ", " + str(vertice[5])
                v1 = " até o vértice " + str(vertice[3])
                memorial += "\n\n\n\tInicia-se a descrição deste perímetro no vértice " +\
                    str(vertice[3]) + ", de coordenadas N " + str(vertice[2]) + \
                    " m e E " + str(vertice[1]) + " m"
                ponto2 = str(vertice[4]) + ", " + str(vertice[5])
            else:
            # define o valor do vértice 2
                ponto1 = ponto2
                ponto2 = str(vertice[4]) + ", " + str(vertice[5])

                # executa a instrução que retorna o azimute e distancia e
                # retorna também as áreas adjacentes 
                adjacente.execute(strAdjacente %
                    (ponto1, srid, ponto2, srid, ponto1, srid, ponto2, srid,
                     tabCadastro, ponto1, srid, ponto2, srid))

                # faz um giro pelo resultado e descre o vértice          
                for adj in adjacente:
                    if adjacente.rowcount > 1 and adj[0] <> id:
                        memorial += " deste segue confrontando com a propriedade " + str(adj[1]) + \
                                    " de " + str(adj[2])
                        #transforma os graus decimais do azimute em GMS
                        memorial += ", com azimute e distância de " + dec2gms(adj[4]) +\
                            " e " + str(adj[3]) + " m até o vértice " + \
                            str(vertice[3]) + ", de coordenadas N " + \
                            str(vertice[2]) + " m e E " + str(vertice[1]) + " m;"
                        break
                    elif adjacente.rowcount == 1:
                        memorial += " deste segue confrontando com a propriedade "+str(cadastro[1])+\
                                " de " + str(cadastro[2]) +\
                                ", com azimute e distância de " + dec2gms(adj[4]) +\
                                " e " + str(adj[3]) + " m até o vértice " + str(vertice[3]) + \
                                ", de coordenadas N " + str(vertice[2]) + " m e E " + \
                                str(vertice[1]) + " m;"
  
    strFinal = """, ponto inicial da descrição deste perímetro. Todas as coordenadas \
    aqui descritas estão georreferenciadas ao Sistema Geodésico Brasileiro, a partir \
    das constantes N 10.000.000,00m  e  E 500.000,00m , e encontram-se \
    representadas no Sistema UTM, referenciadas ao Meridiano Central 45° WGr, \
    tendo como datum o SIRGAS 2000. Todos os azimutes e distâncias, áreas e \
    perímetros foram calculados no plano de projeção UTM."""

    memorial += v1 + strFinal

    arquivo =open(pasta + id +'.txt','w')
    arquivo.write(memorial)
    arquivo.close()
    print"\n\n"+identificacao
    
del cadastros, vertices, adjacente, atualiza

Adendo, estrutura da tabela de lotes:

CREATE TABLE public.servidao_lotes
(
  lote character varying(5),
  denominaca character varying(46),
  proprietario character varying(160),
  municipio character varying(80),
  comarca character varying(18),
  cartorio character varying(9),
  matricula character varying(15),
  area double precision,
  incra character varying(9),
  hectares text,
  perimetro text,
  geom geometry(MultiPolygon,31983)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE public.a_servidao_lotes
  OWNER TO postgres;
Categorias:PostGIS, Python, SQL

Encontrar erro na hidrografia e curvas de nível com PostGIS

Um problema comum de topologia em SIG é a intersecção entre de curvas de nível e hidrografia. Idealmente, um curso d’água passa sobre uma curva de nível apenas uma vez, tal como indicado no ponto A da imagem abaixo. Um erro de topologia ocorre quando o curso d’água passa sobre a mesmo curva de nível mais de uma vez, indicado por B na figura:

hidro_curvas1

Este tipo de problema na base cartográfica não deve ser desprezado, pois além do erro visual, afeta a geração de modelos tridimensionais (TIN e MDT), por exemplo. Na imagem acima, como há poucas curvas de nível e cursos d’água, fica fácil identificar onde há problemas. Mas e se a base possui milhares de cursos d’água e curvas de nível?

Quando há vários elementos de hidrografia e curva de nível se faz necessário um método automatizado que encontre tais problemas. Uma das maneiras que encontrei para identificar este erro foi, utilizando Postgres/PostGIS, fazer uma instrução SQL que retorna um ponto onde isto ocorre:

select c.gid c_gid, c.z c_z, h.gid h_gid,
    st_npoints(st_intersection(c.geom, h.geom)), 
    st_intersection(c.geom, h.geom)
from atemp_hidrografia h, atemp_curvanivel c
where st_npoints(st_intersection(c.geom, h.geom)) > 1
order by h.gid, c.gid

Esta instrução retorna os identificadores de curva de nível, hidrografia, valor z da curva e, o mais importante, a intersecção entre curva de nível e hidrografia. Isto foi obtido com a função st_intersection() do PostGIS, que neste caso retorna uma coleção de pontos onde ocorre interseção da hidrografia com as curvas de nível. Foi utilizada ainda a função st_npoints () para contar o numero de pontos dentro da coleção.
É justamente neste ponto que está a chave para identificar o problema: numa base de dados topologicamente correta, um curso d’água corta apenas uma vez uma curva de nível, por isso quando o resultado da função st_npoints() é maior que 1, este local é identificado como erro. Na imagem abaixo, o X indica os pontos onde há erros entre curva de nível e hidrografia:

hidro_curvas2

Agora é só corrigir.

Categorias:PostGIS, Quantum GIS, SIG/GIS, SQL

Vila Planalto

Esta vila foi construída para abrigar os trabalhadores de construção de Brasília, portanto ela é anterior a cidade e seu primeiro morador foi para lá em 1957 e não devia ter ficado de pé após o término das obras de construção da cidade. Mas ficou.

Apesar de conservar poucas características e construção originais a vila é tombada. É fácil identificar as casas originais, pois são feitas de madeira. Na praça central de Vila Planalto há uma, porém pintada de branco. Há ainda várias casas feitas no sistema de auto-construção e há também casas que poderiam estar nos Jardins ou Alto de Pinheiros em Sampa.

Além destas características, o que mais me chamou a atenção em Vila Planalto é que ao nela entrar, parece que você saiu de Brasília e entrou numa cidade do interior, pois é muito comum ver as pessoas andando pelas ruas, sentadas na calçada conversando ou vendo o tempo passar. Há também crianças brincando pelas ruas e velhos andando tranquilamente sem se preocupar com os carros, que estacionam na contramão sem levar multa ou causar tumulto. (Pessoas andando a pé pelas ruas não é comum em Brasília – aqui só se anda de carro, principalmente para ir na padaria, caso se encontre uma. Um taxista me disse que quando vê alguém andado a pé, se estiver sem passageiro ele diminui e pergunta se ela quer ir de taxi.)*

Numa das praças centrais da vila tem um campo de futebol onde, aos domingos, acontecem aquelas grandes peladas das pequenas cidades do interior. No entanto, a singular diferença, é que um dos times estará atacando tendo sempre, além das traves, a visão do topo das duas torres do Congresso Nacional. É a única coisa que faz lembrar que se está em Brasília.

Na praça central de Vila Planalto, Nelson Corso – primeiro morador, há um restaurante chamado Fogão de Pedra, que tem um ambiente muito agradável e uma boa comida. Eu diria que o padrão dele é de um bom restaurante por quilo de Sampa, inclusive no preço: 28 reais o kg. Não é dificil encontrar políticos almoçando no Fogão de Pedra. Ao lado dele, há um daqueles butecos muito comuns em qualquer vila periférica de São Paulo ou de pequenas cidades, com as tradicionais mesas e cadeiras de plástico de alguma marca de cerveja. De frente para este restaurante, do outro lado da praça, está o Armazém do Geraldo. Ainda há armazéns por aqui.

Como a “primeira” casa da Vila Planalto está a menos de 1km do Palácio do Planalto e do Congresso Nacional e como o planejamento de Brasília não reservou espaços para restaurantes, a vila está se transformando num ponto gastronômico. Pelo menos na hora do almoço. Gente de toda a Esplanada dos Ministérios e até do setor bancário, vai almoçar lá.

Ouvi dizer que se o taxista entrar em Vila Planalto a noite e a empresa dona da frota souber, ele é punido com dois dias de suspensão. Dizem que é perigoso, mas acho que há perigo em qualquer grande cidade brasileira (e não só nas grandes), em razão disso, já peguei uma bicicleta e fui dar umas voltas em Vila Planalto. Há um posto policial na praça central da vila.

Mesmo estando na Praça dos Três Poderes, não tente ir a pé até a Vila Planalto, pois é muito desconfortante andar nesta cidade, mesmo que sejam 500 metros. Não pense que é a avenida Paulista, onde se pode andar quilômetros numa boa.

*Só se vê um pouco de gente andando a pé na W3 e entre os setores bancário e comercial. Apesar de não ser estranho andar a pé entre dois últimos, é desconfortável. No Plano Piloto, só é confortável andar a pé nas áreas estritamente residenciais, ou seja, nas alamedas das superquadras.