GeoServer en Google Maps
29 May 2009 11:10 · Rob van de Meulengraaf · Algemeen
In Google Maps kunnen kaarten met geografische gegevens als lagen over elkaar worden gelegd, bijvoorbeeld een stratenkaart. Deze kaarten bestaan uit meerdere afbeeldingen die tegen elkaar aan liggen, zogenaamde tiles. Een standaard manier om deze kaartafbeeldingen met geografische gegevens op te vragen is via een Web Map Service (WMS). GeoServer biedt een open source implementatie van een WMS. GeoServer is een Java gebaseerde server die het mogelijk maakt om geografische gegevens te bekijken en te wijzigen. Dit artikel laat aan de hand van een eenvoudig voorbeeld zien hoe je GeoServer kunt gebruiken om eigen geografische kaarten te genereren en te tonen in Google Maps.
Geoserver installeren
GeoServer is geïmplementeerd als een Java Web Archive (WAR) en kan geïnstalleerd worden in bijvoorbeeld Tomcat. Er is ook een stand-alone versie. Dit voorbeeld gaat uit van het web archive en Tomcat. Download de war file (1.7.4. is de huidige versie ) en installeer deze in de webapps folder van Tomcat. Controleer of GeoServer goed is geïnstalleerd door met je browser naar http://localhost:8080/geoserver/ te gaan.

