Einfacher Karten-Server mit MapServer, Shape-Files und OpenLayers

Kartendienste wie Open Street Map oder Google Map sind eine wirklich feine und praktische Sache. Schnell mal ein paar Koordinaten eintragen und anzeigen lassen, eine Route ausgeben und so weiter.

Was macht man aber, wenn man keinen Empfang hat, wie zum Beispiel auf hoher See oder irgendwo mitten in der Wildnis? Entweder greift man tief in die Tasche und besorgt sich eine Sattelitenverbindung oder man baut sich mit wenigen Handgriffen seinen eigenen, kleinen Kartenserver.

Die Sachen, die man dafür braucht, sind alle frei verfügbar – das wären Apache als Webserver, MapServer zum generieren der Grafiken und OpenLayers, um die Grafiken in eine WebSeite einzubauen. Desweiteren braucht man Shape-Dateien von dem Gebiet, von dem man den Kartendienst aufsetzen möchte.

Diese findet man in der Regel auch frei im Internet. Oder man holt sich die passenden Shape-Files von Open Street Map, die von GeoFabrik zur verfügung gestellt werden.
Diese Shape-Files sind allerdings sehr fein aufgelöst und man braucht dann schon ein wenig Rechenleistung, um diese in die gewünschten Bilder rendern zu lassen.

Ich habe jetzt für einen Freund so einen Kartendienst auf einem Raspberry installiert, den er dann mit an Bord nimmt und dort steht er per CrossLink-Kabel als Karten-Server für den Bord-Rechner zur Verfügung.

Ich beschreibe hier daher die Installation und Konfiguration auf einem Raspberry Pi.
Ein Beaglebone Black würde sich noch ein wenig besser eignen, da er die Möglichkeit bietet, sich mit dem Bord-Rechner per USB-Kabel zu verbinden und dann eine Ethernet-over-USB verbindung einzurichten, wodurch dann gleichzeitig die Stromversorgung gesichert wäre. Allerdings hab ich nur einen und den brauch ich hier 😉

1. Software installieren
Also um jetzt den Karten-Server auf dem Raspberry aufzusetzen, muss man erstmal die nötige Software installieren:

apt-get install apache2 cgi-mapserver gdal-bin

2. Shape-Files besorgen
Dann besorgt man sich die gewünschten Shape-Files. Ich brauchte nur die Küstenlinien von Europa und habe dazu dieses Shape gefunden:

Europa

Dieses Shape ist gleichzeitig nicht zu hochauflösend und läuft daher auf dem Raspberry auch einigermaßen flüssig. Die Datei heißt zwar world.zip, ist aber wirklich nur Europa drauf 🙂

Dann legt man in seinem Home-Verzeichnis einen Ordner für die Shape-Files an und entpackt diese in den Ordner.

mkdir /home/pi/shapes
mkdir /home/pi/shapes/eu
mv world.zip /home/pi/shapes/eu
cd /home/pi/shapes/eu
unzip world.zip

Danach sollten in diesem Verzeichnis folgende Dateien liegen:

pi@raspberrypi ~/shapes/eu $ ls -l
insgesamt 456
-rw-rw-r-- 1 pi pi   9062 Jul 14 19:54 MyEurope.dbf
-rw-rw-r-- 1 pi pi    145 Jul 14 19:54 MyEurope.prj
-rw-rw-r-- 1 pi pi    452 Jul 14 19:54 MyEurope.sbn
-rw-rw-r-- 1 pi pi    148 Jul 14 19:54 MyEurope.sbx
-rw-rw-r-- 1 pi pi 299032 Jul 14 19:54 MyEurope.shp
-rw-rw-r-- 1 pi pi   1795 Jul 14 19:54 MyEurope.shp.xml
-rw-rw-r-- 1 pi pi    364 Jul 14 19:54 MyEurope.shx
-rw-r--r-- 1 pi pi 131025 Jul 14 19:53 world.zip
pi@raspberrypi ~/shapes/eu $ 

3. MapServer konfigurieren
Der MapServer an sich muss nicht konfiguriert werden, sondern nur die Karten und Layer, die er darstellen soll. Die passiert mittels sogenannter Map-Files.
Um dieses Map-File nun richtig erstellen zu können, braucht man zuerst ein paar Informationen über das Shape.
Diese enthält man mit dem Befehl ogrinfo. Dieser ist Teil des gdal-bin-Pakets, welches ja schon mit installiert wurde. Also

pi@raspberrypi ~/shapes/eu $ ogrinfo MyEurope.shp
INFO: Open of `MyEurope.shp'
      using driver `ESRI Shapefile' successful.
1: MyEurope (Polygon) 

Dadurch erhält man erstmal Informationen darüber, welche Layer in diesem Shape enthalten sind. In diesem Fall ist es nur ein Layer mit dem dem Namen MyEurope. Jetzt braucht man noch Informationen zu diesem Layer.
Diese bekommt man mit

pi@raspberrypi ~/shapes/eu $ ogrinfo MyEurope.shp MyEurope -summary
INFO: Open of `MyEurope.shp'
      using driver `ESRI Shapefile' successful.

Layer name: MyEurope
Geometry: Polygon
Feature Count: 33
Extent: (-31.289030, 27.637497) - (30.128712, 69.060303)
Layer SRS WKT:
GEOGCS["GCS_WGS_1984",
    DATUM["WGS_1984",
        SPHEROID["WGS_84",6378137.0,298.257223563]],
    PRIMEM["Greenwich",0.0],
    UNIT["Degree",0.0174532925199433]]
FIPS_CNTRY: String (2.0)
GMI_CNTRY: String (3.0)
CNTRY_NAME: String (40.0)
SOVEREIGN: String (40.0)
POP_CNTRY: Integer (10.0)
SQKM_CNTRY: Real (12.3)
SQMI_CNTRY: Real (12.3)
CURR_TYPE: String (16.0)
CURR_CODE: String (4.0)
LANDLOCKED: String (1.0)
COLOR_MAP: String (1.0)
Pop2011CIA: Integer (9.0)
Pop2000Wik: Integer (9.0)
url: String (100.0)
pi@raspberrypi ~/shapes/eu $ 

Die drei Informationen, die man unbedingt für das Mapfile benötigt, sind Geometry, Extent und Layer SRS WKT. Hier steht bei Datum „WGS_84“.
Jetzt können wir das erste, einfache Mapfile erstellen.
Dafür legen wir noch ein verzeichnis an und erstellen die Datei eu.map

mkdir /home/pi/maps
nano /home/pi/maps/eu.map

In diese Datei dann einfach den folgenden Code eintragen.

MAP
  # Der Name der Map. Dieser ist frei wählbar
  NAME "Europa"

  # der Pfad zu den Shape-Dateien
  SHAPEPATH "/home/pi/shapes/eu/"
  
  # Groeße von dem zu erzeugenden Bild
  SIZE 800 600

  # Die Extend-Werte aus dem Shape-File
  EXTENT -31.289030 27.637497 30.128712 69.060303
  
  # Typ von dem zu erzeugenden Bild. png hat den vorteil, dass es transparente Hindergruende darstellen kann
  IMAGETYPE PNG

        # Die Projektion des Shapes. Das Shape hatte als Datum "WGS_84", was epsg:4326 entspricht.
        # welchem epsg-Wert die Projektion eines Shapes entspricht, muss man im Internet suchen.
	PROJECTION
	  "init=epsg:4326"
	END
		 
	WEB
	    IMAGEPATH "/var/www/tmp/"
	    IMAGEURL  "/tmp/"
	    METADATA
	    	"wms_enable_request" "*"
	    END
	END

  # Hier werden dann die Layer definiert
  LAYER
    NAME europe
    DATA MyEurope
    STATUS ON
    # der Typ des Shapes - Ausgabe war POLYGON
    TYPE POLYGON
    
    PROJECTION
      "init=epsg:4326"
    END
    
    METADATA
      "wms_title"           "Küstenlinien Europa"
    END
    CLASS
      STYLE
        COLOR 0 0 0
        OUTLINECOLOR 0 0 0
      END
    END
  END
END

Diese Map-Files sind normalerweise sehr viel umfangreicher und beliebig kompliziert, aber für dieses Beispiel ist dieses Map-File schon völlig ausreichend. Weitere Informationen zu den Map-Fies findet man natürlich auf der homepage von MapServer.
Mit strg+o die Datei speichern und mit strg+x den Editor schließen. Das war es auch schon.
Zeit für einen ersten Test:

Wenn man dem Beispiel gefolgt ist und je nachdem, wo Apache und Mapserver installiert wurden, muss die Adresse noch angepasst werden – also etwas wie localhost oder IP des Raspberry.
Also Browser öffnen und in die Adresszeile folgenden Link eingeben:
http://ip-des-servers/cgi-bin/mapserv?map=/home/pi/maps/eu.map&SERVICE=WMS&REQUEST=Getmap&VERSION=1.1.1&LAYERS=europe&SRS=EPSG:4326&BBOX=-31.289030,27.637497,30.128712,69.060303&FORMAT=PNG&WIDTH=800&HEIGHT=600

Und wenn alles geklappt hat, sollte nach kurzer Zeit folgendes Bild erscheinen.

Shapefile-Test
Erster Test mit dem Mapserver

Update:
Um den Request etwas übersichtlicher zu gestalten, indem man nicht jedes mal die map-Datei mit angeben muss, kann man folgende Option wählen (hier beschrieben für Debian / Ubuntu):
Man benennt die Datei mapserv im Verzeichnis cgi-bin um in den Namen seines WMS-Dienstes, also zum Beispiel

cp /usr/lib/cgi-bin/mapserv /usr/lib/cgi-bin/mein-wms

Dann mus man in der Konfigurationsdatei seines Webservers folgendes hinzufügen:
Für Apache die Datei /etc/apache2/sites-available/default.conf bzw. die entsprechende Datei
#MapServer Anwendungen
SetEnvIf Request_URI „/cgi-bin/mein-wms“ map=/home/pi/maps/eu.map

Danach sieht der Request folgendermaßen aus:
http://ip-of-server/cgi-bin/my-wms?SERVICE=WMS&REQUEST=Getmap&VERSION=1.1.1&LAYERS=europe&SRS=EPSG:4326&BBOX=-31.289030,27.637497,30.128712,69.060303&FORMAT=PNG&WIDTH=800&HEIGHT=600

Jetzt hat man schonmal eine Basiskarte. Diese ist aber noch völlig statisch. Um die Karte jetzt interaktiv zu machen und mit etwas Leben zu füllen, braucht man OpenLayers. Open Layers ist eine JavaScript-Bibliothek und entspricht eigentlich dem, was die Google-Maps-Api für Google ist.

Man baut sich also eine einfache HTML-Datei mit Open-Layers zusammen, und es kann los gehen:

 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<html> 
    <head>
    
        <style type="text/css">
            div.olControlMousePosition { color: red; }
        </style>
 
        <script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> 
        <script type="text/javascript">
            function init(){
    
                var center = new OpenLayers.LonLat(10, 49.5);
    
                var map = new OpenLayers.Map( 'map' );

                var baseLayer = new OpenLayers.Layer.MapServer( "Europe Map", "http://ip-des-servers/cgi-bin/mapserv", {map: '/home/pi/maps/eu-test.map', layers: 'europe', srs: 'EPSG:4326', visibility: true } );

                map.addLayer(baseLayer);
                
                var markers = new OpenLayers.Layer.Markers( "Markers" );
                map.addLayer(markers);
                 
                 var myMarker = new OpenLayers.Marker(new OpenLayers.LonLat(13, 52.5));
                 //here add mouseover event
                myMarker.events.register('mouseover', myMarker, function(evt) {
                    popup = new OpenLayers.Popup.FramedCloud("Popup",
                        new OpenLayers.LonLat(13, 52.5),
                        null,
                        '<div>Hallo Welt. Gru&szlig; aus Berlin</div>',
                        null,
                        false);
                    map.addPopup(popup);
                });
                //here add mouseout event
                myMarker.events.register('mouseout', myMarker, function(evt) {popup.hide();});
                markers.addMarker(myMarker);


                map.addControl( new OpenLayers.Control.Zoom() );
                map.addControl(new OpenLayers.Control.MousePosition());
                map.setCenter( center, 4 );
            }
        </script> 
 
    </head> 
     
    <body onload="init()"> 
        <p><h1>Erstes Beispiel</h1><p>
        <div id="map" style="width:800px;height:600px"></div>
        
    </body> 
</html>

Wenn man diese HTML-Datei jetzt aufruft, sollte man dann etwas in der Art im Browser sehen:
Unsere Karte mit einer Zoom-Control oben links, einem Marker mit Popup und einer Anzeige der Mouse-Position unten rechts.

HTML-Beispiel mit OpenLayers
Erstes HTML-Beispiel mit OpenLayers

Jetzt kann man nach belieben weitere Marker, Layer oder was einem sonst noch einfällt der Karte hinzufügen.

„Live“ sehen kann man das Endprodukt hier ( Race Tracker ). Als zusätzlichen WMS-Layer ist noch eine Karte von OpenWeatherMap eingebunden mit den aktuellen Windgeschwindigkeiten. Das ist ein Race-Tracker der Segel-Regatta Round Britain and Ireland .

Wegen Umbau ist der Server mit dem Race-Tracker im Moment nicht erreichbar

Weitere Informationen zu OpenLayers findet man auf openlayers.org

3 Gedanken zu “Einfacher Karten-Server mit MapServer, Shape-Files und OpenLayers

    • Hey

      Sorry, unfortunately i’m not an expert in manipulating shape files, but in the map file the necessary part should be the layer definition. It should be something like

      LAYER
      STATUS ON
      # Type of the Shape – output should then be POINT or something like that
      TYPE POINT

      Hope this helps

      Bjoern

Schreibe einen Kommentar