Nachdem ich mich eine Weile aus der GIS-Welt zurückgezogen hatte, begann ich mit der Arbeit an einem neuen Projekt, bei dem ich die derzeit verwendete Software durch eine Open-Source-Alternative ersetzte. Die erste kleine Anwendung, die erstellt werden musste, war für eine Notrufzentrale, um die Position des Anrufers auf einer Karte anzuzeigen. Danach sollten ein paar Prototypen beweisen, dass es machbar war, den aktuellen Software-Stack durch Open-Source-Alternativen zu ersetzen. In diesem Blog beschreibe ich die verwendeten Tools, ein paar der Probleme, auf die ich gestoßen bin, und natürlich die Lösungen für die Probleme, die Programmierung und Kommunikation beinhalten ;-)
Die verwendeten Tools waren ein Java-basierter Server namens Geoserver und eine clientseitige JavaScript-Bibliothek namens OpenLayers.
Geoserver
GeoServer ist ein Server, mit dem Benutzer Geodaten gemeinsam nutzen und bearbeiten können. Er ist die Implementierung der Standards Web Feature Service (WFS) und Web Map Service (WMS) des Open Geospatial Consortium (OGC).
WMS
Ein Web Map Server veröffentlicht Karten. Kurz gesagt, er wird verwendet, um Bilder aus allen möglichen verschiedenen räumlichen Quellen wie Datenbanken (z.B. Postgis, Oracle Spatial), Dateien (wie Esri Shapefiles, GML (Geography Markup Language), MapInfo) usw. zu erstellen. Es kann auch verwendet werden, um einige zusätzliche Informationen zu erhalten, die mit den geografischen Daten gespeichert sind.
WFS
Ein Web Feature Server ist eine Schnittstelle zum Abrufen, Bereitstellen oder Ändern von geografischen Vektordaten. Er verwendet das GML-Format für die Kommunikation zwischen Client und Server.
OpenLayers
OpenLayers ist eine Open-Source-JavaScript-Bibliothek für die Anzeige geografischer Daten in einer reichhaltigen Webumgebung. Die API kann zur Erstellung von Google Maps-ähnlichen Anwendungen verwendet werden.
Herausforderungen
Bei meinem aktuellen Auftrag stand ich in verschiedenen Teilen der Anwendung vor einigen Herausforderungen. Im nächsten Teil dieses Blogs möchte ich die von mir verwendeten Lösungen erläutern. Ich hoffe, dass jemand davon profitieren wird. Bei jeder Lösung werde ich auch einige der Techniken erläutern, die im GIS-Bereich verwendet werden.
Reprojektion
Eines der Probleme bei der Anwendung, die die Position des mobilen Anrufers anzeigt, war die Genauigkeit der Position. Die Positionsdaten wurden in WGS84 (World Geodetic System) bereitgestellt. Dieses Koordinatenreferenzsystem wird auch für GPS-Koordinaten verwendet. Da die Koordinaten jedoch auf eine Karte der Niederlande übertragen werden mussten, die in einem anderen Koordinatenreferenzsystem (RD) erstellt wurde, mussten die Koordinaten transformiert werden (dies wird Reprojektion genannt).
Das Transformieren zwischen zwei Koordinatensystemen erfordert schwierige mathematische Formeln, aber OpenLayers ist darauf vorbereitet, die Proj4js-Bibliothek zu verwenden, die dies für Sie sehr vereinfacht.
Mit einer einfachen Anweisung wie dieser können Sie also zwischen 2 verschiedenen Projektionen wechseln:
//transform von wgs84 nach rijksdriehoeks 28992
markerLocation =new OpenLayers.LonLat(x,y);
markerLocation.transform(new OpenLayers.Projection('EPSG:4326'),
new OpenLayers.Projection('EPSG:28992'));
Der Haken an der Sache war, dass die Definition für die Projektion EPSG:28992 genau sein musste, damit die Markierung an der richtigen Stelle platziert werden konnte. In unserem Fall war der Teil +to_wgs der Definition sehr wichtig!
Proj4js.defs['EPSG:28992'] = '+title=Amersfoort / RD Neu EPSG:28992 +proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=1.0 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.,49.9,465.8,-0.409,0.36,-1.869,4.08 +Einheiten=m';
Anzeige der aktuellen Position
Eine weitere Anwendung wurde entwickelt, um die Position von Autos auf der Karte der Niederlande anzuzeigen. Mit der richtigen Konfiguration von Geoserver und einem WFS-Layer in OpenLayers war das gar nicht so schwierig. Zumindest nicht auf den ersten Blick.
Das Problem dabei war, dass die Positionen alle 5 Sekunden in der Datenbank aktualisiert wurden, so dass die Ansicht im Browser ebenfalls alle 5 Sekunden aktualisiert werden musste.
layer.refresh({force: true});
Nicht viel Code für eine solche Funktionalität, und es hat funktioniert. Zumindest für etwa 30 Minuten, bis der Browser abstürzte. Was?
Es schien, dass der Browser nach jeder Aktualisierung mehr und mehr Speicher beanspruchte. Irgendwo gab es also ein Speicherleck. Es stellte sich heraus, dass es an der Art lag, wie OpenLayers seine Elemente auf der Seite zeichnet. Dies geschieht durch DOM-Manipulation (element.appendChild und element.removeChild).
Das Problem ist, dass die removeChild-Methode das Kind aus dem visuellen Bereich entfernt, aber eine Referenz im Speicher behält. Dieser Verweis kann verwendet werden, um das Element wieder aufzurufen und es anzuzeigen (weil Sie es versehentlich entfernt haben??). Dieser Speicherplatz wird nur dann gelöscht, wenn eine neue Seite geöffnet wird. Heutzutage öffnen Ajax-ähnliche Anwendungen jedoch keine neue Seite mehr, daher das Speicherleck.
Für den IE (den verwendeten Browser) ist dies ein Konstruktionsfehler, so dass die Hoffnung, dass es in neueren Versionen eine Lösung gibt, gleich Null ist.
Glücklicherweise gibt es eine Abhilfe, mit der Sie das Memory Leak eindämmen können.
Abhilfe
OpenLayers.Util.discardElement = function(element) {
var garbageBin = document.getElementById('IELeakGarbageBin');
if (!garbageBin) {
garbageBin = document.createElement('DIV');
garbageBin.id = 'IELeakGarbageBin';
garbageBin.style.display = 'keine';
document.body.appendChild(garbageBin);
}
// Verschieben Sie das Element in den Mülleimer
versuchen {
garbageBin.appendChild(element);
}
catch(e) {
//Tun Sie nichts
}
garbageBin.innerHTML = '';
if (element.removeNode) element.removeNode(false);
//Löschen Sie das Element;
};
Berechnung der Entfernung
Auf zur nächsten Herausforderung. Eine der Anforderungen war, dass alle Marker innerhalb einer bestimmten Entfernung von einer Region sichtbar sein sollten. Stellen Sie sich eine solche Region vor, die aus über 40.000 Punkten besteht. Die Bestimmung, ob ein Punkt innerhalb von, sagen wir, 10 Kilometern von dieser Region liegt, ist also keine einfache Berechnung. Die Oracle Spatial-Datenbank verfügt über eine entsprechende Funktion, aber die Berechnung für alle Marker war nicht schnell genug (der Client wurde alle 5 Sekunden aktualisiert!).
Die Lösung bestand darin, die Anforderung ein wenig zu ändern und nur die Markierungen innerhalb einer bestimmten Entfernung von einem Punkt anzuzeigen. Dies war eine einfache Berechnung und konnte mit einer Abfrage an den Geoserver erledigt werden
komplexe Typen
Das nächste Problem war die Verwendung komplexer Geometrien. Oracle Spatial unterstützt Kurven und so weiter, aber Geoserver kann nur einfache Geometrietypen wie Punkte, Linienzüge, Polygone, Multilinienzüge und Multipolygone lesen.
Zu meinem Glück fand ich heraus, dass in der Definition einer komplexen Geometrie auch eine einfache Geometrie gekapselt ist. Alles, was ich brauchte, war ein kleiner Code, um diese einfache Geometrie aus der komplexen Geometrie zu extrahieren und voila:
Hier ist der Code-Schnipsel:
if ((L == 0) && (TT == 01) && (point != null) && (elemInfo == null)) {
// Ein-Punkt-Typ-Optimierung
coords = SDO.coordinates(gf.getCoordinateSequenceFactory(), GTYPE,
Punkt);
elemInfo = new int[] { 1, ETYPE.POINT, 1 };
} sonst {
int element = 0;
int etype = ETYPE(elemInfo, element);
if (etype == 0) {
// komplexer Typ, Suche nach gekapseltem Simpletyp (mit etype != 0)
int startpointCoordinates = 0;
// suchen Sie nach einem einfachen
while (etype == 0) {
element++;
etype = ETYPE(elemInfo, element);
startpointCoordinates = STARTING_OFFSET(elemInfo, element);
}
// wenn wir den einfachen Fallback gefunden haben, lesen Sie ihn
if (etype != -1) {
int ol = ordinates.length;
int elemsToCopy = ol - (startpointCoordinates - 1);
double[] newOrdinates = new double[elemsToCopy];
System.arraycopy(ordinates, startpointCoordinates - 1, newOrdinates, 0, elemsToCopy);
elemInfo = new int[] { 1, etype, INTERPRETATION(elemInfo, element) };
ordinates = newOrdinates;
}
}
coords = SDO.coordinates(gf.getCoordinateSequenceFactory(), GTYPE,
ordinates);
}
return create(gf, GTYPE, SRID, elemInfo, 0, coords, -1);
So weit einige der Herausforderungen, auf die ich bei der Verwendung von OpenSource GIS-Software gestoßen bin. Mir ist aufgefallen, dass sowohl die openLayers- als auch die Geoserver-Community sehr hilfsbereit sind und dass beide Projekte mit jeder neuen Version besser werden.
Mal sehen, was die Zukunft dieses Projekts bringt, wenn wir den Client für mindestens 8 Stunden am Stück verfügbar haben müssen. Ich denke, der Browser (zumindest der IE) kommt nicht in Frage. Ich freue mich darauf, die Möglichkeiten einer Flex-Client-Anwendung zu untersuchen.
Verfasst von
Kris Geusebroek
Unsere Ideen
Weitere Blogs
Contact



