Koordinatenproblem: OpenLayers mit OSM+WMS

Hi Community,

ungeachtet von meinen laufenden Recherchen zu einer fertigen Kartenlösung, die bei 123map tatsächlich am besten aufgehoben scheint, habe ich mich daran gemacht, eine eigene Kartenapplikation zu schreiben, um mich überhaupt mal an die Grundfunktionen und Anforderungen einer Gesamtkarte für alle meine Daten zu gewöhnen und den Nutzern vorab schonmal ein Tool anzubieten, falls das eigentliche Projekt noch länger warten muss.

Diesbezüglich habe ich mir einen WMS-Zugang gebastelt, der über OpenLayers meine Daten als single-tile anzeigt. Soweit funktioniert das super und die Anzeige scheint von den Koordinaten her auch perfekt zu passen. Zumindest sind alle Blitzeinschläge dort, wo ich sie auch mit anderen Methoden wiederfinden kann.

Das von mir genutzte Beispiel nutzte dabei eine Hintergrundkarte aus den OL-Examples. Dann wollte ich mal einen OSM-Layer zuschalten oder einen Cloudmap-Tileserver, aber das hat mir das Koordinatensystem durchgerüttelt. Scheinbar kommen die Koordinaten im WMS nicht mehr als Dezimalgrad an, sondern in irgendeinem anderen Format. 123423.76 - so in etwa sehen die Daten aus.

Nun ist die Frage, wie ich die Hintergrundkarte bzw. das Script so umstellen kann, dass mein WMS wieder korrekt angezeigt wird. Ziel wäre nichts am WMS zu ändern, da ich dort schön verzerrungsfreie Dezimalgradkoordinaten als Basis nutze. Andernfalls müsste ich dann wahrscheinlich umrechnen - aber in welches System? Ich kann nirgendwo etwas dazu finden, welches Standardsystem genutzt wird, wenn der OSM Layer gerufen wird. Mich wundert auch, dass ein WMS Layer scheinbar den Standard automatisch umstellt und ein dazugeschalteter OSM layer ebenfalls sein System drüberstülpt.

Anbei mein Minimal-Script:

var map = new OpenLayers.Map(‘map’);

// OSM Layer - wenn ich den zuschalte, kommt vom WMS nur noch Unfug
//var layer = new OpenLayers.Layer.OSM();
//map.addLayer(layer);

