Tiles Server. Renderització

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Mapnik: crea les teves pròpies tiles. Cas d'ús: Andorra

La idea és crear un mapa amb un estil propi, personalitzat. Carregar només els tags que interessin. Per exemple, es podria tenir uns tiles mínims, que només mostrin les vies principals, com el GPS Bryton 450E. També es podria generar els tiles d'una zona concreta, per ex el Berguedà.

Manually building a tile server:

Seuim aquest enllaç, que ha funcionat:

Software installation

sudo apt install libboost-all-dev git-core tar unzip wget bzip2 build-essential autoconf libtool libxml2-dev libgeos-dev libgeos++-dev libpq-dev libbz2-dev libproj-dev munin-node munin libprotobuf-c0-dev protobuf-c-compiler libfreetype6-dev libtiff5-dev libicu-dev libgdal-dev libcairo-dev libcairomm-1.0-dev apache2 apache2-dev libagg-dev liblua5.2-dev ttf-unifont lua5.1 liblua5.1-dev libgeotiff-epsg

Installing postgresql / postgis

Què és PostGis?: PostGIS is a spatial database extender for PostgreSQL object-relational database. It adds support for geographic objects allowing location queries to be run in SQL.

sudo apt-get install postgresql postgresql-contrib postgis postgresql-10-postgis-2.4 postgresql-10-postgis-scripts

En el tutorial es fa servir l'usuari renderaccount. S'entén que és un usuari del SO, per exemple joan:

sudo -u postgres -i (treballem amb l'usuari postgres del SO

createuser joan # answer yes for superuser (although this isn't strictly necessary)

createdb -E UTF8 -O joan gis

Per rederitzar les tiles:
sudo -u postgres renderd -f -c /usr/local/etc/renderd.conf
$ psql 
\c gis

CREATE EXTENSION postgis;
CREATE EXTENSION hstore;
ALTER TABLE geometry_columns OWNER TO joan;
ALTER TABLE spatial_ref_sys OWNER TO joan;

\q
exit (tornem a l'usuari normal del SO)

Evidentment, l'usuari joan ha de ser un usuari del SO. En el cas de què no ho sigui, ara seria el moment de fer-ho:

sudo useradd -m joan
sudo passwd joan

Installing osm2pgsql

És l'eina que ens permetrà migrar les dades OSM i convertir-les a un format PostgreSQL.

Crearem dins del home la carpeta src/, i d'aquí penjaran diferents projectes que necessitem.

mkdir ~/src
cd ~/src
git clone git://github.com/openstreetmap/osm2pgsql.git
cd osm2pgsql

I ara compilem el projecte. Primer necessitem les eines de compilació:

sudo apt install make cmake g++ libboost-dev libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libgeos-dev libgeos++-dev libproj-dev lua5.2 liblua5.2-dev

I ara compilem i instal·lem:

mkdir build && cd build
cmake ..
make
sudo make install

Instal·lació de Mapnik

És el software que necessitem per generar els mapes (els tiles). Recordem que OSM és tan sols una base de dades amb informació geogràfica. Amb Mapnik podem posar totes aquestes dades sobre un mapa, amb diferents nivells de zoom.

sudo apt-get install autoconf apache2-dev libtool libxml2-dev libbz2-dev libgeos-dev libgeos++-dev libproj-dev gdal-bin libmapnik-dev mapnik-utils python-mapnik

Comprovem que tenim Mapnik instal·lat correctament:

python
>>> import mapnik
>>>
>>> quit()

No cal tenir la última versió de Python. Amb una versió 2.7 també funciona.

Install mod_tile and renderd

Què té que veure aquest projecte amb Apache? doncs molt. Estem fent una aplicació web per visualitzar mapes. Els tiles no estan creats. Es creen (es renderitzen) a mida que es demanen. Per tant, davant d'un request d'un determinat tile, es llença l'aplicació que renderitza el tile.

cd ~/src
git clone -b switch2osm git://github.com/SomeoneElseOSM/mod_tile.git
cd mod_tile
./autogen.sh
configure
make
sudo make install
sudo make install-mod_tile
sudo ldconfig

La última línia, ldconfig:

NAME
       ldconfig - configure dynamic linker run-time bindings

SYNOPSIS
       /sbin/ldconfig [-nNvXV] [-f conf] [-C cache] [-r root] directory...
       /sbin/ldconfig -l [-v] library...
       /sbin/ldconfig -p

DESCRIPTION
       ldconfig  creates  the  necessary  links  and  cache to the most recent
       shared libraries found in the  directories  specified  on  the  command
       line

Stylesheet configuration

Aquí definirem com volem visualitzar el mapa. De moment, només ens interessarà la plantilla per defecte. Però és aquí on podrem definir quina és la informació que volem visualitzar en els nostres mapes. I quin és el look que han de tenir.

cd ~/src
git clone git://github.com/gravitystorm/openstreetmap-carto.git
cd openstreetmap-carto
sudo apt install npm nodejs
sudo npm install -g carto
carto -v

M'ha quedat instal·lada la versió 1.2.0.

carto project.mml > mapnik.xml

You now have a Mapnik XML stylesheet at /home/joan/src/openstreetmap-carto/mapnik.xml. Aquest és el fitxer XML important.

Loading data: Andorra

Elegim Andorra perquè és petit, per fer proves.

mkdir ~/data
cd ~/data
wget https://download.geofabrik.de/asia/azerbaijan-latest.osm.pbf

Introduïm la informació que hem descarregat d'Andorra a la base de dades:

osm2pgsql -d gis --create --slim  -G --hstore --tag-transform-script ~/src/openstreetmap-carto/openstreetmap-carto.lua -C 2500 --number-processes 1 -S ~/src/openstreetmap-carto/openstreetmap-carto.style ~/data/andorra-latest.osm.pbf

Shapefile download. Necessitem descarregar informació addicional:

cd ~/src/openstreetmap-carto/
scripts/get-shapefiles.py

Fonts. Necessitem descarregar fonts addicionals.

sudo apt-get install fonts-noto-cjk fonts-noto-hinted fonts-noto-unhinted ttf-unifont

Setting up your webserver

Configure renderd. The config file for renderd is /usr/local/etc/renderd.conf.

sudo nano /usr/local/etc/renderd.conf

num_threads=4
XML=/home/joan/src/openstreetmap-carto/mapnik.xml
URI=/hot/

Configuring Apache

sudo mkdir /var/lib/mod_tile
sudo chown joan /var/lib/mod_tile

sudo mkdir /var/run/renderd
sudo chown joan /var/run/renderd

sudo nano /etc/apache2/conf-available/mod_tile.conf

afegir:
LoadModule tile_module /usr/lib/apache2/modules/mod_tile.so

sudo a2enconf mod_tile
sudo nano /etc/apache2/sites-available/000-default.conf

LoadTileConfigFile /usr/local/etc/renderd.conf
ModTileRenderdSocketName /var/run/renderd/renderd.sock
# Timeout before giving up for a tile to be rendered
ModTileRequestTimeout 0
# Timeout before giving up for a tile to be rendered that is otherwise missing
ModTileMissingRequestTimeout 30
sudo service apache2 reload
sudo service apache2 reload

(dues vegades?)

Running renderd for the first time Next, we’ll run renderd to try and render some tiles. Initially we’ll run it in the foreground so that we can see any errors as they occur:

$ renderd -f -c /usr/local/etc/renderd.conf

I ja podem visualitzar alguna tile:

Running renderd in the background:

La idea és que funcioni el renderd a mida que anem navegant en la zona d'interès.

nano ~/src/mod_tile/debian/renderd.init
sudo cp ~/src/mod_tile/debian/renderd.init /etc/init.d/renderd
sudo chmod u+x /etc/init.d/renderd
sudo cp ~/src/mod_tile/debian/renderd.service /lib/systemd/system/
sudo /etc/init.d/renderd start

I si volem que arrenqui en l'inici de sistema:

sudo systemctl enable renderd

Viewing tiles

A mida que anem navegant, podem veure com es van creant les tiles:

tail -f /var/log/syslog | grep " TILE "

I podem veure les tiles a:

tile_dir=/var/lib/mod_tile

Podem provar altres url, com ara:

...
Feb 26 16:13:51 joan renderd[5048]: DEBUG: START TILE ajt 10 512-519 376-383, new metatile
Feb 26 16:13:51 joan renderd[5048]: DEBUG: DONE TILE ajt 8 120-127 96-103 in 0.415 seconds
Feb 26 16:13:52 joan renderd[5048]: DEBUG: DONE TILE ajt 10 512-519 376-383 in 1.326 seconds
Feb 26 16:13:52 joan renderd[5048]: DEBUG: START TILE ajt 10 520-527 376-383, new metatile
Feb 26 16:13:53 joan renderd[5048]: DEBUG: DONE TILE ajt 10 520-527 376-383 in 0.504 seconds
...

Aplicació mínima per navegar pel mapa d'Andorra

Ho podem fer amb Leaflet o bé amb Openlayers.

script leaflet_andorra.html:

<!DOCTYPE HTML>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
    <style>
      html, body {
        height: 100%;
        padding: 0;
        margin: 0;
      }
      #map {
        /* configure the size of the map */
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      // initialize Leaflet
      var map = L.map('map').setView({lon: 1.5549, lat: 42.5546}, 2);

      // add the OpenStreetMap tiles
      L.tileLayer('http://localhost/hot/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '© <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
      }).addTo(map);

      // show the scale bar on the lower left corner
      L.control.scale().addTo(map);

      // show a marker on the map
      L.marker({lon: 0, lat: 0}).bindPopup('The center of the world').addTo(map);
    </script>
  </body>
</html>

script openlayers_andorra.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Simple Map</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.1.1/css/ol.css" type="text/css">
    <style>
      html, body {
        height: 100%;
        padding: 0;
        margin: 0;
      }
      #map {
        /* configure the size of the map */
        width: 100%;
        height: 100%;
      }
    </style>
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="http://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.1.1/build/ol.js"></script>
  </head>
  <body>
    <div id="map" class="map"></div>
    <div id="popup" style="padding: 10px;background-color: white;"></div>
    <script>
      var map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            // This illustrates a custom tiles source but for using
            // official OpenStreetMap server new ol.source.OSM()
            // instead of new ol.source.XYZ(...) is enough
            source: new ol.source.XYZ({
              attributions: [
              ol.source.OSM.ATTRIBUTION,
                'Tiles courtesy of ' +
                '<a href="http://openstreetmap.org">' +
                'OpenStreetMap' +
                '</a>'
              ],
              url: 'http://localhost/hot/{z}/{x}/{y}.png'
            })
          })
        ],
        controls: ol.control.defaults({
          // Set to display OSM attributions on the bottom right control
          attributionOptions:  {
            collapsed: false
          }
        }).extend([
          new ol.control.ScaleLine() // Add scale line to the defaults controls
        ]),
        target: 'map',
        view: new ol.View({
          center: ol.proj.fromLonLat([0, 0]),
          zoom: 2
        })
      });

      // Add vector layer with a feature and a style using an icon
      var vectorLayer = new ol.layer.Vector({
        source: new ol.source.Vector({
          features: [
            new ol.Feature({
              geometry: new ol.geom.Point(
                ol.proj.fromLonLat([0, 0])
              ),
              name: 'The center of the world'
            })
          ]
        }),
        style: new ol.style.Style({
          image: new ol.style.Icon({
            anchor: [0.5, 46],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            src: 'http://openlayers.org/en/latest/examples/data/icon.png'
          })
        })
      });

      map.addLayer(vectorLayer);

      // Overlay to manage popup on the top of the map
      var popup = document.getElementById('popup');
      var overLay = new ol.Overlay({
        element: popup,
        position: ol.proj.fromLonLat([0, 0])
      });

      map.addOverlay(overLay);

      // Manage click on the map to display/hide popup
      map.on('click', function(e) {
        var info = [];
        map.forEachFeatureAtPixel(e.pixel, function (feature) {
          info.push(feature.get('name'));
        });
        if (info.length > 0) {
          popup.innerHTML = info.join(',');
          popup.style.display = 'inline';
        } else {
          popup.innerHTML = ' ';
          popup.style.display = 'none';
        }
      });
    </script>
  </body>
