Page 3 of 72 (1438 posts)

  • talks about »

Tags

Last update:
Fri Feb 27 19:55:08 2015

A Django site.

QGIS Planet

How to build and debug QGIS with QtCreator

Here is how I build QGIS with QtCreator under ubuntu 14.04

Landsat 8 captures Trentino in November 2014

The beautiful days in early November 2014 allowed to get some nice views of the Trentino (Northern Italy) – thanks to Landsat 8 and NASA’s open data policy:

Landsat 8: Northern Italy 1 Nov 2014
Landsat 8: Northern Italy 1 Nov 2014

Trento captured by Landsat8
Trento captured by Landsat8

Landsat 8: San Michele - 1 Nov 2014
Landsat 8: San Michele – 1 Nov 2014

The beauty of the landscape but also the human impact (landscape and condensation trails of airplanes) are clearly visible.

All data were processed in GRASS GIS 7 and pansharpened with i.fusion.hpf written by Nikos Alexandris.

The post Landsat 8 captures Trentino in November 2014 appeared first on GFOSS Blog | GRASS GIS Courses.

A new QGIS tool (based on ogr2ogr) to import vectors in PostGIS, the fast way

In QGIS there are many tools that can be used to import vectors inside a PostGIS database, each one has pros and cons: SPIT core plugin: available since long ago but now seems to be a unmaintained tool and therefore will be probably removed in a future QGIS release. It  has the advantage to allow […]

QGIS + Postgis: Consultas de agregação

Quando através de uma consulta SQL a uma base de dados postgres\postgis se procede a uma agregação (através do uso da cláusula GROUP BY) é quase certo perder a chave primária da tabela original (geralmente o gid). No entanto, para visualizar o resultado de consultas SQL em QGIS é necessário que exista um campo com valores inteiros distintos para usar como identificadores únicos. Assim, para ultrapassar este contratempo, há que criar uma coluna com essas características.

Essa coluna pode ser feita usando a função ROW_NUMBER(), da seguinte forma:

WITH r as (SELECT
               campo1,
               (ST_Dump(ST_Union(t.geom))).geom as geom
           FROM
               tabela_1 as t
           GROUP BY
               campo1)
SELECT
    ROW_NUMBER() OVER() as id,
    r.*
FROM r;

Copiando toda para a expressão na janela SQL do DB Manager (Base de dados > Gestor BD > Janela SQL), é possível usar o campo id como identificador único.

QGIS_Janela_SQL

AgregacaoSQL_Qgis


Coordenadas dos cantos do mapa em QGIS | Map corner coordinates in QGIS

O desafio | The challenge

Em tempos na lista de discussão do qgis-pt alguém perguntou como dispor as coordenadas dos cantos do mapa no QGIS. Não estando (ainda) disponível tal funcionalidade, tentei chegar sem sucesso a uma solução que fosse de certa forma automática. Depois de remoer a ideia, e de ler um artigo do Nathan Woodrow, achei que a solução poderia passar por criar uma função para o construtor de expressões que pudesse ser usada em etiquetas no mapa.

Some time ago in qgis-pt mailing list, someone asked how to show the coordinates of a map corners using QGIS. Since this features wasn’t available (yet), I have tried to reach a automatic solution, but without success,  After some though about it and after reading a blog post by Nathan Woodrow, it came to me that the solution could be creating a user defined function for the expression builder to be used in labels in the map.

 A solução | The solution

Seguindo as indicações do referido artigo, comecei por criar um ficheiro userfunctions.py, que gravei na pasta .qgis2/python e, com uma ajuda do Nyall Dawson, escrevi o seguinte código.

Closelly following the blog post instructions, I have created a file called userfunctions.py in the  .qgis2/python folder and, with a help from Nyall Dawson I wrote the following code.

from qgis.utils import qgsfunction, iface
from qgis.core import QGis

@qgsfunction(2,"python")
def map_x_min(values, feature, parent):
 """
 Returns the minimum x coordinate of a map from
 a specific composer.
 """
 composer_title = values[0]
 map_id = values[1]
 composers = iface.activeComposers()
 for composer_view in composers():
  composer_window = composer_view.composerWindow()
  window_title = composer_window.windowTitle()
  if window_title == composer_title:
   composition = composer_view.composition()
   map = composition.getComposerMapById(map_id)
   if map:
    extent = map.currentMapExtent()
    break
 result = extent.xMinimum()
 return result

Depois de correr o comando import userfunctions na consola python (Módulos > Consola python), já conseguia usar a função map_x_min() (disponível na categoria python) numa expressão para obter o valor mínimo em X.

After running the command import userfunctions in the python console  (Plugins > Python Console), it was already possible to use the  map_x_min() function (from the python category) in an expression to get the minimum X value of the map.

Screenshot from 2014-09-09 16^%29^%29
Bastava então criar as restantes funções map_x_max(), map_y_min() e map_y_max(). Como parte do código seria repetida, decidi encapsulá-lo na função map_bound() que recebesse como argumentos o título do compositor de impressão e o id do mapa e me devolvesse a extensão do mesmo (sob a forma de um QgsRectangle).

All I needed now was to create the other three functions,  map_x_max(), map_y_min() and map_y_max().  Since part of code would be repeated, I have decided to put it in a function called map_bound(), that would use the print composer title and map id as arguments, and return the map extent (in the form of a QgsRectangle).

from qgis.utils import qgsfunction, iface
from qgis.core import QGis

def map_bounds(composer_title, map_id):
 """
 Returns a rectangle with the bounds of a map
 from a specific composer
 """
 composers = iface.activeComposers()
 for composer_view in composers:
  composer_window = composer_view.composerWindow()
  window_title = composer_window.windowTitle()
  if window_title == composer_title:
   composition = composer_view.composition()
   map = composition.getComposerMapById(map_id)
   if map:
    extent = map.currentMapExtent()
    break
 else:
  extent = None

 return extent

Com essa função disponível podia usá-la internamente nas funções para devolver cada um dos mínimos e máximos em X e Y, tornando o código mais compacto e fácil de manter. Adicionei ainda ao código original alguns mecanismos para evitar erros.

With this function available, I could now use it in the other functions to obtain the map X and Y minimum and maximum values, making the code more clear and easy to maintain. I also add some mechanisms to the original code to prevent errors.

@qgsfunction(2,"python")
def map_x_min(values, feature, parent):
 """
 Returns the minimum x coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.<br>
 <h2>Syntax</h2>
 <p>map_x_min(composer_title, map_id)</p>
 <h2>Arguments</h2>
 <p>composer_title - is string. The title of the composer where the map is.<br>
 map_id - integer. The id of the map.</p>
 <h2>Example</h2>
 <p>map_x_min('my pretty map', 0) -> -12345.679</p>
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.xMinimum()
 else:
  result = None

 return result

@qgsfunction(2,"python")
def map_x_max(values, feature, parent):
 """
 Returns the maximum x coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.<br>
 <h2>Syntax</h2>
 <p>map_x_max(composer_title, map_id)</p>
 <h2>Arguments</h2>
 <p>composer_title - is string. The title of the composer where the map is.<br>
 map_id - integer. The id of the map.</p>
 <h2>Example</h2>
 <p>map_x_max('my pretty map', 0) -> 12345.679</p>
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.xMaximum()
 else:
  result = None

 return result

@qgsfunction(2,"python")
def map_y_min(values, feature, parent):
 """
 Returns the minimum y coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.<br>
 <h2>Syntax</h2>
 <p>map_y_min(composer_title, map_id)</p>
 <h2>Arguments</h2>
 <p>composer_title - is string. The title of the composer where the map is.<br>
 map_id - integer. The id of the map.</p>
 <h2>Example</h2>
 <p>map_y_min('my pretty map', 0) -> -12345.679</p>
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.yMinimum()
 else:
  result = None

 return result

@qgsfunction(2,"python")
def map_y_max(values, feature, parent):
 """
 Returns the maximum y coordinate of a map from a specific composer.
 Calculations are in the Spatial Reference System of the project.<br>
 <h2>Syntax</h2>
 <p>map_y_max(composer_title, map_id)</p>
 <h2>Arguments</h2>
 <p>composer_title - is string. The title of the composer where the map is.<br>
 map_id - integer. The id of the map.</p>
 <h2>Example</h2>
 <p>map_y_max('my pretty map', 0) -> 12345.679</p>
 """
 composer_title = values[0]
 map_id = values[1]
 map_extent = map_bounds(composer_title, map_id)
 if map_extent:
  result = map_extent.yMaximum()
 else:
  result = None

 return result

As funções ficaram disponíveis no construtor de expressões na categoria “Python” (podia ter-lhe dado outro nome qualquer) e as descrições das funções são transformadas em textos de ajuda para fornecer ao utilizador informação de como utilizar as funções.

The functions became available to the expression builder in the “Python” category (could have been any other name) and the functions descriptions are formatted as help texts to provide the user all the information needed to use them.

Screenshot from 2014-09-09 15^%39^%19

Usando as funções recentemente criadas, foi fácil posicionar etiquetas  junto dos cantos do mapa com as coordenadas dos mesmos. Qualquer alteração à extensão do mapa, reflecte-se nas etiquetas, podendo por isso ser usadas convenientemente com a funcionalidade de atlas.

Using the created functions, it was now easy to put the corner coordinates in labels near the map corners. Any change to the map extents is reflected in the label, therefore quite useful to use with the atlas mode.

Screenshot from 2014-09-09 15^%40^%27

O resultado destas funções pode ser usado com outras. Na imagem seguinte apresenta-se uma expressão para apresentar as coordenadas de forma mais compacta.

The functions result can be used with other functions. In the following image there is a expression to show the coordinates in a more compact way.

Screenshot from 2014-09-09 15^%43^%55

Havia um senão… Para as funções ficarem disponíveis, seria necessário importá-las manualmente em cada utilização do QGIS. Algo que não era prático. Novamente com a ajuda do Nathan, fiquei a saber que podemos importar módulos Python no arranque do QGIS colocando na pasta .qgis2/python um ficheiro com o nome startup.py com os comandos de importação. Para o meu caso bastou o seguinte.

There was a setback… For the functions to become available, it was necessary to manually import them in each QGIS session. Not very practical. Again with Nathan’s help, I found out that it’s possible to import python modules at QGIS startup by putting a startup.py file with the import statements in the .qgis2/python folder. In my case this was enough.

import userfunctions

Conclusões | Conclusions

Fiquei bastante satisfeito com o resultado. A possibilidade do utilizador criar as usas próprias funções para usar em expressões vem mais uma vez demonstrar como é fácil personalizar e criar as minhas próprias ferramentas para QGIS. Já estou a matutar em mais aplicações para estar fantástica funcionalidade.

I was pretty satisfied with the end result. The ability to create your own functions in expressions demonstrates once more how easy it is to customize QGIS and create your own tools. I’m already thinking in more applications for this amazing functionality.

UT 9 - Qta da Peninha - Vegetação potencial

Os ficheiros Python com as funções criadas podem ser descarregados AQUI. Basta descompactar os dois ficheiros para a pasta .qgis2/python e reiniciar o QGIS, e as funções devem ficar disponíveis.

You can download the Python files with the functions HERE. Just unzip both files to the .qgis2/python folder, and restart QGIS, and the functions should become available.

Disclaimer: I’m not an English native speaker, therefor I apologize for any errors, and I will thanks any advice on how to improve the text.


Dissolver polígonos em Postgres\Postgis

Trata-se de um cenário muito recorrente em análise espacial. Tendo uma camada\tabela composta por diversos polígonos, queremos “juntá-los” de acordo com valores distintos de um ou mais atributos (exemplo: de uma camada com os limites de freguesias, queremos obter os concelhos, ou, da COS ao 3º nível, obter o 2º ou o 1º)

Este artigo tem como objectivo mostrar como fazê-lo em Postgres\Postgis.

Tabela de exemplo

Como exemplo vou usar uma tabela como o seguinte formato:

CREATE TABLE tabela_1
    (gid serial PRIMARY KEY,
     campo1 character varying(128),
     campo2 integer,
     geom geometry(MultiPolygon,27493);

tabela1_original_tabela

tabela1_original

Dissolver todos os polígonos

Em primeiro lugar podemos simplesmente agregar todos os elementos num multi-polígono único. Para tal usamos a função ST_Union().

SELECT
    ST_Union(t.geom) as geom
FROM
    tabela_1 as t;

tabela1_union

Separar polígonos que não sejam contíguos

Se por outro lado não quisermos que o resultado apresente multi-polígonos usamos a função ST_Dump() recolhendo o campo da geometria.

SELECT
    (ST_Dump(ST_Union(t.geom))).geom as geom
FROM
    tabela_1 as t;

tabela1_union_dump

Dissolver polígonos com base em valores dos campos

Se quisermos dissolver os polígonos que tenham valores iguais num ou mais campos, basta incluí-los na cláusula GROUP BY. Se quisermos que esses campos apareçam no resultado (geralmente queremos) há que referi-los no início do SELECT.

SELECT
    campo1,
    campo2,
    (ST_Dump(ST_Union(t.geom))).geom as geom
FROM
    tabela_1 as t
GROUP BY
    campo1,
    campo2;

tabela1_union_by_value

Nota 1: Para quem prefere usar interfaces gráficos, preencher formulários e clicar em botões, o uso de SQL para fazer este tipo de operações pode parecer demasiado complicado e até um pouco retrógrado. Mas uma coisa garanto, com alguma prática as dificuldades iniciais são ultrapassadas e os benefícios que se retiram deste tipo de abordagem são muito recompensadores.

Nota 2: Visualizar o resultado deste tipos consultas de agregação (que usam a cláusula GROUP BY) no QGIS pode ser desafiante, este artigo explica como ultrapassar essa dificuldade.


Mapa antigo no QGIS | Old map in QGIS

Inspirado num artigo da Anita Graser, tentei usar o QGIS para criar um mapa de Cascais que tivesse um aspecto antigo, como que se tivesse sido metodicamente desenhado à mão, embora tivesse ligeiramente maltratado.

Inspired in a post by Anita Graser, I’ve tried to use QGIS to create a Cascais‘s old looking map, like if it have been draw by hand in a methodical way.

Comecei por definir a simbologia para cada um dos elementos a representar.

I have started by defining the styles for each elements to represent.

Edifícios | Buildings

Para preenchimento dos edifícios tentei usar uma cor que lembrasse os telhados portugueses, e muito usada em mapas antigos de cidades, com um contorno ligeiramente mais escuro do mesma cor.

To fill the buildings, I have tried to use a color that reminds me the portuguese roofs, similar to the color commonly used in old maps of cities, with a slightly darker outline of the same color.

Para dar dimensão aos edifícios criei uma sombra por baixo, adicionando um “simple fill” em tons escuros e usando a opção Offset X,Y. Os valores escolhidos tiveram em conta a direcção predominante das fachadas dos edíficios de forma a que o efeito fosse visível por toda a área do mapa.

To give a bit of dimension, a shadow was created beneath, using a “simple fill” with dark colors and using a Offset X,Y. The values were chosen assuming the predominant direction of building’s facades, so that the effect could be seen all over the map area.

Capturar_4

Capturar_6

Espaços verdes | Green spaces

Para espaços verdes, usei 3 camadas de simbologia. Uma base com o preenchimento a verde. Uma segunda camada com um contorno grosso ligeiramente mais escuro, e com uma funcionalidade que surgiu na versão 2.2 e que permite mostrar as linhas de contorno apenas no interior do polígono. Para tal é necessário escolher o tipo “outline: simple line” e seleccionar a opção “draw line only inside polygon”.

For the green spaces, 3 symbol layers were used. One with a green “simple fill”. A second one with a thick outline (outline: simple line) in a darker green, and using the new 2.2 functionality that allows one to show outlines only in the polygons inside.

Capturar_5

.A última camada de simbologia é uma linha fina num verde mais escuro que as restantes.

The last symbol layer is just a tin line of a green even darker than the other two.

Capturar_7

O Mar | The Sea

Para o mar usei a mesma técnica que para os espaços verdes, mas em tons de azul e com o contorno do meio mais exagerado.

For the sea, the same effect as the green spaces was used, but in blues and with the middle outline even thicker.

Capturar_8

 Estradas | Roads

Para símbolo das estradas usei uma linha grossa com um tom pastel alaranjado. Criei também etiquetas dos nomes das ruas ao longo das linhas usando uma fonte script (no meu caso o Pristina Bold). Para melhorar a legibilidade adicionei um pequeno buffer branco com 50% de transparência.

In the road, it was used a thick line with a orange pastel color. Some street names labels were created on top of the line using a script font (in have used Pristina Bold). To improve the label readability, a small white buffer with 50% transparency was added.

Captura de tela 2014-04-11 17.55.04

Capturar_9

Praia | Beach

Nas praias, para além da base, usei um point pattern fill, com um círculo bastante pequeno.

In the beaches, besides a simple fill as background, a point patern fill was used with a very small dot.

Capturar_11Capturar_10

Composição do mapa | Map composing

Embora o aspecto do mapa não esteja muito longe do resultado final, é no Print Composer que se dão os toques finais. Em primeiro lugar, comecei por preencher toda a folha com a imagem de uma textura de papel antigo (aliás, o mesmo usado pela Anita no seu artigo). Para o efeito não ficar demasiado pesado, apliquei uma transparência de 20% à imagem.

Though the map is looking almost done, it’s in the print composer that the final touches are given. First, the map sheet is totally covered with an image of an old papel (the same used by Anita). A bit of transparency is added (20%), so that the effect is not too strong.

Captura de tela 2014-04-14 11.24.53

Depois adiciona-se o mapa propriamente dito e nas suas propriedades alteramos o modo de rendering de “normal” (usado por defeito) para “multiply“. Desta forma parece que o mapa foi desenhado directamente sobre o papel antigo.

Alterwards, the actual map is added, and in the map item properties, the rendering mode is changed from “normal” (by default) to “multiply”. This way it looks like if the map was draw directly on the old paper.

Captura de tela 2014-04-14 11.30.07

Depois é uma questão de adicionar mais umas etiquetas (nomes de praias e locais), uma rosa dos ventos e uma escala gráfica (usando sempre o modo de rendering “multiply” para parecer que foi desenhado por cima da folha), e… Voilá, temos mapa!

After this, it’s all about adding a few more labels (the beach and places names), a north arrow and the graphic scale (always using “multiply” rendering mode), and… Voilá, we have a map!

mapa_antigo


Instalar duas versões de QGIS em Linux

QGIS24_QGISmaster

Em altura de testes à versão em desenvolvimento do QGIS (versão master), dá jeito  ter também instalada a última versão estável do QGIS. Em windows isso não representa um problema, uma vez que se podem instalar várias versões do QGIS em paralelo (tanto via Osgeo4w como standalone). Em linux, o processo não é tão directo pelo facto da instalação se realizar por obtenção de diversos pacotes disponíveis nos repositórios, não sendo por isso possível instalar mais do que uma versão sem que se originem quebras de dependências. Assim, instalando a versão estável através dos repositórios, as alternativas para instalação da versão em desenvolvimento são:

  • Compilar o QGIS master do código fonte;
  • Instalar o QGIS master num docker;
  • Instalar o QGIS master numa máquina virtual;

Neste artigo vou mostrar como compilar o código fonte em Ubuntu 14.04. Afinal não é tão difícil quanto parece. Meia dúzia de comandos e um pouco de paciência e vai-se lá. Usei como base as indicações do ficheiro INSTALL.TXT disponível no código fonte com umas pequenas alterações.

Instalar todas as dependências necessárias

Num terminal correr o seguinte comando para instalar todas as dependências e ferramentas necessárias à compilação do QGIS. (adicionei o ccmake e o git ao comando original)

sudo apt-get install bison cmake doxygen flex git graphviz grass-dev libexpat1-dev libfcgi-dev libgdal-dev libgeos-dev libgsl0-dev libopenscenegraph-dev libosgearth-dev libpq-dev libproj-dev libqscintilla2-dev libqt4-dev libqt4-opengl-dev libqtwebkit-dev libqwt5-qt4-dev libspatialindex-dev libspatialite-dev libsqlite3-dev lighttpd pkg-config poppler-utils pyqt4-dev-tools python-all python-all-dev python-qt4 python-qt4-dev python-sip python-sip-dev spawn-fcgi txt2tags xauth xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable xvfb cmake-curses-gui

Configurar o ccache

Este passo permite optimizar a compilação e tornar a compilação mais rápida nas próximas vezes que se fizer:

cd /usr/local/bin
sudo ln -s /usr/bin/ccache gcc
sudo ln -s /usr/bin/ccache g++

 Obter o código fonte do Github

O código fonte pode ser colocado numa pasta à escolha de cada um. Seguindo a sugestão do ficheiro de instruções acabei por colocar tudo na minha pasta home/alexandre/dev/cpp.

mkdir -p ${HOME}/dev/cpp
cd ${HOME}/dev/cpp

Já dentro da pasta home/alexandre/dev/cpp, podemos obter o código do qgis executando o seguinte comando git:

git clone git://github.com/qgis/QGIS.git

Nota: Se pretendesse fazer alterações ao código e experimentar se funcionava, então deveria fazer o clone do fork do qgis do meu próprio repositório, ou seja:

git clone https://github.com/SrNetoChan/Quantum-GIS

Preparar directorias de compilação e instalação

O código fonte tem de ser compilado e instalado em locais próprios para evitar conflitos com outras versões do QGIS. Por isso, há que criar uma pasta para efectuar a instalação:

mkdir -p ${HOME}/apps

E outra onde será feita a compilação:

cd QGIS
mkdir build-master
cd build-master

Configuração

Já na pasta build-master damos início ao processo de compilação. O primeiro passo é a configuração, onde vamos dizer onde queremos instalar o QGIS master. Para isso executamos o seguinte comando (não esquecer os dois pontos):

ccmake ..

Na configuração é necessário alterar o valor do CMAKE_INSTALL_PREFIX que define onde vai ser feita a instalação, no meu caso usei a pasta já criada ‘home/alexandre/apps’ . Para editar o valor há que mover o cursor até à linha em causa e carregar em [enter], depois de editar, volta-se a carregar em [enter]. Depois há que carregar em [c] para refazer a configuração e depois em ‘g’ para gerar a configuração.

Screenshot from 2014-10-08 23:33:39

 Compilação e instalação

Já com tudo configurado resta compilar o código e depois instalá-lo:

make
sudo make install

Nota: Estes dois passos podem demorar um bocadinho, principalmente na primeira vez que o código for compilado.

Depois de instalado podemos correr o QGIS master a partir da pasta de instalação:

cd ${HOME}/apps/bin/
export LD_LIBRARY_PATH=/home/alexandre/apps/lib
export QGIS_PREFIX_PATH=/home/alexandre/apps
${HOME}/apps/bin/qgis

Para se tornar mais cómodo, podemos colocar os últimos 3 comandos num ficheiro .sh e gravá-lo num local acessível (desktop ou home) para executarmos o qgis sempre que necessário.

Screenshot from 2014-10-09 00:36:52

UPDATE: Actualizar a versão master

Como já foi referido num comentário, a versão em desenvolvimento está constantemente a ser alterada, por isso para testar se determinados bugs foram entretanto corrigidos há que a actualizar. Trata-se de um processo bastante simples. O primeiro passo é actualizar o código fonte:

cd ${HOME}/dev/cpp/qgis
git pull origin master

E depois é voltar a correr a compilação (que desta feita será mais rápida):

cd build-master
ccmake ..
make
sudo make install

Séries de mapas com formatos múltiplos em QGIS 2.6 – Parte 1 | Multiple format map series using QGIS 2.6 – Part 1

Para não variar, a nova versão do QGIS (o QGIS 2.6 Brigthon) traz um conjunto alargado de novas funcionalidades que permitem ao utilizador fazer mais, melhor e mais rápido do que com a versão anterior. Uma das novidades desta versão é a possibilidade de controlar algumas propriedades dos itens do compositor através de dados (por exemplo, o tamanho e a posição). Algo que abre a porta a aplicações bastante interessantes. Nos próximos artigos, proponho-me a mostrar como criar séries de mapas com multiplos formatos.

Like always, the new QGIS version (QGIS 2.6 Brigthon) brings a vast new set of features that will allow the user to do more, better and faster than with the earlier version. One of this features is the ability to control some of the composer’s items properties with data (for instance, size and position). Something that will allow lots of new interesting usages. In the next posts, I propose to show how to create map series with multiple formats.

Neste primeiro artigo, o objectivo é que, mantendo o tamanho da folha, o mapa seja criado com a orientação (paisagem ou retrato) que melhor se adapte à forma do elemento do atlas. Para exemplificar, usei a amostra de dados do Alaska para criar  um mapa de cada uma das regiões do Alaska.

In this first post, the goal is that, keeping the page size, the map is created with the most suitable orientation (landscape or portrait) to fit the atlas feature. To exemplify, I will be using the Alaska’s sample dataset to create a map for each of Alaska’s regions.

Em primeiro lugar comecei por criar o meu layout numa dos formatos, colocando vários itens nas posições que desejava.

I have started by creating the layout in one of the formats, putting the items in the desired positions.

mapa_base_atlas

Para  controlar a orientação da folha através do atlas, fui ao separador “Composição” e na opção orientação, usei no botão propriedades definidos por dados a seguinte expressão:

To control the page orientation with the atlas feature, in the composition tab, I used the following expression in the orientation data defined properties:

CASE WHEN bounds_width( $atlasgeometry ) >=  bounds_height( $atlasgeometry ) THEN 'landscape' ELSE 'portrait' END

Usando a opção de pré-visualização do atlas, podemos verificar que a orientação da folha já muda de acordo com a forma do elemento do atlas. No entanto, os itens não acompanham essa mudança e alguns ficam até fora da área de impressão.

Using the atlas preview, I could verify that the page’s orientation changed according to the form of the atlas feature. However, the composition’s items did not follow this change and some got even outside the printing area.

Screenshot from 2014-11-08 23:29:49

Para controlar o tamanho e posição dos itens do mapa tive em consideração o tamanho de uma folha A4 (297 x 210 mm), as dimensões das margens do mapa ( 20 mm, 5 mm, 10 mm, 5 mm) e os pontos de referência dos itens.

To control both size and position of the composition’s items I had in consideration the A4 page size (297 x 210 mm), the map margins ( 20 mm, 5 mm, 10 mm, 5 mm) and the item’s reference points.

No caso do item “mapa”, usando como ponto de referência o canto superior esquerdo, foi necessário alterar a sua altura e largura. Sabia que a altura do item era é subtracção do tamanho das margens superiores e inferiores (30 mm) da altura folha por isso a expressão a usar foi:

For the map item, using the upper left corner as reference point, it was necessary to change it’s height and width. I knew that the item height was the subtraction of the top and bottom margins (30 mm) from the page height, therefore I used the following expression:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 297 ELSE 210 END) - 30

De forma análoga, a expressão a usar para a largura foi:

Likewise, the expression to use in the width was:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 210 ELSE 297 END) - 10

Screenshot from 2014-11-09 00:02:15

Os restantes itens ocupavam sempre uma posição relativa na folha sem que fosse necessário alterar o seu tamanho e por isso tinha apenas de controlar a sua posição. Por exemplo, o título encontrava-se centrado no topo da folha, e portanto, usando como ponto de referência o topo-centro, bastou definir a seguinte expressão para a posição X:

The rest of the items were always at a relative position of the page without the need to change their size and therefore only needed to control their position. For example, the title was centered at the page’s top, and therefore, using the top-center as reference point, all that was needed was the following expression for the X position:

Screenshot from 2014-11-09 00:13:17

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry)  THEN 297 ELSE 210 END)  / 2.0

Screenshot from 2014-11-09 00:30:57

Já a legenda exige alterar a posição em X e em Y. Usando como ponto de referência o canto inferior direito, a expressão para a posição em X foi:
On the other hand, the legend needed to change the position in both X and Y. Using the bottom-right-corner as reference point, the X position expression was:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 297 ELSE 210 END) - 7

E para a posição em Y:
And for the Y position:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 210 ELSE 297 END) - 12

Screenshot from 2014-11-09 00:47:28

Para os restantes itens (rosa dos ventos, escala gráfica e texto no canto inferior esquerdo), as expressões a usar eram em tudo similares às já apresentadas, e, após definidas em cada um dos itens, fiquei com o layout preparado para se adaptar às duas orientações da folha.

For the remaining items (North arrow, scalebar, and bottom left text), the expression were similar to the ones already mentioned, and, after setting them for each item, I got a layout that would adapt to both page orientation

output_9

Depois disso, a impressão/exportação de todos os (25) mapas ficou à distância de um só clique.

From that point, printing/exporting all (25) maps was one click away.

mosaico_regioes

No próximo artigo da série, procurarei explicar como criar séries de mapas em que seja o tamanho da folha a adaptar-se de forma a manter uma escala constante.

In the next post of the serie, I will try to explain how to create map series where it’s the size of the page that change to keep the scale’s value of the scale constant.


Séries de mapas com formatos múltiplos em QGIS 2.6 – Parte 2 | Multiple format map series using QGIS 2.6 – Part 2

No último artigo, tentei mostrar como usei o QGIS 2.6 para criar séries de mapas cuja orientação da folha se adaptasse à forma do elemento do atlas. Esse método é útil quando a escala final dos mapas não é relevante, ou quando os elementos usados no atlas têm uma dimensão muito semelhante, permitindo a adopção de uma escala única. No entanto, quando é necessário manter a mesma escala de impressão dos mapas e os elementos do atlas apresentam diferenças de extensão, é necessário alterar o tamanho da folha. Nesta segunda parte do artigo, tentarei mostrar como cheguei a uma solução para isso.

In my last post, I have tried to show how I used QGIS 2.6 to create a map series where the page’s orientation adapted to the shape of the atlas features. This method is useful when the final scale of the maps is irrelevant, or when the size of the atlas elements is  similar, allowing one to use a fixed scale. On the other hand, when using a fixed scale is mandatory and the features size are too different, it is needed to change the size of the paper. In this second part ot the post, I will try to show how I came to a solution for that.

Como base usei o mapa criado na 1ª parte do artigo, do qual fiz um duplicado. Para exemplificar o método procurei criar uma série de mapas à escala 1:2.000.000. Uma vez que iria adaptar tanto a altura como a largura da folha aos elementos do atlas, não me precisava de preocupar com a orientação da folha em si e por isso comecei por desactivar as propriedades definidas por dados na opção orientação.

As a base, I used the map created in the previous post, from which I did a duplicate. To exemplify the method I tried to create a map series at 1:2.000.000 scale. Since I was going to change both width and height of the paper, I did not need to set an orientation, and therefore I deactivated the data defined properties of the orientation option:

Fiz algumas contas usando a escala, as dimensões do elemento do atlas e as margens definidas anteriormente e e cheguei às seguintes expressões a usar na  largura e altura da folha, respectivamente:

With some maths with the map scale, the size of the atlas feature and the already defined margins, I came up with the following expressions to use, respectively,  in width and height:

((bounds_width( $atlasgeometry ) / 2000000.0) * 1000.0) * 1.1 + 10
((bounds_height( $atlasgeometry ) / 2000000.0) * 1000.0) * 1.1 + 30

Passo a explicar. (bounds_width( $atlasgeometry ) / 2000000.0) é a largura do elemento do atlas representado à escala 1:2.000.000 em unidades do projecto (neste caso metros). Este resultado é multiplicado por 1000 para o converter em milímetros (unidade usada nas definições do compositor). Para que o elemento de atlas não ficasse resvés aos limites do mapa decidi dar 10% de margem em torno do mesmo, o que justifica a multiplicação por 1.1. E por fim adicionei a dimensão das margens do mapa que tinham sido definidas na 1ª parte do artigo (i.e., 20 mm, 5 mm, 10 mm, 5 mm).

Allow me to clarify. (bounds_width( $atlasgeometry ) / 2000000.0) is the atlas feature’s width in meters when represented at 1:2.000.000. This is multiplied by 1000 to convert it to millimeters (the composer’s settings units). In order to keep the atlas feature not to close to the margin, I have decided to add 10% of margin around it, hence the multiplication by 1.1. To finish I add the map margins value,that where already set in the previous post (i.e.,20 mm, 5 mm, 10 mm, 5 mm)

Screenshot from 2014-11-16 22:58:34

Como se pode ver pela imagem anterior, após a introdução das expressões nas opções de largura e altura da folha, a sua dimensão já se alterava em função do tamanho do elemento de atlas. No entanto, como seria de esperar, os itens do mapa mantiveram-se teimosamente na mesma posição. Foi por isso necessário alterar as expressões definidas para a dimensão e posição de cada um deles.

As one can see from the previous image, after setting the expressions in the paper width and height options, it’s size already changed according to the size of the atlas features. But, as expected, all the itens stubbornly kept their positions.For that reason, it has been necessary to change the size and position expressions for each of then.

Começado pelo tamanho do item de mapa, as expressões a usar na altura e largura não foram difíceis de perceber uma vez que seriam as dimensões da folha menos as margens:

Starting by the map item size, the expressions to use in width and height were not difficult to understand since they would be the paper size without the margins size:

((bounds_width( $atlasgeometry ) / 2000000.0) * 1000.0) * 1.1
((bounds_height( $atlasgeometry ) / 2000000.0) * 1000.0) * 1.1

Screenshot from 2014-11-16 23:07:43

Para posicionar correctamente os elementos, bastou substituir nas expressões das opções X e Y os “CASE WHEN … THEN … END” que determinavam o tamanho da largura ou altura da folha, pelas expressões descritas anteriormente. Por exemplo, as expressões usadas para a posição da legenda em X e Y:

To position the items correctly, all was needed was to replace the “CASE WHEN … THEN … END” statement by the expressions defined before. For instance, the expressions used in the X and Y options for the legend position:

(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 297 ELSE 210 END) - 7
(CASE WHEN  bounds_width(  $atlasgeometry ) >=  bounds_height( $atlasgeometry) THEN 210 ELSE 297 END) - 12

Passaram a ser, respectivamente:
Became, respectively:

(((bounds_width( $atlasgeometry ) / 2000000.0) * 1000.0) * 1.1 + 10) - 7
(((bounds_height( $atlasgeometry ) / 2000000.0) * 1000.0) * 1.1 + 30) - 12

Screenshot from 2014-11-16 23:22:40

Alterando as expressões de posicionamento X e Y dos restantes itens do compositor cheguei à estrutura final.

Changing the expressions of the X and Y position options for the remaining composer’s items I have reached the final layout.

alaska_region_Kenai Peninsula

Depois disso, a impressão/exportação de todos os (25) mapas ficou, mais uma vez, à distância de um só clique.

Once again, printing/exporting all (25) maps was only one click away.

mosaico_regioes_fixed

Uma vez que o QGIS permite exportar imagens do compositor georreferenciadas, adicionando-as ao QGIS obtive este resultado interessante.

Since QGIS allows exporting the composer as georeferenced images, opening all maps in QGIS I got this interesting result.

Screenshot from 2014-11-17 00:02:38

Como se pode ver pelos resultados, através deste método, podemos obter mapas com formatos bastante estranhos. Por essa razão, na 3ª e última parte deste artigo, procurarei mostrar como criar uma série de mapas com escala fixa, mas usando formatos de folhas standard (A4, A3, A2, A1 e A0).

As one can see by the results, using this method, we can get some quite strange formats. That is why in the 3rd and last post of this article, I will try to show how to create a fixed scale map series using standard paper formats (A4, A3, A2, A1 e A0).

Disclaimer: I’m not an English native speaker, therefor I apologize for any errors, and I will thanks any advice on how to improve the text.


Mapas de fluxos em QGIS

Hoje surgiu a questão “Como consigo fazer um mapa em que a sobreposição de símbolos aumente a opacidade?“. Fiz o meu melhor para descrever como fazê-lo em QGIS, que transcrevo agora para português.

Este tipo de mapas pode ser feito em QGISs usando a uma combinação da transparência e cor dos símbolos e o blending mode dos elementos.

Note-se a diferença entre a transparência e blending mode da camada (que é aplicado a toda a camada) e a transparência do símbolo e blending dos elementos (que acumulam com outros elementos da mesma camada).

Esta opções estão disponíveis em Propriedades da camada > Estilo.

testes_opacidade_opcoes

Com um valor de transparência do símbolo de 95%, a cor do elemento tornar-se à totalmente opaca quando pelo menos 20 elementos de sobrepuserem. Este número é limitado à sobreposição de 100 elementos(tranparencia 99%).

Usando diferentes modos de blending (como a multiplicação ou a adição) consegues-se obter outros efeitos.

Testes_com_opacidade_2

Duplicando a camada, usando diferentes cores (no exemplo abaixo o verde para uma camada e o vermelho para a imediatamente baixo) e usando blending mode dogde,consegue-se obter efeitos ainda mais interessantes.

opacity dodge


Novo plugin QGIS | New QGIS plugin – “Walking time”

Finalmente “terminei” o meu novo plugin. Coloquei o termo entre aspas porque creio que ainda há espaço para alguma melhorias. Este plugin surgiu da necessidade de estimar o tempo de percurso das pequenas e grandes rotas de cascais, e começou como um pequeno script em python. Depois decidi criar um interface gráfico e publicá-lo como plugin porque talvez seja útil a mais pessoas.

I have finally “finished” my new plugin. I uses some quotation marks, since I believe that there is still space for a few improvement. This plugin arised with the need to calculate the travel time for the Cascais oficial pedestrian routes, and started as a simple python script. I have then decided to create a graphic interface and publish it as a plugin in the hope that someone else finds it useful.

icon_large

O Walking time é um plugin python para QGIS que usa a Tobbler’s hiking function para estimar o tempo de percurso ao longo de uma linha consoante o declive.

The Walking time is a QGIS python plugin that uses Tobbler’s hiking function to estimate the travel time along a line depending on the slope.

Os dados de input necessários são uma camada vectorial de linhas e uma camada raster com valores de elevação (1). É possível ajustar a velocidade base (em terreno plano) de acordo com o tipo de caminhada ou caminhante. Por defeito, o valor usado é de 5 km\h (2). O plugin actualiza ou cria campos com o tempo estimado em minutos, no sentido directo e no sentido inverso (3). É possível correr o plugin para todos os elementos da camada vectorial, ou apenas nos percursos seleccionados (4).

The input data required are a vector layer with lines and a raster layer with elevation values ​​(1). One can adjust the base velocity (on flat terrain) according to the type of walking or walker. By default, the value used is 5 km \ h (2). The plugin update or create fields with estimated time in minutes in forward and in reverse direction (3). One can run the plugin for all elements of the vector layer, or only on selected routes (4).

O plugin pode também ser usado para preparar uma rede (grafo) para realizar análise de redes onde se queira usar como custo o tempo de percurso.

The plugin can also been used to prepare a network (graph) to perform network analysis when the use of travel walking time as cost is intended.

Captura de tela 2014-03-24 12.12.17-01

Repositório QGIS | QGIS repository: http://plugins.qgis.org/plugins/walkingtime/

Código | Code: https://github.com/SrNetoChan/WalkingTime

Reportar bugs | Bug report: https://github.com/SrNetoChan/WalkingTime/issues


Use o operador “IN” sff | Please use the “IN” operator

Já não é a primeira vez que vejo pessoas que para seleccionarem elementos pelos valores dos seus atributos, usam expressões como:

It’s not the first time that I see people that, to select feature by their fields values use expressions like this:

"field" = 'value1' OR "field" = 'value2' OR "field" = 'value3' [OR ...]

Uma forma mais prática e bonita de o fazer é usar o operador IN.

A more practical and pretty way of doing this is by using the IN operator instead.

"field" IN ('value1','value2','value3'[,...])

Este operador existe em quase todos os softwares SIG que conheço. No QGIS, pode ser usado mesmo quando não existe um botãozinho para clicar.

This operator is available in almost every GIS software I know. In QGIS, it can be used even if there isn’t a small little button to click.
Captura de tela 2014-04-23 16.50.40

Na verdade, trata-se de uma abreviatura do que é usado em SQL, onde o operador é usado na expressão WHERE.

In fact, this is an abbreviation of what is used in SQL, where the operator is used in the WHERE statement:

SELECT *
FROM parks
WHERE "tipo" IN ('PI','CM','PJ');

QGIS Cloud - Speed up the loading time of the web client

QGIS Cloud is your personal geo-data infrastructure in the internet. Publish maps and data. Share geo-information with others. And all of this very easily, without server, infrastructure and expert knowledge. If you know QGIS Desktop, then you know QGIS cloud just as well. Just install the QGIS cloud plugin from the official QGIS plugin repository and you’re good to go. You can publish as many maps as you want.

But the default settings of QGIS projects you like to publish via QGIS Cloud are not the best with respect to the performance of the QGIS Webclient / WMS. This point is noticeable when the published project contains many layers. Than the default settings are leading to bad performance. The size of the WMS GetCapabilities request is not negligible. Have a look at the first request:

QGIS Cloud slow response

The second request has a much faster response time than the first one:

QGIS Cloud fast response

What’s the difference between this two requests? First of all the slow request has to download and parse 3.1MB of XML data. The fast request has to download and parse 22KB only. However that work’s much faster. What makes the difference? If you have a look at the first request result, you can see, that tons of coordinate reference systems (CRS) are defined for every layer. These are all CRS supported by QGIS. In fact most of them will never be used. As the result the solution is to reduce the number of CRS in the QGIS Cloud WMS and WFS services. To achieve that you have to restrict the CRS in the QGIS project settings. Open the OWS Server tab and activate the CRS restrictions option and add all CRS of interest.

QGIS Cloud Webclient slow initialisation with none restricted CRS

QGIS Cloud Webclient fast initialisation with restricted CRS

QGIS Cloud - Speed up the loading time of the web client

QGIS Cloud is your personal geo-data infrastructure in the internet. Publish maps and data. Share geo-information with others. And all of this very easily, without server, infrastructure and expert knowledge. If you know QGIS Desktop, then you know QGIS cloud just as well. Just install the QGIS cloud plugin from the official QGIS plugin repository and you’re good to go. You can publish as many maps as you want.

But the default settings of QGIS projects you like to publish via QGIS Cloud are not the best with respect to the performance of the QGIS Webclient / WMS. This point is noticeable when the published project contains many layers. Than the default settings are leading to bad performance. The size of the WMS GetCapabilities request is not negligible. Have a look at the first request:

QGIS Cloud slow response

The second request has a much faster response time than the first one:

QGIS Cloud fast response

What’s the difference between this two requests? First of all the slow request has to download and parse 3.1MB of XML data. The fast request has to download and parse 22KB only. However that work’s much faster. What makes the difference? If you have a look at the first request result, you can see, that tons of coordinate reference systems (CRS) are defined for every layer. These are all CRS supported by QGIS. In fact most of them will never be used. As the result the solution is to reduce the number of CRS in the QGIS Cloud WMS and WFS services. To achieve that you have to restrict the CRS in the QGIS project settings. Open the OWS Server tab and activate the CRS restrictions option and add all CRS of interest.

OWS_server

QGIS Cloud Webclient slow initialisation with none restricted CRS

QGIS Cloud Webclient fast initialisation with restricted CRS

Exploring QGIS 2.6 – Item panel for map composer

In recent releases QGIS’ map composer has undergone some large usability improvements, such as the ability to select and interact with multiple items, and much improved navigation of compositions. Another massive usability improvement which is included in QGIS 2.6 is the new “Items” panel in the map composer. The panel shows a list of all items currently in the composition, and allows you to individually select, show or hide items, toggle their lock status, and rearrange them via drag and drop. You can also double click the item’s description to modify its ID, which makes managing items in the composition much easier.

QGIS composer’s new items panel

This change has been on my wish list for a long time. The best bit is that implementing the panel has allowed me to fix some of the composer’s other biggest usability issues. For instance, now locked items are no longer selectable in the main composer view. If you’ve ever tried to create fancy compositions with items which are stacked on top of other items, you’ll know that trying to interact with the lower items has been almost impossible in previous QGIS versions. Now, if you lock the higher stacked items you’ll be able to fully interact with all underlying items without the higher items getting in the way. Alternatively you could just temporarily hide them while you work with the lower items.

This feature brings us one more step closer to making QGIS’ map composer a powerful DTP tool in itself. If you’d like to help support further improvements like this in QGIS, please consider sponsoring my development work, or you can contact me directly for a quote on specific development.

More experiments with Game of Life

As promised in my recent post “Experiments with Conway’s Game of Life”, I have been been looking into how to improve my first implementation. The new version which you can now find on Github is fully contained in one Python script which runs in the QGIS console. Additionally, the repository contains a CSV with the grid definition for a Gosper glider gun and the layer style QML.

Rather than creating a new Shapefile for each iteration like in the first implementation, this script uses memory layers to save the game status.

You can see it all in action in the following video:

(video available in HD)

Thanks a lot to Nathan Woodrow for the support in getting the animation running!

Sometimes there are still hick-ups causing steps to be skipped but overall it is running nicely now. Another approach would be to change the layer attributes rather than creating more and more layers but I like to be able to go through all the resulting layers after they have been computed.


Serving live tiles from a QGIS project via TileStache

I'm more then likly way behind the 8 ball here, aren't all the cool kids doing tiles these days, but regardless I thought it was pretty cool to share. The other day I found TileStache a neat little Python app that can generate, cache, and serve tiles from a list of providers. The normal way is via Mapnik (and others) to render a image, there is also a vector provider which can render vector tiles. Nifty.

A while ago I wrote qgis2img which can generate an image for project, or layers, and export it for you. It serves two roles, one is to benchmark a project and layer render times, the other as a simple export tool. I thought it would be pretty cool to be able to export tiles from it but was I never really up for working on the math and all the logic so I left it. Then I found TileStache.

The best part about TileStache, apart from that it's Python, is that you can make your own providers for it, and the API is dead easy

class Provider:
    def __init__(self, layer):
        self.layer = layer

    def renderArea(self, width, height, srs, xmin, ymin, xmax, ymax, zoom):
        pass

How easy is that! Just implement one method and you are good to go. So that's what I did. I created a custom provider that will load a QGIS project and render out images. Thanks to the work done by Martin from Lutra Consulting for the multithreaded rendering in QGIS 2.4 this is a hell of a lot easier then it used to be.

Ignoring some of the setup code to create and load the session the whole export logic is in these few lines

   extents = QgsRectangle(xmin, ymin, xmax, ymax)
   settings.setExtent(extents)
   settings.setOutputSize(QSize(width, height))
   layers = [layer.id() for layer in project.visiblelayers()]
   image, rendertime = qgis2img.render.render_layers(settings, layers, RenderType=QgsMapRendererSequentialJob)

with render_layers defined as

def render_layers(settings, layers, RenderType):
    settings.setLayers(layers)
    job = RenderType(settings)
    job.start()
    job.waitForFinished()
    image = job.renderedImage()
    return image, job.renderingTime()

As this is build on top of my qgis2img tool you can see the full code here

Running it is as simple as installing TileStache, cloneing qgis2img, updating tilestache.cfg, and running the server.

$ pip install TileStache
$ git clone https://github.com/DMS-Aus/qgis2img.git
$ cd qgis2img

In tilestache.cfg you can just change the path to the project to render:

{
  "cache": {
    "name": "Test",
    "path": "/tmp/stache"
    },
  "layers": {
    "qgis":
    {
      "provider": {"class": "qgis2img.tilestache:Provider",
                   "kwargs": {"projectfile": "data/test.qgs"}
                  }
    }
  }
}

Then run the server

$ tilestache-server /path/to/tilestache.cfg

Note: The path to the .cfg file seems to have to be the full path. I had issues with relative paths working.

To view the tiles you can load the preview URL that TileStache provides or you can use it in something like LeafLet

<!DOCTYPE html>
<html>
<head>
    <title>QGIS Tiles WOOT!</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
</head>
<body>
    <div id="map" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0;"></div>
    <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
    <script>

        var map = L.map('map').setView([51.505, -0.09], 5);

        L.tileLayer('http://10.0.0.11:8080/{id}/{z}/{x}/{y}.png', {
            maxZoom: 18,
            id: 'qgis'
        }).addTo(map);

    </script>
</body>
</html>

And the result is live tiles from a QGIS project.

tiles

Winning!

Some Caveats

  • The provider currently doesn't use metatiles so labels and points will get chopped at tile edge. I have working code for this but haven't pushed it yet.

  • I don't kill the QGIS session that I create. Creating a session for each request was really expensive so I just keep it around.

  • I only load the project once so any changes mean starting and stopping the server. Wouldn't be hard to add a file watcher for this.

  • It's just me using this at home for fun, I have no idea on how it would scale, or even if it would, but I would be keen to hear feedback on that theory.

Serving live tiles from a QGIS project via TileStache

I'm more then likly way behind the 8 ball here, aren't all the cool kids doing tiles these days, but regardless I thought it was pretty cool to share. The other day I found TileStache a neat little Python app that can generate, cache, and serve tiles from a list of providers. The normal way is via Mapnik (and others) to render a image, there is also a vector provider which can render vector tiles. Nifty.

A while ago I wrote qgis2img which can generate an image for project, or layers, and export it for you. It serves two roles, one is to benchmark a project and layer render times, the other as a simple export tool. I thought it would be pretty cool to be able to export tiles from it but was I never really up for working on the math and all the logic so I left it. Then I found TileStache.

The best part about TileStache, apart from that it's Python, is that you can make your own providers for it, and the API is dead easy

class Provider:
    def __init__(self, layer):
        self.layer = layer

    def renderArea(self, width, height, srs, xmin, ymin, xmax, ymax, zoom):
        pass

How easy is that! Just implement one method and you are good to go. So that's what I did. I created a custom provider that will load a QGIS project and render out images. Thanks to the work done by Martin from Lutra Consulting for the multithreaded rendering in QGIS 2.4 this is a hell of a lot easier then it used to be.

Ignoring some of the setup code to create and load the session the whole export logic is in these few lines

   extents = QgsRectangle(xmin, ymin, xmax, ymax)
   settings.setExtent(extents)
   settings.setOutputSize(QSize(width, height))
   layers = [layer.id() for layer in project.visiblelayers()]
   image, rendertime = qgis2img.render.render_layers(settings, layers, RenderType=QgsMapRendererSequentialJob)

with render_layers defined as

def render_layers(settings, layers, RenderType):
    settings.setLayers(layers)
    job = RenderType(settings)
    job.start()
    job.waitForFinished()
    image = job.renderedImage()
    return image, job.renderingTime()

As this is build on top of my qgis2img tool you can see the full code here

Running it is as simple as installing TileStache, cloneing qgis2img, updating tilestache.cfg, and running the server.

$ pip install TileStache
$ git clone https://github.com/DMS-Aus/qgis2img.git
$ cd qgis2img

In tilestache.cfg you can just change the path to the project to render:

{
  "cache": {
    "name": "Test",
    "path": "/tmp/stache"
    },
  "layers": {
    "qgis":
    {
      "provider": {"class": "qgis2img.tilestache:Provider",
                   "kwargs": {"projectfile": "data/test.qgs"}
                  }
    }
  }
}

Then run the server

$ tilestache-server /path/to/tilestache.cfg

Note: The path to the .cfg file seems to have to be the full path. I had issues with relative paths working.

To view the tiles you can load the preview URL that TileStache provides or you can use it in something like LeafLet

<!DOCTYPE html>
<html>
<head>
    <title>QGIS Tiles WOOT!</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
</head>
<body>
    <div id="map" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0;"></div>
    <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
    <script>

        var map = L.map('map').setView([51.505, -0.09], 5);

        L.tileLayer('http://10.0.0.11:8080/{id}/{z}/{x}/{y}.png', {
            maxZoom: 18,
            id: 'qgis'
        }).addTo(map);

    </script>
</body>
</html>

And the result is live tiles from a QGIS project.

tiles

Winning!

Some Caveats

  • The provider currently doesn't use metatiles so labels and points will get chopped at tile edge. I have working code for this but haven't pushed it yet.

  • I don't kill the QGIS session that I create. Creating a session for each request was really expensive so I just keep it around.

  • I only load the project once so any changes mean starting and stopping the server. Wouldn't be hard to add a file watcher for this.

  • It's just me using this at home for fun, I have no idea on how it would scale, or even if it would, but I would be keen to hear feedback on that theory.

Open source GIS interview for XYHT

20141108_175726_0A few weeks ago, I had the pleasure to give an interview about open source GIS for the American magazine XYHT. We talked about the open source development model and the motivation behind contributing to open source projects. You can read the full interview in the November issue.

XYHT is available as a classic print magazine as well as for free online and focuses on “positioning and measurement” topics:

http://www.xyht.com


  • <<
  • Page 3 of 72 ( 1438 posts )
  • >>

Back to Top

Sponsors