ehemalige Veranstaltungen ia3.netz + ia3.data sowie ia4.Netz im Studiengang Interaktive Medien
(c) 2020 Hochschule Augsburg - Fakultät für Informatik - Prof.Dr.Nik Klever
Ortsbezogene Daten basieren auf dem Geografischen Koordinatensystem, welches einem Koordinatensystem auf einer Kugel mit den Breitengraden $\varphi$ und den Längengraden $\lambda$:
Mit der Einführung des GPS-Systems ab 1995 und insbesondere seit der Freigabe für die öffentliche Nutzung im Jahr 2000 hat sowohl die Navigierung als auch die Datenhaltung standortbestimmter Informationen exponentiell zugenommen. In welchem Kfz ist heute kein Navi enthalten ? Und wer benutzt heutzutage sein Smartphone nicht, um Restaurants, Museen, Events, billigste Tankstellen, Bankautomaten, etc., etc. im Umkreis seines aktuellen Standorts zu finden ?
Das GPS System bzw. jedes globale Satellitennavigationssystem beruht auf der Bestimmung der Entfernung eines Satelliten zu einem entsprechenden GPS-Empfänger über die Signallaufzeit eines von diesem Satelliten ausgesendeten Signals. Wenn die Entfernung zu mindestens 3 Satelliten bekannt ist, kann der Schnittpunkt dreier Kugelflächen berechnet werden. Mindestens ein weiterer Satellit ist notwendig, um die Uhrzeit im GPS-Empfänger zu synchronisieren, sodass letztendlich damit die aktuelle Position (d.h. die Koordinaten) auf der Erdoberfläche bestimmt werden kann.
Die Koordinaten bestimmen zwar die aktuelle Position auf der Erdoberfläche, aber ohne eine dazugehörige Karte sind diese Koordinaten in der Regel nutzlos. Basis aller heutigen Kartendarstellungen ist die sogenannte Mercator-Projektion, welches die Kugelform der Erde in eine winkelgetreue flächige Darstellung projeziert.
Basis allen Kartenmaterials bis ins letzte Drittel des vergangenen Jahrhunderts war die Arbeit und Aufzeichnung der Vermessungsämter, die im staatlichen Auftrag die Aktualisierung aller geobasierten Daten u.a. auch mit regelmäßigen Luftaufnahmen durchführen. Alle Karten (Strassenkarten, Ortskarten, Wanderkarten, etc.) bauen in der Regel auf Daten der Vermessungsämter auf. Erst mit dem Aufkommen globaler und kommerziell verfügbarer Satellitendaten beschäftigen sich auch andere Organisationen mit der Erstellung von Karten.
OpenStreetMap hat keine eigene API, aber es gibt andere JavaScript Karten Bibliotheken, die hierfür verwendet werden können. Die bekanntesten sind
Leaflet.js hat eine kompaktere und einfachere API, wohingegen OpenLayers eine umfangreichere API besitzt.
In einer Wegaufzeichnung (Tracking) liegen eine Anzahl von Orts-Daten entlang eines Weges in einer Datei wegdaten.csv im CSV Format mit Längengrad, Breitengrad und Höhe pro Zeile vor, d.h. pro Zeile ist ein Ortsdatum mit Längengrad;Breitengrad;Höhe\n aufgezeichnet.
f = open('wegdaten.csv','r')
gesamterInhalt = f.read()
f.close()
zeilen = gesamterInhalt.split('\n')
print("erste Zeile: "+zeilen[0])
print("zweite Zeile: "+zeilen[1])
# Löschen der letzten Zeile, wenn diese leer ist
if not zeilen[-1]: del zeilen[-1]
print("letzte Zeile: "+zeilen[-1])
# Anzahl der Wegdaten
print(len(zeilen)-1)
# Überschrift in der ersten Zeile
ueberschrift = zeilen[0].split(';')
# erstes Wegdatum in der zweiten Zeile
einErstesWegDatum = zeilen[1].split(';')
for i in einErstesWegDatum:
print(i)
for i in einErstesWegDatum:
print(i)
print(type(i))
x=float(i)
print(type(x))
wegDatumAlsDictionary = dict(lon=einErstesWegDatum[0],lat=einErstesWegDatum[1],alt=einErstesWegDatum[2])
print(wegDatumAlsDictionary)
wegDatumAlsDictionary = {'lon':einErstesWegDatum[0],'lat':einErstesWegDatum[1],'alt':einErstesWegDatum[2]}
print(wegDatumAlsDictionary)
wegDatumAlsDictionary = dict((('lon',einErstesWegDatum[0]),('lat',einErstesWegDatum[1]),('alt',einErstesWegDatum[2])))
print(wegDatumAlsDictionary)
spaltendefinition = zeilen[0].split(';')
print(spaltendefinition)
wegDatumAlsDictionary = dict(((spaltendefinition[0],einErstesWegDatum[0]),
(spaltendefinition[1],einErstesWegDatum[1]),
(spaltendefinition[2],einErstesWegDatum[2])))
print(wegDatumAlsDictionary)
siehe Python Tutorial
spaltendefinition = zeilen[0].split(';')
print(spaltendefinition)
listcomprehension = [(spaltendefinition[x], einErstesWegDatum[x]) for x in range(len(spaltendefinition))]
print(listcomprehension)
wegdatum = dict(listcomprehension)
print(wegdatum)
spaltendefinition = zeilen[0].split(';')
print(spaltendefinition)
listcomprehension = [(spaltendefinition[x], float(einErstesWegDatum[x])) for x in range(len(spaltendefinition))]
print(listcomprehension)
wegdatum = dict(listcomprehension)
print(wegdatum)
class Ort(object):
def __init__(self,lon,lat,alt=0.0):
self.lon = lon
self.lat = lat
self.alt = alt
def getKoord(self):
return (self.lon,self.lat,self.alt)
def setKoord(self,lon,lat,alt=0.0):
self.lon = lon
self.lat = lat
self.alt = alt
spaltendefinition = zeilen[0].split(';')
print(spaltendefinition)
wegdatum = Ort(float(einErstesWegDatum[0]),float(einErstesWegDatum[1]),float(einErstesWegDatum[2]))
print(wegdatum.getKoord())
class Ort(object):
def __init__(self,kw):
self.lat = kw['lat']
self.lon = kw['lon']
if 'alt' in kw:
self.alt = kw['alt']
else:
self.alt = 0.0
def getKoord(self):
return dict(lon=self.lon,lat=self.lat,alt=self.alt)
def setKoord(self,lon,lat,alt):
self.lon = lon
self.lat = lat
self.alt = alt
spaltendefinition = zeilen[0].split(';')
print(spaltendefinition)
listcomprehension = [(spaltendefinition[x], float(einErstesWegDatum[x])) for x in range(len(spaltendefinition))]
dictionary = dict(listcomprehension)
wegdatum = Ort(dictionary)
print(wegdatum.getKoord())
# bzw. in einer Zeile
wegdatum = Ort(dict([(spaltendefinition[x], float(einErstesWegDatum[x])) for x in range(len(spaltendefinition))]))
print(wegdatum.getKoord())
f = open('wegdaten.csv','r')
gesamterInhalt = f.read()
f.close()
zeilen = gesamterInhalt.split('\n')[:-1]
spaltendefinition = zeilen[0].split(';')
alleWegDaten = []
for zeile in zeilen[1:]:
spalten = zeile.split(';')
listcomprehension = [(spaltendefinition[x], float(spalten[x])) for x in range(len(spalten))]
wegdatum = dict(listcomprehension)
alleWegDaten.append(wegdatum)
class Ort(object):
def __init__(self,kw):
self.lat = kw['lat']
self.lon = kw['lon']
if 'alt' in kw:
self.alt = kw['alt']
else:
self.alt = 0.0
def getKoord(self):
return dict(lon=self.lon,lat=self.lat,alt=self.alt)
def setKoord(self,lon,lat,alt):
self.lon = lon
self.lat = lat
self.alt = alt
f = open('wegdaten.csv','r')
gesamterInhalt = f.read()
f.close()
zeilen = gesamterInhalt.split('\n')[:-1]
spaltendefinition = zeilen[0].split(';')
alleWegDaten = []
for zeile in zeilen[1:]:
spalten = zeile.split(';')
wegdatum = Ort(dict((spaltendefinition[x], float(spalten[x])) for x in range(len(spalten))))
alleWegDaten.append(wegdatum)
siehe Google Static Maps API Developer Guide
Holen sie sich auf der dortigen Seite einen entsprechenden API-Schlüssel
Ausgehend von der URL http(s)://maps.googleapis.com/maps/api/staticmap? können an diese URL diverse Parameter angehängt werden.
Notwendig ist immer der Parameter
sinnvoll ist der Parameter
und Wegpunkte können mit dem Parameter
gesetzt werden.
GOOGLEAPIKEY = "............" # setzen sie hier ihren API-Schlüssel ein
url = "http://maps.googleapis.com/maps/api/staticmap?size=640x640&maptype=satellite&key={}".format(GOOGLEAPIKEY)
url += "&markers=color:blue"
for wegdatum in alleWegDaten:
url += "|{:.6f},{:.6f}".format(wegdatum.lat,wegdatum.lon)
#
# statt der obigen Zeile würde ebenfalls gehen
#
# url += "|{lat:.6f},{lon:.6f}".format(**wegdatum.getKoord())
print(url)
from IPython.display import Image
Image(url=url)
Erweiterung der obigen Anwendung in der Art, dass alle Punkte, die in einem bestimmten Umkreis um den folgenden Mittelpunkt (longitude, latitude) und Radius (radius - Dimension in m
) liegen, mit andersfarbigen Markern versehen werden.
longitude = 10.906
latitude = 48.358867
radius = 100
mittelpunkt = Ort(dict(lat=48.358867,lon=10.906,alt=0))
url = "http://maps.googleapis.com/maps/api/staticmap?size=640x640&maptype=satellite&key={}".format(GOOGLEAPIKEY)
url += "&markers=color:green|{:.6f},{:.6f}".format(mittelpunkt.lat,mittelpunkt.lon)
url += "&markers=color:blue"
for wegdatum in alleWegDaten:
url += "|{:.6f},{:.6f}".format(wegdatum.lat,wegdatum.lon)
Image(url=url)
siehe Erich Seifert's Java-Python Vergleich
Zur Herleitung der Formel des Abstands auf einer Kugel siehe den Wikipedia-Beitrag zu Orthodrome
import math
class Ort(object):
def __init__(self,kw):
self.lat = kw['lat']
self.lon = kw['lon']
if 'alt' in kw:
self.alt = kw['alt']
else:
self.alt = 0.0
def getKoord(self):
return dict(lon=self.lon,lat=self.lat,alt=self.alt)
def setKoord(self,lon,lat,alt):
self.lon = lon
self.lat = lat
self.alt = alt
def abstand(self,zweiterort,typ="Kugel"):
if typ == "Flaeche": # Berechnung des Abstands auf einer Fläche
return math.sqrt((self.lon - zweiterort.lon)**2+(self.lat - zweiterort.lat)**2)*111
else: # Berechnung des Abstands auf einer Kugel
RadiusErde = 6371000 # mittlerer Radius der Erde in m
lat1 = math.radians(self.lat)
lat2 = math.radians(zweiterort.lat)
lon1 = math.radians(self.lon)
lon2 = math.radians(zweiterort.lon)
return math.acos(math.sin(lat1) * math.sin(lat2) + \
math.cos(lat1) * math.cos(lat2) * math.cos(lon2-lon1)) * RadiusErde
f = open('wegdaten.csv','r')
gesamterInhalt = f.read()
f.close()
zeilen = gesamterInhalt.split('\n')[:-1]
spaltendefinition = zeilen[0].split(';')
alleWegDaten = []
for zeile in zeilen[1:]:
spalten = zeile.split(';')
wegdatum = Ort(dict((spaltendefinition[x], float(spalten[x])) for x in range(len(spalten))))
alleWegDaten.append(wegdatum)
mittelpunkt = Ort(dict(lat=48.358867,lon=10.906,alt=0))
radius = 100
url = "http://maps.googleapis.com/maps/api/staticmap?size=640x640&maptype=satellite&key={}".format(GOOGLEAPIKEY)
url += "&markers=color:green|{:.6f},{:.6f}".format(mittelpunkt.lat,mittelpunkt.lon)
url += "&markers=color:blue"
for wegdatum in alleWegDaten:
if wegdatum.abstand(mittelpunkt) > radius:
url += "|{:.6f},{:.6f}".format(wegdatum.lat,wegdatum.lon)
url += "&markers=color:red"
for wegdatum in alleWegDaten:
if wegdatum.abstand(mittelpunkt) < radius:
url += "|{:.6f},{:.6f}".format(wegdatum.lat,wegdatum.lon)
Image(url=url)
GPX ist ein einfaches XML basiertes Dateiformat zum Abspeichern und Austauschen von Geodaten. Es wurde 2002 von der Fa. TopoGrafix entwickelt und als XML Schema auf deren Webseite Documentation in der Version 1.1 freigegeben.
Eine gute Einführung zu GPX zusammen mit einem einfachen Beispiel findet sich auf der Wikipedia Webseite GPS Exchange Format.
Entsprechend den Beispielen im Skript XML Programmieren Teil 1), wird im folgenden ein SAX-Parser erstellt der den Inhalt einer GPX-Datei verwendet und wie im vorangegangenen Beispiel alle Wegdaten in einer Liste von Objekten des Typs Ort abspeichert.
Die obige Wegaufzeichnung (Tracking) liegt ebenfalls in einer Datei wegdaten.gpx im GPX Format vor. Sie erkennen an der Datei, dass Längengrad und Breitengrad als Attribute des GPX-Tags trkpt und die Höhe als Inhalt des Elements ele enthalten ist. Diese Daten gilt es als Instanzen der Klasse Ort wie im Beispiel der CSV-Datei in einer entsprechende Liste zu speichern.
from xml.sax import make_parser, parseString, handler, SAXException, SAXParseException
class SAXGPXParser(handler.ContentHandler, Ort):
def __init__(self):
self.alleWegDaten = []
self.aktuellerName = ''
def startElement(self, name, attrs):
self.aktuellerName = name
if name == 'trkpt':
self.wegdatum = {}
for attr in attrs.getNames():
self.wegdatum[attr] = float(attrs.getValue(attr))
def characters(self, content):
if self.aktuellerName == 'ele':
self.wegdatum['alt'] = float(content)
self.alleWegDaten.append(Ort(self.wegdatum))
def endElement(self, name):
self.aktuellerName = ''
f = open('wegdaten.gpx','r')
gesamterInhalt = f.read()
f.close()
instanz = SAXGPXParser()
parseString(gesamterInhalt,instanz)
print(instanz.alleWegDaten[0].getKoord())
KML ist im Gegensatz zu GPX ein sehr komplexes XML basiertes Dateiformat zum Abspeichern und Austauschen von Geodaten. Die Fa. Keyhole wurde 2004 von Google übernommen und wird seitdem auch von Google weiterentwickelt. 2008 wurde die Version 2.2 - für die ein gutes Google Developers Tutorial exisitiert - vom Open Geospatial Consortium als Standard anerkannt und übernommen.
Die obige Wegaufzeichnung (Tracking) liegt ebenfalls in einer Datei wegdaten.kml im KML Format vor.
Erweitern sie die Geolocation Anwendung in der Art, dass die gesamte bisherige Anwendung mit einer Klasse class WegDaten dargestellt wird, die folgenden drei Methoden besitzt und in der die einzelnen Wegpunkte als Instanzen der Klasse Ort verwendet werden:
__init__(self,filename_oder_url)
parseCSV(self)
writeGoogleStaticMapsUrl(self,lon,lat,alt,radius)
Es macht Sinn die Klassen Ort, SAXGPXParser und WegDaten in einer Datei GeoLocation.py zusammenzufügen.
Die Initialisierung der Instanz von WegDaten, der Aufruf der Instanzmethoden parseCSV bzw. parseGPX und writeGoogleStaticMapsUrl geschieht analog dem bisherigen Beispiel.
Der Konstruktor von WegDaten muss entsprechend dem Hochladen von Dateien angepasst werden.
Hinweis:
Bereits in den Aufgaben im Skript Flask Grundlagen wurde die eigentliche API für das Hochladen von Dateien auf der Werkzeug Webseite angesprochen. Auch in diesem Fall muss die hochgeladene Datei nicht mittels der Funktion save auf dem Filesystem gespeichert, sondern nur der Inhalt für die Berechnung verwendet werden. Dies geschieht mit der Funktion stream, die wie eine geöffnete Datei angesehen werden kann.
Erstellen sie eine Methode createGoogleMapsObject, indem sie das Flask Plugin Flask-GoogleMaps dazu verwenden. Installieren Sie dieses Plugin über
pip install flask-googlemaps
Sehen sie sich hierzu insbesondere die Beispiele auf der Github-Seite von Flask-GoogleMaps an - diese sind nur wenig anzupassen.