</html>

Dibuixar les tiles a mà

(TBD)

https://openlayersbook.github.io/

https://wiki.openstreetmap.org/wiki/Tile_servers

https://www.thunderforest.com/maps/opencyclemap/

https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png

3 exemples de renderització:
https://b.tile.openstreetmap.org/3/4/2.png
https://tile.thunderforest.com/cycle/3/4/2.png?apikey=f695b42354e84626afef4de11a5d6080
http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/3/4/2 -> compte! és una altra zona

http://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png

http://www.cach.ly/help/index.php/Custom_Tile_URL

https://wiki.openstreetmap.org/wiki/Slippy_Map
I aquí està explicat com ha de ser el format dels tiles:
https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames

Per ex: Bagà és
42.2575/1.8676

i ho vull visualitzar amb un zoom de 14. On és la tile que em mostra aquesta informació?

n = 2 ^ zoom
xtile = n * ((lon_deg + 180) / 360)
ytile = n * (1 - (log(tan(lat_rad) + sec(lat_rad)) / π)) / 2

2^14 = 16384
x = 16384((1.8676+180) / 360) = 8277
y = 16384* (1-(ln(tg(0.03259)+sec(0.03259))/pi))/2 = 6066

https://b.tile.openstreetmap.org/14/8277/6066.png

Això és el que necessito:
http://tools.geofabrik.de/map/#12/41.9194/1.8279&type=Geofabrik_Standard&grid=1


creat per Joan Quintana Compte, febrer 2020

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines