Difference between revisions of "HBUMNMapServer ger Capter 2"
Line 1,246: | Line 1,246: | ||
− | *=IMAGECOLOR < | + | *=IMAGECOLOR <red> <green> <blue>= Hintergrundfarbe für die fertige Legende |
*=TRANSPARENT <ON|OFF>= Schaltet Transparenz für den Hintergrund der Legende ein oder aus. Voreingestellt ist der Hintergrund nicht transparent. | *=TRANSPARENT <ON|OFF>= Schaltet Transparenz für den Hintergrund der Legende ein oder aus. Voreingestellt ist der Hintergrund nicht transparent. | ||
− | *=OUTLINECOLOR < | + | *=OUTLINECOLOR <red> <green> <blue>= Umrissfarbe für die Kästchen, die die Symbole in der Legende umranden. |
*=KEYSIZE <x> <y>= Breite und Höhe der Symbole in der Legende in Pixeln. Vorgabe ist 20x10. | *=KEYSIZE <x> <y>= Breite und Höhe der Symbole in der Legende in Pixeln. Vorgabe ist 20x10. | ||
*=KEYSPACING <x> <y>= Horizontaler und vertikaler Abstand der Symbole bzw. der Beschriftungen zueinander. Vorgabe ist 5 und 5. | *=KEYSPACING <x> <y>= Horizontaler und vertikaler Abstand der Symbole bzw. der Beschriftungen zueinander. Vorgabe ist 5 und 5. | ||
Line 1,438: | Line 1,438: | ||
Dieses Stück HTML-Code generiert also nicht nur eine Legende, sondern auch gleich die Elemente für das Navigationsformular aus dem Inhalt des Mapfiles. Wird dem Mapfile nun ein neuer Layer hinzugefügt (oder ein Layer entfernt), wird die Legende automatisch korrekt generiert, ohne dass man am Template etwas ändern müßte. | Dieses Stück HTML-Code generiert also nicht nur eine Legende, sondern auch gleich die Elemente für das Navigationsformular aus dem Inhalt des Mapfiles. Wird dem Mapfile nun ein neuer Layer hinzugefügt (oder ein Layer entfernt), wird die Legende automatisch korrekt generiert, ohne dass man am Template etwas ändern müßte. | ||
− | |||
=Templates= | =Templates= |
Revision as of 11:57, 13 July 2008
Mapfile
\index{Mapfile}
Das Mapfile wird Ihnen größte Freude bereiten. Sie werden die meisten Ihrer Fehler damit machen, und die meiste Zeit, die Sie mit dem MapServer überhaupt verbringen, wird das Editieren Ihrer Mapfiles zum Inhalt haben.
Bedeutung des Mapfiles
Das Mapfile ist die zentrale Layout- und Konfigurationsdatei einer MapServer-Anwendung. Sie beschreibt Inhalt und Darstellung der fertigen Karte und enthält zusätzliche Informationen, um Maßstäbe, Legenden und Referenzkarten passend zur fertigen Karte zu erstellen.
Auch die Metadaten, die zur OGC-konformen Funktionsweise benötigt werden, sind im Mapfile angegeben.
Bevor wir jedoch in alle Details des Mapfiles einsteigen, werfen wir einen Blick auf die generelle Funktionsweise des MapServers.
==MapServer als CGI==\index{CGI}(2)
Dies ist der "`Standard"'-Weg, den MapServer zu benutzen: indem er als Programm in einem Webserver wie beispielsweise dem Apache residiert. Über den URL bekommt das Programm Parameter zugewiesen und ändert seine Ausgabe anhand dieser Parameter.
Ein Beispiel. Ein typischer URL sieht etwa folgendermaßen aus:
http://www.example.com/cgi-bin/mapserv \
? map=/usr/local/www/mapfile.map
Das ganze ist für den Druck umgebrochen, es handelt sich um eine einzige Zeile, und die Leestellen im URL sind ebenfalls nur für die Lesbarkeit hinzugefügt. Backslashes an den Enden zeigen an, dass die Zeile noch nicht beendet ist. Diese Unix-typische Notation wird im folgenden im ganzen Buch Verwendung finden.
Beachten Sie bitte, dass die Domain =example.com= für anschauliche Zwecke in der Literatur~rfc2606 reserviert ist und Ihnen kein Ergebnis bei einem Aufruf anzeigen wird. Ersetzen Sie diesen Domainnamen durch den tatsächlichen Namen Ihres Hosts.
Der MapServer, das eigentliche Programm, das die Arbeit macht, liegt offensichtlich in einem =cgi-bin= genannten Verzeichnis des Webservers. Ruft man ihn einfach ohne Parameter auf, also etwa folgendermaßen:
http://www.example.com/cgi-bin/mapserv
dann sollte man als Antwort folgendes in seinem Browser sehen:
No query information to decode. QUERY_STRING is set, but empty.
\begin{figure} \begin{center} \mmfig{0.35}{motzing}{Der MapServer motzt herum; genau das, was man am Anfang sehen möchte.} \end{center} \end{figure}
Also wie in Abbildung~\ref{motzing}. Wie reagiert man darauf? Indem man sich freut, denn alles ist in Ordnung; hurra, er kann schon rummotzen! Dies ist die Meldung, die man sehen möchte. MapServer beschwert sich lediglich, dass er keine Parameter zur Verarbeitung genannt bekommen hat. Nach einer neuen Installation ist diese Meldung nach dem ersten Testaufruf das gewünschte Ergebnis.
Der erste Parameter wird mit einem Fragezeichen =?= eingeleitet, alle weiteren werden mit einem Kaufmanns-Und =\&= voneinander getrennt.
Zwingend notwendig ist die Angabe eines Mapfiles über den Parameter =map== \footnote{Man kann diese Preisgabe des Ortes, an dem das Mapfile liegt, auch nach außen verbergen. Mehr dazu später.}, damit dem MapServer bekannt ist, welches Layout für die Karte zur Anwendung kommen soll.
Liegt Ihr Mapfile unter Unix etwa unter =/usr/local/maps/mymap.map= , so wäre also folgender Aufruf korrekt:
http://www.example.com/cgi-bin/mapserv?map=/usr/local/maps/mymap.map
Pfade unter Windows werden ebenfalls so angegeben, wie Sie es gewohnt sind, also beispielweise mit =C:= am Anfang.
Die Modi
MapServer kennt nun verschiedene Betriebsmodi , die über den Parameter =mode== notiert werden. Es gibt die folgenden Modi:
- =browse= : Läßt Sie die Karte browsen. Das bedeutet im wesentlichen, dass MapServer die Templates berücksichtigt, die im Mapfile angegeben sind, und somit HTML-Dateien mit Navigationselementen ausliefert. Wenn kein Modus angegeben ist, geht MapServer immer von =browse= aus. Was es mit Templates genau auf sich hat, erfahren Sie in Abschnitt~20 ab Seite~\pageref{text:mapfile:templates}.
- =map= : Dieser Modus läßt den MapServer Template-Angaben ignorieren und nur die Karte ausliefern. Zum Testen Ihres Mapfiles ist dies wahrscheinlich genau der Modus, den Sie haben möchten.
- =query= : Dieser Modus und seine Funktion, das Abfragen von Daten, die der Karte zugrunde liegen, werden ab Seite~\pageref{text:mapfile:queries} beschrieben.
- =nquery= : Wo =query= immer nur ein Ergebnis zurückliefern kann, kann =nquery= mehrere Ergebnisse liefern, sowohl im gleichen Layer als auch aus verschiedenen Layern (und auch beides zusammen, natürlich). Die Template-Angaben für diesen Modus können recht umfangreich sein.
Wenn Sie also Ihr Mapfile =mymap.map= im Modus =map= aufrufen wollten -- wodurch lediglich eine Karte, aber kein HTML-Interface produziert würde --, würden Sie folgendes notieren:
http://www.example.com/cgi-bin/mapserv \
? map=/usr/local/maps/mymap.map \
& mode=map
Die weiteren Parameter
Alle Variablen, die das Aussehen einer Karte beeinflussen könen, werden über solche Parameter übergeben. Das schließt das Mapfile und den Modus mit ein, und darüberhinaus \ldots\ nun, eben alles andere, inklusive der Kartenebenen, die Sie sehen möchten, die Eckpunkte des gewünschten Kartenausschnitts, und noch diverse andere Dinge mehr. Da kann ein URL schnell einmal wie folgt aussehen:
http://www.example.com/cgi-bin/mapserv \
? map=/usr/local/maps/mymap.map \
& mode=map \
& layer=postleitzahlen&layer=fluesse&layer=strassen \
& imgext=18.0+9.0+30.0+15.0
Und sie kann noch viel viel länger werden. Und Ihr erster Gedanke, wenn Sie das sehen, ist natürlich vollkommen korrekt: Das will kein Mensch jedesmal eintippen müssen.
Daher werden diese Parameter für gewöhnlich über Eingaben in einem HTML-Formular generiert. Dazu gehört dann beispielsweise auch die Karte, die Sie im Browserfenster anklicken. Diese Formulare werden aus den Templates generiert, die weiter oben schon einmal erwähnt worden sind.
Für das erste setzen wir uns ausschließlich mit der Gestaltung der Karte auseinander, wofür Sie nur den Modus =map= ohne zusätzliche Parameter benötigten. Wenn ab Seite~\pageref{text:mapfile:templates} die Templates dazukommen, wird Ihr Wissen um eine Navigation in der Karte erweitert. Ab Seite~\pageref{text:mapfile:cgiparams} finden Sie schließlich eine Aufzählung aller möglichen CGI-Parameter.
Neben der CGI-Fassung gibt es zwei weitere Wege, die Funktionalitäten des MapServers zu nutzen. Beide unterscheiden sich zum Teil radikal von der Weise, die in diesem Kapitel behandelt wird.
\subsubsection*{Der OGC-konforme MapServer}\index{OGC}
Der OGC-konforme MapServer arbeitet ebenfalls als CGI-Programm und muß vor allen Dingen mit Metadaten versorgt werden, die dann bei der Kommunikation mit anderen Servern und mit Client-Appli\-ka\-tio\-nen verwendet werden.
Leider weicht sowohl die Notation des aufrufenden URL als auch die Notation der Metadaten im Mapfile ein wenig von der des MapServers im 'Normalbetrieb' ab, was nicht zur Lesbarkeit der ganzen Datei beiträgt. Die Unterschiede in der Notation werden im entsprechenden Kapitel ab Seite~\pageref{text:ogc} natürlich erläutert.
\subsubsection*{MapScript}\index{MapScript}
MapScript muß nicht gezwungenermaßen mit einem Mapfile arbeiten, z.B. wenn man damit nur Shapefiles bearbeiten möchte. Sobald man beginnt, mit Karten arbeiten zu wollen, muß man jedoch auch mit MapScript ein Mapfile laden, das dann verwendet werden kann.
Alle Sektionen im Mapfile werden dann als Objekte in einer Programmiersprache behandelt. Grundsätzlich ist nicht einmal ein Webserver vonnöten, auch lokale Applikationen lassen sich mit MapScript realisieren.
Am häufigsten sieht man MapScript jedoch in seiner Variante für PHP im Einsatz, die dann natürlich wieder in Webservern läuft. Als Beispiel konzentrieren wir uns in diesem Handbuch auf eben diese Version von MapScript.
Grundlegender Aufbau des Mapfiles
Werfen wir zuerst einen ganz allgemeinen Blick darauf, wie Inhalte im Mapfile notiert werden, bevor dann näher beschrieben wird, welche Einträge es denn gibt.
Das Mapfile besteht aus einzelnen Blöcken, die mit einem Schlüsselwort beginnen und mit einem =END= abgeschlossen werden:
WEB
...
END
Dieses Beispiel zeigt den Beginn und das Ende eines =WEB= -Blocks. Innerhalb eines solchen Blocks folgen Deklarationen von Schlüsselworten und dazugehörigen Werten, oder wieder neue Blöcke. Beispiele für Blöcke in Blöcken sind Classes innerhalb von Layern.
Ausnahmen für diese Notation sind der Header des Mapfiles und das Mapfile selber, das zwar mit einem END abgeschlossen werden muss, aber kein einleitendes Schlüsselwort kennt.
Wann immer im folgenden drei Punkte in Beispielen zu sehen sind, sollen diese Punkte nicht tatsächlich eingegeben werden; es handelt sich vielmehr um Platzhalter, die zeigen, dass etwas weggelassen worden ist.
Es können drei verschiedene Dinge als Werte notiert werden: Schlüsselworte, Zahlen oder Zeichenketten.
SCHLÜSSELWORT SCHLÜSSEL
STATUS ON
SCHLÜSSELWORT "ZEICHENKETTE"
DATA "myshapefile"
SCHLÜSSELWORT ZAHL [ZAHL ...]
EXTENT 0 0 4000 4000
Im Gegensatz zu Schlüsselworten und Zeichenketten ist es bei Zahlen in den meisten Fällen nötig, mehr als nur eine zu schreiben. So benötigt man für den Extent einer Karte stets vier Zahlen, die die beiden Koordinaten jeweils eines Eckpunktes bezeichnen.
Zeichenketten sollten generell nicht mit Zahlen beginnen: =zweiterlayer= ist als Layername in Ordnung, =2terlayer= nicht.
Ausnahmen dazu bilden Angaben zu Projektionen von Karten und Layern und die Metadaten in diversen Sektionen. Deren Notation wird in den entsprechenden Abschnitten näher beschrieben.
Zwei Arten von Angaben verdienen besondere Beachtung: Pfade in das Dateisystem und Farben.
\subsubsection*{Notation von Pfaden}
Pfade können absolute oder relative Angaben sein. Absolute Angaben sehen etwa folgendermaßen aus:
SHAPEPATH "c:\mapserver\daten"
SHAPEPATH "/usr/local/GIS/daten/"
Absolute Pfade heißen so, weil sie den vollständigen Pfad von der Wurzel des Dateisystems bis hin zur Datei angeben.
Relative Pfade bewegen sich immer in Relation zu etwas, in unserem Fall zum Mapfile:
SHAPEPATH "daten/"
In diesem Fall gibt es also im Verzeichnis des Mapfiles ein Unterverzeichnis mit dem Namen =daten= .
\subsubsection*{Farbwerte}
Farben werden als RGB-Werte angegeben, also bestehend aus ihren jeweiligen Anteilen von Rot, Grün und Blau, in Werten von 0 bis 255\footnote{Dadurch lassen sich theoretisch <math>2^{24}</math> Farben, also die bekannten 16 Millionen darstellen}. Einige Beispiele:
COLOR 0 0 0 # schwarz
COLOR 255 255 255 # weiß
COLOR 255 0 0 # rot
COLOR 0 255 0 # grün
COLOR 0 0 255 # blau
Und so weiter. Farben, bei denen alle drei Zahlen gleich sind, ergeben Grautöne. Im Web finden sich einige Farb- und Umrechnungstabellen.
Beachten Sie bitte: Ohne weitere Angaben zum Ausgabeformat -- siehe Seite~\pageref{text:mapfile:ausgabeformate} -- produziert MapServer nur Bilder mit einer Palette von 256 Farben. Mehr über Farben in MapServer erfahren Sie in eben diesem Abschnitt.
Der Header
\index{Header}\index{Mapfile!Header}(3)
Der Header im Mapfile enthält globale Angaben, die sich auf alle Sektionen im Mapfile beziehen oder das Aussehen des fertigen Bildes bestimmen, das produziert werden soll. Der Header ist die einzige Sektion, die nicht durch ein END abgeschlossen wird. Er besitzt auch kein einleitendes Schlüsselwort.
Ein Beispiel für einen kompletten Header\footnote{Um keinen Fehler im Modus =map= zu produzieren, reichen eigentlich schon SIZE und EXTENT, zusammen mit einem END für ein vollständiges Mapfile.}:
NAME "brandenburg"
EXTENT 0.0 0.0 1.0 1.0
SIZE 450 450
SHAPEPATH "daten/brandenburg/"
Sie können die folgenden Angaben im Header Ihres Mapfiles machen:
- =NAME <name>= Ein Name als Beschreibung der Karte. Dieser Name sollte einzigartig sein und im weiteren nicht als Name für Layer verwendet werden. Der Name der Karte wird für WMS-konforme Aufrufe verwendet -- siehe auch das entsprechende Kapitel --, als auch als Prefix für die Namen temporär erzeugter Dateien des MapServer.
- =STATUS <ON|OFF>= : Der Status der Karte, ob an oder aus. Da man ein Mapfile normalerweise schreibt, um eine Karte anzuzeigen, drängt sich =ON= geradezu auf.\\ Ausschalten will man das nur dann, wenn man nur die anderen Elemente benutzen will, die man im Mapfile definiert, also zum Beispiel Maßstäbe und Legenden.
- =EXTENT <minx miny maxx maxy>= : Eine Bounding Box um die Daten herum. Wird im URL für den Mapserver keine Bounding Box explizit angegeben, ist diese Angabe im Mapfile eine Standardeinstellung, die automatisch verwendet wird. Dieser Wert muß zwingendermaßen vorhanden sein.\\ Sorgen Sie dafür, dass hier ein sinnvoller Wert steht. MapServer ist nicht in der Lage, aus den vorliegenden Daten einen 'Default'-Extent zu ermitteln. Auf das Problem angesprochen, meinten die Entwickler, so ein Feature auch nicht implementieren zu wollen, zumal einige Datenformate gar keinen Extent speichern und das Errechnen aus den Daten selbst viel zu aufwendig wäre.
- =SIZE <width height>= : Die Größe des zu produzierenden Bildes, anzugeben in Breite und Höhe in Pixeln. Auch dies ist eine Voreinstellung, die Verwendung findet, wenn es keine andere explizite Angabe gibt. Die Größe des zu produzierenden Bildes ist auf 2048 Pixel im Quadrat beschränkt.
- =SHAPEPATH <path>= : Der Ort im Dateisystem, an dem die Daten liegen. Kann ein relativer Pfad zum Mapfile sein, oder ein absoluter, der irgendwo anders in das lokale Dateisystem weist.
- =SYMBOLSET <filename>= : Die Datei, in der Symbole definiert werden. Was es mit Symbolen auf sich hat, und wie Symbole im Mapfile selber anstatt in einer seperaten Datei notiert werden können, erfahren Sie in Abschnitt~17.
- =FONTSET <filename>= : Die Datei, die Aliase für TrueType-Schriften enthält. Zum Aufbau dieser Datei und der Verwendung von Schriften im MapServer siehe den Abschnitt ab Seite~\pageref{text:mapfile:fonts}.
- =IMAGECOLOR <red green blue>= : Hintergrundfarbe des fertigen Kartenbildes, in RGB-Werten.
- =IMAGEFORMAT <name>= : Name des Ausgabeformats, das produziert werden soll. Muß ein interner Name für ein Bildformat sein, oder der Name eines Ausgabeformates, der mit einer =OUTPUTFORMAT= -Sektion definiert worden ist. Mehr zu Ausgabeformaten finden Sie ab Seite~\pageref{text:mapfile:ausgabeformate}.
\subsubsection*{Das Wort MAP}
Sie können ein Mapfile auch mit dem Schlüsselwort =MAP= einleiten:
MAP
NAME "brandenburg"
SIZE 400 400
...
END
Das ist nicht notwendig. Sie können so allerdings dem abschließenden =END= am Ende des Mapfiles sozusagen einen Startparameter zur Seite stellen. Es sieht hübscher aus, hat aber keine Funktion.
Die Web-Sektion
\index{Web}\index{Mapfile!Web}
Der Web-Block im Mapfile definiert das Verhalten des MapServer-Interface nach außen und beinhaltet URLs für verschiedene Gelegenheiten, einige interne Informationen, die nicht nach außen weitergegeben werden, sowie eventuell Metadaten für verschiedene Anwendungsfälle, für gewöhnlich zum Beispiel für OGC-konformes Verhalten.
Der Web-Block wird mit den Schlüsselwort =WEB= eingeleitet und durch ein =END= abgeschlossen.
'Web' ist als Name eigentlich irreführend, da die Daten in diesem Abschnitt nicht notwendigerweise nur von Web-Diensten genutzt werden. Aber der MapServer wurde als Web-Applikation entwickelt, und daher ist es unwahrscheinlich, dass sich an dieser Benennung etwas ändern wird.
Die folgenden Elemente können in der Web-Sektion verwendet werden:
- =ERROR <url>= \index{ERROR}: Definiert einen URL, an den der Benutzer weitergeleitet wird, wenn ein Fehler in der MapServer-Applikation auftritt. Kann eine absolute URL sein, die mit =http://= eingeleitet wird, oder ein Pfad relativ zur Lage des Mapfiles. Wird =ERROR= nicht definiert, wird einfach nur die Fehlernachricht als Text ausgegeben.\\ Beachten Sie dabei, dass das für das Debuggen während der Entwicklung Ihrer Anwendung nicht begehrenswert ist, da keine der MapServer-Fehlermeldungen mehr ausgegeben werden. Das will man für gewöhnlich nur für das fertige System haben, sobald man seine Benutzer nicht mehr mit den Fehlermeldungen des MapServers konfrontieren möchte, sondern mit einer hübschen Fehlerseite.
- =EMPTY <url>= \index{EMPTY}: URL, an den der Benutzer weitergeleitet wird, wenn ein Query keine Resultate erbracht hat. Wenn =EMPTY= nicht definiert ist, wird dafür der Wert von =ERROR= benutzt.
- =FOOTER <filename>= \index{FOOTER}: Der Fußteil einer fertigen Ausgabe. Kommt nur bei Queries zur Anwendung, die mehrere Ergebnisse zurückliefern sollen.
- =HEADER <filename>= \index{HEADER}: Der Kopfteil einer fertigen Ausgabe. Kommt nur bei Queries zur Anwendung, die mehrere Ergebnisse zurückliefern sollen.
- =TEMPLATE <url|filename>= \index{TEMPLATE}: Das Template, das das eigentliche Interface zum Benutzer darstellt. Darstellung der Karte und die Navigation darin werden durch das Template übernommen. Der Aufbau eines Templates wird detailliert in Abschnitt~20 behandelt.
- =IMAGEPATH= \index{IMAGEPATH}: Der Pfad zu dem Verzeichnis, in dem die vom MapServer generierten Bilder abgelegt werden sollen. Dieser Pfad muß auf dem System existieren und muß vom Webserver (bzw. von dem Benutzer, mit dessen Rechten der Webserver läuft) beschreibbar sein. Diese Angabe muß mit dem Verzeichnistrenner der jeweiligen Plattform enden, also =/= auf Unix-Systemen und so weiter.
- =IMAGEURL= \index{IMAGEURL}: Der URL zum genannten =IMAGEPATH= . =IMAGEURL= wird vom Webbrowser zurückgegeben und muß daher im Webserver so konfiguriert sein, dass =IMAGEURL= auf =IMAGEPATH= abgebildet wird. Auf Unix-Systemen wird meistens der URL =/tmp= auf das lokale Verzeichnis =/tmp/= (oder auch =/var/tmp/= ) abgebildet. Damit gibt man jedoch auch sein temporäres Verzeichnis dem öffentlichen Zugriff preis. Sinnvoller ist es, ein eigenes Verzeichnis für diese Dateien anzulegen. Mehr Überlegungen zu diesem Thema finden Sie in Anhang~\ref{anhang:sicherheit}.
- =LOG <filename>= \index{LOG}: Die Logdatei für den MapServer. Diese Datei muß auf dem System existieren und muss vom Webserver (bzw. von dem Benutzer, mit dessen Rechten der Webserver läuft) beschreibbar sein. Mehr zu Log-Dateien erfahren Sie weiter unten in Abschnitt~31.
- =MINSCALE= \index{MINSCALE}: Der minimale =SCALE= , in dem Karten zu sehen sind. Wird eine Karte mit einem kleineren =SCALE= vom Client angefordert, liefert MapServer eine Karte in dem =SCALE= zurück, der =MINSCALE= entspricht. Mehr zur Verwendung von =SCALE= -ähnlichen Parametern im Mapfile finden Sie in Sektion~19.
- =MAXSCALE= \index{MAXSCALE}: Der maximale =SCALE= , in dem Karten zu sehen sind. Wird eine Karte mit einem größeren =SCALE= vom Client angefordert, liefert MapServer eine Karte in dem =SCALE= zurück, der =MAXSCALE= entspricht. Mehr zur Verwendung von =SCALE= -ähnlichen Parametern im Mapfile finden Sie in Sektion~19.
- =MINTEMPLATE= \index{MINTEMPLATE}: Template, das anstelle von =TEMPLATE= benutzt werden soll, wenn der Client eine Karte angefordert hat, deren =SCALE= unter =MINSCALE= liegt. Mit einem solchen Template lassen sich Applikationen ineinander verschachteln, indem ab bestimmten Zoomtiefen einfach andere Templates benutzt werden.
- =MAXTEMPLATE= \index{MAXTEMPLATE}: Template, das anstelle von =TEMPLATE= benutzt werden soll, wenn der Client eine Karte angefordert hat, deren =SCALE= über =MAXSCALE= liegt. Mit einem solchen Template lassen sich Applikationen ineinander verschachteln, indem ab bestimmten Zoomtiefen einfach andere Templates benutzt werden.
Der Parameter =IMAGEQUALITY= , mit dem sich Kompressionsraten für produzierte JPEG-Bilder setzen ließ, wird nicht mehr unterstützt. Verwenden Sie stattdessen einen entsprechenden Parameter in einer =OUTPUTFORMAT= -Sektion (siehe weiter hinten). Das gleiche gilt für =INTERLACED= .
Layer
\index{Layer}\index{Mapfile!Layer}
MapServer organisiert seine Daten in Schichten, die übereinander liegen -- eben den Layern. Diese Schichten werden dann zu einem fertigen Bild zusammengefügt. Einzelne Sets von Raster- oder Polygondaten müssen jeweils in einen eigenen Layer eingebunden werden. Über die Layer werden auch Queries definiert, die dazu verwendet werden, Anfragen an zusätzlich gespeicherte Daten zu stellen. Auf diese Weise können beispielsweise Flächen angeklickt und detaillierte Informationen zu diesen angezeigt werden.
Bei nicht-OGC-konformen MapServern spielt die Reihenfolge der Layer im Mapfile eine wichtige Rolle. Der oberste Layer im Mapfile wird als erstes gezeichnet, und liegt somit in der Karte zuunterst. Rasterbilder bieten sich meist als unterster Layer an. Auf den ersten Layer wird dann der zweite Layer im Mapfile gezeichnet, und so weiter.
Wir betrachten im folgenden den Aufbau eines Vektorlayers mit Zugriff auf ein Shapfile. Rasterdaten werden in Abschnitt~7 besprochen.
- =NAME <name>= : Ein Name als Beschreibung des Layers. Mehrere Layer können identische Namen tragen und werden dann als ein einziger Layer behandelt. Diese Vorgehensweise wird manchmal für Beschriftungen (Annotationen, siehe weiter hinten) gewählt, um in einem Zug den Layer samt Beschriftung ein- oder ausblenden zu können. Ansonsten sollte der Name so gewählt werden, dass er eindeutig ist.
- =DATA <filename>= : Der Dateiname des Shapefiles. Dieser Name ist relativ zum =SHAPEPATH= im Header des Mapfiles. Die Zeichenkette hier wird also einfach angehangen. Der Name sollte ohne den Anhang .shp angegeben werden. Bitte beachten Sie, dass die zum Shapefile gehörige .dbf -Datei immer vorhanden sein muss, auch wenn man nicht auf ihren Inhalt zugreift. Das gleiche gilt natürlich auch für die Indexdatei mit der Endung .shx , nur wird diese ja beim Zugriff auf das Shape tatsächlich verwendet. Des weiteren können Sie hier auch einfach den absoluten Pfadnamen einer Datei angeben.
- =STATUS <ON|OFF|DEFAULT>= : Der Status des Layers. Es gilt drei verschiedene Stadien zu unterscheiden. =DEFAULT= stellt den betreffenden Layer auf jeden Fall dar, unabhängig davon, ob der Benutzer ihn über den URL anfordert. Auf diese Weise läßt sich die Darstellung beispielsweise eines Hintergrundbildes erzwingen, ohne dass man ihn von außen abschalten kann. =OFF= stellt den Layer gar nicht da, unabhängig davon, ob er von außen angefordert worden ist. =ON= hingegen macht den Layer darstellbar, und er wird angezeigt, wenn er über den entsprechenden Parameter des URL angefordert worden ist.
- =TYPE <POINT|LINE|POLYGON>= : Für Vektorlayer kommen nur diese drei verschiedenen Typen in Frage. Punktlayer sind offensichtlich nur für Punktdaten geeignet. Generell lassen sich Linien- und Vektordaten als das jeweils andere darstellen. Das wirkt sich im wesentlich auf die Art und Weise aus, mit der MapServer die Definitionen in den Klassen des Layers interpretiert. Mehr dazu im Abschnitt über Classes.
Beachten Sie bitte, dass in den Layer-Sektionen mit diesen Angaben noch keine Aussagen über das Layout der Daten gemacht werden. Diese Aussagen werden erst in den Klassen innerhalb eines Layers getroffen!
Gruppierungen von Layern
(4) \index{Groups}\index{Layer!Groups}
Zuweilen möchte man mehrere Layer gleichzeitig ansprechen, indem man sie beispielsweise in einem Schwung an- und wieder ausschaltet. Wenn man für jeden dieser Layer einen eigenen Eintrag in der Navigation zuläßt, kann es schnell unübersichtlich werden.
Eine Möglichkeit ist, zusammengehörigen Layern den gleichen Namen zu geben. Wenn man also drei Layer hat, die beispielsweise Landstraßen, Autobahnen und Bundesstraßen darstellen, kann man sie alle drei =strasse= nennen und ist fertig.
Das widerspricht jedoch ein wenig der Idee, drei verschiedende Layer zu haben. Man hätte dann ebenso gut alle Daten in einem Shapefile unterbringen und die Art der Darstellung mit entsprechenden Classes über die Daten in der .dbf -Datei erledigen können.
Das Schlüsselwort =GROUP= erlaubt die Gruppierung von Layern unter Beibehaltung ihrer Namen mitsamt der Möglichkeit, sie alle auf einmal ansprechen zu können. Man schaue sich folgendes Fragment an:
LAYER
NAME "autobahnen"
GROUP "strassen"
...
END
LAYER
NAME "bundesstrassen"
GROUP "strassen"
...
END
LAYER
NAME "landstrassen"
GROUP "strassen"
...
END
Nun ist es möglich, im URL eines MapServer-Aufrufs weiterhin folgendes zu schreiben:
...&layer=landstrassen&layer=autobahnen&...
Zusätzlich gewinnt man aber auch die folgende Notation:
...&layer=strassen&...
Weitere Layer-Optionen
Im folgenden eine Liste aller weiteren Schlüsselworte, die in Layern Verwendung finden können. Falls Sie dieses Buch von vorne nach hinten durchlesen\footnote{Sowas soll's geben.}, werden Sie einige der Begriffe wahrscheinlich noch nicht kennen. Sie sollten dann später noch einmal hierher zurückkehren und sich die Bedeutung der Dinge klarmachen.
(5)
- =REQUIRES <expression>= Legt bestimmte Voraussetzungen fest, unter denen ein Layer angezeigt wird. Ein Beispiel:
LAYER NAME "gruenflaechen" STATUS ON REQUIRES "[parks] != 1" ... END
Dieser Layer würde also nur dann angezeigt, wenn ein anderer Layer mit dem Namen =parks= nicht zu sehen ist. Logische Operatoren wie =AND= und =OR= können hier Verwendung finden. - =MAXSCALE <double>= Der maximale SCALE, bei dem der Layer noch gezeichnet werden soll. Dieser Wert ist unter Umständen nicht vertrauenswürdig -- siehe auch den Abschnitt~19 über Maßstäbe.
- =MINSCALE <double>= Das gleiche für einen minimalen SCALE.
- =LABELANGLEITEM <COLNAME>= Gibt bei einem Shapefile die Spalte in der .dbf -Datei an, in der ein Winkel stehen soll, um den ein Label im Layer gedreht werden soll.
- =LABELMAXSCALE <integer>= Der maximale SCALE, in dem Labels in diesem Layer gezeichnet werden sollen. Anmerkungen zu diesem Wert siehe weiter oben.
- =LABELMINSCALE <integer>= Der minimale SCALE, bei dem Labels in diesem Layer noch gezeichnet werden sollen.
- =LABELREQUIRES <expression>= Siehe weiter oben das =REQUIRES= -Schlüsselwort; wirkt sich aber nur auf die Label in einem Layer aus.
- =MAXFEATURES <integer>= Die maximale Anzahl an Features, die in diesem Layer gezeichnet werden sollen.
- =OFFSITE <integer>= Kommt nur bei Rasterbildern zur Anwendung und gibt die Nummer der Farbe in der Farbpalette an, die transparent geschaltet werden soll.
- =POSTLABELCACHE <TRUE|FALSE>= Gibt an, ob der Layer vor oder nach allen Labels gezeichnet werden soll. Voreinstellung ist =FALSE= .
- =SYMBOLSCALE <double>= Der SCALE, bei dem Labels (und Symbole) in ihrer vollen Größe gezeichnet werden. Auf diese Weise erreicht man Beschriftungen, die beim Herein- und Herauszoomen mitskalieren.
- =TRANSFORM <TRUE|FALSE>= Definiert, ob ein Layer von dem Koordinatensystem seiner Daten in ein Bildkoordinatensystem transformiert werden soll. Voreinstellung ist =TRUE= . Eine nützliche Funktion, wenn man Bilder an festen Stellen in jeder Karte einbinden möchte, beispielsweise Nordpfeile oder Logos.
=Classes=\index{Classes}\index{Klassen}\index{Mapfile!Classes}
Hinweis : Beachten Sie auf alle Fälle die Hinweise in Abschnitt~6, insbesondere, wenn Sie bisher älteren MapServer-Versionen als 4.0 gearbeitet haben.
Classes residieren ausschließlich innerhalb eines Layers. Sie definieren, wie die Daten innerhalb eines Layers tatsächlich dargestellt werden.
Zur Illustration ein erstes kleines Beispiel:
LAYER
NAME "fluesse"
DATA "shapes/fluesse"
TYPE LINE
STATUS ON
CLASS
COLOR 0 0 255
END
END
In diesem Vektorlayer gibt es lediglich eine einzige Class, was bedeutet, dass alle Shapes aus dem Shapefile auf die gleiche Weise dargestellt werden. In diesem Fall sind sie blau eingefärbt.
Beachten Sie, dass Sie zur Einfärbung von Linien und Punkten das Attribut =COLOR= benutzen müssen, wohingegen dieser Wert bei Polygonen die Füllfarbe bezeichnet. Der Rand des Polygons wird durch =OUTLINECOLOR= angesprochen.
\subsection*{Datenabhängiges Einfärben}
Wozu aber nun Classes einführen, wenn man diese Angaben auch direkt in den Layer schreiben könnte? Weil man durch Classes themenbezogene Darstellungen erreichen kann. Sehen wir uns das folgende Beispiel an:
LAYER
NAME "fluesse"
DATA "shapes/fluesse"
TYPE LINE
STATUS ON
CLASSITEM "NAME"
CLASS
EXPRESSION "Wolga"
COLOR 255 31 31
END
CLASS
EXPRESSION /./
COLOR 31 31 255
END
END
Wir sehen zuerst ein neues Schlüsselwort, =CLASSITEM= . Die Zeichenkette dahinter benennt die Spalte in der .dbf -Tabelle, anhand derer wir im folgenden filtern wollen. Alle Angaben in den Classes, die sich in diesem Layer befinden, orientieren sich an der Spalte mit diesem Namen.
In der ersten Class befindet sich eine =EXPRESSION= , ein Ausdruck. Damit ein Feature mit den Angaben in dieser Klasse dargestellt wird, muß das =CLASSITEM= auf diesen Ausdruck passen. Oder für das Beispiel: die erste Klasse findet Anwendung auf alle Shapes im Shapefile, deren NAME in der .dbf -Datei 'Wolga' lautet.
Die Classes in einem Layer werden von oben nach unten abgearbeitet, und die erste passende Class wird zur Darstellung verwendet.
Der Ausdruck in der letzten Class in diesem Beispiel bedeutet übrigens 'alle Zeichen'. Jeder mögliche Inhalt einer Spalte passt auf diesen Ausdruck. Es ergibt Sinn, eine solche 'Catch all'-Class anzulegen, um allen Features ein Standardaussehen zu verpassen, die nicht von einer der vorherigen Class abgedeckt worden sind. Eine Erklärung der möglichen Ausdrücke erfolgt im nächsten Abschnitt.
\subsection*{Mögliche Ausdrücke}
Es gibt drei verschiedene Weisen, eine =EXPRESSION= zu formulieren: mit Zeichenketten, mit regulären Ausdrücken und schließlich mit logischen Ausdrücken.
Zeichenketten sind bereits im obigen Beispiel zu sehen gewesen. Die Einträge in den Spalten der .dbf -Datei werden darauf geprüft, ob sie genau diesen Wert enthalten. Diese Art von =EXPRESSION= ist durch den MapServer am schnellsten abzuarbeiten.
Logische Ausdrücke sind Ausdrücke, die durch logische Operatoren gebildet werden können. Dazu gehören Konstrukte für gleich, ungleich, größer als, kleiner als und so weiter; darüber hinaus und, oder, nicht, und alle Kombinationen, die sich daraus ergeben. Dabei können weitere Spaltennamen in der .dbf-Datei referenziert werden. Als Beispiel ein Ausschnitt aus einem Layer:
CLASSITEM "NAME"
CLASS
EXPRESSION ([NAME] eq "Wolga" and [SIZE] < 10)
COLOR 255 0 0
END
CLASS
EXPRESSION /^A.+e<math>/
COLOR 0 0 255
END
CLASS
EXPRESSION /./
OUTLINECOLOR 128 128 128
END
Die erste Klasse findet Anwendung auf alle Shapes, deren Spalte =NAME= im .dbf-File den Eintrag Wolga haben und gleichzeitig einen kleineren Wert als 10 in der Spalte =SIZE= .
Obwohl diese Audrücke schon eine Menge Flexibilität bieten, kann man noch einen Schritt weiter gehen, wie man in der zweiten Klasse sehen kann. Die Art des dortigen Ausdrucks ist Informatikern als sogenannter regulärer Ausdruck bekannt. Der Ausdruck passt auf alle Einträge in der =NAME= -Spalte, auf die folgendes zutrifft: der erste Buchstabe ist ein großes A , das von einer beliebigen Anzahl beliebiger Zeichen (mindestens jedoch einem) gefolgt wird, abgeschlossen durch ein kleines e .
Die letzte Regel zeigt ebenfalls einen regulären Ausdruck. Er passt auf jedes beliebige Zeichen. Da die Classes von oben nach unten auf der Suche nach der ersten passenden Regel für ein Feature abgesucht werden, handelt es sich um eine sogenannte catch all -Regel, die auf alles zutrifft, was nicht vorher schon irgendwo gepasst hat.
Reguläre Ausdrücke sind ein ungemein mächtiges Werkzeug, das jedoch etwas Mühe zu Lernen erfordern kann. MapServer verwendet POSIX-konforme reguläre Ausdrücke, die auf jedem Unix-System in einer =man= -Page~man:7:regex erklärt werden.
=Styles=(6)\index{Styles}\index{Mapfile!Styles}
Mit MapServer 4.0 ist eine weitere Art eingeführt worden, die Darstellung eines Layers zu notieren. Um genau zu sein, sollte diese Art langsam aber sicher bevorzugt werden, zumal sie auch zusätzliche Vorteile bietet.
Aber zunächst sollen Sie natürlich erfahren, um was es geht. MapServer kennt ein neues Objekt, also eine Sektion, mit dem Namen =STYLE= . Diese Sektion trit nur innerhalb von Classes auf und wird selbtsverständlich jeweils mit einem =END= abgeschlossen. Das ganze soll den Zweck haben, den gestalterischen Part einer Class vom logischen zu trennen. Anstatt also folgendes zu notieren:
CLASS
EXPRESSION ([NAME] eq "Havel" and [SIZE] > 20)
SYMBOL "punkt"
COLOR 32 64 218
END
würden Sie in Zukunft folgendes schreiben:
CLASS
EXPRESSION ([NAME] eq "Havel" and [SIZE] > 20)
STYLE
SYMBOL "punkt"
COLOR 32 64 218
END
END
Im Moment können Sie noch beides verwenden. Im Sinne einer sauberen Arbeitsweise sollte Sie allerdings dazu übergehen, Styles zu benutzen und die Parameter, die für die Darstellung zuständig sind, nicht mehr direkt in den Classes zu notieren.
Die folgenden Parameter wandern in die Style-Sektion einer Class:
- =ANTIALIAS=
- =BACKGROUNDCOLOR=
- =COLOR=
- =MAXSIZE=
- =MINSIZE=
- =OFFSET=
- =OUTLINECOLOR=
- =SIZE=
- =SYMBOL=
Die Notierung der Parameter erfolgt wie weiter vorne ab Seite~\pageref{text:mapfile:class:parameters} beschrieben.
Warum sollte man das haben wollen? Es soll in Zukunft möglich sein, Styles mit Namen zu versehen, und dadurch Styles im gesamten Mapfile durch eben ihren Namen zu referenzieren. Dadurch kann bei umfangreichen Mapfiles einiges an Schreibarbeit eingespart werden. Insbesondere wird aber zukünftig Arbeit einsparen, weil Sie dann nur noch Styles von einem Mapfile ins andere Kopieren müssen, ohne auch noch an einer Class herumhantieren zu müssen.
Des weiteren kann man mehrere Styles in einer Class haben, sie werden der Reihe nach von oben nach unten ausgewertet; dabei wird, wie schon bei den Layern im Mapfile, der oberste Style zuerst gezeichnet. Dadurch ist es endlich möglich, mehr als die bisherigen 2 Symbole übereinander zu legen, wie es bisher mit =SYMBOL= und =OVERLAYSYMBOL= geschehen ist.
Außerdem -- dieser Teil ist allerdings reine Spekulation des Autors -- dürfte eine Abspaltung des darstellenden Teils einer Class die Implementierug der so genannten styled layer descriptors vereinfachen, einem OGC-Standard~pdf:spec:sld10, mit dem sich die Darstellung von Kartenfeatures über URL-Parameter beeinflussen läßt.
=Rasterdaten=(7) \index{Rasterdaten}\index{Mapfile!Rasterdaten}
Rasterdaten sind alle Arten von Daten, deren Dimensionen in Länge und Breite in Pixeln gemessen werden kann, vulgo: Bildformate. Die Bildformate, die von MapServer unterstützt werden, müssen in zwei Kategorien eingeteilt werden: die von der Software lesbaren (Input) und die Ausgabeformate (Output).
Als Ausgabe liefert MapServer Bilder, die von Webbrowsern darstellbar sind. Da sich MapServer dabei auf die Grafikbibliothek GD stützt, ist er auf deren Fähigkeiten angewiesen.
Ein typischer Rasterlayer wird im Mapfile etwa auf folgende Art angelegt:
LAYER
NAME "brandenburg_luftbild"
DATA "bilder/brandenburg.tif"
TYPE RASTER
STATUS ON
END
In diesem Beispiel wird ein tiff -Bild eingebunden, das anscheinend ein Luftbild der Region Brandenburg zum Inhalt hat. Der =TYPE= des Layers ist als =RASTER= angegeben.
Welche Formate eingelesen werden können, ist im wesentlichen eine Frage, die bei der Konfiguration noch vor der Kompilierung der Software geklärt wird. Einige Formate können dabei als eingebaut angesehen werden, indem der MapServer direkt auf die entsprechenden Bibliotheken zugreift. Andere Formate werden über die Rasterbibliothek GDAL gehandhabt.
Welche Formate Ihr MapServer handhaben kann, können Sie durch das Ausführen des CGI-Binaries auf der Kommandozeile mit dem Kommandozeilenschalter -v herausfinden:
thfischer@grobi # ./mapserv -v
MapServer version 4.0 OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=PDF
OUTPUT=SWF SUPPORTS=PROJ SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER
SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT
INPUT=EPPL7 INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE
In diesem Beispiel sehen wir =.jpeg= als (lesend) unterstütztes Rasterformate. Weitere Formate können durch Verwendung der GDAL-Schnittstelle angesprochen werden, insbesondere findet hier das Lesen von =.tif= -Bildern über GDAL statt. Mehr zu diesen Bibliotheken finden Sie weiter hinten im Buch.
Beachten Sie, dass es für Rasterdaten keine Queries auf den Layer geben kann, da mit den gängigen Rasterformaten keine Metadaten gespeichert werden.
==Bildkataloge==(8) \index{Rasterdaten!Kataloge}\index{Bildkataloge}
Bilddaten können sehr schnell sehr groß werden. Detaillierte Rasterbilder können viele Megabyte, wenn nicht gar Gigabyte groß werden. Solche Datenmengen sind nur schwierig zu handhaben, sowohl für den Mapserver als auch, was die Verwaltung angeht. Um die Verarbeitung zu beschleunigen und die Handhabung zu vereinfachen, kann man sich so genannter Bildkataloge bedienen.
Des weiteren kann es natürlich passieren, dass man seine Daten gleich in mehreren Bildern bekommt, aber sicherlich nicht für jedes Bild einen eigenen Layer im Mapfile anlegen möchte. Man könnte die Layer natürlich mittels =GROUP= zusammenfassen; aber man müßte eben immer noch alle Layer ins Mapfile eintragen.
Das Format von MapServer-Bildkatalogen verwendet keinen verbreiteten Standard, der dazu führen würde, dass Sie die Bildkataloge auch mit anderen Programmen einlesen könnten. Allerdings verläßt sich MapServer auf standardisierte Datenformate, sodass eine Konvertierung von dieser Seite aus keine Schwierigkeiten bereiten sollte.
Dabei werden alle Bilder (sie müssen mit Worldfiles georeferenziert sein) über ein Shapefile verortet. Das Shapefile erhält dabei die Koordinaten der einzelnen Bilder, die .dbf -Datei der Reihe nach die dazugehörigen Dateinamen der Bilder.
Die Notation solcher Kataloge im Mapfile erfolgt folgendermaßen:
LAYER
NAME "luftbild"
TYPE RASTER
STATUS ON
TILEINDEX "luftbildshape"
TILEITEM "IMAGEFILENAME"
END
In diesem Beispiel trägt das Katalog-Shapefile den Namen =luftbildshape= . Mit =TILEITEM= gibt man an, wie die Spalte in der .dbf -Datei heißt, die die Dateinamen der Rasterbilder trägt.
Das Erzeugen von Bildkatalogen muß durch zusätzliche Software geschehen. Die Bibliothek GDAL bringt dafür ein Werkzeug namens =gdaltindex= mit -- siehe Seite~\pageref{text:tools:gdaltindex}
Durch den Aufbau mittels eines Shapefiles lassen sich die einzelnen Kacheln selber übrigens sehr schön visualisieren, indem man das betreffende Shape als Layer einbindet.
Rasterdaten klassifizieren
Rasterdaten können, ähnlich wie Vektordaten, klassifiziert werden. Dabei werden alle Pixel einer bestimmten Farbe (oder einer bestimmten Menge von Farben) auf eine andere Farbe abgebildtet. Das macht man gerne bei 1-Bit-Bildern. Diese bestehen nur aus zwei Farben (also schwarz und weiß). Man färbt dann alle schwarzen Pixel in der gewählten Farbe ein, und schaltet dann die weißen Pixel für gewöhnlich transparent. Auf diese Weise lassen sich viele solcher Bilder in Schichten übereinander legen.
Es können aber auch Bilder mit 256 Farben klassifiziert werden.
Schauen wir uns ein Beispiel an:
LAYER
NAME "grundwasser"
TYPE RASTER
STATUS ON
CLASSITEM "[pixel]"
CLASS
EXPRESSION ([pixel] < 128)
COLOR 255 0 0
END
CLASS
EXPRESSION ([pixel] >= 128)
COLOR 0 0 255
END
END
Das =CLASSITEM= , nach dem wir filtern möchten, trägt den Namen =pixel= und repräsentiert die Nummer der Farbe in der Farbpalette des Bildes. Das funktioniert im Moment übrigens nur bei GD-Ausgabetreibern korrekt; der GDAL-Treiber\footnote{Zu Ausgabeformaten und -treibern siehe auch Seite~\pageref{text:mapfile:ausgabeformate}.} biegt vor der Bearbeitung des Bildes die Farbpaletten um, sodass man sich nicht auf die Position in der Farbpalette verlassen kann.
Die erste Class verleiht nun den ersten 128 Farben in der Farbpalette des Bildes ein grelles Rot, alle anderen Pixel werden durch die zweite Class blau dargestellt.
FIXME: ist das analog für truecolor-bilder etc.?
Umprojizieren von Rasterdaten
Der Gedanke läuft einem zuwider, wenn man sich die Mathematik klar macht. Man betrachte ein 4000 mal 4000 großes Tiff-Bild. Wenn man dieses Bild komplett umprojizieren möchte, müssen also 16 Millionen Pixel darauf geprüft werden, ob sie im neuen Zielbild liegen. Und wenn wir nun annehmen, dass wir 16 mal 16 solcher Kacheln haben, landen wir bei über 4 Milliarden Pixeln. Dass diese Berechnung eine Weile dauert, ist auf den ersten Blick ersichtlich.
Wenn Sie es jedoch einmal ausprobieren, werden Sie erstaunt sein, wie schnell MapServer Ihnen eine umprojizierte Karte liefert. Leider immer noch nicht schnell genug, wie man es im Dauerbetrieb, beispielsweise auf einer Website, haben will. Sie können sehr wohl mit der Geschwindigkeit vor Ihren Freunden angeben. Für den Dauerbetrieb lohnt es sich aber, die Projektion für Ihre Daten vorher zu machen.
Gleiche Überlegungen gelten übrigens auch für verschiedene Zoomstufen. Es lohnt sich durchaus, im Vorhinein zu überlegen, welche Zoomstufen am häufigsten zu sehen sein werden, um dann mit =MINSCALE= und =MAXSCALE= für diese Stufen verschiedene Datensätze anzuzeigen. Weitere Überlegungen zur Performance von MapServer-Anwendungen finden Sie ab Seite~\pageref{anhang:performance}.
Rasterdaten mit GDAL
\begin{figure} \begin{center} \mmfig{0.65}{gtopo30}{Die GTOPO30-Daten, hier ein Ausschnitt des Kanals zwischen Frankreich und Großbritannien.} \end{center} \end{figure}
Die Bibliothek GDAL ist für das Einlesen von Rasterdaten in MapServer zuständig, die über die 'herkömmlichen' Formate wie TIFF, JPEG, PNG und so weiter hinausgehen. Eine Liste von unterstützten Formaten finden Sie auf der GDAL-Website~http:website:gdal. Für diverse Formate müssen Sie unter Umständen die eine oder andere Zusatzbibliothek installiert haben. Bei Fragen oder Problemen hilft entweder ebenfalls die GDAL-Site weiter, oder eine Anfrage auf der MapServer-Mailingliste.
Die Notation von GDAL-gelesenen Rasterdaten weicht glücklicherweise überhaupt nicht von der von herkömmlichen Rasterdaten ab. Als Beispiel sollen hier die GTOPO30-Daten herhalten, die man sich von~ftp:gtopo30 herunterladen kann\footnote{Achtung, falls Sie es auf den kompletten Datensatz für die ganze Welt abgesehen haben sollten: vollständig entpackt handelt es sich um 2,1 GB Daten. Beachten Sie bitte, dass es sich dabei um =Textdateien= handelt, die Barbeitung also durchaus zeitintensiv ist.}.
Interessant sind für die Notation die Dateien mit der Endung =.DEM= . Die Abkürzung steht für digital elevation model , also für digitales Höhenmodell.
Sie können diese Daten in ein Unterverzeichnis entpacken -- nennen wir es =gtopo30= -- und dann gdaltindex für das Erzeugen eines Bildkatalogs aufrufen:
- gdaltindex gtopo30.shp gtopo30/*.DEM
Haben Sie das getan, können Sie sich einfach einen Layer wie folgt konstruieren:
LAYER
NAME "gtopo30"
TYPE RASTER
STATUS ON
TILEINDEX "gtopo30"
END
Und damit sind Sie dann auch schon fertig! Das Ergebnis sind dann beispielsweise aus wie in Abbildung~\ref{gtopo30}. Das DEM-Format wird behandelt wie jedes andere Rasterformat auch. Dem entsprechend können Sie eine einzelne dieser DEM-Dateien auch wie gewohnt folgendermaßen einbinden:
LAYER
NAME "gtopo30"
TYPE RASTER
STATUS ON
DATA "gtopo30/W180S60.DEM"
END
Vektordaten
\index{Vektordaten}
In seinen 'Jugendzeiten' war MapServer im wesentlichen darauf ausgelegt, Shapefiles darzustellen. Das macht sich insbesondere bei der Notation im Mapfile bemerkbar, wo bei Vektordaten einige Shapfile-spezifische Termini verwendet werden.
Zuerst ein Beispiel für Vektordaten in einem Layer:
LAYER
NAME "gruenflaechen"
TYPE POLYGON
STATUS ON
DATA "gruenflaechen_0323333"
CLASS
EXPRESSION /./
COLOR 255 240 128
OUTLINECOLOR 128 120 64
END
END
Der Typ eines Vektorlayers kann =POINT= , =LINE= oder =POLYGON= sein. Beachten Sie dabei, dass die beiden letztgenannten intern im wesentlichen gleich sind und daher in einigen Fällen austauschbar sind.
=DATA= verweist in diesem Fall auf ein Shapefile mit dem angegebenen Namen. Dieser Name ist relativ zum =SHAPEPATH= im Header des Mapfiles.
Das war auch schon alles, was es zur Notation von Shapefile-Layern im Mapfile zu sagen gibt. MapServer ist in der Lage, über Zusatzbibliotheken weitere Vektorformate zusätzliche zu Shapefiles einzulesen und zu verarbeiten.
==Indizes für Shapefiles==\index{Index}\index{Index!Shapefiles}(9)
Mit sogenannten Quadtree-Indizes läßt sich die Bearbeitung von Shapefiles erheblich beschleunigen. Wie solche Indizes für den MapServer erstellt werden, erfahren Sie auf Seite~\pageref{text:tools:shptree}, wo das Werkzeug =shptree= vorgestellt wird. Hier soll nur kurz die dahinter stehende Idee erläutert werden.
In einem Shapfile, das beispielsweise 100 Shapes hat, muß für einen gegebenen Ausschnitt geprüft werden, ob das Shape ganz oder in Teilen in diesem Ausschnit liegt und demnach angezeigt werden soll. Das geschieht über die Bounding Box eines Shapes, die mit im Shapefile gespeichert ist.
Ein Quadtree-Index folgt dem Gedanken, die Fläche des Shapefiles in vier Teile einzuteilen, und die darin liegenden Shapes in einem Index festzuhalten. Bei einem Zugriff wird zuerst die Fläche gesucht, in der der Ausschnitt liegt, und somit die Anzahl der zu prüfenden Shapes vermindert.
Die einzelnen Flächen lassen sich danach noch einmal in vier Unterflächen aufteilen (und diese wiederum in vier Unterflächen, und so weiter), sodass bei der Darstellung eine baumartige Struktur entsteht.
Die Größe und Lage der einzelnen Flächen muß übrigens nicht genau jeweils ein Viertel der größeren Fläche einnehmen. Die einzelnen Flächen werden nach Anzahl der darin liegenden Shapes gewichtet.
==Graticule-Layer==\index{Graticules}\index{Grids}(10)
Ein Gitternetz kann in einer Karte zur Orientierung wertvoll sein. Leider hat man nicht immer ein entsprechendes Shapefile zur Hand. Abhilfe schaffen sogenannte Graticule-Layer, mit denen sich ein solches Gitternetz einfach definieren läßt.
Betrachten wir einen solchen Layer anhand eines Beispiels:
LAYER
NAME "gitternetz"
TYPE LINE
STATUS ON
GRID
END
CLASS
COLOR 0 0 0
LABEL
TYPE BITMAP
SIZE TINY
COLOR 0 0 0
END
END
PROJECTION
"init=epsg:4326"
END
END
Zwei Dinge fallen sofort auf. Zuerst einmal sieht man keine =DATA= -Angabe. Brauchen wir an dieser Stelle auch gar nicht, da unser Gitter für jeden Kartenaufruf dynamisch generiert werden soll.
Außerdem findet man eine neue Sektion =GRID= . In dieser Sektion werden die Eigenschaften des Gitters gesetzt.
Der Typ eines Gitterlayers ist =LINE= . Die Gestaltung des Gitters wird wie gewohnt in einer Class vorgenommen, und das Gitter kann beschriftet werden. Die Labels für die Beschriftung erscheinen immer an allen vier Seiten einer Karte. Für TrueType-Fonts empfiehlt sich eine sehr kleine Schriftgröße, da diese Beschriftung sonst sehr schnell aufdringlich wirken kann.
Der =PROJECTION= -Block gibt die Projektion des Gitters an. Der Layer wird dann so behandelt, als würde es sich bei der Datenquelle um ein Shapefile handeln, das in eben dieser Projektion vorliegt. Ohne Projektionsblock erhalten Sie ein einfaches rechteckiges Gitter; mit Projektion ist das Gitter natürlich entsprechend verzerrt.
Beachten Sie, dass die Beschriftung des Gitters immer im Koordinatensystem der Quellprojektion erfolgt. Wenn Sie also beispielsweise den EPSG-Code 4326 als Projektion für Ihren Gitterlayer angeben, so wird dieses Gitter in Gradangaben beschriftet werden, selbst wenn Sie eine Karte mit Gauss-Krüger-Koordinaten erzeugen.
Innerhalb des =GRID= -Blocks können Sie die folgenden Angaben machen, die allesamt nur eine einzelne Zahl als Parameter erwarten:
- =MINSUBDIVIDE= und =MAXSUBDIVIDE= : Jede der Kurven (Linien), aus denen das Gitter besteht, wird als separate Linie behandelt und besteht somit aus einzelnen Punkten. Je mehr Punkte für eine Linie gezeichnet werden müssen, desto mehr Prozessorzeit kostet das offensichtlich. Mit diesen beiden Parametern können Sie festlegen, aus wievielen Punkte eine Linie minimal beziehungsweise maximal zusammengesetzt sein darf. Sind die beiden Werte gleich, bestehen die Linien immer aus genausovielen Punkten wie angegeben.
- =MININTERVAL= und =MAXINTERVAL= : Mit diesen beiden Parameter können Sie ein minimales bzw. ein maximales Interval zwischen zwei Kurven des Gitters angeben. Die Angabe wird im Koordinatensystem des Gitters gemacht.
- =MINARCS= und =MAXARCS= : Setzt die minimale bzw. maximale Anzahl von Kurven pro Achse. Beachten Sie bitte, dass bei diesen beiden Parametern und den beiden vorhergehenden versucht wird, den Vorgaben nachzukommen. Sollten die von Ihnen notierten Werte nicht zum gewünschten Ergebnis führen, sollten Sie ein wenig experimentieren, um ein Gefühl dafür zu bekommen, wie sich der Code bei verschiedenen Werten verhält.
=Projektionen=(11) \index{Projektion}\index{Mapfile!Projektion}(12)
Zuerst die These: die Erde ist eine Kugel. Diese Kugel muß für eine Karte auf eine Ebene abgebildet werden. Das gilt für eine Papierkarte ebenso wie für einen Computerbildschirm. Wenn man jetzt bedenkt, dass es viele verschiedene Ideen gibt, Abbildungen von der Kugel auf die Ebene vorzunehmen, und wenn man dann noch einwirft, dass die Erde ja eigentlich gar keine richtige Kugel ist -- dann ist man in der Welt der Projektionen angekommen, die ebenso faszinierend wie enervierend sein kann.
\begin{figure} \begin{center} \mmfig{0.75}{projektion}{Ein und dieselbe Datenquelle in zwei verschiedenen Projektionen. Links EPSG:4326, rechts EPSG:31464.} \end{center} \end{figure}
Der Effekt, um den es geht, ist in Abbildung~\ref{projektion} zu sehen. Die rechte Darstellung der Datenquelle verwendet die Geo-Koordinaten der Bundeslandgrenzen (Ellipsoid WGS84). Die rechte Darstellung entspricht einer Projektion in die Ebene nach der Gauss-Krüger-Methode, hier im vierten Meridianstreifen.
Der MapServer verwendet für Projektionen eine eigene Bibliothek (proj.4 ) die von Haus aus bereits viele Projektionen kennt. Diese Bibliothek unterstützt aber auch EPSG-Codes~http:website:epsg, die seit Einführung der OGC-Konformität die gängige Art und Weise darstellen, Projektionen im Mapfile zu notieren.
Projektionen interessieren an zwei Stellen: einmal bei der Frage, in welchen Projektionen die Daten vorliegen, und in welcher Projektion die fertige Karte dargestellt werden soll. MapServer ist in der Lage, die Projektion von Vektordaten 'on the fly' vorzunehmen. Dabei könen die Daten verschiedener Layer durchaus verschiedener Projektion sein. Mit Unterstützung der Bibliothek GDAL ist MapServer auch in der Lage, Rasterdaten umzuprojizieren; die benötigte Rechenleistung dafür ist jedoch beträchtlich, da in einem Rasterbild jeder einzelne Punkt umprojiziert werden muß.
Mehr zur Bibliothek GDAL erfahren Sie in Anhang~\ref{anhang:formate}, in dem die vom MapServer unterstützten Formate vorgestellt werden.
Notation
Projektionen sind, wie bereits angemerkt, an zwei Stellen von Bedeutung: erstens wenn festgestellt werden soll, in welcher Projektion bestimmte Daten vorliegen, zweitens bei der Frage, in welcher Projektion die Karte ausgeliefert werden soll.
Dabei können die Projektionen, in denen die Daten vorliegen, auf Layer-Ebene zugewiesen werden. Jeder Layer kann also in einer eigenen Projektion vorliegen. MapServer ist in der Lage, Vektorlayer auf Anfrage umzuprojizieren. Unter Verwendung des Bibliothek GDAL funktioniert das auch für Rasterdaten. Das Umprojizieren von Rasterdaten ist jedoch derart rechenaufwendig, dass man es in den meisten Fällen vermeiden will.
Die Ausgabeprojektion muß verständlicherweise einheitlich sein, denn die fertige Karte kann schließlich nur in einer bestimmten Projektion vorliegen. Eine Ausnahme bildet ein OGC-konformer MapServer, der verschiedene Projektionen nach außen anbieten und über einen URL-Parameter aufgefordert werden kann, eine dieser Projektionen als Ergebnis zu liefern.
Die Notation von Projektionen geschieht über eine eigene Sektion mit dem Namen =PROJECTION= . In dieser Sektion können Projektionen entweder als eine Liste von Parametern für die Projektionsbibliothek proj.4 eingetragen werden, oder mit EPSG-Codes.
Das erste Beispiel zeigt die 'klassische' Notation anhand der Projektionsbibliothek:
PROJECTION
"proj=utm"
"ellps=GRS80"
"zone=15"
"north"
"no_defs"
END
Die Art der möglichen Parameter für die Projektionsbibliothek proj.4 entnehmen Sie bitte der Dokumentation dieser Software~http:website:libproj.
Die zweite Möglichkeit erschließt sich durch EPSG-Codes:
PROJECTION
"init=epsg:12345"
END
12345 ersetzen Sie an dieser Stelle selbstverständlich durch den gewünschten EPSG-Code. Intern greift die Projektionsbibliothek an dieser Stelle übrigens auf eine Tabelle zu, die diese Codes dann auf die "`Original"'-Parameter abbildet. Achten Sie unbedingt darauf, =epsg= tatsächlich in Kleinbuchstaben zu notieren. Unter Windows ist das nicht relevant; entwickeln Sie jedoch unter einem anderen System, oder soll Ihre Anwendung portierbar sein, ist das wichtig.
Die Sektion =PROJECTION= kommt für die gesamte Karte nach dem Header im Mapfile zur Anwendung; für die Layer hat die Sektion natürlich innerhalb der =LAYER= -Sektion zu stehen, allerdings außerhalb etwaiger =CLASS= es, =LABEL= s und allem Anderen, das eine eigene Sektion einleitet.
\subsubsection*{Hinweis}(13)
Man möchte eigentlich meinen, dass die EPSG-Codes in Stein gemeißelt sind. Einmal vergeben, würde sich ein solcher Code nicht mehr ändern.
Leider ist diese Annahme ein Irrtum. Die Vergangenheit hat gezeigt, dass es passieren kann, dass Projektionen um mehrere Stellen in der Liste 'verrutschen' können. Zumindest einige deutsche und teilweise auch österreichische Projektionscodes sind in der Vergangenheit bei einem Versionssprung der Projektionsbibliothek nicht mehr vorhanden gewesen. Die interne Liste für den jeweiligen Release von proj.4 wird scriptgesteuert aus der Access-Tabelle generiert, die man auf der Website der EPSG findet. Änderungen in der Tabelle schlagen also sofort auf die Projektionsbibliothek durch.
Bei unerwarteten Fehlermeldungen nach einem Upgrade der Projektionsbibliothek sollten Sie also prüfen, ob Ihre Projektionscodes noch korrekt sind und diese eventuell anpassen.
Dieses unvorhersehbare Verhalten der EPSG kann natürlich zu haarsträubenden Komplikationen bei kaskadierten WMS-Servern führen, wenn nur einer der Server aktualisiert wird.
Orthographische Projektion
\begin{figure} \begin{center} \mmfig{0.55}{ortho}{Eine orthographische Projektion stellt die Daten in einem Kreis dar, der einer Aufsicht auf einem Globus ähnlich sieht. Leider ist die Funktion in MapServer noch fehlerhaft.} \end{center} \end{figure}
Eine orthographische Projektion sieht aus wie ein Blick auf einen Globus. Falls die fertige Karte einen großen Teil der Welt abdeckt, sehen Sie die fertige Karte als Kreis.
Das kann schick aussehen, leider hat der Code für diese Projektion in MapServer noch den einen oder anderen Bug, die dann auftreten, sobald Features dargestellt werden sollen, die teilweise hinter dem Horizont verschwinden. Dann versucht MapServer immer noch Linien zu ziehen, die dann quer durch das ganze Bild gehen.
Zum Zeitpunkt der Drucklegung war die Darstellung leider immer noch fehlerhaft. Dennoch soll Ihnen ein Überblick über die Theorie nicht vorenthalten bleiben.
Als Zielprojektion im Kopf des Mapfiles definieren Sie eine orthographische Projektion wie folgt:
PROJECTION
"proj=ortho"
"ellps=WGS84"
"lat_0=0.0"
"lon_0=0.0"
"x_0=0.0"
"y_0=0.0"
END
Dabei sind =lat_0= und =lon_0= die Koordinaten des Punktes, der als Mittelpunkt in der Karte zu sehen sein soll, in Längen- und Breitenangabe. Das ist sozusagen der Punkt, an dem Sie direkt auf den Globus schauen. Die beiden verbleibenden Parameter sind eine Verschiebung, jeweils ein Modifikator auf den Rechts- und den Hochwert des Punktes.
Das Ergebnis sieht dann in etwa so aus, wie Sie es in Abbildung~\ref{ortho} sehen können. Wegen der fehlerhaften Implementation ist die Darstellung von Features, die sich über den Horizont erstrecken, allerdings noch mangelhaft.
Und falls Sie später das Kapitel über MapScript lesen und Anregung für eine Übung suchen sollten, wie wäre es damit: erstellen Sie eine MapScript-Seite, die eine Karte in ortographischer Projektion darstellt. Beim Mausklick in die Karte soll allerdings nicht hinein- oder herausgezoomt werden, sondern eben dieser angeklickte Punkt soll als neuer Bezugspunkt für die Projektion dienen. Der 'Globus' wird also anhand des Klicks 'gedreht'. Viel Spaß dabei =:)=
Projektionen im realen Einsatz
Der Autor hat schon von Leuten gehört, die meinten, Projektionen würden die Daten 'verfälschen'. Zu einem gewissen Grad ist das sicherlich richtig; im Grunde genommen handelt es sich aber nur um eine andere Art der Darstellung.
Kartographen sind übrigens nicht die einzigen Menschen, die sich mit Projektionen in die Ebene auseinandersetzen müssen. Eine ganze Industrie in Gestalt der Spiele- und Grafikkartenindustrie lebt mit und von dem Problem, (dreidimensionale) Objekte auf eine plane Fläche (den Computerbildschirm) abzubilden.
Falls Sie in Ihrer Anwendung MapServer Daten on the fly umprojizieren lassen möchten, sollten Sie sich im Vorhinein über Ihre Zielgruppe Gedanken machen. Menschen könnten es Ihnen durchaus übelnehmen, wenn die Karten im Webbrowser wie in Abbildung~\ref{projektion} links aussehen -- nämlich angeblich 'gequetscht'. Denken Sie immer daran, wass die Benutzer wohl als Darstellung aus ihrem Atlas daheim~diercke:2002 gewohnt sein könnten.
=Schriften=\index{Schriften}\index{Fonts}(14)
MapServer kennt zur Beschriftung von Features zwei Typen von Schriften: Bitmap- und TrueType-Schriften. Während erstere bereits im MapServer `"eingebaut"' sind, sind TrueType-Schriften separate Dateien, die Sie der Anwendung bereitstellen müssen. Hingegen benötigen Bitmap-Schriften keine zusätzliche Vorbereitung, um verwendet zu werden; Sie können direkt mit Abschnitt~15 fortfahren.
Ein weiteres Problem mit TrueType-Schriften können lizenzrechtlicher Natur sein. Ob Sie die Schriftdateien, die Sie für den Gebrauch mit beispielsweise Photoshop gekauft haben, einfach so zur Beschriftung und Veröffentlichung von Karten im Internet verwenden dürfen, müssen Sie individuell mit dem Hersteller der Schriften regeln.
Wie die Symbole für eine Karte werden auch die TrueType-Schriftarten in einer separaten Datei deklariert. Anders als die Symbole für ein Mapfile können die Schriften jedoch nicht alternativ direkt in das Mapfile eingetragen werden; sie müssen immer in einer separaten Datei stehen.
Der Verweis auf eine Schriftendatei erfolgt über das Schlüsselwort FONTPATH im Header des Mapfiles:
...
FONTPATH "fonts/fonts.list"
...
Diese Angabe kann sowohl ein absoluter Pfad im System sein, als auch relativ zum Mapfile.
Im Innern ist diese Liste sehr simpel aufgebaut:
arial arial.ttf
times times.ttf
...
In jeder Zeile steht zuerst ein Alias, gefolgt von mindestens einer Leerstelle (oder einem Tab) und der Name der .ttf-Datei. Das Alias ist ein Name, der im Folgenden im Mapfile verwendet wird, um auf die Schriftart Bezug zu nehmen.
Für Bitmap-Schriften müssen, wie gesagt, keine solche Vorbereitungen getroffen werden.
Annotationen
\index{Annotationen} \index{Beschriftungen} (15)
Beschriftungen von Layern sind für MapServer wiederum eigene Layer, mit einem eigenen Typ mit dem Namen =ANNOTATION= .
Die Art der Beschriftung (was wann wie beschriftet werden soll und auf welche Art) wird in den Klassen dieses Layers festgelegt. Dadurch erreicht man eine recht hohe Flexibilität, indem man Beschriftungen von Features unabhängig davon darstellen kann, ob das Feature selber zu sehen ist. Und wenn man beides unter den selben Umständen angezeigt haben möchte, verwendet man für beide Layer einfach die gleiche Klassendefinition.
Für eine Oberfläche zur Navigation in der Karte bedeutet das auf der anderen Seite zusätzliche, unerwünschte Komplexität, da die Beschriftungslayer nun unter Umständen durch den Benutzer als eigene Layer an- und abgewählt werden müssen.
Diesen Umstand kann man auf zwei Wegen umgehen. Eine Methode ist, dem Beschriftungslayer den gleichen Namen zu geben, wie dem Layer, der die Daten anzeigt. Dann werden beide Layer über diesen Namen angesprochen. Der zweite Weg ist, beide Layer zu einer =GROUP= zusammenzufassen, über deren Namen man auf beide Layer gleichzeitig zugreifen kann. Mehr über das Gruppieren von Layern erfahren Sie ab Seite~\pageref{text:mapfile:layer:group}
Man könnte auch alle Beschriftungen in einer =GROUP= zusammenfassen, sodass sie sich alle mit einem Mal an- und ausschalten lassen.
Es lassen sich im übrigen nur Vektorlayer beschriften.
Die Notation von Beschriftungslayern sieht wie folgt aus:
LAYER
NAME "strasssen_annotation"
GROUP "beschriftungen"
TYPE ANNOTATION
...
CLASSITEM "NUMMER"
LABELITEM "NUMMER"
CLASS
...
LABEL
TYPE BITMAP
SIZE NORMAL
COLOR 0 0 0
POSITION CR
PARTIALS TRUE
END
END
END
Es werden also diverse Änderungen im Vergleich zu einem dartstellenden Layer vorgenommen. Der Typ des Layers ist =ANNOTATION= .
Das Schlüsselwort =LABELITEM= funktioniert so ähnlich wie =CLASSITEM= . Während letzteres jedoch angibt, anhand welcher Spalte in der .dbf -Datei die nachfolgenden Classes gefiltert werden sollen, definiert =LABELITEM= die Spalte, aus der der Inhalt für die Beschriftungen geholt werden soll. Auf diese Weise läßt sich also nach einem Kriterium filtern und nach einem anderen beschriften, was die Angelegenheit flexibler gestaltet.
==Die Label-Sektion==\index{Label}\index{Mapfile!Label}
Die eigentliche Definition einer Beschriftung erfolgt dann in den einzelnen Classes. Im obigen Beispiel werden die im MapServer eingebauten Bitmap-Schriften verwendet. Zur genauen Notation von Bitmap- und TrueType-Schriften siehe auch die nächsten beiden Abschnitte.
Wie so häufig kommt erhöhte Flexibilität auch an dieser Stelle auf Kosten größeren Aufwands. Für jede zu beschriftende Klasse muß eine eigene Label-Sektion eingerichtet werden.
Die folgenden Parameter finden in allen Arten von Labeln Verwendung, unabhängig davon, ob es sich um Bitmap- oder TrueType-Beschriftungen handelt:
- =BACKGROUNDCOLOR <red> <green> <blue>= Mit dieser Option bekommt das Label eine Hintergrundfarbe verpaßt; man sieht dann ein Rechteck in dieser Farbe, in dem sich dann das Label befindet. Voreinstellung ist gar keine Farbe.
- =BACKGROUNDSHADOWCOLOR <red> <green> <blue>= Wirft einen Schatten in der angegebenen Farbe um das eben genannte Rechteck. Voreinstellung ist kein Schattenwurf.
- =BACKGROUNDSHADOWCOLORSIZE <x> <y>= Legt den Offset für den genannten Schatten in x- und y-Richtung fest. Voreinstellung in beide Richtungen ist 1.
- =BUFFER <integer>= Definiert einen Abstand, den andere Beschriftungen zu einem Label mindestens haben müssen, um gezeichnet werden zu können. Erhöht die Lesbarkeit bei vielen Beschriftungen, kann aber zu Problemen führen (siehe Abschnitt~16, Hinweise ).
- =COLOR <red> <green> <blue>= Die Farbe, in der die Schrift gemalt werden soll.
- =OUTLINECOLOR <red> <green> <blue>= Umrißarbe für die Schrift.
- =FORCE <TRUE|FALSE>= Erzwingt das Zeichnen einer Beschriftung. Dadurch werden Einträge wie =BUFFER= ignoriert. Diese Option ist als Vorgabe nicht aktiviert.
- =POSITION=
- =PARTIALS <TRUE|FALSE>= Unter Umständen liegen einzelne Features so ungünstig, dass seine Beschriftung nur teilweise sichtbar wäre. Mit =PARTIALS= wird festgelegt, ob diese teilweise Beschriftungen angezeigt werden sollen.
- =WRAP <zeichen>= Legt ein Zeichen fest, das als Zeilentrenner interpretiert werden soll. Das Ergebsnis sind mehrzeilige Beschriftungen.
Labels lassen sich außer zur Beschriftung auch bei TrueType-Symbolen verwenden; siehe auch Abschnitt~18
==Bitmap-Schriften==\index{Bitmap-Schriften} \index{Beschriftungen!Bitmap}\index{Annotationen!Bitmap}
Bitmap-Schriften skalieren schlecht und sehen, gelinde gesagt, nicht sonderlich gut aus. Sie benötigen jedoch keinen zusätzlichen Aufwand und sind in jeder MapServer-Installation automatisch vorhanden. Auch benötigen sie wesentlich weniger Rechenzeit.
Wenn Sie die Beschriftung nur um der Beschriftung willen einsetzen möchten und keine besonderen Anforderungen an ihr Aussehen stellen, sind Bitmap-Schriften das, was Sie haben möchten.
Ein =ANNOTATION= -Layer mit Bitmap-Schriften sieht beispielsweise folgendermaßen aus:
LAYER
NAME "strassen"
STATUS ON
TYPE ANNOTATION
DATA "strassen"
LABELITEM "NUMMER"
CLASS
LABEL
TYPE BITMAP
SIZE SMALL
COLOR 0 0 0
OUTLINECOLOR 255 255 255
END
END
END
Jedes Feature wird hier mit einer kleinen, weiß umrandeten, schwarzen Beschriftung versehen.
Die folgenden Optionen sind nur beim Einsatz von Bitmap-Schriften von Belang:
- =SIZE <TINY|SMALL|MEDIUM|LARGE|GIANT= Diese fünf verschiedenen Größen sind fix, und es gibt keine Zwischengrößen. Experimentieren Sie am besten mit allen herum, um ein Gefühl dafür zu kriegen, wie groß sie im Einsatz sind.
==TrueType-Schriften==\index{TrueType-Schriften} \index{Beschriftungen!TrueType}\index{Annotationen!TrueType}
TrueType-Schriften skalieren besser als die im MapServer eingebauten Schriftarten und sehen generell besser aus, benötigen jedoch einiges an zusätzlicher Vorbereitung, beispielsweise bei der Installation und weil das Anlegen einer Font-Datei für den MapServer nötig wird. Auch der Aufwand an Rechenzeit ist merklich größer.
Falls Sie jedoch Wert auf qualitativ hochwertige Schriften legen oder gar eine gewisse Stimmung erzeugen möchten -- indem Sie Frakturschriften in den Karten Ihrer mittelalterlichen Rollenspielwelt verwenden, um ein Beispiel zu nennen --, so kommen Sie um TrueType-Schriften nicht herum.
LAYER
NAME "strassen"
STATUS ON
TYPE ANNOTATION
DATA "strassen"
LABELITEM "NUMMER"
CLASS
LABEL
TYPE TRUETYPE
FONT "Arial"
SIZE 12
COLOR 0 0 0
OUTLINECOLOR 255 255 255
END
END
END
Der Typ des Labels muß natürlich =TRUETYPE= sein. Anstelle eines von fünf festen Strings treten Angaben in Pixeln. Und natürlich muß der Name der Schrift angegeben werden -- dafür wird ein Alias verwendet, der in der Font-Datei definiert worden sein muß (siehe auch Beginn dieser Sektion).
Die folgenden Optionen im Label-Objekt lassen sich nur dann verwenden, wenn TrueType-Schriften zum Einsatz kommen:
- =ANGLE <double>= Eine Winkelangabe in Grad, um die die Beschriftung gedreht werden soll. Kann nur in Linien-Layern benutzt werden. Wird anstatt eines Zahlenwertes =AUTO= verwendet, richtet sich der Text an der Linie aus.
- =ANTIALIAS <TRUE|FALSE>= Schaltet Kantenglättung für Schriften an oder aus.
- =FONT <name>= Name der Schriftart, wie er in der Font-Datei festgelegt worden ist.
==Hinweise==(16)
Automatische Beschriftungen von ebenso automatisch generierten Karten haben einige Tücken, derer man sich bewußt sein sollte, bevor man vom Ergebnis enttäuscht wird.
Angaben wie das zuvor genannte =BUFFER= beispielsweise bewirken, dass diverse Labels gar nicht erst gezeichnet werden. Das kann zum Beispiel zur Folge haben, dass die kleinen Orte um eine große Stadt durchaus beschriftet werden -- und dann aber kein Platz mehr für eine Beschriftung neben der Stadt ist und diese dann in der fertigen Karte ohne auskommen muß.
Zu allem Überfluss können sich die Labels nach dem nächsten Zoom oder gar nur nach einem Pan so verschoben haben, dass besagte Stadt plötzlich eben doch beschriftet ist. Der Benutzer kann sich dann fragen, welch merkwürdige Karte er da vor sich hat.
Es gibt mehrere Möglichkeiten, mit diesem Phänomen umzugehen. Man kann stundenlang mit Schriftgrößen und Zoomstufen herumexperimentieren -- aber der nächste Benutzer wird eben doch die Einstellung finden, an die man nicht gedacht hat.
Sicherlich sinnvoll ist es, mit =MINSIZE= und =MAXSIZE= Maßstäbe festzulegen, ab denen bestimmte Beschrifungen zulässig werden. Features, die unter allen Umständen beschriftet werden sollen, sollten mit =FORCE TRUE= dazu gezwungen werden.
Die korrekte Vorgehensweise bei diesen Phänomen dürfte von Fall zu Fall unterschiedlich sein; auf alle Fälle sollte man sich aber der Existenz des Problems bewußt und darauf vorbereitet sein, es eventuell in Angriff nehmen zu müssen, falls jemand darauf stößt.
=Symbole=\index{Symbole}(17)
Symboldateien definieren Darstellungen, die von den normalen Formen abweichen, die also mehr sind als simple Striche für Polygonumrandungen oder Linienvektoren.
Notiert werden Symbole entweder direkt im Mapfile als einzelne Sektionen nach dem Header. Oder aber in einer eigenen Datei, genannt =SYMBOLSET= , die im Header deklariert wird -- siehe auch Seite~\pageref{text:mapfile:header}. Begonnen wird ein Symbol mit =SYMBOL= , abgeschlossen wird es mit =END= .
Farben werden für Symbole nicht in den Symbol-Sektionen definiert, sondern in den Classes, die die Symbole verwenden.
MapServer kennt die folgenden Arten von Symbolen, die in Symboldateien definiert werden können, und die in einer Symbol-Sektion über =TYPE= deklariert werden:
- =VECTOR= Ein oder mehrere Vektoren, die aneinandergefügt ein Symbol ergeben. Dadurch können Rechtecke, Dreiecke und andere geometrische Formen realisiert werden.
- =ELLIPSE= Ellipsen werden über zwei Radien definiert. Sind beide Werte gleich, entsteht ein Kreis. Ergänzt die geometrischen Formen, die mit =VECTOR= möglich sind.
- =PIXMAP= Linien können mit (möglichst kleinen) Bilddateien gezogen werden. Ebenso können Polygone mit solchen Bilder ausgefüllt werden. Das Format dieser Bilder muß vom MapServer unterstützt werden. Das schließt beispielsweise .gif -Bilder aus, wenn es sich um einen MapServer handelt, der .png -Bilder generiert.
- =TRUETYPE= Einzelne Symbole aus TrueType-Schriften können zur Annotation von Features in Karten benutzt werden. Es gibt einige TrueType-Zeichensätze, die speziell für die Verwendung in Karten erstellt worden sind.
Ferner können sogenannte Overlaysymbole für Linien definiert werden, bei denen ein Liniensymbol über ein anderes gelegt wird; mehr dazu weiter unten.
Die folgenden Parameter können für Symbole gesetzt sein, wenn es sich nicht um TrueType-Symbole handelt.
- =NAME <name>= Name des Symbols. Sollte immer gesetzt sein, falls man seine Symbole nicht über ihre Nummer innerhalb der Symboldatei referenzieren möchte -- was spätestens dann für Unheil sorgen wird, wenn man zusätzliche Symbole mitten in der Datei einfügt.
- =FILLED <TRUE|FALSE>= Das Symbol soll gefüllt sein.
- =PIXMAP <dateiname>= Eine Bilddatei, die als 'Pinsel' verwendet werden soll. Kommt nur für Symbole vom Typ =PIXMAP= zur Anwendung.
- =STYLE= Eine eigene Sektion innerhalb eines Symbols, die einen Stil für Linien-Symbole definiert. Es handelt sich um einen einzelnen Punkt (referenziert als =SYMBOL 0= ), der je nach Stil an- und wieder ausgeschaltet wird. Zur Verdeutlichung ein Beispiel:
STYLE 2 3 2 4 END
Mit diesem =STYLE= werden zwei Pixel einer Linie gezeichnet, dann drei Pixel Pause gemacht, dann werden wieder zwei Pixel gezeichnet, woraufhin wieder vier Pixel ausgelassen werden. Danach geht das ganze wieder von vorne los. - =POINTS= Dies ist eine eigene Sektion innerhalb eines Symbols und beschreibt ein Symbol über Vektoren.
- =TRANSPARENT <index>= Der Index der Farbe in einer Farbpalette, die bei einem Pixmap-Symbol transparent geschaltet werden soll.
\subsubsection*{Points}
Vektor-Symbole werden über eine eigene Sektion innerhalb eines Symbols definiert, die mit =POINTS= beginnt, mit =END= abgeschlossen wird und Paare von Zahlen enthält; Punkte eines Vektors eben.
Ein Beispiel für ein Vektor-Symbol:
SYMBOL
TYPE VECTOR
NAME "dreieck"
POINTS
1 1
3 3
3 1
1 1
END
END
Dieses Symbol beschreibt ein Dreieck. Beachten Sie, dass Sie für einen geschlossenen Kantenzug immer den ersten Punkt noch einmal als letzten Punkt einfügen müssen.
Punkte, bei denen beide Koordinaten negativ sind, werden als Trenner betrachtet. Dadurch können Sie beispielsweise Kreuze und ähnliches realisieren, also Symbole, die aus mehreren Segmenten bestehen.
==TrueType-Symbole==\index{TrueType!Symbole}\index{Symbole!TrueType}(18)
TrueType-Schriften als Symbole funktionieren, indem man einzelne Zeichen aus der Schriftart herausgreift, und damit dann einzelne Punkte annotiert, oder das Symbol an einer Linie immer wieder wiederholt.
Beachten Sie, dass Unterstützung für TrueType-Schriften in den MapServer kompiliert sein muss, um diese Art von Beschriftung benutzen zu können.
Die folgenden Parameter in einer Symbol-Sektion kommen nur zum Tragen, wenn es sich um ein TrueType-Symbol handelt:
- =ANTIALIAS <FALSE|TRUE>= Gibt an, ob auf dem Symbol ein Antialiasing stattfinden soll.
- =CHARACTER <index>= Die Nummer des Zeichens innerhalb der TrueType-Datei, das als Symbol benutzt werden soll.
- =FONT <name>= Alias der TrueType-Schriftart, die für das Symbol benutzt werden soll. Dieser Alias muß im =FONTSET= definiert sein.
- =GAP= Der Abstand zwischen zwei TrueType-Symbolen. Kommt nur für Linien zur Anwendung.
Als Beispiel für ein TrueType-Symbol soll an dieser Stelle die Schriftart WebDings herhalten:
SYMBOL
NAME "haus"
TYPE TRUETYPE
FONT "webdings"
ANTIALIAS TRUE
CHARACTER "G"
END
Dieses Beispiel greift aus der Schriftart WingDings das Zeichen heraus, das ein kleines Häuschen darstellt. Sie könnten damit beispielsweise Ihre Ferienhäuser in der Karte markieren.
Die Notation =\&\#71;= kennen Sie vielleicht aus HTML-Seiten, wo einzelne Zeichen auf diese Weise notiert werden können. 71 ist die Position des Zeichens in der TrueType-Datei; falls Sie die Position nicht kennen, müssen Sie raten oder ein Programm zurate ziehen, dass Ihnen die einzelnen Zeichen darstellt und deren Position angibt.
Pixmap-Symbole
Pixmaps lassen sich entweder an Linien entlangziehen oder zum Füllen von Fläche verwenden. Natürlich kann man mit ihnen auch einzelne Punkte annotieren. Damit können Sie beispielsweise Ihr Firmenlogo an verschiedenen Filialen einblenden:
SYMBOL
NAME "logo"
TYPE PIXMAP
IMAGE "firmenlogo.png"
TRANSPARENT 0
END
==Overlay-Symbole==\index{Symbole!Overlay}\index{Overlaysymbole}
Overlaysymbole werden separat in den Klassen eines Layers definiert. Dabei werden ganz einfach die als Overlay deklarierten Symbole über die 'normalen' Symbole gelegt. Anwendung findet so etwas zum Beispiel bei Autobahnen:
CLASS
...
SYMBOL 0
SIZE 4
COLOR 0 0 0
OVERLAYSYMBOL 0
OVERLAYSIZE 2
OVERLAYCOLOR 255 0 0
END
Das Resultat ist eine vier Pixel breite schwerze Linie, auf der sich eine zwei Pixel breite rote befindet. Anders formuliert: eine zwei Pixel breite rote Linie mit einem schwarzen Rand.
Auf diese Weise kann man beispielsweise auch gestrichelte Linien auf breite Linien legen und damit Mittelstreifen symbolisieren etc.
Es gibt die folgenden Optionen für Overlaysymbole:
- =OVERLAYSYMBOL= : Definiert wie =SYMBOL= , welches Symbol verwendet werden soll.
- =OVERLAYBACKGROUNDCOLOR= : Hintergrundfarbe des Overlaysymbols
- =OVERLAYCOLOR= : Farbe des Symbols
- =OVERLAYMINSIZE= : Minimaler Maßstab, bei dem das Overlaysymbol angezeigt werden soll.
- =OVERLAYMAXSIZE= : Maximaler Maßstab, bei dem das Overlaysymbol angezeigt werden soll.
- =OVERLAYOUTLINECOLOR= : Umrandungsfarbe für das Overlaysymbol
- =OVERLAYSIZE= : Größe des Overlaysymbols.
Diese Angaben sind also allesamt äquivalent zu den Angaben in normalen Symbolen ohne den Zusatz OVERLAY .
Mit der Ankunft des =STYLE= -Objekts und der entsprechenden Möglichkeit, mehr als zwei Symbole übereinander zu legen, werden die Overlayparameter allerdings wohl ihre Daseinsberechtigung verlieren. Mehr dazu siehe Abschnitt~6.
Beispiele
Erfahrungsgemäß bereiten Symbole gerade dem Einsteiger Schwierigkeiten. Daher sehen wir uns einige Beispiele an, die wir nach und nach zu komplexeren Symbolen ausbauen.
Für das einfachste aller Symbole, einen Punkt, wird wohl kein Screenshot benötigt:
SYMBOL
NAME "punkt"
TYPE ELLIPSE
POINTS
1 1
END
FILLED TRUE
END
Dieses Symbol können Sie nun in einem Layer verwenden, und dann dementsprechend die Dicke der Linie mit =SIZE= festlegen.
Hinweis : Beachten Sie bitte, dass es keinen Unterschied macht, ob Sie =1 1= oder =2 2= in diesem Beispiel schreiben. Es handelt sich hier um Vektoren, dabei spielt der Skalar vor den eigentlichen Koordinaten keine Rolle. =2 2= ist also das gleiche wie zweimal =1 1= , und dieses 'zweimal' wird verworfen. Wichtig ist das Verhältnis der Zahlen zueinander. Wenn Sie also eine Ellipse haben wollen, die doppelt so breit wie hoch ist, schreiben Sie =2 1= . Sie könnten auch =6 3= schreiben, aber dadurch würde die Ellipse in der Karte nicht größer. Die Darstellungsgröße in der Karte wird über den Parameter =SIZE= in der entsprechenden Class geregelt.
Das wichtigste Gestaltungselement bei Linien ist die Möglichkeit, Abstände auf der Linie zu bestimmen. Damit lassen sich zum Beispiel gepunktete (dotted ) oder gestrichelte (dashed ) Linien realisieren. Ein Beispiel für ein Punkt-Symbol für eine Linie gestrichelte und gepunktete Linie:
SYMBOL
NAME "funky"
TYPE ELLIPSE
POINTS
1 1
END
FILLED TRUE
STYLE 2 2 1 1
END
Dieses Symbol entspricht dem letzten, mit dem Unterschied, dass hier ein =STYLE= verwendet wird. Die Angabe bedeutet, dass die ersten zwei Pixel des Linienzuges gezeichnet werden sollen, die nächsten beiden dann wieder nicht; danach wird ein Pixel gesetzt, der folgende dann wieder nicht. Es wird also immer die bezeichnete Anzahl von Pixeln gesetzt und dann wieder nicht gesetzt. Danach fängt das ganze wieder von vorne an. Beachten Sie bitte, dass die hier benutzte =STYLE= -Eigenschaft nichts mit dem Style-Objekt zu tun hat, wie es weiter vorne beschrieben worden ist.
Auf Beispiele für Overlaysymbole soll hier nicht eingegangen werden, da diese Methode veraltet ist. Stattdessen sollten Style-Objekte in den Classes benutzt werden.
\begin{figure} \begin{center} \mmfig{0.65}{symbols-star}{Städte, markiert mit einem sternförmigen Vektorsymbol.} \end{center} \end{figure}
Falls Sie mal ein komplexeres Symbol sehen wollen, schauen Sie sich die Sternchen in Abbildung~\ref{symbols-star} an. Die Sterne kommen folgendermaßen zustande:
SYMBOL
NAME "stern"
TYPE VECTOR
FILLED TRUE
POINTS
0 .375
.35 .375
.5 0
.65 .375
1 .375
.75 .625
.875 1
.5 .75
.125 1
.25 .625
END
END
Es handelt sich also um ein Vektorsymbol, das aus zehn Punkten besteht. Sie können sich beim Entwurf eigener Symbole das ganze auf Karo- oder Millimeterpapier aufmalen und dann die Koordinaten ablesen. Der Ursprung für Ihr Koordinatensystem muß in der linken oberen Ecke liegen. Beachten Sie, dass der höchste Wert in den Koordinaten der Punkte =1= ist. Sie könnten die auch alle Werte beispielsweise mit zwei multiplizieren, und es würde keinen Unterschied machen. Das ist der Effekt der Vektorrechnung, der weiter oben erläutert ist.
\subsubsection*{Markierungen für Gefälle}
Insbesondere während Schulungen wird der Autor gerne gefragt, wie es sich mit der Gestaltung von Höhenlinien verhielte; dabei möchte man beispielsweise in der abfallenden Richtung einer Höhenlinie in regelmäßigen Abständen einen kleinen, parallel zur Linie verlaufenden Strich anbringen, um die Richtung des Gefälles anzuzeigen.
Dazu muß leider gesagt werden, dass diese Art der Gestaltung insbesondere bei Shapefiles nicht möglich ist, da Shapefiles keine Topologie oder eine Richtungsinformation speichern. Zwar werden Sie GIS-Programme sehen, bei denen sich eine solche Gestaltung vornehmen läßt. Allerdings speichert die betreffende Software dann eine entsprechenede Information über die Laufrichtung der Shapes seperat ab. Diese Möglichkeit ist MapServer wegen seiner rein darstellerischen Fähigkeiten verschlossen.
=Maßstäbe=(19) \index{Maßstab}\index{Scalebar}\index{Mapfile!Maßstab}\index{Mapfile!Scalebar}
Maßstäbe setzen die Größen auf der Karte in eine Relation zur Realität. Dieser Zusammenhang wird einem am Comupterbildschirm jedoch zum Verhängnis.
Man sollte nicht auf die Idee kommen, einen Pixelmaßstab auf dem Bildschirm auszumessen, und etwa zu sagen: "`Ah, 10 Pixel sind 100 Meter, und 10 Pixel sind 0.5 Zentimeter, also sind 0.5 Zentimeter 100 Meter."' Ein Maßstab auf dem Bildschirm steht ausschließlich in Relation zur angezeigten Karte, nicht zur realen Welt, da sich Pixel nicht in Zentimeter umrechnen lassen, sondern stets von der Größe des Bildschirms und der verwendeten Auflösung abhängig sind.
Wenn ein Maßstab für 10 Pixel in der Karte 100 Meter in der Realität angibt, dann sind diese zehn Pixel bei 1280x1024 Pixeln Auflösung auf einem 19 Zoll Bildschirm wesentlich kleiner als bei einer Auflösung von 800x600 Pixeln auf einem 14 Zoll Bildschirm.
MapServer geht bei Maßstabsangaben (=SCALE= ) immer von <math>\frac{1}{72}</math> inch pro Pixel aus. Dieser Wert kann allerdings bestenfalls als vage Annäherung betrachtet werden. Bei =SCALE= handelt es sich immer um den Kehrwert eines Maßstabes. Wenn Sie den Maßstab also beispielsweise als 1:20000 kennen, ist =SCALE= gleich 20000.
Bei den Beschriftungen für Maßstäbe im MapServer beachten Sie bitte, dass MapServer bisher noch keinen Gebrauch von TrueType-Schriften an dieser Stelle macht.
Die Sektion für Maßstäbe im Mapfile wird mit =SCALEBAR= eingeleitet. Sie darf nicht innerhalb einer anderen Sektion stehen und muss nach dem Header stehen. Die folgenden Parameter sind für diese Sektion bekannt:
- =BACKGROUNDCOLOR <red> <green> <blue>= Die Hintergrundfarbe für den Scalebar, nicht für das komplette Bild, das den Scalebar ausmacht.
- =TRANSPARENT <ON|OFF>= Schaltet Transparenz für den Hintergrund des Scalebars ein oder aus. Voreingestellt ist der Hintergrund nicht transparent.
- =IMAGECOLOR <red> <green> <blue>= Die Hintergrundfarbe für das Bild, in dem sich der Scalebar befindet.
- =COLOR <red> <green> <blue>= Die Farbe, in der der Scalebar gemalt werden soll.
- =INTERLACE <TRUE|FALSE>= legt fest, ob der fertige Maßstab interlaced sein soll.
- =SIZE <x> <y>= Breite des Scalebars in Pixeln. Das ist nicht die Größe des fertigen Bildes, sondern nur des Maßstabs im Bild. Auch Beschriftungen werden hier noch nicht einberechnet.
- =INTERVALS= Anzahl der Intervalle auf dem Maßstab. Voreinstellung ist 4.
- =UNITS <feet|inches|kilometers|meters|miles>= Die Einheit, in der der Maßstab beschriftet sein soll. Voreinstellung ist Meilen. Gradangaben sind übrigens keine sinnvollen Einheiten für einen Maßstab. Voreinstellung ist =miles= .
- =OUTLINECOLOR <red> <green> <blue>= Umrissfarbe für die einzelnen Intervalle des Maßstabs. Soll keine Umrißfarbe verwendet werden, reicht als Wert auch =-1= .
- =STYLE <0|1>= Es gibt zwei verschiedene Styles. Style =1= ist im wesentlichen ein horizontaler, beschrifteter Strich, während Stil =0= in weiße und schwarze Sektionen unterteilt ist.
- =STATUS <ON|OFF|EMBED>= Schaltet den Maßstab an oder aus. Mit =EMBED= wird der Maßstab angeschaltet und in die fertige Karte eingebettet.
- =POSITION <ul|uc|ur|ll|lc|lr>= Bei einem in die Karte eingebetteten Maßstab wird dieser an der angegebenen Position dargestellt. In der Tabelle in der PHP MapScript-Referenz, die auf Seite~\pageref{tab:ref:mapscript:const} beginnt, finden Sie eine Erklärung der möglichen Werte.
- =POSTLABELCACHE <TRUE|FALSE>= Wird nur für Maßstäbe verwendet, die in die Karte eingebettet sind. Der Maßstab wird dann erst in die Karte eingefügt, nachdem alle Labels in der Karte gezeichnet worden sind. Voreinstellung ist =FALSE= .
- =LABEL= An dieser Stelle wird ein separates =LABEL= -Objekt eingefügt, das für die Beschriftung des Maßstabs zuständig ist. Bisher können in Maßstäben keine TrueType-Schriften verwendet werden.
Legenden
\index{Legende}\index{Mapfile!Legende}
Legenden erklären die in der Karte verwendeten Symbole und Zeichen. Ohne eine Legende ist eine Karte prinzipiell ohne Inhalt, da man ohne sie den Linien, Farben usw. keine Bedeutung zuordnen kann.
MapServer ist in der Lage, konfigurierbare Legenden automatisch zu generieren. Diese Legenden können dann auf die bekannte Weise über Template-Tags in das Layout der Applikation eingebunden werden.
Neben den klassischen Bitmap-Legenden (die gesamte Legende ist ein einziges Bild, das in eine HTML-Seite eingebunden wird), gibt es seit der Version~{3.6} auch HTML-Legenden, die über Templates kleine HTML-Abschnitte erzeugen.
Die klassische MapServer-Legende
Diese Art von Legende ist ein fertiges Bild, das vom MapServer generiert wird. Auf die Gestaltung dieser Legende hat man nicht so viel Einfluss wie bei der HTML-Legende (siehe weiter unten).
Die Sektion für Legenden im Mapfile wird mit =LEGEND= eingeleitet. Sie darf nicht innerhalb einer anderen Sektion vorkommen und muß nach dem Header stehen. Die folgenden Parameter sind für diese Sektion bekannt:
\begin{figure} \begin{center} \mmfig{0.35}{legende}{Die drei Vektorlayertypen in einer klassischen MapServer-Legende: Punkte, Linien und Polygone} \end{center} \end{figure}
- =IMAGECOLOR <red> <green> <blue>= Hintergrundfarbe für die fertige Legende
- =TRANSPARENT <ON|OFF>= Schaltet Transparenz für den Hintergrund der Legende ein oder aus. Voreingestellt ist der Hintergrund nicht transparent.
- =OUTLINECOLOR <red> <green> <blue>= Umrissfarbe für die Kästchen, die die Symbole in der Legende umranden.
- =KEYSIZE <x> <y>= Breite und Höhe der Symbole in der Legende in Pixeln. Vorgabe ist 20x10.
- =KEYSPACING <x> <y>= Horizontaler und vertikaler Abstand der Symbole bzw. der Beschriftungen zueinander. Vorgabe ist 5 und 5.
- =STATUS <ON|OFF|EMBED>= Schaltet die Legende an oder aus. Mit =EMBED= wird die Legende angeschaltet und in die fertige Karte eingebettet.
- =POSITION <ul|uc|ur|ll|lc|lr>= Bei einer in die Karte eingebetteten Legende wird diese an der angegebenen Position dargestellt. In der Tabelle in der PHP MapScript-Referenz, die auf Seite~\pageref{tab:ref:mapscript:const} beginnt, finden Sie eine Erklärung der möglichen Werte.
- =INTERLACE <TRUE|FALSE>= Ob das Bild interlaced sein soll.
- =POSTLABELCACHE <TRUE|FALSE>= Wird nur für Legenden verwendet, die in die Karte eingebettet sind. Die Legende wird dann erst in die Karte eingefügt, nachdem alle Labels in der Karte gezeichnet worden sind. Voreinstellung ist =FALSE= .
- =LABEL= An dieser Stelle wird ein separates =LABEL= -Objekt eingefügt, das für die Beschriftung des Maßstabs zuständig ist. Bisher können in Maßstäben keine TrueType-Schriften verwendet werden.
- =TEMPLATE= Definiert ein Template, das für HTML-Legenden verwendet werden soll. Siehe den folgenden Abschnitt über HTML-Legenden.
In Abbildung \ref{legende} kann man sehen, wie Legenden für verschiedene Arten von Vektorlayern aussehen. Polygone werden durch ein Rechteck dargestellt, das gegebenenfalls eine Füllfarbe hat. MapServer bedient sich an dieser Stelle bei den Angaben im Mapfile. Punktlayer werden durch einen (wenig überraschend) Punkt dargestellt, während Linienlayer eine kleine gezackte Linie bekommen.
==HTML-Legenden==\index{HTML-Legenden}
Als Alternative zu den normalen .gif- beziehungsweise .png-Bildern, die als Legenden generiert werden, gibt es für die CGI-Version des Mapservers noch die Möglichkeit, eigene Legenden über HTML-Templates zu gestalten. Die fertige Legende wird dabei weiterhin an der Stelle im Haupt-Template eingefügt, an der das Schlüsselwort =[legend]= steht.
Interessant wird eine HTML-Legende dann, wenn man in die kleinen Bruchstücke von HTML auch Teile des Formulars zur Navigation in der Karte einfügt -- später mehr dazu.
Im LEGEND-Block des Mapfiles kann ein TEMPLATE definiert, etwa folgendermaßen:
LEGEND
...
TEMPLATE "legend.html"
END
\subsubsection*{Aufbau des Templates}
Innerhalb eines Templates können drei verschiedene Blöcke definiert werden: für Groups, Layers und Classes. Diese Begriffe folgen den Bedeutungen im Mapfile. Es kann also HTML-Code für Gruppen von Layern generiert werden, für die Layer in diesen Gruppen und dann für jede einzelne Class in diesen Layern wiederum eigener Code. Dieser Aufbau eignet sich besonders für den Aufbau in HTML-Tabellen.
Alle Inhalte der Templatedatei, die sich außerhalb der möglichen Blöcke befinden werden schlicht ignoriert und eignen sich somit dafür, Kommentare einzufügen, die später in der fertigen HTML-Seite nicht erscheinen sollen. Für Kommentare innerhalb der Blöcke müssen selbstverständlich HTML-konforme Kommentare benutzt werden, die mit == abgeschlossen werden.
Für gewöhnlich werden mit Groups- und Layerblöcken Kopfzeilen für HTML-Bereiche definiert, in denen dann die einzelnen Classes der Reihe nach aufgelistet werden.
\subsubsection*{Groups}
Mit der Verwendung eines solchen Blocks legt man die Erzeugung von Legenden fest, in denen Layer gruppiert dargestellt werden, und zwar anhand ihrer Gruppierung im Mapfile. Wird eine Groups-Sektion verwendet, werden alle Gruppierungen als solche in der Legende dargestellt. Möchte man keine Gruppierung von Layern in der Legende, verwendet man diesen Block einfach nicht.
Wird dieser Block definiert, erscheinen Layer nicht in der Legende, die zu keiner Gruppe gehören, und ebensowenig sind deren Classes zu sehen.
Mit =[leg_group_html]= wird ein solcher Block eingeleitet, und mit einem entsprechenden =[/leg_group_html]= wieder abgeschlossen.
Die folgenden Tags können in einem Group-Block erscheinen:
- =[leg_group_name]= : Gibt den Namen der Gruppe aus.
- =[leg_icon <width=X> <height=Y>]= : Steht für das erzeugte Icon. Der erzeugte Text ist der URL zu diesem Icon. Im Kontext einer Group gibt dieser Tag das Icon für den ersten Layer in der Group zurück. Die beiden Parameter =width= und =height= sind optional und verändern die Breite und die Höhe des fertigen Icons.
- =[metadata name=<feld>]= : Ist der Mapserver über entsprechende Einträge im Mapfile OGC-konform ausgelegt, können an dieser Stelle entsprechende Metadaten ausgegeben werden. Mehr zu OGC-konformen Mapservern gibt es in Kapitel~\ref{text:ogc} zu erfahren. Auch andere Metadaten aus der Web-Sektion, wie Sie in Abschnitt~21 beschrieben sind, lassen sich hier einfügen.
\subsubsection*{Layers}
Analog zu Groups wird mit =[leg_layer_html]= ein Block für einen Layer in der HTML-Legende eingeleitet und mit =[/leg_layer_html]= wieder abgeschlossen. Im startenden Tag können allerdings noch einige zusätzliche Parameter übergeben werden:
- =order_metadata=<schlüssel>= In Abschnitt~21 haben Sie erfahren, dass Sie in Layern beliebige Metadaten in einem eigenen Block speichern können. Anhand solcher Einträge können Sie nun die Reihenfolge der Layer in der HTML-Legende kontrollieren. Anschaulich:
LAYER ... METADATA legendenposition 2 END ... END
Haben Sie ein jedem Layer eine solche Klassifizierung, können Sie in der HTML-Legende die Sortierung kontrollieren mit:[leg_layer_html order_metadata=legendenposition] ... [\leg_layer_html]
- =opt_flag=<wert>= Dieser Wert kontrolliert die Verhaltensweise dieses Layerblocks. Es handelt sich um eine Bitmaske, d.h. für eine Kombination der folgenden Optionen addieren Sie die entsprechenden Werte aufeinander auf. Sie werden immer eine eindeutige Zahl erhalten. Die Werte sind:
- =1= Zeigt den Layer in der Legende an, auch wenn sich der gezeigte Ausschnitt außerhalb des Layers befindet. Dieses Verhalten ist nicht voreingestellt.
- =2= Zeigt den Layer in der Legende an, auch wenn sein =STATUS= auf =OFF= gesetzt ist. Dieses Verhalten ist nicht voreingestellt.
- =4= Zeigt den Layer in der Legende an, auch wenn sein =TYPE= auf =QUERY= gesetzt ist und daher nur befragt werden kann, aber nicht in der Karte erscheint. Dieses Verhalten ist nicht voreingestellt.
- =8= Zeigt den Layer in der Legende an, auch wenn sein =TYPE= auf =ANNOTATION= gesetzt ist und daher nur Beschriftungen darstellt. Dieses Verhalten ist nicht voreingestellt. Möchten Sie beispielsweise die ersten beiden Optionen zulassen, setzen Sie =opt_flag= auf <math>1+2=3</math>. Selbstverständlich können in einem Layer-Block in der Legende eigene Tags verwendet werden:
- =[leg_layer_name]= Fügt den Namen des Layers an dieser Stelle ein.
- =[leg_icon width=<breite> height=<höhe>]= Fügt den URL eines automatisch generierten Legenden-Icons ein, wie man es auch aus der klassischen MapServer-Legende kennt. Die Breiten- und Höhenangaben erfolgen in Pixeln und sind optional. Wenn ein Layer mehrere Classes aufweist, wird ein Icon für die erste Class im Layer generiert.
- =[metadata name=<feld>]= Fügt beliebige Metadaten aus der entsprechenden Sektion des Layers ein -- siehe auch weiter oben.
\subsubsection*{Classes}
Und natürlich kommen auch die Classes in HTML-Legenden zu ihrem Recht. Sie werden mit =[leg_class_html]= eingeleitet und am Ende mit =[/leg_class_html]= wieder abgeschlossen.
Ebenso wie die Blöcke für Layer kennen auch die Blöcke für Classes den Parameter =opt_flag= . Wenn er verwendet wird, wird er auch mit den gleichen Parametern gefüttert wie sein Pendant im Layer-Block.
Bitten beachten Sie, das Classes ohne einen =NAME= nicht in HTML-Legenden auftauchen werden.
Sie können die folgenden Tags innerhalb eines Class-Blockes in HTML-Legenden verwenden:
- =[leg_class_name]= Der Name der Klasse. Jede Klasse, die überhaupt in der Legende auftauchen soll, benötigt einen Namen.
- =leg_icon width=<breite> height=<höhe>= Das Legenden-Icon für die Class, wie im Layer beschrieben.
- =[metadata name=<feld>]= Fügt beliebige Metadaten aus der entsprechenden Sektion der Class ein; siehe auch weiter oben.
\subsection*{Konditionale in HTML-Legenden}\index{HTML-Legenden!Konditionale}
Konditionale sind Wenn-Dann-Anweisungen. Aus einer Programmiersprache wie C kennt man das unter der folgenden Notation:
if (<bedingung> {
... hier passiert etwas ...
}
else {
... hier passiert etwas anderes ...
}
Solche Konditionale lassen sich auch in HTML-Legenden nutzen, etwa um Dinge nur unter bestimmten Bedingungen einzublenden. Es gibt eine gemeinsame Notation, aber für jeden möglichen Block (Group, Layer und Class) eigene Eigenschaften, die abgefragt werden können.
Um es ein wenig genauer zu nehmen: es handelt sich weniger um eine Wenn-Dann-Anweisung, als vielmehr um ein reines Wenn. Ein else ist nicht implementiert.
Notiert werden Konditionale folgendermaßen:
[if name=<feld> oper=<operator> value=<wert>] ... [/if]
Das heißt soviel wie: Vergleiche =feld= dahingehend, ob es in der Beziehung =oper= zum Wert =wert= steht. Wenn das der Fall ist, füge den Block bis zum =[/if]= ein.
Da das reichlich abstrakt ist, hier ein Beispiel:
[leg_layer_html]
[if name=layer_type oper=eq value=2]
[leg_layer_name]
[/if]
[/leg_layer_html]
In diesem Layer-Block wird der Name des Layers immer dann ausgegeben, wenn sein Typ gleich 2 ist. Der Typ 2 ist nur im Kontext von Layern definiert: Sie erfahren weiter unten, welche Werte wofür stehen.
Das =eq= steht für equal und bedeutet 'gleich'. Daneben gibt es noch =neq= (ist nicht gleich), =isset= (hat überhaupt einen Wert) und =isnull= (ist leer). Die Voreinstellung ist =eq= . Wenn man diesen Operator verwenden möchte, kann man den Teil mit =oper== auch weglassen.
\subsubsection*{Groups}
Die folgenden Konditionale können als =name= in Group-Blöcken in HTML-Legenden benutzt werden:
- =group_status= Der Status einerer Group ist gleich dem =STATUS= des ersten Layers in der selben. Als Werte kommen in Frage: =0= für =OFF= , =1= für =ON= und =2= für =DEFAULT= .
- =<metadata>= Jeder Metadaten-Eintrag in der Web-Sektion läßt sich als Wert für ein Konditional benutzen.
\subsubsection*{Layers}
Die folgenden Konditionale können als =name= in Layer-Blöcken in HTML-Legenden benutzt werden:
- =layer_name= Der Name des Layers.
- =layer_group= Der Name der Group, in dem sich der Layer befindet.
- =layer_status= Der Status des Layers. Als Werte kommen in Frage: =0= für =OFF= , =1= für =ON= und =2= für =DEFAULT= .
- =layer_type= Der Typ des Layers. Infrage kommen: =0= für =POINT= . =1= für =LINE= , =2= für =POLYGON= , =3= für =RASTER= . =4= für =ANNOTATION= und =5= für =QUERY= .
- =<metadata>= Jeder Metadaten-Eintrag aus der Layer- wie aus der Web.Sektion läßt sich als Wert für ein Konditional benutzen.
\subsubsection*{Classes}
Schließlich bleiben noch die Konditionale, die als =name= in Class-Blöcken in HTML-Legenden benutzt werden können. Um genau zu sein, sind die Werte hier vollständig mit denen im Layer-Block identisch, sodass sich eine Aufzählung erübrigt.
\subsection*{Hinweise}
Für HTML-Legenden benötigen Sie mindestens die Version 3.5.1 des Mapservers.
Der 'traditionelle' =[legend]= -Block liefert den URL eines Bildes zurück, wohingegen HTML-Legenden (wenig überraschend) Blöcke von HTML zurückliefern.
Wenn der HTML-Legendenmodus über die aufrufende URL für den Mapserver angegeben wird, aber kein Template im Mapfile für die Legende definiert ist, wird weiterhin ein Bild erzeugt.
\subsection*{Beispiel}
Ein Beispiel soll erhellen, wie man die Macht von HTML-Legenden ausschöpfen kann. Betrachten Sie die folgenden Zeilen, die ein Ausschnitt aus einem Legenden-Template sind:
[leg_layer_html opt_flag=3]
<input type="checkbox" name="layer"
value="[leg_layer_name]" [[leg_layer_name]_check]>
<img src="[leg_icon width=18 height=12]" align="center">
[leg_layer_name]
[/leg_layer_html]
Das Ergebnis ist in Abbildung~\ref{mapfile-legende-html} zu sehen.
Der Block definiert, wie Legenden für die im Mapfile vorhandenen Layer in der Legende auftauchen sollen. Der Wert 3 für =opt_flag= sagt, dass ein Layer in der Legende stehen soll, auch wenn sich alle Daten des Layers außerhalb des dargestellten Ausschnitts befinden, und dass er in der Legende stehen soll, auch wenn sein =STATUS= auf =OFF= gesetzt ist.
\begin{figure}
\begin{center}
\mmfig{0.3}{mapfile-legende-html}{HTML-Legenden im Einsatz}
\end{center}
\end{figure}
Es folgt eine Zeile in einer HTML-Tabelle, die aus drei Spalten besteht. In der letzten Spalte steht der Name des Layers. In der vorletzten Spalte wird die Quelle für das Bild vom MapServer eingefügt, hier mit einer Größe von 18 mal 12 Pixeln.
Die erste Zeile ist etwas trickreicher. Hier wird eine Checkbox für ein HTML-Formular generiert, die als value den Namen des Layers erhält. Dadurch wird dem MapServer mitgeteilt, welche Layer darzustellen sind und welche nicht -- der Benutzer klickt einfach die Checkboxen an.
Der letzte Teil ist der interessante: wenn ein Layer beim letzten Aufruf angezeigt worden ist, sucht MapServer in Templates nach Tags wie =layername_check= und ersetzt diese Tags dann durch =checked= . Dadurch wird die Checkbox im Browser markiert. Die Namen der Layer werden hier jedoch nicht hartkodiert, sondern bei der Abarbeitung des Legenden-Templates der Reihe nach ersetzt. Dadurch entsteht für jeden Layer eine passende Checkbox.
Dieses Stück HTML-Code generiert also nicht nur eine Legende, sondern auch gleich die Elemente für das Navigationsformular aus dem Inhalt des Mapfiles. Wird dem Mapfile nun ein neuer Layer hinzugefügt (oder ein Layer entfernt), wird die Legende automatisch korrekt generiert, ohne dass man am Template etwas ändern müßte.
Templates
(20) \index{Templates}\index{Mapfile!Templates}
In der Web-Sektion des Mapfiles können diverse Templates definiert werden, die als Ergebnis eines Aufrufs ausgeliefert werden können. Bei den Templates handelt es sich um HTML-Dateien, in denen neue, MapServer-eigene Tags definiert werden, die in eckigen Klammern notiert werden.
Damit ein Template als Ergebnis ausgeliefert wird, muß der Modus =browse= im URL angegeben sein, im Gegensatz zum Modus =map= , der lediglich die Karten als Bilder zurückliefert.
Auch für die beiden Abfragemodi =query= und =nquery= werden Templates verwendet. Was es mit Queries auf sich hat, und wie man sie in seine Applikationen einbaut, ist ab Seite~\pageref{text:mapfile:queries} in Erfahrung zu bringen.
Die verschiedenen Arten von Templates
Templates kommen an mehreren verschiedenen Stellen im Mapfile mit unterschiedlicher Notation vor. Hier eine Aufzählung aller Möglichkeiten, ein Template für diverse Anwendungsfälle zu deklarieren.
Grundsätzlich können Templates lokal im Dateisystem liegen, wobei dann ihr Dateiname angegeben wird. Templates können aber auch als URL deklariert werden und somit von entfernten Rechnern herbeigeholt werden.
\subsubsection*{Web-Sektion}
Die Web-Sektion kennt die folgenden Template-Angaben:
- =TEMPLATE <datei|url>= Ist das Template für die Applikation, die im Modus =browse= läuft. Das einzige Template, das beim simplen Navigieren in der Karte zum Einsatz kommt.
- =HEADER <datei|url>= Ein Kopf-Template, das ausgegeben wird, bevor irgendwelche MapServer-Ergebnisse generiert werden. Findet lediglich beim Modus =nquery= zusammen mit =FOOTER= Anwendung, um die verschiedenen Abfrageergebnisse in ein beginnendes und ein abschließendes HTML einbetten zu können.
- =FOOTER <datei|url>= Das Pendant zu =HEADER= , das nach dem Einfügen aller Ergebnisse angehängt wird.
- =MINTEMPLATE <datei|url>= Ein Template, das benutzt werden soll, wenn der minimale =SCALE= für die Anwendung (gesetzt durch =MINSCALE= in der Web-Sektion) unterschritten wird. Auf diese Weise kann man MapServer-App\-li\-ka\-tionen verschiedener Detailstufen ineinander verschachteln.
- =MAXTEMPLATE <datei|url>= Ein Template, das benutzt werden soll, wenn der maximale =SCALE= für die Anwendung (gesetzt durch =MAXSCALE= in der Web-Sektion) überschritten wird.
\subsubsection*{Layer-Sektion}
In der Layer-Sektion lassen sich die folgenden Template-Angaben machen:
- =TEMPLATE <datei|url>= Präsentiert Abfrageergebnisse. Wenn mehrere Abfrageergebnisse präsentiert werden sollen, wird für jedes der Ergebnisse dieses Template einmal eingefügt und Gebrauch von =HEADER= und =FOOTER= gemacht (siehe weiter unten).
- =FOOTER <datei|url>= Kommt bei multiplen Abfragen zum Tragen und wird angehängt, nachdem alle Ergebnisse zusammengefügt worden sind.
- =HEADER <datei|url>= Das Pendant zu =FOOTER= ; wird vor allen Abfrageergebnissen eingefügt.
Das Template via =TEMPLATE= benutzt man im wesentlichen dann, wenn man nicht, wie im folgenden beschrieben, ein solches Template in jeder Class des Layers haben möchte.
\subsubsection*{Class-Sektion}
Für eine Class gibt es nur eine Template-Angabe, namentlich die folgende:
- =TEMPLATE <datei|url>= Präsentiert Abfrageergebnisse. Wenn mehrere Abfrageergebnisse präsentiert werden sollen, wird für jedes der Ergebnisse dieses Template einmal eingefügt und Gebrauch von =HEADER= und =FOOTER= gemacht, in dem sich die Class befindet.
Wenn man nicht für jede einzelne Class ein =TEMPLATE= notieren möchte, kann man eine solche Angabe auch auf der Ebene des Layers machen.
Aufbau
Ein einfaches Beispiel für ein HTML-Template:
<html>
<head><title>Beispiel</title></head>
<body>
<img src="[img]">
</body>
</html>
Wenn der MapServer über den URL aufgerufen wird, findet er in der Web-Sektion die Angabe für das Template, ersetzt die Tags in eckigen Klammern durch seine neu generierten Werte, und liefert dann die fertige HTML-Seite aus.
Im obigen Beispiel würde der MapServer eine Karte generieren, die einen URL zugewiesen bekommt. Dieser URL würde anstelle des =[img]= -Tags eingesetzt werden.
Für die Templates, die für die Ergebnisse von multiplen Abfragen generiert werden, gilt, dass es sich nicht um komplette HTML-Dateien handeln darf. Beispielsweise möchten Sie für ein Abfrageergebnis einer Class eventuell folgendes Template definieren:
[ID]
[NAME]
[AREA]
Die Deklaration der Tabelle und alles andere, was für eine vollständige HTML-Datei vonnöten ist, erfolgt dann durch weitere Templates in =HEADER= und =FOOTER= .
Für Templates, die das Navigationsinterface beschreiben (=TEMPLATE= in der Web-Sektion) und solche für die Präsentation von einzelnen Abfrageergebnissen (definiert durch =TEMPLATE= in Layern) sind hingegen natürlich vollständige HTML-Dateien notwending.
Im Folgenden nun alle möglichen Tags, die vom MapServer unterstützt werden. Sie können übrigens auch eigene Tags definieren. Wenn Sie einen Parameter im URL übergeben, der dem MapServer nicht bekannt ist, wird dieser im Template ersetzt, wenn ein entsprechender Tag vorhanden ist. Wenn im URL also =meintag=17= steht, und im Template ein Tag =[meintag]= zu finden ist, wird dieser durch 17 ersetzt. Es gibt auch immer eine Fassung, bei der Sonderzeichen (Leerzeichen etc.) durch Escapesequenzen markiert sind; für diese Tags muß dann ein =_esc= angehängt werden. Für das genannte Beispiel hieße der Tag also =[meintag_esc]= .
Zuvorderst einige allgemeine Tags:
- =[version]= : Die Versionsnummer des eingesetzten MapServers.
- =[id]= : Eine (recht)\footnote{Die Einschränkung 'recht' eindeutig soll hier nur bedeuten, dass keine Eindeutigkeit im mathematischen Sinne vorliegt. Einem Kryptographen würden sich die Haare sträuben bei der Verwendung der Session-ID als Baustein für einen 'eindeutigen' Wert. Zur Vermeidung von Kollisionen bei unseren dynamisch generierten Bildern sollte sie jedoch ausreichen.} eindeutige Session-ID für den Aufruf des MapServers, zusammengesetzt aus momentanem Datum und Zeit, sowie der Prozess-ID des Aufrufs. Diese ID ist also solange eindeutig, wie man pro Sekunde nicht mehr Anfragen bekommt, als das System gleichzeitig Prozesse starten kann. Man hätte dann allerdings noch ganz andere Probleme, als dass die ID des MapServer-Aufrufes nicht mehr eindeutig sein könnte.
- =[host]= : Der Hostname des ausführenden Rechners.
- =[port]= : Der Port, auf dem der Webserver die Anfrage entgegengenommen hat. In den meisten Fällen ist dies 80.
- =[web_meta data <key>]= : Zeigt die Metadaten aus der Web-Sektion eines OGC-konformen Mapfiles an.
Tags für Verweise auf Dateien:
- =[img]= : Der URL, an dem sich das neu generierte Kartenbild befindet.
- =[ref]= : Dito für eine eventuell erzeugte Referenzkarte.
- =[legend]= : Dito für eine eventuell erzeugte Legende.
- =[scalebar]= : Dito für eine eventuell erzeugte Maßstabsleiste.
- =[queryfile]= : Pfad zu dem File, in dem eine Query abgespeichert worden ist, falls =savequery= als Parameter gesetzt wurde. Mehr zu diesem Thema im Abschnitt über Queries, siehe Seite~\pageref{text:mapfile:query:cached}.
- =[map]= : Pfad zum Mapfile.
Die folgenden Tags lassen sich für Angaben über die Bildgeometrie verwenden:
- =[center]= : Gibt das Zentrum des Bildes in Pixeln an. Beispiel: ist das fertige Bild 300x300 Pixel groß, so steht in diesem Tag 149,149. Wofür braucht man das? Wenn man in einem Navigationsformular einen Knopf zum 'Auffrischen' der Karte hat (man möchte beispielsweise Layer hinzuschalten, aber den Ausschnitt nicht ändern), so kommt kein Klick in der Karte zustande, der den MapServer auf das neue Zentrum für den anzuzeigenden Ausschnitt hinweist. Mit diesem Tag ist jedoch im Formular folgendes Konstrukt möglich:
<input type="hidden" name="imgext" value="[center]">
Dadurch wird ein impliziter Mausklick auf das Zentrum der Karte gesetzt. - =[center_x]= und =[center_y]= : Die x- und y-Koordinate des Bildzentrums als einzelne Werte.
- =[mapsize]= : Die momentane Größe der Karte in Breite und Höhe in Pixeln, getrennt durch ein Leerzeichen. Mit einem =_esc= am Ende auch als escaped Version vorhanden.
- =[mapwidth]= und =[mapheight]= : Breite beziehungsweise Höhe der Karte in Pixeln.
- =[scale]= : Maßstab der Karte. Zu Maßstäben siehe vor allen Dingen auch Abschnitt~19
Angaben über die Geometrie der Karte sind mit folgenden Tags möglich. Die letzten drei Punkte in dieser Aufzählung sind nur dann verfügbar, wenn der MapServer mit der Projektionsbibliothek proj.4 kompiliert worden ist und es eine Projektionsangabe im Mapfile gibt.
- =[mapx]= und =[mapy]= : x- und y-Koordinate des Mausklicks.
- =[mapext]= und =[mapext_esc]= : Die vollen Extents der Karte, separiert durch Leerzeichen.
- =[maxx]= , =[maxy]= , =[minx]= und =[miny]= : Die einzelnen Koordinaten der Karte.
- =[rawext]= und =[rawext_esc]= : Die Extents der Karte, bevor sie auf die gewünschte Pixelgröße angepaßt worden ist, getrennt durch Leerzeichen.
- =[rawmaxx]= , =[rawmaxy]= , =[rawminx]= und =[rawminy]= : Die einzelnen Koordinaten der Extents der Karte, bevor die Karte auf die gewünschte Pixelgröße angepaßt worden ist.
- =[maplon]= und =[maplat]= : Längen- und Breitengrad des letzten Mausklicks in der Karte.
- =[mapext_latlon]= und =[mapext_latlon_esc]= : Voller Extent der Karte in Längen- und Breitengrade, separiert durch Leerzeichen.
- =[minlon]= , =[minlat]= , =[maxlon]= und =[maxlat]= : Die einzelnen Koordinaten der Extents der Karte in Längen- und Breitengraden.
Die folgenden Tags geben Aufschluss über die Layer in einer Karte:
- =[get_layers]= : Eine Aufzählung aller Layer, die in der aktuellen Karte aktiv sind, sodass sie in eine URL eingebunden werden können. Zum Beispiel:
layer=fluesse&layer=eisenbahn&layer=seen
- =[layers]= und =[layers_esc]= : Die Namen aller aktiven Layer, voneinander durch Leerzeichen getrennt.
- =[layername_check]= und =[layername_select]= : Im Tag muß an dieser Stelle nicht 'layer' stehen, sondern der tatsächliche Name des Layers. Ist ein Layer aktiv, wird der Tag durch das Wort =checked= bzw. =selected= ersetzt. Auf diese Weise wird von Seitenaufruf zu Seitenaufruf mitgeschleift, ob ein Layer ausgewählt ist. Ein Beispiel für einen Layer namens 'fluesse':
<input type="checkbox" name="layer" value="fluesse" [fluesse_select]> Flüsse
Wenn der Layer im URL angefordert worden ist, ist diese Checkbox automatisch selektiert. - =[layername_meta <key>]= : Dieser Tag wird, genauso wie der entsprechende Tag in der Web-Sektion, durch Metadaten aus einem OGC-konformen Mapfile gefüllt.
Auch für das Zoomverhalten gibt es einige Tags für das Template:
- =[zoomdir_<-1|0|1>]=
- =[zoom_minzoom to maxzoom_<select|check>]=
Zu guter Letzt natürlich noch die Tags, die für Queries interessant sind. Dementsprechend werden diese Tags nur dann ausgefüllt, wenn sie sich in einem Template befinden, das von einer Query abgearbeitet wird.
- =[shpext]= : Die Extents des Shapes, das das Suchergebnis darstellt.
- =[shpminx]= , =[shpmaxx]= , =[shpminy]= und =[shpmaxy]= : Dito, nur in die einzelnen Punktkoordinaten aufgeschlüsselt.
- =[shpmid]= : Der Mittelpunkt eines gewähltes Shapefiles. Steht nur zur Verfügung, wenn Queries bearbeitet werden.
- =[shpmidx]= und =[shpmidy]= : X- respektive y-Koordinate des Mittelpunkts.
- =[shpidx]= : Index des aktuellen Shapefiles. Steht nur zur Verfügung, wenn Queries bearbeitet werden.
- =[tileindex]= : Index der momentanen Rasterkachel. Steht ebenfalls nur zur Verfügung, wenn Queries bearbeitet werden.
- =[DBase column name]= : Jede beliebige Spalte einer .dbf -Datei kann in Query-Templates als Tag verwendet werden. Die entsprechenden Ergebnisse werden dann eingefügt.
- =[cl]= : Name des aktuellen Layers. Sinnvoll in Layerheadern oder -footern.
- =[lrn]= : Die Nummer eines Suchergebnisses im aktuellen Layer. Sinnvoll in Querytemplates.
- =[nl]= : Anzahl der Layer, in denen es Suchergebnisse gegeben hat. Sinnvoll in Web-Headern oder -footern.
- =[nlr]= : Gesamtzahl aller Ergebnisse im aktuellen Layer. Sinnvoll in Web-Headern und -footern.
- =[nr]= : Gesamtzahl aller Suchergebnisse. Sinnvoll in Web-Headern und -footern.
- =[rn]= : Die Nummer des Suchergebnisses innerhalb aller Suchergebnisse. Sinnvoll in Web-Headern und -footern.
=Metadaten=(21)\index{Mapfile!Metadaten}\index{Metadaten}
Die Web-Sektion (und nicht nur diese) kann zwei Arten von Metadaten aufnehmen. Zum einen sind diejenigen Daten zu nennen, die für eine OGC-konforme Interaktion mit der Außenwelt sorgen. Wie mit diesen Daten umzugehen ist, erfahren Sie in Kapitel~\ref{text:ogc}.
Des weiteren können Sie sozusagen "`freie"' Einträge vornehmen, die Sie dann -- in eckigen Klammern, siehe den nächsten Abschnitt über Templates -- als Parameter in das Template übernehmen und so in die HTML-Ausgabe einfügen können.
Ein Beispiel:
METADATA
autor "Thorsten Fischer"
adresse "Heilbronner Strasse 10"
END
Diese Zeilen ermöglichen Ihnen, beispielsweise das folgende im Template zu tun:
Der Autor [autor] kann unter
der Adresse [adresse] erreicht werden
MapServer ersetzt diese Tags dann durch die Parameter aus der =METADATA= -Sektion.
Beachten Sie, dass Sie solche Metadaten auch auf Layer-Ebene einfügen können. Diese Daten können Sie dann später beispielsweise dazu verwenden, die Layer in HTML-Legenden auf eine bestimmte Weise zu sortieren.
Eine weitere Idee zum Einsatz von Metadaten sind Links. Speichern Sie zum Layer gehörende URLs als Metadaten und fügen Sie sie später in Templates oder HTML-Legenden ein.
=Queries=\index{Queries}\index{Mapfile!Queries}(22)
Zuweilen möchte man seine Daten nicht nur betrachten. Auch wenn es die größte Stärke des MapServer ist, schnell Karten generieren zu können und diese dann ausliefern zu lassen, ist eine minimale GIS-Funktion zuweilen wünschenswert. Die Anfragen auf die den Karten zugrundeliegenden Datenbestände werden beim MapServer Queries genannt.
Notation
Im HTML-Template, das das Benutzer-Interface für den MapServer definiert, muß natürlich zuerst die Möglichkeit geschaffen werden, neben dem Bewegen in der Karte auch Queries zuzulassen -- man muss zwischen beiden Modi wählen können. Das kann beispielsweise durch entsprechende Radio-Buttons passieren:
...
<input type="radio" name="mode" value="browse" checked> Browsen
<input type="radio" name="mode" value="query"> Anfrage stellen
...
Beim Absenden des Formulars übermitteln die Radio-Buttons (wie man sie beispielsweise auch im offiziellen MapServer-Demo findet) den entsprechenden Modus an das MapServer-CGI.
Möchte man mehrere Abfrageergebnisse zulassen, benötigt man den Modus =nquery= :
<input type="radio" name="mode" value="nquery"> Mehrere Anfragen
Alle drei Modi können natürlich im gleichen Formular vorkommen.
Desweiteren müssen Sie in allen Layern, für die Sie Abfragen zulassen möchten, ein =TEMPLATE= definieren. Dabei können Sie einzelne Templates in den Classes des Layers definieren (die dann nur für Abfrageergebnisse der jeweiligen Klasse gelten) oder aber eine Angabe für den kompletten Layer machen; das muß dann außerhalb der Classes geschehen.
Für die einfache Query wird außerdem nur der oberste sichtbare Layer der Karte befragt\footnote{Also der letzte sichtbare Layer im Mapfile}.
Wie Templates für Abfrageergebnisse notiert werden, ist bereits in der umfänglichen Sektion über Templates beschrieben worden. Beachten Sie auf alle Fälle immer, ob Sie nur einfache oder multiple Ergebnisse bei Ihren Anfragen zulassen. Ist letzteres der Fall, sollten Sie sich über die Anordnung von =HEADER= - und =FOOTER= -Templates Gedanken machen.
Ein Beispiel. Sie haben folgendes in Ihrem Layer notiert:
LAYER
NAME "gemeinden"
...
HEADER "gemeinden_head.html"
FOOTER "gemeinden_foot.html"
...
CLASS
TEMPLATE "gemeinden.html"
END
END
Für eine einfach Query würde lediglich einmal =gemeinden.html= mit entsprechendem Ergebnis zurückgeliefert werden. Nehmen wir aber nun an, dass der Modues auf =nquery= gesetzt ist, und mehrere Features mit einem Mausklick erwischt worden sind -- um ein Beispiel zu wählen: 3 Stück --, so wäre das Ergebnis wie folgt:
gemeinden_header.html
gemeinden.html
gemeinden.html
gemeinden.html
gemeinden_footer.html
Das gleiche wiederholt sich dann noch für alle anderen Layer, die darunter liegen. Außerdem können für =nquery= auch noch ein Header sowie ein Footer in der WEB-Sektion des Mapfiles definiert werden. Diese werden dann jeweils einmal dargestellt: einmal vor allen Suchergebnissen, und einmal dahinter.
==Query maps==\index{Query map}(23)
Querymaps sind kleine Karten, die in Ergebnistemplates dazu dienen, die Resultate von Queries zu visualisieren. Sie sind als eigene Sektion im Mapfile definiert, außerhalb jeder anderen Sektion (am besten nach dem Header) und sehen beispielsweise folgendermaßen aus:
QUERYMAP
COLOR 255 0 0
SIZE 200 200
STATUS ON
STYLE HILITE
END
In diesem Fall wird eine 200x200 Pixel große Querymap erzeugt, in der angefragte Features rot markiert werden.
Die folgenden Optionen können in Querymap-Sektionen auftauchen:
- =COLOR <r> <g> = Gibt die Farbe an, in der die angefragten Features markiert werden. Ergibt nur Sinn, wenn der =STYLE= auf =HILITE= gesetzt ist. Voreinstellung ist gelb.
- =SIZE <x> <y>= Die Größe, in der die Querymap gezeichnet werden soll. Voreinstellung ist die Größe der Karte.
- =STATUS <ON|OFF>= Legt fest, ob die Querymap gezeichnet werden soll.
- =STYLE <NORMAL|HILITE|SELECTED>= Dieser Stil legt für den angefragten Layer fest, wie die gewählten Features gemalt werden sollen. =NORMAL= zeichnet die Karte ohne Änderung. =HILITE= zeichnet den Layer, markiert aber die gewählten Features mit der Farbe =COLOR= ; diese Art ist auch die Voreinstellung. =SELECTED= zeichnet lediglich die gewählten Features.
Wie werden Querymaps nun dargestellt? Es gibt für diese Abfragekarten kein eigenes Schlüsselwort, vielmehr ändert sich der Tag =[img]= , wenn in einen Query-Modus geschaltet wird. Es wird dann nicht mehr die Karte, sondern eben die dazugehörige Abfragekarte dargestellt.
Abgebildet wird in der Querymap der Ausschnitt der Karte, in dem man die Anfrage gestellt hat. Darin markiert sind die Abfrageergebnisse, wie man es im =QUERYMAP= -Block angegeben hat.
Sie können übrigens eine Querymap auch separat von allem anderen mit dem Modus =querymap= anfordern, genauso, wie auch eine normale =map= .
\subsubsection*{Cached Queries}(24)\index{Queries!Cached Queries}\index{Cached Queries}
Cached Queries sind eine Möglichkeit, Abfrageergebnisse abzuspeichern. Mit Cached Queries können Sie die Abfrageergebnisse in einer Karte darstellen, deren Extents Sie beliebig wählen können. Sie sind nicht auf den Ausschnitt beschränkt, an den die Anfrage gestellt wird.
Um eine Cached Query benutzen zu können, müssen Sie zuerst eine weitere Zeile in Ihr HTML-Template aufnehmen:
<input type="hidden" name="savequery" value="true">
Dadurch werden nun bei Query-Aufrufen temporäre Dateien angelegt, wie es etwa auch für generierte Karten geschieht. Der Name dieser Datei läßt sich in einem Template nun mit Hilfe von Template-Tags rekonstruieren:
<img src="[program]&map=[map]&
queryfile=[map_image_path]<NAME>[id].qy
[get_layers]&mode=map&size=200+200
Der Wert =[map]= wird sowieso immer übergeben, und =get_layers= wird bei jedem Aufruf des MapServers automatisch aus den übergebenen Layern erstellt.\\ =map_image_path= fügt der MapServer ebenfalls automatisch aus dem Mapfile ein. Der Wert von =[id]= ist eine eindeutige ID für den jeweiligen MapServer-Aufruf und wird auch vom MapServer ausgefüllt. Der String =<NAME>= ist der Wert, der im Mapfile als =NAME= im Mapfile für die Karte gesetzt ist, und muß von Ihnen von Hand eingetragen werden.
Der Trick ist nun, dieser Karte eine Bounding Box in bekannter Notation nach Ihrem Wunsch mitzugeben; man erhält somit beliebige Kartenausschnitte, in denen Abfrageergebnisse angezeigt werden.
==Joins==\index{Joins}
Der Grundgedanke bei Joins entspricht dem gleichlautenden Begriff bei SQL-Da\-ten\-ban\-ken: die Inhalte zweiter Dateien mit Daten werden zu einem einzigen Datensatz zusammengefügt. Dazu benötigt man in beiden Datensätzen ein gemeinsames Datum, wie zum Beispiel eine ID, um den Inhalt den einen Datensatzes dem anderen zuordnen zu können.
In MapServer kommt das Konzept vor allen Dingen zum Einsatz, um die Inhalte zweier DBF-Dateien zu einem einzigen zusammenzufügen, der dann dazu benutzt wird, die Expressions in Classes oder auch Query-Ergebnisse zu evaluieren.
FIXME: funktioniert nicht?
Weitere Arten von Queries
Über die beiden Modi =query= und =nquery= hinaus definiert MapServer noch eine ganze Menge weiterer Typen für Datenanfragen. Auf einige dieser Modi soll hier noch im Detail eingegangen werden.
indexquery
Eine Indexquery sucht ein Shape über seine ID im Shapefile heraus. Im Aufruf sieht das beispielsweise folgendermaßen aus:
http://www.example.com/cgi-bin/mapserv
? map=/pfad/zum/mapfile.map
& mode=indexquery
& qlayer=bundeslaender
& shapeindex=15
Der Aufruf dieser Art von Query erfolgt über den Modus =indexquery= . Der Layer, der das Ziel der Anfrage sein soll, wird mit =qlayer= bestimmt.
Für das Ergebnis dieses Aufrufs wird wie gewohnt das Template benutzt, das sie im entsprechenden Layer definiert haben (bzw. in den dortigen Classes). Anstatt aber nun die Koordinaten eines Mausklicks auszuwerten, wird gezielt nach einem bestimmten Shape gesucht. Das obige Beispiel zum Beispiel sucht nach dem sechszehnten Shape im Layer =bundeslaender= , und die Darstellung im Query-Template sieht dann dementsprechend aus.
Falls Sie eine Querymap definiert haben sollten, so werden bei der Darstellung der Karte beim obigen Aufruf die Extents verwendet, die im Mapfile definiert sind. Der CGI-Parameter =mapext= kann verwendet werden, um wie im Modus =browse= einen anderen Kartenausschnitt festzulegen. Falls Sie diesen Parameter nicht auf bestimmte Werte setzen, sondern stattdessen =mapext=shapes= verwenden, wird direkt auf das Ergebnisshape gezoomt.
Nur die Querymap als Bild können Sie sich übrigens mit dem Modus =indexquerymap= zurückliefern lassen.
Zusätzlich zu den Parametern im gezeigten Beispielaufruf gibt es auch noch =tileindex= , für den Fall, dass sie gekachelte Shape-Daten verwenden.
itemquery und itemnquery
Durch eine Itemquery können Sie Features anhand von nichträumlichen Eigenschaften auswählen. Bei Daten aus Shapefiles (auf die wir uns hier konzentrieren wollen) kommen diese Eigenschaften selbstverständlich aus den =.dbf= -Dateien.
Um über den URL auf diese Eigenschaften zugreifen zu können, müssen wir sie mit einem Namen bekannt machen. Dazu benutzen wir den Parameter =FILTER= im entsprechenden Layer:
LAYER
...
DATA "bundeslaender"
FILTERITEM "NAME"
FILTER "
...
END
In diesem Beispiel verwenden wir die DBF-Tabellenspalte =NAME= und machen sie nach außen als =name= bekannt.
Zugriff erhalten wir nun über diesen Namen. Im URL notieren wir jetzt folgendes:
FIXME
FIXME:mehr
Da diese Art von Query mit Angabe einer Zeichenkette funktioniert, ist es in den meisten Fällen sinnvoll, dem Benutzer eine Auswahlliste zur Verfügung zu stellen, aus der er sich dann Features nach Namen auswählen kann.
FIXME
featurequery und featurenquery
\begin{figure} \begin{center} \mmfig{0.55}{featurenquery-berlin}{Eine =featurenquery= . Hier wurde das Bundeland Berlin gewählt und nach allen Features (Postleitzahlgebieten und bestimmte Kacheln) gefragt, die von der Fläche des Bundelandes geschnitten werden.} \end{center} \end{figure}
In diesem Modus wird ein Feature ausgewählt, und alle dafür eingestellten Layer werden befragt, welche Features durch dieses Feature geschnitten werden. Sie können ein Beispiel dafür in Abbildung~\ref{featurenquery-berlin} sehen: Hier wurde das Bundesland Berlin durch einen Mausklick ausgewählt, und das Ergebnis ist eine Liste aller Features, die die Fläche eben dieses Bundeslandes schneiden.
Beachten Sie bitte, dass wir an dieser Stelle nur die Fassung dieser Query mit dem =n= im Namen betrachten. =featurequery= funktioniert analog zum Paar =query= /=nquery= mit nur einem einzigen Suchergebnis.
Als erstes benötigen Sie für diese Art von Query selbstverständlich einen entsprechenden Modus:
... & mode = featurenquery & ...
Danach muß spezifiziert werden, anhand welchen Layers die Auswahl getroffen werden soll. Vorstellbar wäre zum Beispiel eine Auswahlbox mit einer Liste aller Layer, aus der dann ein Layer als Bezugsebene ausgewählt werden kann. Der zuständige Parameter heißt =slayer= . Heißt der Layer beispielsweise =gruenflaechen= , so notiert man:
... & slayer = gruenflaechen & ...
Jeder Layer, der über =layer== im URL spezifiziert wird und ein =TEMPLATE= gesetzt hat, wird nun für den Vergleich heraungezogen.
Das Abarbeiten der Query-Templates läuft in der gewohnten Weise ab; für jedes Ergebnis in einer Class werden die Templates hintereinander gehangen, für den Layer dann eventuell noch Header davor und Footer dahinter, und um das ganze herum dann eventuell vorhandene Header und Footer aus der Web-Sektion.
Hinweis : Zum Zeitpunkt der Drucklegung funktionierte diese Art von Query nicht mit umprojizierten Daten. Quell- und Zielprojektion mußten übereinstimmen, um Suchergebnisse zu erhalten.
itemfeaturequery und itemfeaturenquery
FIXME
PostgreSQL und PostGIS
\index{PostGIS}\index{PostgreSQL}
PostGIS, ein Zusatz für die freie Datenbank PostgreSQL, ist die 'Standard'-Daten\-bank\-an\-bindung für den MapServer. PostGIS setzt einen großen Teil der Simple Features des OGC um und kann nicht nur als Datenquelle für den MapServer dienen, sondern generell raumbezogene SQL-Anfragen verarbeiten.
Die Anbindung einer PostGIS-Datenbank wird in Kapitel~\ref{text:database} ab Seite~\pageref{text:database:postgis} beschrieben.
=OGR=\index{OGR}(25)
Die OGR-Bibliothek ist das vektor-orientierte Gegenstück zu GDAL. Obwohl es sich um eine eigenständige Bibliothek handelt, wird sie zusammen mit GDAL ausgeliefert.
Neben den Shapefiles gibt es nämlich noch eine ganze Reihe anderer Vektorformate. Shapefiles sind so ziemlich das minimalistischste, was man sich vorstellen kann, sie beinhaltet lediglich die Koordinaten von Punkten. Viele Vektorformate sind allerdings etwas komplexer, und enthalten gleich mehrere Datensätze, einen Haufen zusätzliche Metadaten oder gleich Informationen über die Gestaltung der Daten.
Besonders bei der letztgenannten Klasse von Formaten sollte man vorsichtig sein und von OGR nicht zuviel erwarten. Zwar gibt es für diese Formate die Möglichkeit, das Layout der Daten auszulesen, aber nicht immer kann diese Information auch umgesetzt werden.
Von der Notation her gibt es, ähnlich wie bei Datenanbindungen, nur eine grundlegende Änderung: Im Layer wird nun nicht mehr =DATA= als Schlüsselwort für die Datenquellen verwendet, sondern die beiden Parameter =CONNECTIONTYPE= (dieser ist dann immer =OGR= ) und =CONNECTION= . Dabei wird =CONNECTION= dann von den notwendigen Details wie dem gewünschten Layer aus dem Datensatz usw. gefolgt.
FIXME: vervollständigen!1!
=Spezifikation von Ausgabeformaten=(26)
Mit Version 4.0 des MapServers ist man nun endlich in der Lage, mehrere verschiedene Ausgabeformate für die fertige Karte zu spezifizieren. Bisher war man auf ein einziges Rasterbild-Format festgelegt (PNG respektive GIF).
FIXME: mehr
Ein Mapfile kann eine, mehr als eine oder sogar gar keine OUTPUTFORMAT-Sektion haben. Ohne jede Angabe wird bei einkompilierter GD-Bibliothek ein PNG-Bild zurückgeliefert.
Eine OUTPUTFORMAT-Sektion sieht typischerweise so aus:
OUTPUTFORMAT
NAME "png"
DRIVER "GD/PNG"
MIMETYPE "image/png"
IMAGEMODE RGB
EXTENSION "png"
END
Zuerst erhält die Sektion einen Namen. Danach wird ein "Treiber" für die Erstellung des Bildes angegeben. Für die typische PNG-Ausgabe mit der Bibliothek GD steht hier GD/PNG .
Der Mimetype ist wichtig, um dem Browser, der die fertige Karte entgegennimmt, mizuteilen, welcher Art die Daten sind, die da ankommen\footnote{Für Windows-Benutzer: Nein, der Dateiname sagt nichts über die Art einer Datei aus. Er ist im Grunde nicht einmal Bestandteil einer Datei. Microsoft hat das aber schon vor einer ganzen Weile vergessen.}. Er ist für diese Sektion allerdings Optional, da MapServer auch versucht, ihn automatisch zu bestimmen.
Der IMAGEMODE gibt unter anderem die Farbtiefe des Bildes an (siehe die Sektion über Rasterbilder; ist aber auch für Flash relevant), und schließlich die Dateinamenerweiterung des Outputs.
Im folgenden sollen für die verschiedenen Anwendungsfälle alle möglichen Optionen in der OUTPUTFORMAT-Sektion angegeben werden.
Rasterbilder
Bisher gibt es gibt es nur zwei Treiber für Rasterbildformate im MapServer: die inzwischen klassische Ausgabe mittels GD, und ganz neu GDAL. Letzteres kann bisher nur GeoTIFF-Bilder produzieren, aber es ist ein Anfang.
FIXME: blah
Der Parameter =IMAGEMODE= sagt aus, in welcher Farbtiefe das Bild produziert werden soll, und wie Transparenzen gehandhabt werden sollen:
- =PC256= : Produziert ein Bild mit einer eigenständigen Farbpalette mit (maximal) 256 Farben. Dies ist der klassische MapServer-Modus. Der Raster-Treiber GD/GIF kennt ausschließlich diesen Modus. TRansparenz ist mit diesem Modus möglich.
- =RGB= : 24-Bit RGB-Farbbild. Ohne Transparenz.
- =RGBA= : 32-Bit RGBA-Farbbild mit Alphakanal (Transparenz).
- FIXME: mehr?
Über alle diese Optionen hinaus gibt es noch treiberabhängige Angaben, die sogenannten FORMATOPTIONs. Sie werden folgendermaßen notiert:
OUTPUTFORMAT
NAME "jpg"
DRIVER "GD/JPEG"
MIMETYPE "image/jpeg"
IMAGEMODE RGB
EXTENSION "jpg"
FORMATOPTION "QUALITY=75"
END
Jedes OUTPUTFORMAT kann dabei keine, eine oder mehrere (passende!) Angaben für FORMATOPTIONs haben. Im folgenden sind alle diese Optionen für die einzelnen Treiber beschrieben.
Der GD-Treiber
Der GD-Treiber kennt die folgenden, optionalen Parameter in der OUTPUTFORMAT-Sektion:
- =QUALITY= Legt für JPEG-Bilder die Kompression fest. Liegt zwischen =0= (niedrigste Qualität, höchste Kompression) und =100= (höchste Qualität, niedrigste Komprimierung).
- =INTERLACE= Legt fest, ob PNG- bzw. GIF-Bilder interlaced sein sollen (=ON= ) oder nicht (=OFF= ).
FIXME: mehr
Der GDAL-Treiber
Generell kann man dem GDAL-Treiber alles als Parameter mitgeben, was die Bibliothek als Optionen kennt; was alles in Frage kommt, erfahren Sie in der Dokumentation von der Website~http:website:gdal.
FIXME: vervollständigen!1!
==Vektorformate==(27)
Vektorausgabeformate sind ein neues Feature in MapServer 4.0. Die Fülle von Einstellungen, die man dabei theoretisch machen kann, wird durch die Einführung von =OUTPUTFORMAT= abgefangen.
Alle bisher unterstützten Vektorformate zeichnen sich durch die Eigenschaft aus, dass sie nicht von sich aus im Browser darstellbar sind, sondern eine zusätzliche Bearbeitung oder doch zumindest den Einsatz von seperaten Plugins im Webbrowser notwendig machen.
Wachsender Beliebtheit bei den Vektorformaten im Web erfreut sich auch SVG, ein XML-basiertes Format. Folglich sind Fragen nach einer Unterstützung für dieses Format auf der Mailingliste an der Tagesordnung. Bisher hat sich aber noch niemand die Mühe gemacht, Unterstützung für dieses Format zu implementieren. Das kann sich im Laufe der Zeit selbstverständlich ändern.
Unterstützung für die Ausgabe von PDF-Dateien wird mit der Bibliothek PDFLib realisiert. Dafür wird MapServer beim Kompilieren ganz einfach gegen diese Bibliothek gelinkt.
Das Ausgabeformat wird recht simpel folgendermaßen notiert:
OUTPUTFORMAT
NAME "pdf"
MIMETYPE "application/pdf"
DRIVER PDF
END
Da man PDF nicht einfach über einen =<img>= -Tag in seine HTML-Seite einbinden kann, bietet sich ein anderes Vorgehen an. Man baut ein Template zum Browsen der Karte wie gewohnt, gibt dem Benutzer aber noch einen Link mit einer Beschriftung wie 'diese Karte als PDF herunterladen' mit auf den Weg. Diesen Link kann man sich für den aktuellen Kartenausschnitt mit den entsprechenden MapServer-Tags bauen, zum Beispiel wie folgt:
<a href="/cgi-bin/mapserv?map=[map]&imgext=[mapext]&FIXME=pdf ...">
Die Liste der Parameter ist hier nicht vollständig, aber die Idee wird klar.
Wer den Verlauf der Entwicklung von MapServer 4.0 mitverfolgt hat, hat vielleicht mitbekommen, dass zu Beginn der PDF-Unterstützung lediglich ein PNG-Bild erzeugt worden ist, das dann in ein PDF-Dokument eingebettet wurde. Das ist nicht mehr der Fall, nun liefert MapServer für Vektordaten richtiges PDF zurück.
Wenn man eine Weile mit diesem Ausgabeformat experimentiert, wird man merken, dass die reine Ausgabe einfach nur einer Karte im PDF-Format recht unbefriedigend ist. Wer gestalterisch tätig werden möchte, der muß mit einer Skriptsprache Hand anlegen.
Hinweis : Beachten Sie bitte unbedingt, dass die Nutzung für die hier verwendete Bibliothek PDFLib nicht für ausnahmslos alle Nutzungen kostenlos ist. Bitte informieren Sie sich auf der Website~http:website:pdflib der Bibliothek über die Details.
Außerdem ist die Erzeugung von PDF eine recht rechenintensive Sache, deren Einsatz man demnach mit Bedacht planen sollte.
Shockwave Flash
Flash ist ein Vektorformat, das im Web vor allen Dingen dafür verwendet wird, Animationen darzustellen. Daher spricht man bei einem Flash-Element in einer Website gewöhnlich von einem 'Movie', sogar dann, wenn es sich eigentlich um statischen Inhalt handelt. MapServer bietet mit Version 4.0 nun auch die Möglichkeit, fertige Karten als Flash-Movies auszuliefern.
Dabei stützt sich MapServer auf die Bibliothek Ming~http:website:ming, die im Moment von Wolfgang Hamann weiterentwickelt wird, nachdem er diese Aufgabe im November 2002 vom ursprünglichen Entwickler übernommen hat\footnote{Leider hat sie im Laufe der Zeit keine Updates mehr erfahren.}. Die Software zeichnet sich insbesondere durch ihre vielfältigen Bindungen an andere Programmiersprachen aus.
Die Installation für Flash-Unterstützung wird für das Selberkompilieren von Binaries ab Seite~\pageref{anhang:installation:compile:flash} besprochen.
Es gibt für uns zwei Arten, Flash-Output zu generieren: einmal einen Movie für die komplette Karte, und einmal einen Movie für jede einzelnen Layer:
OUTPUTFORMAT
NAME "swf"
MIMETYPE "application/x-shockwave-flash"
DRIVER swf
IMAGEMODE PC256
FORMATOPTION "OUTPUT_MOVIE=SINGLE"
# FORMATOPTION "OUTPUT_MOVIE=MULTIPLE"
END
Wenn Sie mit diesem =OUTPUTFORMAT= einen Aufruf durchführen, werden Sie feststellen, dass Sie eine Datei (oder mehrere, wenn Sie =MULTIPLE= statt =SINGLE= im Beispiel gewählt haben) mit der Endung =.swf= in Ihrem temporären Verzeichnis aufgetaucht ist.
Bevor Sie diese Dateien tatsächlich benutzen können, müssen Sie sich aber noch ein wenig Arbeit machen. Was Sie benötigen, ist Kenntnis in der Sprache ActionScript, und ein Flash-SDK. Leider würde es den Rahmen dieses Buches sprengen, das eine oder das andere zu erläutern. Daher bleibt mir nur der Verweis auf das Archiv der MapServer-Mailingliste, wo Sie auf der Suche nach Beispielapplikationen und Diskussionen fündig werden können.
=Features=(28)
Für manche Dinge ist es nicht nötig -- oder schlicht zu aufwendig -- ein eigenes Shapefile oder eine andere Datenquelle zu haben. Sie können einfache Features auch als =FEATURE= -Block direkt im Mapfile notieren. Ein Beispiel:
FEATURE
POINTS
1 1
10 10
10 1
1 1
END
TEXT "Dreieck"
END
Hier definieren wir ein Dreieck in der linken oberen Ecke der fertigen Karte. Der Parameter =TEXT= definiert die Beschriftung des Features.
Beachten Sie, dass für einen geschlossenen Linienzug der letzte Punkt dem ersten Punkt entsprechen muß. Für die Einbettung eines =FEATURE= in einen Layer schauen Sie sich bitte den nächsten Abschnitt an.
Fix positionierte Elemente
Zuweilen möchte man in eine fertige Karte noch eine Information einfügen, die immer gleich bleibt; ein Logo, eine Urhebernotiz, was auch immer. Das Problem ist natürlich, dass bisher immer alles georeferenziert war und daher immer auf einen bestimmten Punkt fixiert.
\begin{figure} \begin{center} \mmfig{0.60}{transform-label}{Ein fixes Label in einer Karte, hier der URL der MapMedia-Website.} \end{center} \end{figure}
Mit dem Parameter =TRANSFORM= in einem Layer können Sie dieses Verhalten jedoch ein wenig manipulieren. Dieser Parameter gibt an, ob das Koordinatensystem der Datenquelle im Verhältnis zum fertigen Bild transformiert werden soll oder nicht. Die Standardeinstellung ist immer =TRUE= , was nicht weiter verwundert, denn bisher wurde immer das Koordinatensystem der Daten in das Koordinatensystem des Bildes (Angabe in Pixeln und Ursprung links oben) umgewandelt.
Setzen Sie diesen Wert jedoch auf =FALSE= , können Sie neue Dinge tun, unter anderem auch mit einer =FEATURE= -Sektion, beispielsweise wie folgt:
LAYER
NAME "credits"
STATUS DEFAULT
TRANSFORM FALSE
TYPE ANNOTATION
FEATURE
POINTS
10 10
END
TEXT 'http://www.mapmedia.de/'
END
CLASS
LABEL
TYPE TRUETYPE
FONT "arial"
SIZE 11
ANTIALIAS TRUE
COLOR 0 0 0
END
END
END
Dieser Layer besteht aus nur einem Feature, einem Punkt, dessen Koordinaten fest angegeben sind, und ebenso seine Beschriftung. In der dazugehörigen Class ist die Beschriftung mit Schriftart, Farbe usw. definiert. Dadurch, dass der Status auf =DEFAULT= gesetzt ist, und dass man diesen Layer als letzten Layer im Mapfile notiert, hat man einen Effekt wie in Abbildung~\ref{transform-label}: eine Beschriftung, die immer in der Karte zu sehen ist.
FIXME: raster?
=CGI-Parameter=(29)
FIXME:aufzählung
==Parameter einschränken==(30)
FIXME:Restriktion durch eine EXPRESSION
\subsection*{Ändern des Mapfiles}
Von außen (über den aufrufenden URL) können auch praktisch alle Inhalte des Mapfiles verändert werden. Der Aufbau dieser neuen Parameter ist recht simpel und orientiert sich an der Struktur eines Mapfiles.
Betrachten wir den Aufbau eines Mapfiles: eine Map beinhaltet (mindestens einen) Layer, dieser mindestens eine Klasse (wenn es sich um einene Vektorlayer handelt). Diese Klasse kann nun wiederum ein Label beinhalten, welches seinerseits eine Farbe hat.
Die Adressierung kann auf verschiedene Weise geschehen. Zuerst einmal über Nummern. Im folgenden Beispiel bekommt die erste Klasse im zweiten Layer die Farbe Rot zugewiesen:
...&map_layer_1_class_0_color=255
Das '\
Darüber hinaus lassen sich Layer auch über ihren Namen referenzieren:
...&map_fluesse_class_0_color=255
Wenn der Layer nur eine Klasse hat, sollte man den Index einfach weglassen.
Des weiteren lassen sich auf diesem Weg simple Features zu einem Layer hinzufügen. Der Layer muß existieren. Hier das Beispiel aus der offiziellen MapServer-Dokumentation:
...&map_user_feature=new&map_user_feature_points=12345.6789+12345.6789
&map_user_feature_text=My+House!
Dem Layer user wird auf diese Weise ein Punkt mit den angegebenen Koordinaten hinzugefügt, und er wird auch gleich beschriftet. Wird ein Layername mehrfach verwendet, wird das Feature einfach erweitert. Auf diese Weise lassen sich beispielweise Polygone mit 'Löchern' hinzufügen.
=Logs=(31)
Für einen Serverdienst möchte man selbstverständlich Log-Dateien angelegt bekommen. Ein Server läuft die ganze Zeit vor sich hin, sodass man, im Gegensatz zu einer Desktop-Anwendung, im Fehlerfall meistens nicht anwesend ist. Dann sind Protokolle der Serveraktivitäten natürlich notwendig für die Fehlersuche.
Aber auch für den Entwickler sind Logfiles wichtig, zeigen sie ihm doch, wo er nach Ursachen zu suchen hat, wenn sich die Anwendung, an der er arbeitet, nicht so verhält wie erwartet.
Wofür auch immer man seine Logs verwendet, definiert wird die Logdatei in MapServer in der Web-Sektion:
WEB
...
LOG "/pfad/zur/datei.log"
END
Es gibt nur eine einzige Logdatei pro Mapfile, in der MapServer sowohl Fehlermeldungen als auch erfolgreiche Zugriffe loggen kann.
Das Format für Logfiles ist leider nict dokumentiert, sodass man sich mit einem Blick in den Quellcode weiterhelfen muß\footnote{Siehe Funktion =writeLog= in =mapserv.c= }. Ein Eintrag in einem Logfile sieht beispielsweise folgendermaßen aus:
Fri Mar 21 16:02:48 2003,1031,10.0.1.2,demonstration,0, \
7.848750 49.445625 19.098750 55.070625,13.473750 52.258125, \
bundeslaender,normal execution
So ein Eintrag erstreckt sich immer über eine einzelne Zeile. Alle Bestandteile sind durch Kommata voneinander getrennt. Die vorliegende Zeile ist im einzelnen wie folgt zu verstehen:
- =Fri Mar 21 16:02:48 2003= Ist ein Zeitstempel; Datum und Uhrzeit des Aufrufs.
- =1031= Die aktuelle Prozess-ID.
- =10.0.1.2= Die IP-Adresse des aufrufenden Hosts. Wird aus der Umgebungsvariable =REMOTE_ADDR= gelesen und ist =NULL= \footnote{Hier ist die Zeichenkette ='NULL'= gemeint}, wenn diese Variable nicht gesetzt ist.
- =demonstration= Der Name des Mapfiles, wie er mit =NAME= im Header gesetzt ist.
- =0= Der Modus des Aufrufes, also z.B. =map= , =browse= und so weiter. Es gibt 26 verschiedene, die allesamt in =maptemplate.h= in einem Aufzählungstyp definiert sind.
- =7.848750 49.445625 19.098750 55.070625= sind die Extents des angezeigten Kartenausschnitts.
- =13.473750 52.258125= Ist der Punkt in der Karte, der angeklickt worden ist. Dieser Punkt hat den Aufruf des MapServers verursacht.
- =bundeslaender= Eine Liste der angeforderten Layer, durch Leerzeichen voneinander getrennt.
- =normal execution= Ist alles glatt gelaufen, findet sich dieser Eintrag am Ende einer Zeile.
Für ausführlicheres Logging gibt es den Parameter =DEBUG= , der im Header, in Layern und in Classes definiert werden kann. Mit dieser Einstellung produzieren bisher allerdings im wesentlichen nur Raster- und WMS-konforme Layer ausführlichere Fehlermeldungen. Es steht zu erwarten, dass dieser Parameter noch weiter ausgebaut wird.
\subsubsection*{Log-Dateien im Webserver}
Neben den Logs des MapServers haben Sie im Fehlerfall natürlich immer noch die Logs Ihres Webservers zur Verfügung. Im Fehlerfall finden Sie hier auch die HTTP-Fehlercodes, die dann nützlich sind, wenn es nicht MapServer-Fehler sind, die Ihnen Probleme bereiten. Insbesondere bei der Apache-Fehlermeldung Internal Server Error finden Sie normalerweise detaillierte Einträge, die Ihnen helfen können, die Ursache des Problems schnell zu lokalisieren.