// Tile-Server aus den OpenLayers-Examples
var layer = new OpenLayers.Layer.WMS( “OpenLayers WMS”,
http://vmap0.tiles.osgeo.org/wms/vmap0”, {layers: ‘basic’}, { transitionEffect: ‘resize’ });
map.addLayer(layer);

// Mein eigener WMS
var mein_wms_layer = new OpenLayers.Layer.WMS(“Daten”,
“…/render_wms.php”, {layers: ‘basic’},
{ singleTile: true, ratio: 1 } );
mein_wms_layer.addOptions({isBaseLayer: false});
map.addLayer(mein_wms_layer);

map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToMaxExtent();

Sobald Du einen OpenLayers.Layer.OSM als Grundkarte nimmst, ist Deine Karte in Mercatorprojektion (EPSG:900913) (steht da).

Du müsstest also dein WMS auch dazu überreden das in dieser Projektion auszuliefern.

Grüße, Max

Danke

Kennt jemand einen Link, der die Programmierung eines WMS-Bildes mit Mercator beschreibt? Ich bin nach stundenlanger Suche bisher nicht fündig geworden. im Grunde muss ja ein Script her, was aus gegebenen maxlat-minlat-maxlong-minlong Werten eine Berechnung von Pixel-Punkten innerhalb der gegebenen Bildgrenzen bietet, damit dieses Bild als WMS-Overlay fungieren kann.

Ich finde es erstaunlich, so wenig darüber im Netz zu finden. Eine reine Berechnung von Koordinaten nützt hier ja keinem etwas, da ein Verhältnis zum rechtwinkligen Grafikbereich hergestellt werden muss, um darauf dann Informationen zu zeichnen (also letztlich eine Funktion zeichne_punkt(x,y) die dann innerhalb des Bildes mit Mercator Punkte setzen kann). Man könnte auch eine andere Projektion erzeugen und dieses Bild dann transformieren, aber das kann ja nicht das Ziel sein, dann mit Verzerrungen im WMS-Bild zu leben. Das Ausgangsbild muss also bereits Mercator sein.

Ähm wirf doch mal einen Blick hierauf: http://wiki.openstreetmap.org/wiki/DE:Installation_und_Verwendung_von_MapServer_f%C3%BCr_Aerowest_Luftbilder
Setzt natürlich voraus, das die Bilder georeferenziert sind.
Auf Seite zwei gibt es noch einen weiteren Thread der sich mit WMS Servern beschäftigt.

ich verstehe Dein Problem nicht so recht. Die Projektion des Ausgangsmaterial ist eigentlich egal. Ich habe meist Daten in WGS84, aber auch exostische Formate. OL fordert es in 900913 an. Es ist nur wichtig, dass der Mapserver das auch in 900913 ausliefern kann. Irgendwelche Kunststücke mit umprogrammieren sind eigentlich nicht nötig.

Schau mal ob bei Dir sowas in der Mapfile steht


    WEB
        METADATA
                        "wms_title"     "Thomas WMS-Server"
                        "labelcache_map_edge_buffer" "-10"
                        "wms_onlineresource" "to_be_replaced_by_wms.py"
                        "wms_srs"       "EPSG:4326 EPSG:900913"
                        "wms_connectiontimeout" "240"
        END

Wichtig ist noch, dass in Deiner epsg Datei (bei mir unter /usr/share/proj/epsg) eine Definition für 900913 hinterlegt ist. Wenn nicht, ergänze


#Google
<900913> +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +no_defs <>

Nur der Vollständigkeit halber. Bei mir sieht ein WMS Layer in OL so aus


        wmsdefault = new OpenLayers.Layer.WMS( "name","http://blablub.net/wms?", {
                        layers: 'default',
                        isBaselayer:true,
                        projection:new OpenLayers.Projection("EPSG:900913"),
                        format: 'aggpng24'
                });

Vielleicht sollten wir erstmal wissen, welche Software hinter diesem WMS steckt…

Falls es ein (UMN-) Mapserver ist, steht die Lösung schon da, bei anderen wird sich das auch finden lassen. Bei Selbstgetipptem kann man bestimmt irgendwie proj.4 einbinden, alles selber umrechnen stelle ich mir schwer vor (das Ellipsoid würde mir sorgen machen)…

Grüße, Max

Das Problem kann ich versuchen noch einmal konkret zu beschrieben. Ich spreche mit dem Aufruf meines Single-Tile-Layers in OpenLayers ein eigenes Script an, was dieses Single-Tile-Bild erstellt, Informationen platziert und ausliefert.

OpenLayers erzeugt dabei eine Anfrage an das Script und übermittelt eine BoundingBox sowie die Tilegröße. Beispiel:

LAYERS->basic
SERVICE->WMS
VERSION->1.1.1
REQUEST->GetMap
STYLES->
EXCEPTIONS->application/vnd.ogc.se_inimage
FORMAT->image/jpeg
SRS->EPSG:900913
BBOX->-61991041.4244,-29156140.063875,61991041.4244,29156140.063875
WIDTH->1584
HEIGHT->745

Ich habe jetzt schon einiges darüber gelesen, wie man Koordinaten in spherical mercator umwandelt und irgendwelche Tile-Nummern errechnet. Was mir aber bisher nicht erschließt ist, wie ich aus der gegebenen Boundingbox und Tile-Größe die korrekten Pixel-Positionen meiner Daten auf dem Tile-Bild berechne.

Gegeben sei also eine Bounding-Box in Mercator-Koordinaten (also 4 Stück) und die Pixelgröße des Tiles. Gesucht ist die Formel, um für Koordinate x/y den entsprechenden Pixel auf dem Bild zu bekommen.
Ergebnis ist ein fertiges Bild in Mercatorprojektion, was dann von OpenLayers korrekt über die OSM-Karte gelegt wird.

Mit meiner bisher genutzten Plattkarte ist das ja alles kein Problem, da berechne ich die Pixelpositionen mit einer linearen Funktion. Bei Mercator gibt es aber Verzerrungen. Diverse Formeln im Netz, die mit irgendwelchen Zoom-Faktoren arbeiten helfen mir hier ja auch wenig.

Hast du einfach mal überlegt einen echten wms Server zu benutzen? Deine Daten in die Datenbank und dann macht sich der Mapserver die Arbeit.

In meinem o.g. Beispiel macht OL genau das gleiche wie bei Dir. Auch bei mir wird vom WMS ein Bild in diesen komischen Koordinaten angefordert. Das stört aber den WMS nicht. Der liefert die korrekten Tiles an der richtigen Stelle aus. Wofür willst Du die Pixel-Position auf den Tiles berechnen?

Dein Single Tile Layer liegt in einer bestimmten Projektion vor. Das sagst Du dem WMS. Dann sagst Du Deinem WMS, dass er auch in 900913 ausliefern darf. Mit OL forderst Du es dann in 900913 an. Der Rest geht automatisch.

Ich glaube das Problem ist anders. Er hat eben keine vorberechneten Bilder, sondern nur Icons, welche ständig ihre Position ändern. Der WMS Server exitiert also nicht wirklich sondern es wird dann ein Bild (oder mehrer) für die jeweilige Boundingbox berechnet. Und um diese Bilder zu berechnen möchte er wissen an welcher stelle die POIs auf transparenten Untergrund gemalt werden müssen.
An der Stelle halte ich es für sinnvoller die Bilder live mit mapnik zu rendern. Es ist ja dann immer nur ein POItyp je Layer und geht daher recht schnell.
Vielleicht reicht dafür auch Kosmos, der ist nicht ganz so anspruchsvoll im Toolchain.

Ich kann keinen Mapserver benutzen, weil die Tiles eigene Daten beinhalten und als Overlay genutzt werden sollen. Ich glaube nicht, dass der Mapserver meine Daten darstellen kann und zudem wird er damit wesentlich langsamer sein. Es handelt sich um zehntausende Datenpunkte, die auf dem Single-Tile mittels Grafik-Script gemappt werden sollen. Was auch erwähnt werden sollte ist, dass die Daten nicht vorproduziert oder gerendert werden können. Die ändern sich permanent und es muss jeweils ein Live-Bild vom WMS ausgeliefert werden.

Ich benötige einfach nur einen Hinweis darauf, wie man sich sein eigenes Tile rendern kann über verallgemeinerte Formeln. Wie lösen das all die Anbieter von entsprechenden Overlays? Die müssen doch im Hintergrund auch einen Renderer haben, der über die Boundingbox und die Tilegröße entsprechende Pixel setzt. Es ist erstaunlich, dass darüber so gut wie keine Lektüre existiert. Wenn ich das Script irgendwann fertig habe, werde ich es sicher veröffentlichen. ich denke schon, dass mancheiner dafür Verwendung findet, um einfach mal fix flexible Overlays mit eigenen Daten zu erzeugen.

In welcher Sprache ist Dein Script?

Wenn Du vor der Ausgabe die Koordinaten konvertieren könntest (z.B. mit proj, gdaltransform…), könntest Du mit den umgewandelten Koordinaten linear weiterrechnen.

Also meiner Meinung nach du hast zwei Möglichkeiten. Entweder wie Mapnik/openstreetmap.org in kleinen Zoomstufen live rendering. Wenn du Tiles du einfach mal probierst in Kosmos braucht ein einzelnes Tile nur wenig Rechenzeit. Insbesondere wenn nur wenige Details darin enthalten sind.

Die zweite Möglichkeit ist die Auswertung der Boundigbox und dann eine Abfrage in der Datenbank welche Tiles das betrifft und daraus dann eine Featuredatei erzeugen, die ausgeliefert wird. Dann setzt OL die POIs. Aufgrund der kleinen Boundigbox sind die Daten dann vielleicht auch händelbar.

Das schreit eigentlich schon nach einer Datenbank.
Mapserver (oder geoserver) kann sich die benötigten Daten direkt aus der Datenbank holen, rendern und in jeder gewünschten Projektion als Bild ausliefern.

Gruß,
ajoessen

Also es kommt wirklich nur ein Single-Tile mit Grafikoverlay möglich. Aus Performancegründen. Ihr könnt ja mal testen, 50000 Pois auf einer Karte zu visualisieren, das geht nur per Overlaygrafik.

Das Script ist in PHP gehalten. Die Daten (keine Pois, es sind wissenschaftliche Daten) stehen in einer Datenbank mit Dezimalgrad-Koordinaten. Die große Keule mit Mapnik o.Ä. rauszuholen brächte sicher bis auf Serverlast keine Punkte. Es scheint nicht einfach zu sein, einfach nur ein Single-Tile ohne Zusatzsoftware mit gegebener Bounding-Box zu erstellen. Im Grunde ist es vielmehr ein mathematisches Problem, als eine Softwarefrage. Die gängigen WMS-Systeme müssen das aber irgendwie dennoch gelöst haben, die bekommen ja auch nicht mehr als eine Boundingbox und Tilegröße (nur dass es dort eben oft mehrere Standard-Tiles sind, während ich Single-Tile habe)

hat Dein Single Tile immer genau die gleiche Ausdehnung? Falls ja, könntest Du einmal eine worldfile erzeugen (georeferenzieren). Und Dein Single Tile jeweils durch die aktuelle Version ersetzen. Das würde sich dann recht einfach per WMS ausliefern lassen.

Wegen dem Umrechnen: Hilft Dir das?
http://turbo.uni-hohenheim.de/wiki/index.php/Koordinatensysteme#Umrechnung_von_Koordinaten

Nein, das Single-Tile hat immer neue Abmessungen, je nach Zoom & Kartenausschnitt des Nutzers. Ich könnte ein Worldfile erzeugen, aber dann würde man beim Reinzoomen keine Details erkennen, da dann ja eine Grafikvergrößerung stattfindet. Ziel ist schlichtweg dass jeder beliebige Input von BBOX+Tile_größe_X+Tile_größe_Y zu einer Output-Grafik generiert wird.

Ich schau mir den Link mal eben an, danke.

Der mapserver kann auch selber die Daten aus der Datenbank abfragen, rendern und ausliefern.
Und zwar nur die Daten, die im aktuell angefragten Bildschirmbereich liegen. Man muss halt ein passendes Style-file dazu schreiben.
Die 50000 POI sind sicherlich nicht alle auf einmal zu sehen, oder? Sonst müsste man bei dieser Zoomstufe auf Clustering ausweichen.

Gruß,
ajoessen

Die sind alle zu sehen und dürfen sich ruhig überlagern. Das ist so gewollt. Deswegen nutze ich ja auch ein Single-Tile, da muss ich mir keine Gedanken über Performance machen.

Ich werde mir das mit dem Mapserver mal reinziehen, aber stylefile schreiben usw. klingt schonmal nicht gut. Im Grunde bräuchte ich nur die Kartenprojektionsroutine, ohne Schnickschnack rundherum. Icons usw. habe ich ja ohnehin schon in meinem Script einprogrammiert - nur die Zeichenposition auf dem Tile wird benötigt.