User:Maxbe/csv-Dateien mit Mapserver darstellen

From OpenStreetMap Wiki
Jump to: navigation, search

Am Beispiel der Haltestellendaten vom VBB

Zutaten

Ein (umn-)mapserver von mapserver.org. Der sollte als Input-Format OGR können:

max@d3:~$ /home/www/wms/cgi-bin/mapserv6 -v
MapServer version 6.0.3 OUTPUT=PNG OUTPUT=JPEG ... INPUT=OGR

Ausserdem die ogrtools von gdal.org/ogr/, die als Input-Format CSV können:

max@d3:~$ ogrinfo --formats
Supported Formats:
  ..
  -> "CSV" (read/write)
  ..

Ich weiss nicht mehr, ob das der Standard bei der Installation war, ich glaube schon, jedenfalls habe ich mich nie darum gekümmert...


Die CSV-Datei

Ausserdem braucht man die Daten der Haltestellen in einer CSV-Datei. Die vom VBB sieht z.B. so aus:

stop_id,stop_code,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,location_type,parent_station
5100071,,"Zbaszynek",,52.2389370,15.8215110,,,0,
5100081,,"Poznan Gl.",,52.3986540,16.9088520,,,0,
5100083,,"Kunowice",,52.3430780,14.6425210,,,0,
5100319,,"Bedow",,52.0724110,15.3135220,,,0,
5100397,,"Boczow",,52.3264190,14.9480280,,,0,

Die erste Zeile enthält die Namen der Felder, alle weiteren Zeilen enthalten die Daten dazu. Hier interessiert uns eigentlich nur stop_name sowie stop_lat und stop_lon.

Diese Datei laden wir runter und legen sie als vbb-stops.csv ab (.csv als Endung ist wichtig).


Die OVF-Datei

Der Mapserver kann nicht selbst die CSV-Dateien lesen, möglicherweise geht das mit einkompilierter csv-Unterstützung, ich weiss aber nicht, ob es sowas gibt. Also der Umweg über OGR.

OGR hat einen Treiber "Virtual Format", wo ich mit XML-Steuerdaten sagen kann wo die Daten liegen und was davon die Koordinaten sind. Diese Steuerdatei vbb-stops.ovf müssen wir erzeugen:

<OGRVRTDataSource>
   <OGRVRTLayer name="vbb-stops">
       <SrcDataSource>(PFAD zur CSV-Datei)/vbb-stops.csv</SrcDataSource>
       <GeometryType>wkbPoint</GeometryType>
       <LayerSRS>WGS84</LayerSRS>
       <GeometryField encoding="PointFromColumns" x="stop_lon" y="stop_lat"/>
   </OGRVRTLayer>
 </OGRVRTDataSource>

Das einzig wichtige in dieser Datei ist der Pfad zur CSV-Datei, der Name des Layers "vbb-stops", sowie die Angabe, welche der Felder dort x und y-Koordinaten sind.

Testen der OVF-Datei

