Sou novo no fascinante mundo do SIG e tenho pesquisado o assunto nos últimos dias. Meu objetivo é fornecer mapas em todo o mundo com dados OSM em meus próprios servidores.
Minha pilha é:
- Postgres + Postgis - Para armazenar, transformar e processar dados GIS.
- Mapnik - Biblioteca para renderização de blocos
- Tilestache - servir e armazenar em cache blocos
- Nginx - proxy reverso para Tilestache
- Folheto ( cliente de mapa Slippy )
Para importar e estilizar dados OSM, estou usando
- Arquivo PBF (Extrair / Planeta)
- osm2pgsql
- CartoCSS
- openstreetmap-carto
- Kosmtik - GUI do mapa para desenvolvimento / depuração
Como o arquivo completo do planeta é enorme, atualmente estou usando um extrato de São Paulo , que é bom / pequeno o suficiente para testes.
Antes de abordar o problema que estou tendo, orientarei as etapas que eu levei até agora:
O que funcionou
O PostgreSQL e o PostGIS estão instalados corretamente. Estou usando 9.6 para o primeiro, 2.3 para o último. Também adicionei as extensões postgis_topology
e hstore
, que serão usadas mais tarde.
Eu tenho o osm2pgsql 0.92.0 instalado. Para importar o extrato de São Paulo, eu uso
osm2pgsql -G U <user> -d <db> -C 1000 -W --hstore --style openstreetmap-carto.style --tag-transform-script openstreetmap-carto.lua <pbf>
Os argumentos hstore
, style
e tag-transform-script
são necessários para a utilização adequada do estilo do OSM, conforme descrito aqui .
Conforme descrito na instalação do openstreetmap-carto, também adicionei índices personalizados e baixei os shapefiles e as fontes necessárias (exceto os emoji).
Verifiquei se os dados de extração estão carregados corretamente no banco de dados usando o QGIS. Consegui visualizar e consultar todos os pontos, polígonos, linhas e estradas. Está tudo lá.
Problemas
O próximo passo é renderizar os blocos, e é aí que estou tendo problemas. Eu tenho o mapnik e o python-mapnik 3.x, assim como o carto 0.18.2.
No project.mml do OSM , eu gerei meu próprio project.xml usando carto
. Fiz as seguintes alterações no resultado:
- Adicione o nome de usuário do Postgres (parâmetro
user
no XML do Mapnik ). As informações de conexão restantes são obtidas em ~ / .pgpass . - Substitua o diretório relativo
data/<shape>.shp
para/full/path/data/<shape>.shp
- Substitua o diretório relativo
symbols/<symbol>.svg
para/full/path/symbols/<symbol>.svg
Eu meio que testei essas alterações por unidade: diretórios incorretos para arquivos de forma e símbolos gerarão um erro quando o Mapnik tentar carregar o estilo. O mesmo se aplica a informações incorretas do banco de dados.
E aqui está o problema: cada bloco renderizado pelo Mapnik está "em branco" (plano de fundo azul, que é o plano de fundo definido para o OSM). Aqui está o que eu tentei corrigir esse problema:
Coisas que eu tentei
Talvez o estilo gerado seja inválido de alguma forma. Talvez algum polígono / forma (do oceano?) Esteja cobrindo outro.
Eu instalei o Kosmtik e funcionou bem! Consegui navegar pelo extrato, inspecionar dados, aumentar e diminuir o zoom em todos os níveis.
Talvez eu esteja gerando blocos no local errado
Eu configurei o TileStache com o Mapnik como provedor. Em seguida, configurei regras de redirecionamento http://[abc].tile.openstreetmap.org
para o http://myserver/<layer>
uso do switcheroo, conforme descrito aqui . Isso significa que o acesso openstreetmaps.org
teria todos os blocos renderizados no meu servidor.
Curiosamente, o zoom 1 funciona (aquele com 4 peças). Suponho que ele use apenas o shapefile planeta / mundo, que foi baixado com o estilo. Tudo o resto, independentemente do zoom ou da localização, torna-o "em branco". Portanto, mesmo ao navegar no local da extração, ela não será renderizada corretamente.
Observe que, ao usar o Kosmtik, pude ver o nome do extrato a partir do zoom 4.
Talvez eu esteja gerando blocos no local errado
As projeções são difíceis. Talvez haja algo sendo "traduzido incorretamente" em algum lugar.
Então, analisei os pedidos que Kosmtik estava fazendo (já que eles estavam funcionando). Ele usa a biblioteca Modestmaps, que se traduz no formato Slippy ( <zoom>/<x>/<y>
), mesmo formato usado pelo Leaflet, TileStache e openstreetmap.org
.
Por exemplo, solicitar 17/48561/74357.png
no Kosmtik funciona, mas o mesmo bloco retorna como "em branco" no TileStache. Minha teoria era que, de alguma forma, o TileStache estava traduzindo para outra coordenada, fora da área de extração. (Embora o TileStache estivesse usando "mercator esférico" como a projeção).
Então, eu decidi usar as ligações python do Mapnik diretamente. Até agora, eu lidei com três tipos diferentes de projeções, eis o que sei sobre elas. Por favor me corrija se eu estiver errado:
- EPSG4326 / WGS84 - Projeção lon / lat usual, igual à usada no GPS. Unidade é graus.
- EPSG3857 / {Web, Google, Pseudo} mercator / 900913 - Usado na maioria dos mapas da web em mosaico. A unidade está em metros (não metros "reais", pois distorce fortemente perto dos polos).
- "Formato Slippy" - Não é uma projeção, mas mais um formato para traduzir.
Portanto, o Slippy 17/48561/74357
estaria próximo -46.632(lon), -23.531(lat)
no EPSG4326 e próximo -5191050.49, -2696361.67
no EPSG3875 / Google mercator.
Usando python, eu gerei os blocos dessas coordenadas diretamente no Mapnik. O resultado sempre foi azulejos em branco. Eu acredito que eu estou usando as projeções corretas (mais sobre isso depois).
Primeiro, uma coisa a observar. É claro que o problema não está no Mapnik, nem no estilo. Por um lado, o Kosmtik usa o Mapnik como back-end e funciona bem. Segundo, se eu propositalmente gerar um bloco fora da área de extração no Kostmik, recebo um bloco em branco, conforme o esperado.
Isso me leva a acreditar que estou usando a projeção errada no script python do Mapnik e no TileStache. Antes de mostrar o código, uma observação sobre o OSM (novamente, corrija-me se estiver errado):
- Os dados "nativos" do OSM são armazenados no EPSG4326
- o osm2pgsql importa dados do OSM como EPSG3857, e essa é a projeção no Postgis.
- O estilo do Mapnik (XML) tem duas projeções, entrada e saída, explicadas aqui :
- A projeção de entrada é definida no objeto Mapa e é o "sistema de coordenadas em que o mapa é renderizado"
- A projeção de saída é definida no objeto Camada e deve ser igual aos meus dados.
O XML do meu Mapnik resultante tem:
<Map srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" background-color="#b5d0d0">
#snip#
<Layer name="world" #snip# srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over">
Então, a meu ver, as projeções de entrada e saída estão em "merc" (3857), e está correto! Meus dados são armazenados com 3857 e o mapa resultante deve estar em 3857.
Finalmente, aqui estão as diferentes chamadas do Mapnik que eu tentei:
Box2d com 3857 coordenadas:
map = mapnik.Map(800, 800)
bbox = Box2d(-5191050.49, -2696361.67, -5191059.49, -2696370.70)
mapnik.load_map(map, '/path/to/style.xml')
map.zoom_to_box(bbox)
mapnik.render_to_file(map, 'output.png') # Blank
Box2d com 4326 coordenadas transformadas em 3857
merc = mapnik.Projection('+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over')
longlat = mapnik.Projection('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
bbox = mapnik.Box2d(-23.53, -46.63, -24.03, -47.03)
transform = mapnik.ProjTransform(longlat, merc)
merc_bbox = transform.forward(bbox)
# load, zoom, render -> Blank
Eu também tentei com estilos diferentes. O resultado está sempre em branco, mas isso é inesperado, porque acredito que essas coordenadas estariam dentro do meu extrato. Ao tentar renderizar coordenadas fora da extração, ela é renderizada corretamente em branco.
De qualquer forma, eu estou perdido e eu queria saber se alguém poderia lançar alguma luz, eu deve estar faltando alguma coisa. Mas até agora, estou lutando com esse problema há mais de 24 horas e não tenho ideia do que pode estar errado.