Als je op de Config link klikt kom je in het beheer scherm terecht. Linksboven zie je daar de knoppen Toepassen, Opslaan en Laden. Wijzigingen worden pas aktief indien je op Toepassen hebt geklikt. Met Opslaan worden ze opgeslagen op schijf en met Laden wordt de op schijf opgeslagen configuratie opnieuw geladen. Dit wil je het begin nogal eens vergeten. De configuratie bestaat uit een verzameling tekst en XML bestanden die ook met een gewone tekstverwerker kunnen worden bewerkt. De groene statusbalken geven aan dat de configuratie correct is.
Om GeoServer te kunnen gebruiken als WMS server is geo data uit een externe bron nodig. Geoserver ondersteund o.a. andere WMS servers, Oracle Spatial en PostgreSQL PostGIS en ook het veel gebruikte ESRI™ Shape formaat. Dit formaat is gemakkelijk voor demonstratie doeleinden en wordt dan ook gebruikt in dit voorbeeld.
Geometrische data configureren
Geometrische data is slechts beperkt als open source beschikbaar in Nederland. Een voorbeeld van publiek beschikbare gegevens zijn de wijk- en buurt gegevens van het Centraal Bureau voor de Statistiek (CBS). Deze omvatten alle grenzen van de Nederlandse gemeenten, wijken en buurten plus wat statistische informatie over deze gebieden. De geografische gegevens zijn wel gegeneraliseerd, wat wil zeggen dat het aantal coördinaten is verminderd met behoud van de vorm. Voor exactere gegevens kun je bijvoorbeeld terecht bij het Kadaster.
Maak een nieuwe namespace aan in GeoServer. Klik achtereenvolgens op Config, Data, Namespace en Nieuw. Geef als prefix de naam “cbs” en klik op Nieuw. Geef vervolgens als URI bijvoorbeeld op: http://www.cbs.nl en klik op invoeren. Vergeet niet om met de knoppen Toepassen en Opslaan linksboven de configuratie definitief op te slaan.
Om de geografische gegevens te kunnen visualiseren moet je een stijl definiëren. Klik achtereenvolgens op Config, Data, Stijl en Nieuw. Gebruik als Stijl-ID de naam gemeentegrenzen en klik op Nieuw. Vul vervolgens als SLD het volgende in:
<?xml version="1.0" encoding="UTF-8"?> <StyledLayerDescriptor version="1.0.0" xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <NamedLayer> <Name>Gemeentegrenzen</Name> <UserStyle> <Title>Gemeentegrenzen</Title> <Abstract></Abstract> <FeatureTypeStyle> <FeatureTypeName>Feature</FeatureTypeName> <Rule> <Name>Grenzen</Name> <Title>Grenzen</Title> <LineSymbolizer> <Stroke> <CssParameter name="stroke"> <ogc:Literal>#000000</ogc:Literal> </CssParameter> <CssParameter name="stroke-width"> <ogc:Literal>1</ogc:Literal> </CssParameter> </Stroke> </LineSymbolizer> </Rule> </FeatureTypeStyle> </UserStyle> </NamedLayer> </StyledLayerDescriptor>
Een SLD of Styled Layer Descriptor is een standaard manier om te bepalen hoe geografische gegevens moeten worden weergegeven. In dit geval als een lijn met een bepaalde kleur en dikte waardoor de contouren van een gemeente te zien zullen zijn. Later een meer uitgebreid voorbeeld. Klik vervolgens op invoeren en sla de configuratie op.
Download daarna de gemeente gegevens van 2008 en importeer deze in GeoServer door een nieuwe Feature Data Set aan te maken door achtereenvolgens op Config, Data, Dataopslag en Nieuw te klikken. Selecteer bij Feature Beschrijving Data Set de optie Shapefile en geef als Feature Data Set ID de naam gemeente op en klik op Nieuw. Selecteer bij Namespace vervolgens de net aangemaakte optie cbs. Geef bij Url de locatie van de shapefile die je net gedownload hebt op als: file:/downloadfolder/buurt_2008_gen1/gem_2008_gen.shp en klik op Invoeren. GeoServer laadt vervolgens de data in de shapefile en toont alle kolomdefinities die het gevonden heeft, één hiervan bevat de geometrische data als alles goed is gegaan: the_geom. Selecteer bij Stijl de net aangemaakte optie gemeentegrenzen. Vul bij SRS het correcte ruimtelijk-referentiesysteem nummer in, in dit geval 28992. De gebruikte projectie staat in dit geval in het bestand gem_2008_gen.prj. Als je op de link SRS Lijst klikt krijg je een overzicht van een aantal SRS codes. Je kunt de goede hierbij zoeken. Er zijn heel veel van deze codes die onderling soms maar weinig verschillen.
Indien GeoServer lege of verkeerde kaartafbeeldingen genereert dan is de meest waarschijnlijke oorzaak foutieve instelling. Genereer vervolgens de Bouding Box door op de knop Genereren te klikken. Dit bepaald het gebied waarbinnen de gegevens geldig zijn. Klik vervolgens op invoeren en sla de configuratie op.
Controleer of alles werkt door op Demo te klikken en daarna op Map-Preview. Klik vervolgens op de Layer cbs:gem_2008_gen. Als alles goed is gegaan krijg je de kaart van Nederland te zien met daarop alle gemeente grenzen.
De volgende stap is om deze kaart te projecteren op Google Maps.
Projecteren kaart op Google Maps
We kunnen deze kaart tonen in Google Maps door een eigen Map Type of door een eigen Overlay te definiëren. Dit laatste is het gemakkelijkste en gebruiken we dan ook in dit voorbeeld. We gaan daarvoor uit van het overlay voorbeeld uit de google maps tutorial.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example: Tile Overlays</title>
<script src="http://maps.google.com/maps?file=api&v=2"
type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
if (GBrowserIsCompatible()) {
// Set up the copyright information
// Each image used should indicate its copyright permissions
// Copyright is however not shown for an overlay
// see: http://code.google.com/p/gmaps-api-issues/issues/detail?id=663
var cbsCopyright = new GCopyright(1,
new GLatLngBounds(new GLatLng(-90,-180),new GLatLng(90, 180) ),0,
"Copyright(c) 2008,Centraal BureauvoordeStatistiek/Kadaster,Emmen,2008");
var myCopyright = new GCopyrightCollection("(c) ");
myCopyright.addCopyright(cbsCopyright);
// create the custom tile url, every tile will be requested from our geoserver
// screenpixels coordinates have to be converted to lat/lng to send the correct
// requests to the geoserver
CustomGetTileUrl = function(tile, zoom) {
var upperLeftPoint = new GPoint(tile.x * 256, (tile.y + 1) * 256);
var lowerRightPoint = new GPoint((tile.x + 1) * 256, tile.y * 256);
var upperLeftLatLng = G_NORMAL_MAP.getProjection().fromPixelToLatLng(upperLeftPoint, zoom);
var lowerRightLatLng = G_NORMAL_MAP.getProjection().fromPixelToLatLng(lowerRightPoint, zoom);
var boundingBox = upperLeftLatLng.x + "," + upperLeftLatLng.y +
"," + lowerRightLatLng.x + "," + lowerRightLatLng.y;
return "http://localhost:8080/geoserver/wms?REQUEST=GetMap&SERVICE=WMS&VERSION=1.1.1" +
"&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=true&WIDTH=256&HEIGHT=256&REASPECT=false" +
"&LAYERS=cbs:gem_2008_gen" +
"&STYLES=gemeentegrenzen" +
"&BBOX=" + boundingBox;
}
// Create the tile layer overlay and
// implement the three abstract methods
var tilelayer = new GTileLayer(myCopyright);
tilelayer.getTileUrl = CustomGetTileUrl;
tilelayer.isPng = function() { return true;};
tilelayer.getOpacity = function() { return 1.0; }
var myTileLayer = new GTileLayerOverlay(tilelayer);
var map = new GMap2(document.getElementById("map_canvas"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addControl(new GScaleControl());
map.setCenter(new GLatLng(52.13,5.71),8);
map.addOverlay(myTileLayer);
}
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<div id="map_canvas" style="width: 800px; height: 600px"></div>
<p>Bron: Copyright(c) 2008,Centraal BureauvoordeStatistiek/Kadaster,Emmen,2008</p>
</body>
</html>Het enige dat we moeten veranderen in dit voorbeeld is de copyright boodschap, de getTileUrl methode van de tilelayer en de locatie voor de setCenter methode. Deze laatste laten we naar Nederland wijzen. Het tonen van een copyright boodschap is een voorwaarde voor het gebruik van de CBS gegevens en voor geografische gegevens in het algmeen. De getTileUrl overrulen we zodat deze de eerder gemaakte WMS service aanroept voor elke te tonen tile. De parameters zijn vastgelegd in de WMS specificatie en bevatten onder ander de LAYER die we opvragen (cvs:gem_2008_gen), de STYLE die we daarvoor willen gebruiken (gemeente) en de bounding box of BBOX. Deze bounding box geeft de begrenzing aan voor welk gebied de tile moet worden gegenereerd. Elke tile hoeft maar voor een bepaald gebied gegenereerd te worden. Deze bouding box wordt opgegeven in lengte- en breedtegraden. De method getTileUrl wordt aangeroepen voor een tile waarvoor alleen de pixel coördinaten van de map in de browser bekend zijn. Deze worden daarom eerst omgerekend naar coördinaten in lengte- en breedtegraden.
Om te testen kun je deze pagina gewoon in de docroot van GeoServer zetten, bijvoorbeeld als demo.html. Als je je browser vervolgens naar http://localhost:8080/geoserver/demo.html laat wijzen zou je de kaart van Nederland in Google Maps te zien moeten krijgen met daar overheen de gemeente grenzen van Nederland.
De stijl of SLD die we voor dit voorbeeld gebruikt hebben is redelijk simpel. Een SLD heeft echter veel meer mogelijkheden en kan bijvoorbeeld ook gegevens anders weergeven afhankelijk van de waarde daarvan.
Kaart vormgeven
In een iets uitgebreider voorbeeld gebruiken we een van de velden die in de CBS data beschikbaar zijn namelijk BEV_DICHTH welke de bevolkingsdichtheid per gemeente aangeeft in inwoners per vierkante kilometer. Maak een nieuwe stijl door achtereenvolgens op Config, Data, Stijl en Nieuw te klikken. Gebruik als Stijl-ID de naam bevolkingsdichtheid en klik op Nieuw. Vul vervolgens als SLD het volgende in:
<?xml version="1.0" encoding="UTF-8"?> <StyledLayerDescriptor version="1.0.0" xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <NamedLayer> <Name>Bevolkingsdichtheid</Name> <UserStyle> <Title>Bevolkingsdichtheid</Title> <Abstract></Abstract> <FeatureTypeStyle> <FeatureTypeName>Feature</FeatureTypeName> <Rule> <Name>Dichtbevolkt</Name> <Title>Dichtbevolkt</Title> <ogc:Filter> <ogc:PropertyIsGreaterThan> <ogc:PropertyName>BEV_DICHTH</ogc:PropertyName> <ogc:Literal>3000</ogc:Literal> </ogc:PropertyIsGreaterThan> </ogc:Filter> <PolygonSymbolizer> <Fill> <CssParameter name="fill-opacity">0.5</CssParameter> <CssParameter name="fill"> <ogc:Literal>#FF0000</ogc:Literal> </CssParameter> </Fill> </PolygonSymbolizer> </Rule> <Rule> <Name>Dunbevolkt</Name> <Title>Dunbevolkt</Title> <ogc:Filter> <ogc:PropertyIsBetween> <ogc:PropertyName>BEV_DICHTH</ogc:PropertyName> <ogc:LowerBoundary> <ogc:Literal>0</ogc:Literal> </ogc:LowerBoundary> <ogc:UpperBoundary> <ogc:Literal>100</ogc:Literal> </ogc:UpperBoundary> </ogc:PropertyIsBetween> </ogc:Filter> <PolygonSymbolizer> <Fill> <CssParameter name="fill-opacity">0.5</CssParameter> <CssParameter name="fill"> <ogc:Literal>#00FF00</ogc:Literal> </CssParameter> </Fill> </PolygonSymbolizer> </Rule> <Rule> <Name>Gemeentegrenzen</Name> <Title>Gemeentegrenzen</Title> <PolygonSymbolizer> <Stroke> <CssParameter name="stroke-opacity">0.5</CssParameter> <CssParameter name="stroke"> <ogc:Literal>#000000</ogc:Literal> </CssParameter> </Stroke> </PolygonSymbolizer> </Rule> </FeatureTypeStyle> </UserStyle> </NamedLayer> </StyledLayerDescriptor>
Bij een bevolkingsdichtheid van meer dan 3000 kleuren we de gemeente rood in. Indien deze lager is dan 100 dan kleuren we de gemeente groen in. Met de opacity geven we de mate van doorzichtigheid aan. Een waarde van 0.0 is onzichtbaar en bij een waarde van 1.0 zijn onderliggende lagen niet meer te zien.
Vervolgens moeten we nog aangeven dat deze stijl gebruikt moet worden i.p.v. de gemeentegrenzen. Dit kun je doen door in demo.html STYLES=gemeentegrenzen te veranderen in STYLES=bevolkingsdichtheid. Als je de demo opnieuw laadt zie je als het goed is Nederland met enkele ingekleurde rode en groene vlakken:
Conclusie
In dit artikel heb ik laten zien dat het eenvoudig is om met GeoServer geografische gegevens te projecteren op Google Maps. Met behulp van zelf te definiëren stijlen is het mogelijk om deze gegevens op verschillende manieren te visualiseren.
Bronnen
GeoServer
Google Maps API
Google Maps API Tutorial
CBS wijk- en buurt gegevens
















Mooie tutorial Rob! Het is een ingewikkeld onderwerp en heeft een steile leercurve voor beginners, maar je maakt het op deze manier veel toegankelijker. Complimenten.
Felix Ogg (Finalist) - June 3, 2009 11:38
Kijk, daar heb je wat aan! Binnen 24 uur kan ik m’n eigen maps produceren, en dat op een x64 machine waarop geoserver niet maar zo 1-2-3 werkt. Als ik nu nog een xml stijl editor ergens kan vinden ….
Thx Rob
Giorgio Pocoloco - July 15, 2009 10:08