max@d3:/home/www/wms/maps$ ogrinfo -al vbb-stops.ovf | more
Warning 4: Failed to open ../maps/vbb-stops.csv, Permission denied.
Warning 1: Cannot open datasource `../maps/vbb-stops.csv' in update mode.
Trying again in read-only mode
INFO: Open of `vbb-stops.ovf'
      using driver `VRT' successful.

Layer name: vbb-stops
Geometry: 3D Point
Feature Count: 12812
Extent: (10.700868, 50.839245) - (16.908852, 54.524383)
Layer SRS WKT:
GEOGCS["WGS 84",
    DATUM["WGS_1984",
        SPHEROID["WGS 84",6378137,298.257223563,
            AUTHORITY["EPSG","7030"]],
        TOWGS84[0,0,0,0,0,0,0],
        AUTHORITY["EPSG","6326"]],
    PRIMEM["Greenwich",0,
        AUTHORITY["EPSG","8901"]],
    UNIT["degree",0.0174532925199433,
        AUTHORITY["EPSG","9108"]],
    AUTHORITY["EPSG","4326"]]
stop_id: String (0.0)
stop_code: String (0.0)
stop_name: String (0.0)
stop_desc: String (0.0)
stop_lat: String (0.0)
stop_lon: String (0.0)
zone_id: String (0.0)
stop_url: String (0.0)
OGRFeature(vbb-stops):1
 stop_id (String) = 5100071
 stop_code (String) = 
 stop_name (String) = Zbaszynek
 stop_desc (String) = 
 stop_lat (String) = 52.2389370
 stop_lon (String) = 15.8215110
 zone_id (String) = 
 stop_url (String) = 
 location_type (String) = 0
 parent_station (String) = 
 POINT (15.821511 52.238937)
OGRFeature(vbb-stops):2
 stop_id (String) = 5100081
 stop_code (String) = 
 stop_name (String) = Poznan Gl.
 stop_desc (String) = 
 stop_lat (String) = 52.3986540
 stop_lon (String) = 16.9088520
 zone_id (String) = 
 stop_url (String) = 
 location_type (String) = 0
 parent_station (String) = 
 POINT (16.908852 52.398654)

Falls hier jede Menge Haltestellen vorbeirauschen, hat man gewonnen. Man sieht auch, welche Felder vorhanden sind. Und vor allen sieht man bei jeden OGRFeature einen Eintrag "POINT()", der die Koordinate des Features enthält.

Das Mapfile

Jetzt müssen wir dem Mapserver nur noch sagen, dass wir ein Bild aus dieser ovf-Datei erstellen wollen. Das teilen wir ihm im Mapfile "vbb-stops.map" mit:

MAP
OUTPUTFORMAT
   NAME agg
   DRIVER AGG/PNG8
   FORMATOPTION "INTERLACE=OFF"
   MIMETYPE "image/png"
   TRANSPARENT ON
   IMAGEMODE RGBA
END

FONTSET "osmfonts.lst"
MAXSIZE 10000
SIZE 800 800
EXTENT -180 -85 180 85

WEB
 METADATA
  "ows_enable_request" "*"
  wms_srs "EPSG:900913 EPSG:4326 EPSG:3857"
  wms_title "vbb-stops"
 END
END

PROJECTION
"init=epsg:900913"
END
 
SYMBOL
   NAME "circle"
   TYPE ELLIPSE
   POINTS 1 1 END
   FILLED TRUE
END
 
LAYER 
   NAME "vbb-stops"
   STATUS OFF
   MAXSCALEDENOM 500000
   PROJECTION "init=epsg:4326" END
   TYPE ANNOTATION
   CONNECTIONTYPE OGR
   CONNECTION     "vbb-stops.ovf"

   LABELITEM 'stop_name'
   CLASS
    STYLE
     SYMBOL "circle"
     SIZE   6 
     COLOR  "#000000"
     OUTLINECOLOR "#ffffff"
     OUTLINEWIDTH 2
    END
       LABEL
           TYPE TRUETYPE FONT sc PARTIALS FALSE OUTLINEWIDTH 2
           SIZE 9  
           COLOR "#000000"
           POSITION auto
           STYLE
           GEOMTRANSFORM labelpoly
            COLOR "#ffffff"
           END 
       END
  END
END
END

Den oberen Teil habe ich mir irgendwo rauskopiert, wichtig ist im Layer der Verweis auf "CONNECTIONTYPE OGR" und CONNECTION "vbb-stops.ovf", wo die Verbindung zur ovf geschaffen wird. LABELITEM ist der Name des Feldes, den ich für die Beschriftung verwenden möchte.


Da ist noch eine Datei "osmfonts.lst" dabei, da steht einfach nur drin, welchen TTF-Font ich nehmen will, wenn ich "FONT sc" im Mapfile verwende:

sc osmfonts/DejaVuSansCondensed.ttf
scb osmfonts/DejaVuSansCondensed-Bold.ttf
sci osmfonts/DejaVuSerifCondensed-Italic.ttf

Testen des Mapfiles

Ich baue mir da immer eine kleine html-Seite, wo ich diesen WMS-Layer einbinde, z.B. mit

map.addLayer (new OpenLayers.Layer.WMS("vbb-stops","http://wms.dianacht.de/pfad-zum-mapserver/mapserv?map=/pfad-zum-mapfile/vbb-stops.map",
                                      {layers:'vbb-stops',format:"agg"}, 
                                      {projection:new OpenLayers.Projection("EPSG:900913"), 
                                       numZoomLevels:19, 
                                       isBaseLayer:false,
                                       visibility:true,
                                       singleTile:true
                                       }
                                      ));

Und freue mich, falls ich da ein Bild sehe.