From 201c41f12f972a5e4c10f0d282efdebfc41a51d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Fri, 22 Apr 2016 10:44:39 +0200 Subject: [PATCH 1/8] Introduce Airport --- ogn/commands/database.py | 16 +- ogn/commands/logbook.py | 29 +- ogn/model/__init__.py | 1 + ogn/model/airport.py | 35 ++ ogn/utils.py | 41 +- setup.py | 1 + tests/Germany.cup | 966 +++++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 7 +- 8 files changed, 1081 insertions(+), 15 deletions(-) create mode 100644 ogn/model/airport.py create mode 100644 tests/Germany.cup diff --git a/ogn/commands/database.py b/ogn/commands/database.py index 4c2e1e8..5c4eeb4 100644 --- a/ogn/commands/database.py +++ b/ogn/commands/database.py @@ -1,6 +1,6 @@ from ogn.commands.dbutils import engine, session from ogn.model import Base, AddressOrigin -from ogn.utils import get_ddb +from ogn.utils import get_ddb, get_airports from ogn.collect.database import update_devices from manager import Manager @@ -58,5 +58,17 @@ def import_file(path='tests/custom_ddb.txt'): # (flushes previously manually imported entries) print("Import registered devices from '{}'...".format(path)) - counter = update_devices(session, AddressOrigin.user_defined, get_ddb(path)) + counter = update_devices(session, AddressOrigin.user_defined, + get_ddb(path)) print("Imported %i devices." % counter) + + +@manager.command +def import_airports(path='tests/Germany.cup'): + """Import airports from a ".cup" file""" + + print("Import airports from '{}'...".format(path)) + airports = get_airports(path) + session.bulk_save_objects(airports) + session.commit() + print("Imported {} airports.".format(len(airports))) diff --git a/ogn/commands/logbook.py b/ogn/commands/logbook.py index aa9a993..10a5237 100644 --- a/ogn/commands/logbook.py +++ b/ogn/commands/logbook.py @@ -6,7 +6,7 @@ from sqlalchemy.sql import func, null from sqlalchemy import and_, or_, between from sqlalchemy.sql.expression import true, false, label -from ogn.model import Device, TakeoffLanding +from ogn.model import Device, TakeoffLanding, Airport from ogn.commands.dbutils import session from ogn.collect.logbook import compute_takeoff_and_landing @@ -25,16 +25,23 @@ def compute(): @manager.command -def show(airport_name, latitude, longitude, altitude): - """Show a logbook for located at given position.""" - latitude = float(latitude) - longitude = float(longitude) - altitude = float(altitude) - # get_logbook('Königsdorf', 47.83, 11.46, 601) - latmin = latitude - 0.15 - latmax = latitude + 0.15 - lonmin = longitude - 0.15 - lonmax = longitude + 0.15 +def show(airport_name): + """Show a logbook for .""" + airport = session.query(Airport) \ + .filter(or_(Airport.name==airport_name)) \ + .first() + + if (airport is None): + print('Airport "{}" not found.'.format(airport_name)) + return + + latitude = float(airport.latitude) + longitude = float(airport.longitude) + altitude = float(airport.altitude) + latmin = latitude - 0.05 + latmax = latitude + 0.05 + lonmin = longitude - 0.05 + lonmax = longitude + 0.05 max_altitude = altitude + 200 # make a query with current, previous and next "takeoff_landing" event, so we can find complete flights diff --git a/ogn/model/__init__.py b/ogn/model/__init__.py index 7a16a5b..e5fd495 100644 --- a/ogn/model/__init__.py +++ b/ogn/model/__init__.py @@ -8,3 +8,4 @@ from .aircraft_beacon import AircraftBeacon from .receiver_beacon import ReceiverBeacon from .receiver import Receiver from .takeoff_landing import TakeoffLanding +from .airport import Airport diff --git a/ogn/model/airport.py b/ogn/model/airport.py new file mode 100644 index 0000000..cb3f1e2 --- /dev/null +++ b/ogn/model/airport.py @@ -0,0 +1,35 @@ +from sqlalchemy import Column, String, Integer, Float, SmallInteger + +from .base import Base + + +class Airport(Base): + __tablename__ = "airport" + + id = Column(Integer, primary_key=True) + + name = Column(String, index=True) + code = Column(String(5)) + country_code = Column(String(2)) + style = Column(SmallInteger) + description = Column(String) + latitude = Column(Float) + longitude = Column(Float) + altitude = Column(Integer) + runway_direction = Column(Integer) + runway_length = Column(Integer) + frequency = Column(Float) + + def __repr__(self): + return "" % ( + self.name, + self.code, + self.country_code, + self.style, + self.description, + self.latitude, + self.longitude, + self.altitude, + self.runway_direction, + self.runway_length, + self.frequency) diff --git a/ogn/utils.py b/ogn/utils.py index c66ca08..0741502 100644 --- a/ogn/utils.py +++ b/ogn/utils.py @@ -2,11 +2,14 @@ import requests import csv from io import StringIO -from .model import Device, AddressOrigin +from .model import Device, AddressOrigin, Airport from geopy.geocoders import Nominatim from geopy.exc import GeopyError +from aerofiles.seeyou import Reader +from ogn.parser.utils import feet2m + DDB_URL = "http://ddb.glidernet.org/download" @@ -14,6 +17,9 @@ address_prefixes = {'F': 'FLR', 'O': 'OGN', 'I': 'ICA'} +nm2m = 1852 +mi2m = 1609.34 + def get_ddb(csvfile=None): if csvfile is None: @@ -65,6 +71,38 @@ def get_country_code(latitude, longitude): return country_code +def get_airports(cupfile): + airports = list() + with open(cupfile) as f: + for line in f: + try: + for waypoint in Reader([line]): + airport = Airport() + airport.name = waypoint['name'] + airport.code = waypoint['code'] + airport.country_code = waypoint['country'] + airport.style = waypoint['style'] + airport.description = waypoint['description'] + airport.latitude = waypoint['latitude'] + airport.longitude = waypoint['longitude'] + airport.altitude = waypoint['elevation']['value'] + if (waypoint['elevation']['unit'] == 'ft'): + airport.altitude = airport.altitude*feet2m + airport.runway_direction = waypoint['runway_direction'] + airport.runway_length = waypoint['runway_length']['value'] + if (waypoint['runway_length']['unit'] == 'nm'): + airport.altitude = airport.altitude*nm2m + elif (waypoint['runway_length']['unit'] == 'ml'): + airport.altitude = airport.altitude*mi2m + airport.frequency = waypoint['frequency'] + + airports.append(airport) + except Exception: + print('Failed to parse line: {}'.format(line)) + + return airports + + def haversine_distance(location0, location1): from math import asin, sqrt, sin, cos, atan2, radians, degrees @@ -77,3 +115,4 @@ def haversine_distance(location0, location1): phi = degrees(atan2(sin(lon0 - lon1) * cos(lat1), cos(lat0) * sin(lat1) - sin(lat0) * cos(lat1) * cos(lon0 - lon1))) return distance, phi + diff --git a/setup.py b/setup.py index 7ea7357..b4fa439 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ setup( 'manage.py==0.2.10', 'celery[redis]>=3.1,<3.2', 'alembic==0.8.3', + 'aerofiles==0.3', 'ogn-client==0.3.0' ], extras_require={ diff --git a/tests/Germany.cup b/tests/Germany.cup new file mode 100644 index 0000000..2f59950 --- /dev/null +++ b/tests/Germany.cup @@ -0,0 +1,966 @@ +"Aachen Merzbruck",,DE,5049.383N,00611.183E,189.0m,5,080,520.0m,122.875,"Flugplatz" +"Aalen Heidenheim",,DE,4846.667N,01015.883E,585.0m,5,090,1000.0m,121.400,"Flugplatz" +"Achmer",,DE,5222.633N,00754.800E,53.0m,2,070,940.0m,123.050,"Flugplatz" +"Achterstedt Prv",,DE,5323.850N,00819.783E,1.0m,2,080,460.0m,123.425,"Flugplatz" +"Agathazeller Moo",,DE,4733.300N,01016.367E,727.0m,5,180,450.0m,123.350,"Flugplatz" +"Ahlen Nord Heli",,DE,5147.083N,00754.750E,88.0m,2,070,1060.0m,130.075,"Flugplatz" +"Ahlhorn",,DE,5253.333N,00813.950E,47.0m,5,090,2100.0m,122.100,"Flugplatz" +"Ahrenlohe",,DE,5342.000N,00944.483E,7.0m,5,050,600.0m,122.600,"Flugplatz" +"Aichach",,DE,4828.400N,01108.133E,439.0m,4,020,430.0m,122.300,"Flugplatz" +"Aichelberg X",,DE,4839.967N,00831.183E,798.0m,3,310,250.0m,,"Landefeld" +"Aichhalden",,DE,4838.667N,00832.717E,755.0m,3,020,300.0m,,"Landefeld" +"Ailertchen",,DE,5035.550N,00756.667E,469.0m,2,040,550.0m,123.050,"Flugplatz" +"Albstadt Deger",,DE,4814.983N,00903.833E,891.0m,2,090,960.0m,125.100,"Flugplatz" +"Allendorf",,DE,5102.100N,00840.850E,354.0m,5,110,1240.0m,118.175,"Flugplatz" +"Allstedt",,DE,5122.833N,01126.800E,284.0m,5,070,1200.0m,122.000,"Flugplatz" +"Alsfeld",,DE,5045.033N,00914.917E,292.0m,4,060,650.0m,123.500,"Flugplatz" +"Altenbachtal",,DE,4955.367N,00909.483E,130.0m,4,070,600.0m,126.500,"Segelflug" +"Altdorf Hagenhau",,DE,4923.217N,01125.267E,538.0m,4,050,500.0m,129.975,"Flugplatz" +"Altdorf Wallburg",,DE,4816.200N,00750.533E,194.0m,2,070,840.0m,127.150,"Flugplatz" +"Alte Ems Herbrum",,DE,5301.850N,00718.333E,1.0m,4,100,720.0m,123.150,"Segelflug" +"Altena Hegensche",,DE,5118.783N,00742.217E,473.0m,2,060,600.0m,122.200,"Flugplatz" +"Leipzig-Altenbur",,DE,5058.917N,01230.383E,195.0m,5,040,2230.0m,123.575,"Flugplatz" +"Altenstadt Mil",,DE,4750.133N,01052.267E,741.0m,2,090,680.0m,122.100,"Flugplatz" +"Altfeld",,DE,4949.917N,00932.233E,354.0m,5,100,560.0m,130.125,"Flugplatz" +"Altomuenster Ul",,DE,4822.900N,01116.383E,496.0m,3,020,200.0m,123.425,"Landefeld" +"Altoetting",,DE,4812.967N,01238.900E,398.0m,4,090,540.0m,123.500,"Flugplatz" +"Amberg 29 Rwy",,DE,4926.383N,01148.750E,391.0m,3,290,280.0m,123.350,"Landefeld" +"Amberg Rammerts",,DE,4926.350N,01148.383E,388.0m,4,080,710.0m,123.350,"Flugplatz" +"Am Deister Lauen",,DE,5217.650N,00922.667E,116.0m,3,090,350.0m,123.425,"Landefeld" +"Amoeneburg",,DE,5047.433N,00854.483E,230.0m,4,050,620.0m,122.475,"Flugplatz" +"Ampfing Waldkra",,DE,4815.800N,01224.733E,415.0m,2,090,890.0m,123.600,"Flugplatz" +"Am Salzgittersee",,DE,5210.217N,01018.950E,81.0m,4,050,720.0m,130.125,"Flugplatz" +"Am Stauffenberg",,DE,5121.717N,00937.767E,369.0m,4,090,330.0m,123.500,"Flugplatz" +"Anklam",,DE,5349.967N,01340.133E,6.0m,5,090,1000.0m,122.650,"Flugplatz" +"Ansbach Petersdo",,DE,4921.650N,01040.100E,418.0m,2,090,780.0m,123.650,"Flugplatz" +"Ansbach Mil Heli",,DE,4918.483N,01038.317E,466.0m,5,080,370.0m,122.100,"Flugplatz" +"An Den 7 Bergen",,DE,5203.450N,00948.633E,135.0m,4,080,570.0m,123.500,"Flugplatz" +"Anspach Taunus",,DE,5017.333N,00832.117E,335.0m,2,060,580.0m,121.025,"Flugplatz" +"Antdorf",,DE,4745.600N,01118.267E,615.0m,3,080,480.0m,,"Landefeld" +"Antersberg",,DE,4757.767N,01159.767E,498.0m,4,130,980.0m,123.350,"Flugplatz" +"Argenbuehl Eisen",,DE,4741.483N,00957.783E,684.0m,3,080,400.0m,123.425,"Landefeld" +"Arnbruck",,DE,4907.533N,01259.117E,524.0m,5,160,610.0m,118.550,"Flugplatz" +"Arnsberg Ruhrwie",,DE,5123.250N,00803.633E,185.0m,4,170,850.0m,123.400,"Flugplatz" +"Arnsberg-Menden",,DE,5129.017N,00753.883E,241.0m,5,050,920.0m,123.025,"Flugplatz" +"Arnschwang Ul",,DE,4916.300N,01246.700E,414.0m,3,050,400.0m,123.425,"Landefeld" +"Arnstadt Alkersl",,DE,5050.517N,01104.200E,351.0m,5,090,870.0m,123.000,"Flugplatz" +"Aschaffenburg",,DE,4956.333N,00903.750E,125.0m,5,080,840.0m,132.425,"Flugplatz" +"Aschersleben",,DE,5146.017N,01129.933E,162.0m,2,110,1050.0m,123.375,"Flugplatz" +"Asslarer Huette",,DE,5035.983N,00826.633E,232.0m,4,170,590.0m,129.975,"Flugplatz" +"Attendorn Finnen",,DE,5108.750N,00756.183E,317.0m,2,030,560.0m,121.400,"Flugplatz" +"Aue Bei Hattorf",,DE,5138.000N,01015.283E,190.0m,4,100,1050.0m,122.200,"Flugplatz" +"Auerbach",,DE,5029.833N,01222.683E,573.0m,5,010,800.0m,122.700,"Flugplatz" +"Augsburg",,DE,4825.517N,01055.900E,463.0m,5,070,1590.0m,124.975,"Flugplatz" +"Aukrug",,DE,5403.883N,00947.900E,17.0m,4,110,1000.0m,123.350,"Flugplatz" +"Aurach",,DE,4742.000N,01155.450E,808.0m,3,180,310.0m,,"Landefeld" +"Aventoft",,DE,5453.767N,00849.233E,2.0m,4,090,970.0m,122.400,"Flugplatz" +"Babenhausen",,DE,4957.167N,00858.150E,133.0m,5,060,670.0m,123.200,"Flugplatz" +"Bad Bibra Ul",,DE,5112.133N,01129.867E,298.0m,3,090,600.0m,123.425,"Landefeld" +"Bad Berka",,DE,5054.233N,01115.517E,305.0m,2,070,700.0m,123.650,"Flugplatz" +"Bad Buchau Feder",,DE,4803.300N,00938.383E,579.0m,4,080,500.0m,123.150,"Flugplatz" +"Backnang Heinin",,DE,4855.200N,00927.300E,297.0m,2,110,500.0m,126.500,"Flugplatz" +"Bad Brueckenau",,DE,5016.317N,00949.417E,402.0m,4,130,550.0m,123.500,"Flugplatz" +"Bad Ditzenbach",,DE,4833.767N,00943.733E,730.0m,2,160,600.0m,122.350,"Flugplatz" +"Bad Duerkheim",,DE,4928.383N,00811.783E,107.0m,5,080,600.0m,122.400,"Flugplatz" +"Bad Endorf Jolli",,DE,4755.617N,01217.233E,514.0m,2,170,770.0m,122.500,"Flugplatz" +"Baden Oos",,DE,4847.450N,00811.050E,125.0m,2,030,790.0m,121.000,"Flugplatz" +"Bad Frankenhause",,DE,5122.367N,01108.583E,241.0m,2,080,650.0m,122.600,"Flugplatz" +"Bad Gandersheim",,DE,5151.150N,01001.567E,239.0m,2,170,720.0m,123.000,"Flugplatz" +"Bad Hersfeld",,DE,5050.667N,00942.433E,239.0m,5,010,670.0m,124.000,"Flugplatz" +"Bad Kissingen",,DE,5012.633N,01004.167E,198.0m,2,170,800.0m,122.000,"Flugplatz" +"Bad Koenigshofen",,DE,5017.250N,01025.317E,313.0m,4,070,700.0m,130.125,"Flugplatz" +"Bad Langensalza",,DE,5107.750N,01037.300E,199.0m,2,090,800.0m,130.125,"Flugplatz" +"Bad Marienberg",,DE,5039.650N,00801.717E,544.0m,4,110,860.0m,129.975,"Flugplatz" +"Bad Neuenahr Ahr",,DE,5033.467N,00708.233E,204.0m,5,100,500.0m,122.350,"Flugplatz" +"Bad Neustadt/Saa",,DE,5018.367N,01013.633E,303.0m,5,130,600.0m,123.650,"Flugplatz" +"Bad Rotenfels",,DE,4849.450N,00817.433E,129.0m,3,140,260.0m,,"Landefeld" +"Bad Sobernheim",,DE,4947.483N,00740.000E,244.0m,2,040,680.0m,118.925,"Flugplatz" +"Bad Waldsee Reu",,DE,4754.900N,00942.600E,577.0m,2,150,660.0m,123.000,"Flugplatz" +"Bad Windsheim",,DE,4930.617N,01021.967E,370.0m,2,080,690.0m,118.275,"Flugplatz" +"Bad Worishofen-N",,DE,4800.983N,01036.900E,619.0m,2,080,800.0m,122.600,"Flugplatz" +"Bad Zwischenahn",,DE,5312.617N,00759.317E,9.0m,4,090,900.0m,123.500,"Flugplatz" +"Baerental",,DE,4752.700N,00806.717E,906.0m,3,050,250.0m,,"Landefeld" +"Baiersbron Cls",,DE,4832.283N,00823.900E,507.0m,3,170,230.0m,,"Landefeld" +"Baiersbronn",,DE,4830.933N,00822.400E,574.0m,3,050,220.0m,,"Landefeld" +"Ballenstedt",,DE,5144.750N,01113.750E,153.0m,5,090,680.0m,122.700,"Flugplatz" +"Baltrum",,DE,5343.517N,00722.333E,3.0m,5,100,360.0m,123.050,"Flugplatz" +"Bamberg",,DE,4955.233N,01054.850E,250.0m,5,040,1140.0m,120.175,"Flugplatz" +"Barssel",,DE,5309.867N,00747.650E,3.0m,2,120,770.0m,122.000,"Flugplatz" +"Bartholoma Amali",,DE,4844.800N,01000.300E,637.0m,2,160,900.0m,122.200,"Flugplatz" +"Barth",,DE,5420.300N,01242.617E,6.0m,5,090,1200.0m,118.075,"Flugplatz" +"Bad Salzungen Ul",,DE,5049.017N,01013.083E,236.0m,3,090,500.0m,123.425,"Landefeld" +"Basepohl Mil Cls",,DE,5344.717N,01257.133E,50.0m,3,110,500.0m,122.100,"Landefeld" +"Baumerlenbach",,DE,4913.833N,00925.150E,236.0m,5,080,420.0m,123.150,"Flugplatz" +"Baumholder Mil",,DE,4939.100N,00718.433E,442.0m,5,070,550.0m,122.100,"Flugplatz" +"Bautzen",,DE,5111.617N,01431.183E,174.0m,5,070,2200.0m,120.600,"Flugplatz" +"Bad Wildungen",,DE,5105.633N,00908.900E,332.0m,4,010,980.0m,123.350,"Flugplatz" +"Bayreuth",,DE,4959.117N,01138.467E,482.0m,5,060,1080.0m,127.525,"Flugplatz" +"Bayrischzll",,DE,4740.083N,01201.100E,797.0m,3,170,300.0m,,"Landefeld" +"Becherbach Ul",,DE,4938.567N,00741.033E,421.0m,3,060,400.0m,123.425,"Landefeld" +"Beelen",,DE,5155.900N,00804.900E,59.0m,2,090,450.0m,123.500,"Flugplatz" +"Beilngries",,DE,4901.267N,01129.083E,365.0m,2,100,600.0m,118.350,"Flugplatz" +"Bell Hundheim",,DE,5001.650N,00725.317E,445.0m,3,040,360.0m,120.975,"Landefeld" +"Benediktbeuren",,DE,4742.950N,01123.433E,609.0m,4,090,750.0m,123.500,"Flugplatz" +"Bensheimer Stadt",,DE,4941.517N,00834.967E,93.0m,4,140,620.0m,123.375,"Flugplatz" +"Berg Ravensburg",,DE,4749.967N,00932.500E,594.0m,3,030,270.0m,120.975,"Landefeld" +"Berching",,DE,4907.900N,01126.617E,390.0m,2,020,850.0m,123.350,"Flugplatz" +"Bergheim",,DE,5058.617N,00636.500E,70.0m,4,140,1100.0m,130.125,"Flugplatz" +"Bergneustadt",,DE,5103.117N,00742.433E,481.0m,2,040,600.0m,123.650,"Flugplatz" +"Berliner Heide",,DE,5240.183N,01022.233E,69.0m,4,030,1070.0m,123.500,"Flugplatz" +"Berlin Tegel",,DE,5233.583N,01317.267E,37.0m,5,080,3020.0m,124.525,"Flugplatz" +"Berneck",,DE,4834.383N,00943.783E,746.0m,4,160,840.0m,123.475,"Flugplatz" +"Berlin Schonfeld",,DE,5222.717N,01331.233E,49.0m,5,070,3600.0m,119.575,"Flugplatz" +"Bernau",,DE,4748.283N,00801.783E,921.0m,3,100,250.0m,,"Landefeld" +"Besenbfeldn",,DE,4835.950N,00824.767E,818.0m,3,320,450.0m,,"Landefeld" +"Besenbfelds",,DE,4835.267N,00825.300E,790.0m,3,040,350.0m,,"Landefeld" +"Betzdorf Kirchen",,DE,5049.017N,00749.817E,351.0m,2,080,500.0m,122.750,"Flugplatz" +"Biberach Riss",,DE,4806.700N,00945.800E,580.0m,5,040,980.0m,122.750,"Flugplatz" +"Bielefeld",,DE,5157.883N,00832.683E,137.0m,5,110,1250.0m,118.350,"Flugplatz" +"Bienenfarm",,DE,5239.733N,01244.717E,27.0m,2,120,850.0m,122.850,"Flugplatz" +"Binningen",,DE,4747.967N,00843.217E,489.0m,2,060,860.0m,130.600,"Flugplatz" +"Bischofsberg",,DE,5025.933N,01017.000E,342.0m,4,080,900.0m,122.200,"Flugplatz" +"Bisperode West",,DE,5204.733N,00928.567E,194.0m,4,060,1130.0m,123.150,"Flugplatz" +"Bitburg",,DE,4956.717N,00633.900E,372.0m,5,050,3050.0m,118.700,"Flugplatz" +"Blaubeuren",,DE,4825.183N,00947.850E,677.0m,2,100,870.0m,130.600,"Flugplatz" +"BleXEn",,DE,5332.350N,00832.367E,3.0m,2,090,1000.0m,120.600,"Flugplatz" +"Blomberg Borkhau",,DE,5155.033N,00906.667E,182.0m,2,060,590.0m,118.925,"Flugplatz" +"Blumberg",,DE,4750.667N,00833.917E,701.0m,2,070,780.0m,123.050,"Flugplatz" +"Boberg",,DE,5330.883N,01008.650E,2.0m,4,120,1240.0m,133.500,"Flugplatz" +"Bobzin Scharbow",,DE,5329.167N,01110.100E,49.0m,5,100,600.0m,123.425,"Flugplatz" +"Boehlen",,DE,5112.967N,01222.100E,131.0m,2,060,950.0m,123.000,"Flugplatz" +"Boesingen Ul",,DE,4813.667N,00832.083E,694.0m,3,090,410.0m,123.425,"Landefeld" +"Bohlenberger Fel",,DE,5325.100N,00754.250E,6.0m,4,060,950.0m,129.500,"Flugplatz" +"Bohlhof",,DE,4739.050N,00823.200E,558.0m,4,040,800.0m,129.975,"Flugplatz" +"Bohmte Bad Essen",,DE,5221.067N,00819.683E,45.0m,2,100,580.0m,122.500,"Flugplatz" +"Bohlsbach",,DE,4830.117N,00756.933E,151.0m,3,100,330.0m,,"Landefeld" +"Bonn Hangelar",,DE,5046.133N,00709.767E,61.0m,5,110,800.0m,135.150,"Flugplatz" +"Bopfingen",,DE,4850.900N,01020.050E,619.0m,5,070,930.0m,122.850,"Flugplatz" +"Borghorst Fuecht",,DE,5209.017N,00727.117E,47.0m,4,060,460.0m,123.350,"Flugplatz" +"Borkheide",,DE,5214.033N,01250.833E,62.0m,3,170,820.0m,,"Landefeld" +"Borkenberge",,DE,5146.800N,00717.283E,49.0m,5,080,670.0m,135.000,"Flugplatz" +"Borken HoXFeld",,DE,5151.183N,00648.917E,49.0m,2,120,740.0m,122.925,"Flugplatz" +"Borkum",,DE,5335.650N,00642.967E,1.0m,5,130,1000.0m,123.000,"Flugplatz" +"Boschhof",,DE,4749.000N,01125.000E,597.0m,3,020,400.0m,,"Landefeld" +"Bottenhorn",,DE,5047.683N,00827.650E,516.0m,2,110,520.0m,123.800,"Flugplatz" +"Brannenburg",,DE,4744.333N,01206.967E,467.0m,4,170,400.0m,122.500,"Flugplatz" +"Brandis Wald Cls",,DE,5119.683N,01239.350E,165.0m,3,080,1380.0m,129.250,"Landefeld" +"Brakel Ul 25M",,DE,5144.333N,00912.150E,164.0m,3,080,300.0m,123.425,"Landefeld" +"Brandenburg Mue",,DE,5226.217N,01235.583E,28.0m,2,100,730.0m,118.625,"Flugplatz" +"Braunfels",,DE,5031.533N,00823.583E,240.0m,4,070,430.0m,123.150,"Flugplatz" +"Braunschweig",,DE,5219.150N,01033.267E,92.0m,5,080,2300.0m,120.050,"Flugplatz" +"Bredstedt",,DE,5438.000N,00859.133E,7.0m,3,010,420.0m,122.800,"Landefeld" +"Breitscheid",,DE,5040.617N,00810.183E,562.0m,5,070,780.0m,122.600,"Flugplatz" +"Bremen",,DE,5302.850N,00847.217E,3.0m,5,090,2040.0m,120.325,"Flugplatz" +"Bremgarten",,DE,4754.200N,00737.050E,213.0m,5,050,1660.0m,122.000,"Flugplatz" +"Bremerhaven",,DE,5330.417N,00834.383E,3.0m,5,160,1200.0m,129.050,"Flugplatz" +"Briesen Brand",,DE,5203.183N,01345.950E,70.0m,3,100,1000.0m,,"Landefeld" +"Brilon",,DE,5124.150N,00838.517E,460.0m,5,070,750.0m,129.375,"Flugplatz" +"Brauna Kamenz",,DE,5117.000N,01403.517E,190.0m,3,080,380.0m,122.475,"Landefeld" +"Brockzetel",,DE,5328.883N,00739.100E,9.0m,4,110,1060.0m,123.500,"Flugplatz" +"Brodau Delitzsch",,DE,5129.883N,01219.783E,101.0m,3,010,270.0m,120.975,"Landefeld" +"Bronkow",,DE,5140.317N,01357.817E,128.0m,2,120,900.0m,130.325,"Flugplatz" +"Bruchsal",,DE,4908.117N,00833.817E,113.0m,2,120,500.0m,128.375,"Flugplatz" +"Buechig Ostheim",,DE,5026.900N,01015.150E,388.0m,4,100,550.0m,123.375,"Flugplatz" +"Buechel Mil",,DE,5010.433N,00703.800E,479.0m,5,030,2510.0m,122.100,"Flugplatz" +"Bueckeburg Wein",,DE,5215.050N,00901.067E,77.0m,4,110,1130.0m,129.975,"Flugplatz" +"Bueckeburg Mil",,DE,5216.700N,00904.933E,70.0m,5,080,1840.0m,122.100,"Flugplatz" +"Bueckeburg Nord",,DE,5215.217N,00900.850E,74.0m,4,110,1130.0m,129.975,"Flugplatz" +"Bueren Schwalnbr",,DE,5132.567N,00834.833E,265.0m,4,070,710.0m,123.350,"Flugplatz" +"Buhlbach X Wiese",,DE,4831.500N,00815.600E,649.0m,3,240,200.0m,,"Landefeld" +"Bundenthal Rumbc",,DE,4905.633N,00747.633E,308.0m,4,180,570.0m,123.350,"Flugplatz" +"Burg",,DE,5214.500N,01151.367E,52.0m,2,090,850.0m,122.050,"Flugplatz" +"Burg Feuerstein",,DE,4947.650N,01108.033E,501.0m,5,080,970.0m,130.775,"Flugplatz" +"Burgstaedt Ul ?",,DE,5054.733N,01249.350E,335.0m,3,060,180.0m,123.600,"Landefeld" +"Burgheim",,DE,4841.517N,01102.017E,406.0m,2,140,660.0m,123.350,"Flugplatz" +"Burgebrach Ul",,DE,4950.300N,01046.733E,282.0m,3,100,280.0m,123.425,"Landefeld" +"Butzbach Pfingst",,DE,5026.150N,00837.167E,340.0m,5,100,510.0m,133.500,"Flugplatz" +"Celle Arloh",,DE,5241.267N,01006.733E,64.0m,2,040,900.0m,123.650,"Flugplatz" +"Celle Mil",,DE,5235.467N,01001.333E,40.0m,5,080,1840.0m,122.100,"Flugplatz" +"Cham Janahof",,DE,4912.700N,01239.400E,364.0m,5,100,560.0m,130.125,"Flugplatz" +"Chemnitz Jahns",,DE,5044.850N,01250.233E,370.0m,5,070,900.0m,122.500,"Flugplatz" +"Coburg Brandstn",,DE,5015.750N,01059.750E,449.0m,5,120,630.0m,128.675,"Flugplatz" +"Coburg Steinrue",,DE,5013.833N,01059.717E,356.0m,2,070,700.0m,129.800,"Flugplatz" +"Coleman Mil",,DE,4933.817N,00827.800E,95.0m,5,050,920.0m,122.100,"Flugplatz" +"Cottbus Mil Cls",,DE,5146.083N,01417.517E,70.0m,3,080,2360.0m,,"Landefeld" +"Cottbus Drewitz",,DE,5153.367N,01431.917E,82.0m,5,070,2480.0m,118.125,"Flugplatz" +"Crawinkel Ul",,DE,5046.700N,01049.000E,473.0m,3,050,510.0m,123.425,"Landefeld" +"Crussow Ul",,DE,5300.883N,01404.133E,53.0m,3,140,300.0m,123.425,"Landefeld" +"Dachau Groebenr",,DE,4813.717N,01125.367E,489.0m,2,100,620.0m,118.425,"Flugplatz" +"Dahlemer Binz",,DE,5024.333N,00631.733E,579.0m,5,060,1070.0m,122.375,"Flugplatz" +"Damgarten Cls",,DE,5415.850N,01226.667E,5.0m,3,070,2000.0m,121.500,"Landefeld" +"Damme",,DE,5229.250N,00811.100E,46.0m,5,100,700.0m,133.300,"Flugplatz" +"Dankern Haren Ul",,DE,5248.150N,00709.617E,11.0m,3,100,360.0m,120.975,"Landefeld" +"Dauborn",,DE,5019.300N,00811.633E,164.0m,2,120,330.0m,123.500,"Flugplatz" +"Daun Senheld",,DE,5010.550N,00651.467E,526.0m,5,080,420.0m,123.150,"Flugplatz" +"Deckenpfronn Ege",,DE,4838.300N,00849.050E,578.0m,4,070,800.0m,130.125,"Flugplatz" +"Deggendorf",,DE,4849.817N,01252.783E,314.0m,5,090,550.0m,122.025,"Flugplatz" +"Degmarn",,DE,4915.467N,00916.467E,169.0m,4,080,700.0m,123.500,"Flugplatz" +"Dehausen Diemels",,DE,5127.800N,00902.967E,305.0m,4,160,650.0m,123.150,"Flugplatz" +"Der Dingel Huemm",,DE,5132.167N,00922.783E,220.0m,4,050,870.0m,123.500,"Flugplatz" +"Der Ring Schwalm",,DE,5054.183N,00914.433E,212.0m,4,030,660.0m,123.375,"Flugplatz" +"Dessau",,DE,5149.900N,01211.067E,56.0m,5,090,1000.0m,118.175,"Flugplatz" +"Dettingen 09 Rwy",,DE,4836.567N,00928.267E,374.0m,3,090,220.0m,122.175,"Landefeld" +"Detmold",,DE,5156.450N,00854.250E,189.0m,5,090,510.0m,122.750,"Flugplatz" +"Dettingen Teck",,DE,4836.500N,00928.533E,386.0m,4,130,490.0m,122.175,"Flugplatz" +"Diepholz Mil",,DE,5235.133N,00820.467E,40.0m,5,080,1280.0m,122.100,"Flugplatz" +"Dierdorf Wienau",,DE,5033.950N,00739.150E,291.0m,5,070,580.0m,128.925,"Flugplatz" +"Dillingen",,DE,4923.167N,00644.917E,239.0m,4,060,680.0m,130.125,"Flugplatz" +"Dingelstedt Ul",,DE,5159.183N,01058.033E,122.0m,3,100,330.0m,123.425,"Landefeld" +"Dingolfing",,DE,4839.400N,01229.933E,352.0m,2,080,660.0m,123.600,"Flugplatz" +"Dinkelsbuehl",,DE,4903.900N,01024.150E,488.0m,2,090,700.0m,118.425,"Flugplatz" +"Dinslaken Schwa",,DE,5136.967N,00651.933E,65.0m,5,080,1500.0m,122.700,"Flugplatz" +"Dobenreuth",,DE,4941.817N,01108.600E,338.0m,4,100,470.0m,123.350,"Flugplatz" +"Doebbersen",,DE,5333.567N,01103.050E,42.0m,3,160,250.0m,,"Landefeld" +"Doernberg Rwy21",,DE,5122.017N,00920.200E,439.0m,3,210,320.0m,122.300,"Landefeld" +"Doerzbach Hoheba",,DE,4921.050N,00942.883E,404.0m,3,150,270.0m,123.425,"Landefeld" +"Dolmar Kuendorf",,DE,5036.733N,01028.350E,515.0m,3,040,400.0m,123.425,"Landefeld" +"Donaueschingen",,DE,4758.417N,00831.333E,680.0m,5,180,1290.0m,124.250,"Flugplatz" +"Donauwoerth",,DE,4842.183N,01051.133E,399.0m,5,090,700.0m,134.125,"Flugplatz" +"Donstorf Ul",,DE,5239.300N,00833.417E,33.0m,3,170,310.0m,123.425,"Landefeld" +"Donzdorf Messe",,DE,4840.717N,00950.750E,690.0m,5,090,600.0m,122.600,"Flugplatz" +"Dorsten Kanal",,DE,5139.733N,00659.100E,32.0m,4,090,600.0m,123.350,"Flugplatz" +"Dortmund Wickede",,DE,5131.150N,00736.867E,128.0m,5,060,2000.0m,134.175,"Flugplatz" +"Drensteinfurt",,DE,5146.050N,00744.817E,69.0m,3,030,310.0m,123.425,"Landefeld" +"Dresden",,DE,5108.067N,01346.083E,229.0m,5,040,2850.0m,122.925,"Flugplatz" +"Drosa Bobbe Ul",,DE,5149.517N,01153.800E,72.0m,3,100,660.0m,123.425,"Landefeld" +"Duerabuch Cls",,DE,4815.733N,01112.583E,537.0m,4,080,850.0m,123.500,"Flugplatz" +"Duernbach",,DE,4745.933N,01143.933E,751.0m,3,160,500.0m,,"Landefeld" +"Dueren Huertgen",,DE,5041.633N,00625.100E,360.0m,4,060,770.0m,123.150,"Flugplatz" +"Duesseldorf",,DE,5117.267N,00646.150E,37.0m,5,050,3000.0m,118.300,"Flugplatz" +"Duesseld Wolfsaa",,DE,5115.883N,00651.217E,113.0m,4,070,800.0m,123.150,"Flugplatz" +"Durrweiler Hesel",,DE,4831.500N,00832.433E,650.0m,3,150,350.0m,123.425,"Landefeld" +"Ebern Sendelbach",,DE,5002.383N,01049.367E,253.0m,2,140,520.0m,122.500,"Flugplatz" +"Eberswalde Finow",,DE,5249.633N,01341.617E,37.0m,5,100,1480.0m,119.050,"Flugplatz" +"Edling",,DE,4804.300N,01208.150E,493.0m,3,110,340.0m,,"Landefeld" +"Egelsbach",,DE,4957.650N,00838.483E,119.0m,5,090,1400.0m,118.400,"Flugplatz" +"Eggenfelden",,DE,4823.767N,01243.283E,407.0m,5,080,1160.0m,120.300,"Flugplatz" +"Eggersdorf",,DE,5228.967N,01405.450E,67.0m,2,060,1200.0m,123.000,"Flugplatz" +"Ehlershausen Gr",,DE,5232.150N,01001.183E,45.0m,4,100,1010.0m,122.200,"Flugplatz" +"Eichstaett",,DE,4852.617N,01110.900E,524.0m,2,110,710.0m,123.000,"Flugplatz" +"Eisenhuettenstad",,DE,5211.833N,01435.133E,46.0m,5,110,1170.0m,122.000,"Flugplatz" +"Eisenach Kindel",,DE,5059.533N,01028.567E,335.0m,5,100,1720.0m,119.750,"Flugplatz" +"Ellwangen",,DE,4857.683N,01014.083E,503.0m,2,120,780.0m,122.000,"Flugplatz" +"Elsenthal Grafen",,DE,4849.350N,01322.050E,485.0m,2,160,460.0m,122.500,"Flugplatz" +"Elz",,DE,5025.600N,00800.600E,213.0m,2,070,750.0m,123.600,"Flugplatz" +"Emden",,DE,5323.467N,00713.533E,1.0m,5,070,1300.0m,118.600,"Flugplatz" +"Emmerich",,DE,5149.333N,00616.467E,13.0m,4,130,990.0m,123.350,"Flugplatz" +"Engelbrand",,DE,4849.900N,00838.150E,571.0m,3,060,450.0m,,"Landefeld" +"Enzloesterle",,DE,4839.800N,00827.967E,599.0m,3,040,260.0m,,"Landefeld" +"Epfenbach Ul",,DE,4919.250N,00855.017E,219.0m,3,070,220.0m,123.425,"Landefeld" +"Erbach",,DE,4820.517N,00955.000E,476.0m,2,030,650.0m,118.275,"Flugplatz" +"Erbendorf Schwei",,DE,4950.633N,01204.017E,494.0m,5,120,630.0m,123.350,"Flugplatz" +"Erding Mil",,DE,4819.333N,01156.917E,463.0m,5,080,2510.0m,120.200,"Flugplatz" +"Erfurt",,DE,5058.783N,01057.483E,317.0m,5,100,2600.0m,121.150,"Flugplatz" +"Erkelenz Kueckho",,DE,5103.900N,00621.583E,85.0m,3,160,450.0m,120.975,"Landefeld" +"Ernzen Ul",,DE,4949.733N,00626.133E,345.0m,3,050,450.0m,123.425,"Landefeld" +"Erpetshof Ul ?",,DE,4939.433N,01217.783E,497.0m,3,100,300.0m,123.425,"Landefeld" +"Eschelbach Ul",,DE,4834.183N,01136.533E,459.0m,3,110,380.0m,123.450,"Landefeld" +"Essen Muelheim",,DE,5124.133N,00656.233E,128.0m,5,070,1530.0m,119.750,"Flugplatz" +"Esslingen Jaege",,DE,4845.733N,00920.033E,496.0m,4,120,730.0m,122.475,"Flugplatz" +"Essweiler",,DE,4933.733N,00734.800E,409.0m,4,050,820.0m,129.975,"Flugplatz" +"Etting Adelmanns",,DE,4848.617N,01125.267E,382.0m,4,100,720.0m,123.500,"Flugplatz" +"Eudenbach",,DE,5040.333N,00721.917E,300.0m,4,090,800.0m,118.425,"Flugplatz" +"Eutingen",,DE,4829.133N,00846.700E,497.0m,4,060,710.0m,129.975,"Flugplatz" +"Falkenberg Loen",,DE,5132.867N,01313.683E,85.0m,5,080,1200.0m,130.125,"Flugplatz" +"Fall Sylvenstein",,DE,4734.167N,01132.983E,780.0m,3,160,470.0m,,"Landefeld" +"Farchant N",,DE,4732.417N,01106.483E,665.0m,3,030,350.0m,,"Landefeld" +"Farchant S",,DE,4731.417N,01106.483E,679.0m,3,020,300.0m,,"Landefeld" +"Farrenberg",,DE,4823.133N,00904.600E,794.0m,4,100,750.0m,123.475,"Flugplatz" +"Fassberg Mil",,DE,5255.150N,01011.033E,70.0m,5,090,2170.0m,122.100,"Flugplatz" +"Faulenfuerst1",,DE,4748.450N,00813.033E,1032.0m,3,130,250.0m,,"Landefeld" +"Faulenfuers3",,DE,4748.317N,00813.183E,1025.0m,3,130,280.0m,,"Landefeld" +"Fichtelbrunn",,DE,4929.883N,01139.567E,498.0m,4,090,360.0m,122.300,"Flugplatz" +"Finsterw Heinric",,DE,5138.067N,01340.317E,127.0m,2,080,1000.0m,123.500,"Flugplatz" +"Finsterw Schacks",,DE,5136.450N,01344.283E,122.0m,5,090,1200.0m,123.050,"Flugplatz" +"Fischbek",,DE,5327.350N,00949.783E,64.0m,4,120,910.0m,129.975,"Flugplatz" +"Fischbachau",,DE,4743.350N,01155.983E,754.0m,3,090,300.0m,,"Landefeld" +"Fischhausen",,DE,4742.550N,01152.117E,801.0m,3,140,400.0m,,"Landefeld" +"Flensburg",,DE,5446.400N,00922.733E,40.0m,5,110,1220.0m,122.850,"Flugplatz" +"Flintsbach",,DE,4743.350N,01206.850E,489.0m,4,090,430.0m,122.500,"Flugplatz" +"Frankfurt Hahn",,DE,4956.917N,00715.833E,503.0m,5,030,3800.0m,119.650,"Flugplatz" +"Frankfurt Main",,DE,5002.000N,00834.233E,110.0m,5,070,4000.0m,119.900,"Flugplatz" +"Freiburg",,DE,4801.367N,00749.967E,242.0m,5,160,1400.0m,118.250,"Flugplatz" +"Friedersdorf",,DE,5216.917N,01348.133E,33.0m,2,110,950.0m,122.200,"Flugplatz" +"Friedrichshafen",,DE,4740.283N,00930.683E,418.0m,5,060,2350.0m,120.075,"Flugplatz" +"Fritzlar Mil",,DE,5106.883N,00917.150E,174.0m,5,120,1040.0m,122.100,"Flugplatz" +"Friesoythe Ul",,DE,5301.767N,00748.000E,6.0m,3,080,340.0m,124.000,"Landefeld" +"Friesener Warte",,DE,4950.183N,01102.800E,517.0m,4,010,640.0m,122.200,"Flugplatz" +"Fuenftbronn",,DE,4836.667N,00829.417E,740.0m,3,050,350.0m,,"Landefeld" +"Furstenfeldb Cls",,DE,4812.333N,01116.033E,518.0m,5,090,2750.0m,123.700,"Flugplatz" +"Furth Seckendorf",,DE,4928.883N,01051.517E,334.0m,4,090,620.0m,123.475,"Flugplatz" +"Fuerstenzell",,DE,4831.083N,01320.767E,412.0m,5,150,480.0m,122.000,"Flugplatz" +"Fuessen",,DE,4735.000N,01041.450E,787.0m,4,080,1030.0m,123.350,"Flugplatz" +"Fulda Jossa",,DE,5028.517N,00926.533E,471.0m,2,080,580.0m,122.400,"Flugplatz" +"Further Drachenh",,DE,4917.817N,01252.200E,412.0m,3,120,230.0m,,"Landefeld" +"Gaggenau",,DE,4847.850N,00819.083E,165.0m,3,190,300.0m,,"Landefeld" +"Gammelsdorf",,DE,4834.067N,01155.950E,495.0m,4,180,770.0m,129.975,"Flugplatz" +"Ganderkesee",,DE,5302.167N,00830.317E,31.0m,5,080,830.0m,118.625,"Flugplatz" +"Garbenheimer Wie",,DE,5034.500N,00831.917E,151.0m,4,080,800.0m,122.300,"Flugplatz" +"Gardelegen",,DE,5231.833N,01121.217E,73.0m,2,080,550.0m,122.850,"Flugplatz" +"Garmisch O",,DE,4729.000N,01105.933E,731.0m,3,180,300.0m,,"Landefeld" +"Garmisch W",,DE,4728.300N,01103.283E,743.0m,3,040,250.0m,,"Landefeld" +"Gedern",,DE,5025.950N,00911.667E,371.0m,4,040,700.0m,123.475,"Flugplatz" +"Geesthacht Wiese",,DE,5326.933N,01020.350E,4.0m,3,120,410.0m,133.500,"Landefeld" +"Geilenkirche Mil",,DE,5057.650N,00602.550E,92.0m,5,090,3060.0m,120.050,"Flugplatz" +"Geitau",,DE,4740.767N,01157.733E,818.0m,4,160,550.0m,123.400,"Flugplatz" +"Gelnhausen",,DE,5011.783N,00910.067E,126.0m,2,070,840.0m,123.050,"Flugplatz" +"Gera Leumnitz",,DE,5052.883N,01208.133E,307.0m,5,060,750.0m,118.075,"Flugplatz" +"Geratshof",,DE,4759.583N,01050.617E,634.0m,4,080,250.0m,123.500,"Flugplatz" +"Gernsbach X",,DE,4846.417N,00820.283E,160.0m,3,030,220.0m,,"Landefeld" +"Gerstetten",,DE,4837.233N,01003.667E,599.0m,2,080,530.0m,123.000,"Flugplatz" +"Giebelstadt",,DE,4938.900N,00957.983E,299.0m,5,080,1980.0m,122.500,"Flugplatz" +"Giengen Brenz",,DE,4838.033N,01013.000E,518.0m,5,170,560.0m,122.350,"Flugplatz" +"Giessen Reiskir",,DE,5034.000N,00852.183E,213.0m,2,040,430.0m,123.650,"Flugplatz" +"Giessen Lutzell",,DE,5032.667N,00835.450E,232.0m,5,070,710.0m,122.500,"Flugplatz" +"Giessen Wieseck",,DE,5036.250N,00843.717E,165.0m,4,080,920.0m,122.000,"Flugplatz" +"Glasewitz Eh Fpl",,DE,5350.050N,01218.583E,47.0m,3,070,1100.0m,,"Landefeld" +"Goch Asperden",,DE,5141.450N,00606.233E,16.0m,2,100,750.0m,118.450,"Flugplatz" +"Goeppingen Betzg",,DE,4839.517N,00937.450E,374.0m,2,140,320.0m,,"Flugplatz" +"Goepfersdorf",,DE,5054.817N,01236.700E,291.0m,4,070,700.0m,123.475,"Flugplatz" +"Goerlitz",,DE,5109.533N,01457.017E,238.0m,2,060,740.0m,122.000,"Flugplatz" +"Goettingen Heili",,DE,5124.450N,01008.683E,363.0m,2,060,700.0m,122.200,"Flugplatz" +"Goettelfingen",,DE,4834.350N,00827.933E,776.0m,3,160,510.0m,,"Landefeld" +"Goeppingen Cls",,DE,4842.450N,00941.383E,371.0m,3,070,600.0m,122.100,"Landefeld" +"Goslar Bollrich",,DE,5154.283N,01027.550E,295.0m,4,060,540.0m,123.475,"Flugplatz" +"Gotha Ost",,DE,5058.217N,01043.750E,305.0m,2,080,550.0m,122.500,"Flugplatz" +"Grafenhausen1",,DE,4747.383N,00814.933E,962.0m,3,130,300.0m,,"Landefeld" +"Grafenhause3",,DE,4747.067N,00814.967E,959.0m,3,180,250.0m,,"Landefeld" +"Grabenstetten",,DE,4832.167N,00926.233E,710.0m,2,120,1110.0m,130.125,"Flugplatz" +"Grafenwoehr Mil",,DE,4941.917N,01156.417E,415.0m,5,140,1010.0m,122.100,"Flugplatz" +"Grambeker Heide",,DE,5335.000N,01041.917E,48.0m,4,090,860.0m,123.150,"Flugplatz" +"Gransee",,DE,5300.400N,01312.117E,51.0m,2,110,880.0m,126.725,"Flugplatz" +"Grabenstaett",,DE,4751.167N,01233.067E,537.0m,2,080,480.0m,129.975,"Flugplatz" +"Greding",,DE,4903.733N,01117.517E,525.0m,4,110,650.0m,122.500,"Flugplatz" +"Grefrath Niersho",,DE,5120.050N,00621.583E,31.0m,2,070,670.0m,123.625,"Flugplatz" +"Greiling B Toelz",,DE,4745.917N,01135.717E,713.0m,5,030,1250.0m,123.350,"Flugplatz" +"Greiz Obergroch",,DE,5038.650N,01210.500E,387.0m,2,050,740.0m,122.000,"Flugplatz" +"Griesau",,DE,4857.250N,01225.283E,321.0m,2,150,410.0m,122.600,"Flugplatz" +"Grifte Edermuend",,DE,5113.267N,00926.867E,202.0m,4,050,780.0m,123.500,"Flugplatz" +"Gross Garz Cls",,DE,5257.050N,01135.550E,18.0m,3,020,300.0m,123.425,"Landefeld" +"Grosse Hoehe",,DE,5259.183N,00834.333E,20.0m,4,040,920.0m,123.375,"Flugplatz" +"Gronenfelde Ul",,DE,5221.833N,01429.717E,63.0m,3,120,490.0m,120.975,"Landefeld" +"Grossrueckerswa",,DE,5038.650N,01307.717E,671.0m,2,110,1000.0m,123.000,"Flugplatz" +"Grossenhain",,DE,5118.483N,01333.333E,128.0m,5,110,2400.0m,122.700,"Flugplatz" +"Grosse Wiese",,DE,5208.233N,01034.250E,78.0m,4,070,760.0m,123.350,"Flugplatz" +"Grube",,DE,5414.667N,01101.433E,3.0m,2,090,500.0m,122.600,"Flugplatz" +"Gruenstadt Quirn",,DE,4935.133N,00808.367E,316.0m,4,180,900.0m,122.300,"Flugplatz" +"Gruibingen Norte",,DE,4837.267N,00939.317E,706.0m,4,080,520.0m,129.975,"Flugplatz" +"Guenching Ul",,DE,4916.067N,01134.383E,557.0m,3,060,440.0m,123.500,"Landefeld" +"Gunzburg Donau",,DE,4829.183N,01016.950E,445.0m,2,060,580.0m,118.125,"Flugplatz" +"Guestrow",,DE,5348.333N,01213.800E,14.0m,2,090,700.0m,122.000,"Flugplatz" +"Guetersloh Mil",,DE,5155.383N,00818.383E,73.0m,5,090,2240.0m,130.500,"Flugplatz" +"Gundelfingen",,DE,4834.167N,01021.517E,440.0m,2,100,580.0m,122.500,"Flugplatz" +"Gundelsheim Ul",,DE,4917.450N,00910.367E,273.0m,3,090,350.0m,123.425,"Landefeld" +"Gunzenhausen Re",,DE,4906.733N,01046.917E,485.0m,5,060,720.0m,118.550,"Flugplatz" +"Gustorfer Hoehe",,DE,5104.617N,00632.867E,89.0m,4,090,1030.0m,122.050,"Flugplatz" +"Hagen Hof",,DE,5118.433N,00725.617E,394.0m,4,100,410.0m,129.975,"Flugplatz" +"Hahnweide",,DE,4837.917N,00925.750E,352.0m,2,130,640.0m,123.250,"Flugplatz" +"Hain Modell 40M",,DE,5126.333N,01046.083E,266.0m,3,110,400.0m,123.425,"Landefeld" +"Hain Ul",,DE,5126.250N,01046.467E,268.0m,3,110,540.0m,123.425,"Landefeld" +"Haiterbach Nagol",,DE,4831.917N,00840.667E,596.0m,4,070,470.0m,123.350,"Flugplatz" +"Halbmeil X",,DE,4817.767N,00815.417E,291.0m,3,140,160.0m,,"Landefeld" +"Halle Oppin",,DE,5133.133N,01203.233E,107.0m,5,110,1120.0m,135.150,"Flugplatz" +"Hallertau",,DE,4838.967N,01135.783E,386.0m,4,030,770.0m,123.350,"Flugplatz" +"Hamburg Finkenw",,DE,5332.117N,00950.133E,6.0m,5,050,3180.0m,123.250,"Flugplatz" +"Hamburg Fuhlsbu",,DE,5337.833N,00959.300E,15.0m,5,150,3660.0m,121.275,"Flugplatz" +"Hameln Pyrmont",,DE,5157.967N,00917.450E,360.0m,5,040,600.0m,121.175,"Flugplatz" +"Hamm Lippewiesen",,DE,5141.417N,00749.067E,58.0m,5,060,900.0m,134.050,"Flugplatz" +"Hangensteinerhof",,DE,4855.967N,00848.917E,299.0m,4,070,550.0m,123.150,"Flugplatz" +"Hannover",,DE,5227.617N,00941.017E,55.0m,5,090,3800.0m,120.175,"Flugplatz" +"Harle",,DE,5342.400N,00749.217E,3.0m,5,090,510.0m,122.400,"Flugplatz" +"Hartenholm",,DE,5354.867N,01002.100E,37.0m,5,050,760.0m,118.125,"Flugplatz" +"Hartenstein Thie",,DE,5040.550N,01240.733E,408.0m,3,090,370.0m,120.975,"Landefeld" +"Haslach",,DE,4817.267N,00804.167E,207.0m,3,140,500.0m,,"Landefeld" +"Hassloch Pfalz",,DE,4921.317N,00817.417E,108.0m,4,080,920.0m,123.500,"Flugplatz" +"Hassfurt",,DE,5001.083N,01031.767E,220.0m,5,110,1100.0m,119.800,"Flugplatz" +"Hausach",,DE,4817.083N,00809.767E,235.0m,3,090,440.0m,,"Landefeld" +"Hausen",,DE,4740.433N,00750.483E,393.0m,3,020,400.0m,,"Landefeld" +"Hausham",,DE,4744.800N,01151.150E,781.0m,3,100,300.0m,,"Landefeld" +"Hayingen",,DE,4817.083N,00927.933E,703.0m,4,140,810.0m,123.500,"Flugplatz" +"Heilbronn Boecki",,DE,4907.300N,00910.767E,159.0m,4,070,760.0m,123.500,"Flugplatz" +"Heide Buesum",,DE,5409.200N,00854.100E,3.0m,5,110,720.0m,122.600,"Flugplatz" +"Heiligenberg",,DE,4750.000N,00918.067E,759.0m,4,180,500.0m,123.500,"Flugplatz" +"Heinsberg Aphov",,DE,5103.033N,00603.250E,65.0m,3,140,260.0m,123.425,"Landefeld" +"Heldburg",,DE,5016.200N,01044.067E,286.0m,3,160,600.0m,123.425,"Landefeld" +"Helgoland Duene",,DE,5411.117N,00754.950E,3.0m,5,150,480.0m,122.450,"Flugplatz" +"Hellenhagen",,DE,5201.517N,00933.883E,181.0m,4,100,260.0m,123.150,"Flugplatz" +"Helmstedt Rote",,DE,5214.033N,01058.700E,111.0m,4,080,940.0m,122.475,"Flugplatz" +"Hellingst",,DE,5322.500N,00851.000E,20.0m,4,130,1000.0m,123.500,"Flugplatz" +"Helm Unterthal",,DE,5009.367N,00952.683E,272.0m,3,170,330.0m,,"Landefeld" +"Hengsen Opherdic",,DE,5128.400N,00738.700E,132.0m,4,080,540.0m,123.450,"Flugplatz" +"Heppenheim",,DE,4937.283N,00837.500E,98.0m,2,150,1110.0m,122.475,"Flugplatz" +"Heringsdorf",,DE,5352.717N,01409.133E,28.0m,5,100,2300.0m,132.825,"Flugplatz" +"Hermuthausen",,DE,4918.867N,00944.717E,410.0m,4,080,990.0m,123.500,"Flugplatz" +"Herrenteich",,DE,4920.750N,00829.300E,91.0m,2,040,630.0m,132.050,"Flugplatz" +"Herrischried",,DE,4740.517N,00800.450E,904.0m,3,120,250.0m,,"Landefeld" +"Hersbruck",,DE,4930.450N,01126.617E,335.0m,4,090,470.0m,122.050,"Flugplatz" +"Herten Rheinfld",,DE,4733.600N,00744.900E,284.0m,2,060,730.0m,123.250,"Flugplatz" +"Herzogenaurach",,DE,4934.967N,01052.700E,324.0m,5,080,700.0m,122.850,"Flugplatz" +"Hessisch Lichten",,DE,5111.333N,00944.567E,411.0m,4,090,800.0m,123.500,"Flugplatz" +"Hettstadt",,DE,4947.917N,00950.217E,320.0m,2,090,550.0m,122.425,"Flugplatz" +"Hetzleser Berg",,DE,4938.533N,01109.750E,528.0m,5,080,600.0m,123.600,"Flugplatz" +"Heubach",,DE,4848.183N,00955.667E,433.0m,5,070,750.0m,123.025,"Flugplatz" +"Hienheim",,DE,4852.683N,01145.633E,397.0m,4,110,540.0m,123.500,"Flugplatz" +"Hildesheim",,DE,5210.783N,00956.733E,88.0m,5,070,1220.0m,118.300,"Flugplatz" +"Hilzingen",,DE,4745.633N,00846.050E,459.0m,4,090,820.0m,123.375,"Flugplatz" +"Hinterweiler",,DE,5014.700N,00645.317E,598.0m,3,060,270.0m,123.425,"Landefeld" +"Hirzenhain",,DE,5047.267N,00823.550E,528.0m,2,110,650.0m,118.325,"Flugplatz" +"Hirzenhain Nw-Ha",,DE,5048.100N,00822.667E,544.0m,4,310,150.0m,118.325,"Flugplatz" +"Hockenheim",,DE,4919.483N,00831.667E,93.0m,2,140,840.0m,123.650,"Flugplatz" +"Hodenhagen",,DE,5245.750N,00936.733E,22.0m,2,030,900.0m,119.000,"Flugplatz" +"Hoechenschwand1",,DE,4743.633N,00810.717E,969.0m,3,110,300.0m,,"Landefeld" +"Hoechenschw3",,DE,4744.000N,00809.617E,1016.0m,3,180,250.0m,,"Landefeld" +"Hoelleberg",,DE,5136.650N,00923.917E,257.0m,2,080,520.0m,122.000,"Flugplatz" +"Hoepen",,DE,5308.833N,00947.800E,85.0m,4,100,920.0m,122.475,"Flugplatz" +"Hoerbach",,DE,5040.100N,00815.633E,330.0m,4,050,310.0m,130.125,"Flugplatz" +"HoeXTer Holzmin",,DE,5148.383N,00922.700E,284.0m,5,140,810.0m,123.625,"Flugplatz" +"Hof-Plauen",,DE,5017.317N,01151.200E,598.0m,5,090,1480.0m,124.350,"Flugplatz" +"Hohenfels Mil",,DE,4913.000N,01150.150E,445.0m,5,090,670.0m,122.100,"Flugplatz" +"Hoherodskopf",,DE,5030.100N,00913.350E,674.0m,4,070,860.0m,123.500,"Flugplatz" +"Hohn Mil",,DE,5418.733N,00932.300E,12.0m,5,080,2450.0m,122.100,"Flugplatz" +"Hohentann Lands",,DE,4839.767N,01203.533E,471.0m,3,070,320.0m,123.425,"Landefeld" +"Holtorfsloh",,DE,5319.333N,01004.467E,55.0m,4,150,690.0m,123.350,"Flugplatz" +"Holzdorf Mil",,DE,5146.083N,01310.050E,82.0m,5,090,2420.0m,122.100,"Flugplatz" +"Homberg Ohm",,DE,5044.833N,00901.183E,349.0m,4,040,700.0m,123.500,"Flugplatz" +"Hoppensen Einbec",,DE,5147.183N,00945.317E,180.0m,3,070,380.0m,123.425,"Landefeld" +"Hoppstaedten We",,DE,4936.650N,00711.200E,332.0m,5,060,670.0m,130.650,"Flugplatz" +"Hornberg",,DE,4844.683N,00951.750E,682.0m,4,170,650.0m,122.025,"Flugplatz" +"Hoya",,DE,5248.717N,00909.833E,15.0m,4,120,680.0m,122.475,"Flugplatz" +"Hoym Ul",,DE,5146.683N,01117.117E,144.0m,3,100,350.0m,123.425,"Landefeld" +"Huelben",,DE,4831.750N,00923.867E,718.0m,4,090,660.0m,133.500,"Flugplatz" +"Huensborn",,DE,5055.717N,00753.950E,421.0m,2,090,950.0m,130.125,"Flugplatz" +"Hutten Hotzenwal",,DE,4737.983N,00756.483E,873.0m,4,110,710.0m,130.125,"Flugplatz" +"Huettenbusch",,DE,5317.200N,00856.900E,3.0m,2,090,450.0m,122.850,"Flugplatz" +"Huhnrain As",,DE,5029.400N,00950.833E,434.0m,5,080,500.0m,133.425,"Flugplatz" +"Husum",,DE,5430.600N,00908.300E,18.0m,5,030,1450.0m,122.050,"Flugplatz" +"Ibach",,DE,4743.617N,00803.867E,926.0m,3,170,250.0m,,"Landefeld" +"Ibach X",,DE,4826.700N,00810.100E,326.0m,3,160,250.0m,,"Landefeld" +"Idar Oberstein",,DE,4943.933N,00720.167E,475.0m,2,060,650.0m,122.850,"Flugplatz" +"Igelsloch",,DE,4844.867N,00839.233E,680.0m,3,110,250.0m,,"Landefeld" +"Igelsberg",,DE,4832.250N,00826.133E,749.0m,3,060,300.0m,,"Landefeld" +"Illertissen",,DE,4814.117N,01008.267E,512.0m,2,070,540.0m,118.525,"Flugplatz" +"Illeshe Mil Heli",,DE,4928.433N,01023.283E,329.0m,2,060,1500.0m,122.100,"Flugplatz" +"Imsweiler Donne",,DE,4936.367N,00747.617E,289.0m,3,060,280.0m,123.425,"Landefeld" +"Ingelfingen Bueh",,DE,4919.300N,00939.817E,421.0m,5,070,480.0m,130.600,"Flugplatz" +"Ingolstadt Manch",,DE,4842.933N,01132.033E,366.0m,5,070,2940.0m,122.100,"Flugplatz" +"Ippesheim Ul",,DE,4936.583N,01013.533E,297.0m,3,100,350.0m,120.975,"Landefeld" +"Irsingen",,DE,4902.300N,01030.183E,466.0m,4,260,560.0m,122.475,"Flugplatz" +"Iserlohn Rheiner",,DE,5125.817N,00738.650E,191.0m,4,070,800.0m,123.500,"Flugplatz" +"Iserlohn Suemmer",,DE,5126.250N,00742.100E,157.0m,4,040,440.0m,122.425,"Flugplatz" +"Isny Rotmoos",,DE,4742.017N,01001.233E,689.0m,4,080,450.0m,123.500,"Flugplatz" +"Ithwiesen",,DE,5157.067N,00939.767E,375.0m,2,320,850.0m,122.375,"Flugplatz" +"Itzehoe",,DE,5359.667N,00934.717E,24.0m,5,030,1040.0m,123.375,"Flugplatz" +"Jachenau Hoefen?",,DE,4736.483N,01129.500E,734.0m,3,070,300.0m,,"Landefeld" +"Jena Schongleina",,DE,5054.933N,01142.850E,375.0m,5,020,1170.0m,122.050,"Flugplatz" +"Jesenwang",,DE,4810.467N,01107.517E,565.0m,5,070,410.0m,120.050,"Flugplatz" +"Jever Mil",,DE,5332.017N,00753.317E,6.0m,5,100,2480.0m,118.725,"Flugplatz" +"Johannisau",,DE,5032.217N,00939.750E,265.0m,4,060,300.0m,122.300,"Flugplatz" +"Jueterbog Altes",,DE,5159.800N,01258.017E,94.0m,3,100,480.0m,123.425,"Landefeld" +"Juist",,DE,5340.883N,00703.400E,3.0m,5,080,700.0m,120.500,"Flugplatz" +"Kaelberbronn",,DE,4831.917N,00829.750E,706.0m,3,230,210.0m,,"Landefeld" +"Kalkhorst Agrar",,DE,5358.500N,01101.350E,22.0m,3,060,320.0m,,"Landefeld" +"Kamen Heeren",,DE,5135.417N,00742.600E,63.0m,4,110,970.0m,129.975,"Flugplatz" +"Kamenz",,DE,5117.817N,01407.650E,153.0m,5,030,1100.0m,122.050,"Flugplatz" +"Kammermark",,DE,5311.717N,01209.850E,84.0m,4,080,1040.0m,123.500,"Flugplatz" +"Kamp-Lintfort",,DE,5131.767N,00632.217E,21.0m,2,070,790.0m,123.000,"Flugplatz" +"Karbach",,DE,4952.400N,00940.083E,256.0m,3,090,180.0m,,"Landefeld" +"Karlsruhe Baden",,DE,4846.750N,00804.833E,125.0m,5,030,3000.0m,134.100,"Flugplatz" +"Karlshoefen",,DE,5319.967N,00901.717E,6.0m,5,120,700.0m,118.925,"Flugplatz" +"Karlstadt Saupur",,DE,4958.283N,00947.483E,248.0m,4,090,540.0m,123.475,"Flugplatz" +"Kassel Calden",,DE,5125.250N,00923.533E,250.0m,5,090,2500.0m,118.100,"Flugplatz" +"Kaufbeuren",,DE,4751.683N,01036.850E,726.0m,5,020,1830.0m,122.200,"Flugplatz" +"Kehl Sundheim",,DE,4833.683N,00750.633E,137.0m,2,030,680.0m,122.750,"Flugplatz" +"Kell",,DE,4937.300N,00650.417E,559.0m,4,050,820.0m,123.150,"Flugplatz" +"Kemmen Ul 30M",,DE,5247.733N,01306.283E,35.0m,3,140,360.0m,123.425,"Landefeld" +"Kempten Durach",,DE,4741.467N,01020.283E,710.0m,2,170,900.0m,122.000,"Flugplatz" +"Kerken",,DE,5126.317N,00626.733E,32.0m,3,020,250.0m,123.425,"Landefeld" +"Kiel Holtenau",,DE,5422.767N,01008.717E,31.0m,5,080,1260.0m,119.975,"Flugplatz" +"Kirchzarten",,DE,4757.050N,00757.350E,415.0m,4,180,1170.0m,122.475,"Flugplatz" +"Kirchdorf Inn",,DE,4814.300N,01258.617E,340.0m,2,040,670.0m,118.625,"Flugplatz" +"Kirn",,DE,4946.433N,00731.300E,429.0m,4,140,590.0m,123.375,"Flugplatz" +"Kitzingen",,DE,4944.517N,01012.117E,202.0m,5,070,800.0m,123.150,"Flugplatz" +"Kleinkoschen Ul",,DE,5130.600N,01404.983E,106.0m,3,150,410.0m,122.300,"Landefeld" +"Klein Muehlingen",,DE,5156.850N,01146.183E,53.0m,2,090,470.0m,122.000,"Flugplatz" +"Kleve Wisseler D",,DE,5146.167N,00617.950E,18.0m,4,070,510.0m,123.150,"Flugplatz" +"Kleinhartpenning",,DE,4751.100N,01139.967E,720.0m,3,070,300.0m,,"Landefeld" +"Klietz Scharlibb",,DE,5242.600N,01204.383E,26.0m,2,170,710.0m,122.375,"Flugplatz" +"Klippeneck Feld",,DE,4806.333N,00843.167E,685.0m,3,070,300.0m,,"Landefeld" +"Klippeneck",,DE,4806.467N,00845.750E,962.0m,4,050,1040.0m,122.175,"Flugplatz" +"KliX",,DE,5116.433N,01430.417E,145.0m,2,100,900.0m,118.600,"Flugplatz" +"Kniebis",,DE,4828.350N,00817.650E,920.0m,3,060,250.0m,,"Landefeld" +"Koblenz Winninge",,DE,5019.517N,00731.683E,195.0m,5,060,1170.0m,122.650,"Flugplatz" +"Kochel",,DE,4740.250N,01121.167E,599.0m,3,130,400.0m,,"Landefeld" +"Koln-Bonn",,DE,5051.950N,00708.567E,92.0m,5,140,3810.0m,124.975,"Flugplatz" +"Koenigsdorf",,DE,4749.717N,01127.967E,600.0m,5,100,740.0m,118.275,"Flugplatz" +"Kothen",,DE,5143.417N,01156.883E,93.0m,5,070,800.0m,123.650,"Flugplatz" +"Kohlenbissen Mil",,DE,5259.450N,01009.417E,80.0m,3,070,450.0m,121.500,"Landefeld" +"Konstanz",,DE,4740.900N,00908.283E,396.0m,2,120,760.0m,124.350,"Flugplatz" +"Konz Koenen",,DE,4940.533N,00632.567E,217.0m,4,020,780.0m,123.350,"Flugplatz" +"Korbach",,DE,5115.150N,00852.400E,390.0m,2,030,600.0m,119.975,"Flugplatz" +"Krefeld Egelsber",,DE,5123.083N,00635.267E,43.0m,2,060,640.0m,120.675,"Flugplatz" +"Kronach",,DE,5014.617N,01121.533E,466.0m,4,120,650.0m,123.350,"Flugplatz" +"Kruen",,DE,4730.600N,01116.000E,889.0m,3,070,500.0m,,"Landefeld" +"Kuehrstedt Beder",,DE,5334.083N,00847.367E,9.0m,2,120,580.0m,135.000,"Flugplatz" +"Kulmbach",,DE,5008.100N,01127.550E,506.0m,5,090,710.0m,118.525,"Flugplatz" +"Kunrau Ul 30M",,DE,5234.050N,01059.667E,65.0m,3,080,350.0m,123.425,"Landefeld" +"Kusel Langenbach",,DE,4928.683N,00718.533E,457.0m,4,100,520.0m,123.350,"Flugplatz" +"Kyritz",,DE,5255.133N,01225.517E,40.0m,5,140,1000.0m,122.725,"Flugplatz" +"Laage Mil",,DE,5355.083N,01216.700E,43.0m,5,100,2520.0m,118.425,"Flugplatz" +"Lachen Speyerdo",,DE,4919.800N,00812.767E,118.0m,2,110,1000.0m,118.175,"Flugplatz" +"Lager Hammelbur",,DE,5005.917N,00953.033E,342.0m,2,100,550.0m,118.425,"Flugplatz" +"Lahr",,DE,4822.150N,00749.667E,156.0m,5,030,3000.0m,125.175,"Flugplatz" +"Laichingen",,DE,4829.817N,00938.417E,746.0m,5,070,730.0m,127.700,"Flugplatz" +"Langenberg 36",,DE,5047.617N,00933.683E,360.0m,3,360,250.0m,123.500,"Landefeld" +"Landau Ebenberg",,DE,4910.583N,00808.167E,162.0m,4,100,590.0m,123.375,"Flugplatz" +"Landshut",,DE,4830.700N,01202.000E,399.0m,5,070,900.0m,129.800,"Flugplatz" +"Landsberg Mil",,DE,4804.233N,01054.367E,622.0m,5,070,2050.0m,122.100,"Flugplatz" +"Langenberg Hatte",,DE,5047.850N,00933.800E,350.0m,4,200,880.0m,123.500,"Flugplatz" +"Langeoog",,DE,5344.567N,00729.917E,3.0m,5,050,600.0m,122.025,"Flugplatz" +"Langhennersdorf",,DE,5056.917N,01315.717E,390.0m,2,050,900.0m,122.300,"Flugplatz" +"Langenlonsheim",,DE,4954.500N,00754.467E,92.0m,2,010,450.0m,122.875,"Flugplatz" +"Langenselbold",,DE,5010.617N,00904.000E,118.0m,4,070,400.0m,129.975,"Flugplatz" +"Langenfeld Wiesc",,DE,5108.450N,00659.117E,86.0m,4,070,620.0m,122.475,"Flugplatz" +"Langenbrand",,DE,4848.383N,00837.517E,702.0m,3,330,400.0m,,"Landefeld" +"Laucha",,DE,5114.767N,01141.617E,226.0m,2,090,720.0m,122.475,"Flugplatz" +"Lauda Landefeld",,DE,4934.483N,00942.583E,185.0m,3,160,370.0m,,"Landefeld" +"Lauenbrueck",,DE,5312.467N,00934.400E,29.0m,2,110,600.0m,123.650,"Flugplatz" +"Laufenselden",,DE,5013.300N,00759.917E,400.0m,4,050,510.0m,122.475,"Flugplatz" +"Lauf Lillinghof",,DE,4936.317N,01117.017E,544.0m,5,070,450.0m,133.500,"Flugplatz" +"Laupheim Mil",,DE,4813.200N,00954.617E,540.0m,5,090,1660.0m,122.100,"Flugplatz" +"Lauterbach",,DE,5041.017N,00924.683E,364.0m,2,060,600.0m,122.175,"Flugplatz" +"Leibertingen",,DE,4802.683N,00901.833E,833.0m,4,100,940.0m,129.975,"Flugplatz" +"Lechfeld Mil",,DE,4811.133N,01051.667E,555.0m,5,030,2660.0m,122.100,"Flugplatz" +"Leck",,DE,5447.400N,00857.683E,6.0m,2,120,820.0m,122.600,"Flugplatz" +"Leer Papenburg",,DE,5316.317N,00726.517E,1.0m,5,080,1200.0m,130.775,"Flugplatz" +"Leipheim",,DE,4826.450N,01014.283E,473.0m,5,060,610.0m,122.500,"Flugplatz" +"Leipzig",,DE,5125.433N,01214.183E,143.0m,5,080,3600.0m,121.100,"Flugplatz" +"Lengries1",,DE,4740.850N,01133.600E,698.0m,3,260,400.0m,,"Landefeld" +"Lengries3",,DE,4740.000N,01134.000E,716.0m,3,090,400.0m,,"Landefeld" +"Lenzkirch",,DE,4752.100N,00811.367E,834.0m,3,090,300.0m,,"Landefeld" +"Leutkirch Unterz",,DE,4751.533N,01000.867E,640.0m,5,060,1020.0m,122.875,"Flugplatz" +"Leuzendorf",,DE,4921.100N,01004.467E,463.0m,4,080,400.0m,123.500,"Flugplatz" +"Leverkusen",,DE,5100.917N,00700.367E,49.0m,2,150,920.0m,122.425,"Flugplatz" +"Lichtenfels",,DE,5008.867N,01102.817E,259.0m,2,040,700.0m,123.000,"Flugplatz" +"Lindlar",,DE,5059.817N,00722.600E,327.0m,4,050,900.0m,129.975,"Flugplatz" +"Linkenheim",,DE,4908.500N,00823.667E,97.0m,2,050,740.0m,122.600,"Flugplatz" +"Linnich Ul",,DE,5057.767N,00620.283E,103.0m,3,070,280.0m,123.425,"Landefeld" +"Lombach",,DE,4825.617N,00827.867E,657.0m,3,100,280.0m,,"Landefeld" +"Locktow Ul",,DE,5207.000N,01242.567E,65.0m,3,110,420.0m,126.500,"Landefeld" +"Loechgau",,DE,4900.067N,00904.917E,272.0m,4,110,600.0m,123.475,"Flugplatz" +"Ludwigshafen Dan",,DE,4924.717N,00820.983E,96.0m,4,050,1000.0m,130.125,"Flugplatz" +"Lubeck",,DE,5348.317N,01043.150E,15.0m,5,070,2100.0m,128.700,"Flugplatz" +"Luchow Rehbeck",,DE,5301.033N,01108.683E,10.0m,5,150,650.0m,122.500,"Flugplatz" +"Lunen Lippeweide",,DE,5137.017N,00730.083E,50.0m,4,090,1030.0m,123.500,"Flugplatz" +"Lueneburg",,DE,5314.900N,01027.483E,49.0m,2,070,980.0m,122.175,"Flugplatz" +"Luesse",,DE,5208.600N,01240.217E,64.0m,2,060,1020.0m,129.975,"Flugplatz" +"Magdeburg Cochst",,DE,5151.367N,01125.083E,183.0m,5,080,2500.0m,131.125,"Flugplatz" +"Magdeburg-City",,DE,5204.417N,01137.617E,82.0m,5,090,1000.0m,119.300,"Flugplatz" +"Mainbullau",,DE,4941.700N,00910.950E,455.0m,5,050,700.0m,122.375,"Flugplatz" +"Mainz Finthen",,DE,4958.150N,00808.867E,232.0m,5,080,1000.0m,122.925,"Flugplatz" +"Malmsheim",,DE,4847.083N,00855.050E,451.0m,4,080,710.0m,122.200,"Flugplatz" +"Malsch",,DE,4914.250N,00840.700E,133.0m,4,070,920.0m,129.975,"Flugplatz" +"Mannheim City",,DE,4928.367N,00830.783E,95.0m,5,090,1060.0m,129.775,"Flugplatz" +"Marburg Schoen",,DE,5052.450N,00848.900E,251.0m,2,040,750.0m,123.000,"Flugplatz" +"Markdorf",,DE,4742.567N,00923.350E,431.0m,4,130,600.0m,123.350,"Flugplatz" +"Marl Loemuehle",,DE,5138.817N,00709.817E,73.0m,5,070,830.0m,122.000,"Flugplatz" +"Marpingen",,DE,4927.167N,00702.367E,351.0m,4,100,780.0m,123.475,"Flugplatz" +"Meiersberg",,DE,5117.983N,00657.383E,164.0m,4,130,800.0m,130.125,"Flugplatz" +"Meinerzhagen",,DE,5106.000N,00735.967E,472.0m,5,070,1170.0m,130.600,"Flugplatz" +"Meistern",,DE,4841.583N,00832.700E,772.0m,3,260,260.0m,,"Landefeld" +"Melle Groenegau",,DE,5212.050N,00822.833E,73.0m,5,090,760.0m,122.400,"Flugplatz" +"Mellenthin Ul",,DE,5355.050N,01401.950E,19.0m,3,120,600.0m,123.425,"Landefeld" +"Memmingen",,DE,4759.333N,01014.367E,628.0m,5,060,2400.0m,126.850,"Flugplatz" +"Menden Barge",,DE,5127.583N,00750.167E,207.0m,4,240,920.0m,123.500,"Flugplatz" +"Mendig",,DE,5021.950N,00718.917E,174.0m,5,080,1610.0m,123.475,"Flugplatz" +"Mengen Hohenteng",,DE,4803.233N,00922.367E,555.0m,5,080,1560.0m,135.175,"Flugplatz" +"Mengeringhausen",,DE,5122.583N,00858.867E,363.0m,2,120,540.0m,121.025,"Flugplatz" +"Meppen Mil",,DE,5243.400N,00719.583E,21.0m,2,060,590.0m,122.100,"Flugplatz" +"Merseburg",,DE,5121.750N,01156.467E,104.0m,5,080,1140.0m,122.900,"Flugplatz" +"Meschede Schuren",,DE,5118.167N,00814.367E,439.0m,5,040,900.0m,122.050,"Flugplatz" +"Michelbach Am As",,DE,5013.900N,00804.617E,301.0m,4,070,600.0m,123.375,"Flugplatz" +"Michelstadt",,DE,4940.717N,00858.300E,349.0m,5,080,600.0m,123.650,"Flugplatz" +"Mindelheim Matts",,DE,4806.467N,01031.483E,567.0m,5,150,1140.0m,122.975,"Flugplatz" +"Mitteltal",,DE,4831.350N,00819.617E,589.0m,3,040,160.0m,,"Landefeld" +"Mittelfischach",,DE,4902.133N,00952.233E,385.0m,3,150,500.0m,123.425,"Landefeld" +"Mittenwald",,DE,4725.100N,01115.533E,934.0m,3,010,300.0m,,"Landefeld" +"Moeckmuehl Korb",,DE,4920.650N,00924.017E,354.0m,4,080,670.0m,129.975,"Flugplatz" +"Moeckern Tryppeh",,DE,5210.667N,01155.700E,71.0m,3,170,760.0m,120.975,"Landefeld" +"Moenchengladbach",,DE,5113.817N,00630.267E,40.0m,5,130,1200.0m,120.450,"Flugplatz" +"Moenchsheide",,DE,5030.483N,00715.333E,213.0m,4,100,690.0m,122.000,"Flugplatz" +"Mohorn",,DE,5059.883N,01326.783E,356.0m,3,040,340.0m,123.425,"Landefeld" +"Mohrdorf",,DE,5422.983N,01254.733E,3.0m,5,130,2300.0m,118.625,"Flugplatz" +"Montabaur",,DE,5025.433N,00749.800E,265.0m,4,050,580.0m,123.350,"Flugplatz" +"Moosburg Auf Kip",,DE,4827.400N,01156.500E,421.0m,2,040,650.0m,123.650,"Flugplatz" +"Morbach Ul",,DE,4902.017N,00935.467E,495.0m,3,090,430.0m,123.425,"Landefeld" +"Morschenich",,DE,5052.400N,00633.150E,104.0m,3,070,350.0m,123.425,"Landefeld" +"Mortitz Cls",,DE,5030.450N,01240.900E,100.0m,3,070,640.0m,,"Landefeld" +"Mosbach Lohrbach",,DE,4923.967N,00907.417E,332.0m,5,150,610.0m,122.850,"Flugplatz" +"Mosenberg",,DE,5103.767N,00925.317E,402.0m,2,070,510.0m,123.050,"Flugplatz" +"Muelben",,DE,4927.300N,00906.283E,519.0m,4,340,750.0m,130.125,"Flugplatz" +"Muehldorf",,DE,4816.783N,01230.017E,406.0m,5,080,850.0m,119.775,"Flugplatz" +"Muehlhausen",,DE,5112.783N,01032.967E,247.0m,2,080,900.0m,122.850,"Flugplatz" +"Muellheim",,DE,4749.450N,00738.383E,292.0m,4,160,700.0m,129.975,"Flugplatz" +"Munchen",,DE,4821.233N,01147.167E,454.0m,5,080,4000.0m,118.700,"Flugplatz" +"Munsingen Eisber",,DE,4824.550N,00926.550E,725.0m,4,080,450.0m,123.500,"Flugplatz" +"Munster Osnabruc",,DE,5208.083N,00741.083E,49.0m,5,070,2170.0m,129.800,"Flugplatz" +"Muenster Telgte",,DE,5156.667N,00746.417E,55.0m,5,100,850.0m,122.850,"Flugplatz" +"Mueritz Airpark",,DE,5318.383N,01245.150E,63.0m,5,070,2380.0m,129.975,"Flugplatz" +"Musbach",,DE,4830.167N,00828.717E,697.0m,4,170,1000.0m,130.125,"Flugplatz" +"Nabern Teck",,DE,4836.750N,00928.633E,372.0m,2,140,570.0m,118.325,"Flugplatz" +"Nannhausen",,DE,4958.217N,00728.733E,381.0m,2,060,560.0m,130.600,"Flugplatz" +"Nardt",,DE,5127.100N,01412.150E,117.0m,2,080,950.0m,123.000,"Flugplatz" +"Nastaetten",,DE,5011.883N,00753.333E,363.0m,4,080,1020.0m,126.500,"Flugplatz" +"Nauen Cls",,DE,5237.600N,01254.833E,28.0m,3,100,850.0m,,"Landefeld" +"Naunheim Maifeld",,DE,5015.500N,00719.933E,195.0m,3,060,180.0m,123.425,"Landefeld" +"Neresheim",,DE,4844.500N,01019.667E,538.0m,4,080,750.0m,130.125,"Flugplatz" +"Neuweiler Wiese",,DE,4839.300N,00836.500E,654.0m,3,080,250.0m,,"Landefeld" +"Neubiberg Cls",,DE,4804.383N,01138.283E,576.0m,3,070,2140.0m,,"Landefeld" +"Neubrandenbu Mil",,DE,5336.133N,01318.367E,70.0m,5,090,2290.0m,119.175,"Flugplatz" +"Neuburg Egweil",,DE,4846.917N,01112.917E,412.0m,2,080,640.0m,123.475,"Flugplatz" +"Neuburg Mil",,DE,4842.667N,01112.700E,381.0m,5,090,2450.0m,122.100,"Flugplatz" +"Neuhausen Ob Eck",,DE,4758.600N,00854.250E,806.0m,5,090,1240.0m,119.600,"Flugplatz" +"Neuenstadt A Koc",,DE,4914.567N,00919.033E,168.0m,3,100,250.0m,123.425,"Landefeld" +"Neu Guelze",,DE,5322.867N,01048.250E,12.0m,4,070,800.0m,123.500,"Flugplatz" +"Neuhardenberg",,DE,5236.783N,01414.567E,12.0m,5,080,2400.0m,119.125,"Flugplatz" +"Neuhausen",,DE,5141.083N,01425.383E,85.0m,2,110,1080.0m,122.725,"Flugplatz" +"Neuhaus Sumte",,DE,5317.383N,01054.267E,8.0m,3,130,300.0m,,"Landefeld" +"Neujellingsdorf",,DE,5427.350N,01106.567E,7.0m,2,110,590.0m,122.050,"Flugplatz" +"Neumagen Dhron",,DE,4950.567N,00654.967E,268.0m,2,090,750.0m,118.175,"Flugplatz" +"Neumarkt Oberpfa",,DE,4917.133N,01126.617E,424.0m,5,090,710.0m,119.975,"Flugplatz" +"Neumuenster",,DE,5404.767N,00956.517E,21.0m,5,080,600.0m,123.000,"Flugplatz" +"Neunkirchen BeXB",,DE,4920.400N,00715.200E,272.0m,2,060,450.0m,123.050,"Flugplatz" +"Neuruppin",,DE,5256.567N,01246.767E,43.0m,4,100,1260.0m,123.350,"Flugplatz" +"Neustadt Aisch",,DE,4935.250N,01034.667E,363.0m,5,090,600.0m,118.925,"Flugplatz" +"Neustadt Glewe",,DE,5321.717N,01136.867E,37.0m,2,090,1200.0m,123.375,"Flugplatz" +"Nidda A D Helm",,DE,5024.317N,00859.267E,176.0m,4,040,770.0m,123.375,"Flugplatz" +"Niederrhein",,DE,5136.150N,00608.533E,34.0m,5,090,2440.0m,129.400,"Flugplatz" +"Niederstetten",,DE,4923.517N,00957.500E,469.0m,5,070,1310.0m,122.100,"Flugplatz" +"Nienburg Holzbal",,DE,5242.583N,00909.733E,24.0m,2,080,850.0m,122.000,"Flugplatz" +"Niederwillingen",,DE,5046.817N,01103.117E,395.0m,3,060,350.0m,120.975,"Landefeld" +"Nittenau Bruck",,DE,4913.333N,01217.800E,357.0m,5,010,550.0m,118.925,"Flugplatz" +"Noerdlingen",,DE,4852.217N,01030.283E,421.0m,5,040,750.0m,133.075,"Flugplatz" +"Noervenich Mil",,DE,5049.867N,00639.483E,119.0m,5,070,2450.0m,122.100,"Flugplatz" +"Nordenbeck",,DE,5114.100N,00849.017E,452.0m,2,080,600.0m,122.500,"Flugplatz" +"Norddoellen Vis",,DE,5248.317N,00819.483E,49.0m,3,070,200.0m,123.425,"Landefeld" +"Norderney",,DE,5342.400N,00713.800E,3.0m,5,080,1000.0m,122.600,"Flugplatz" +"Nordhausen",,DE,5129.567N,01050.267E,210.0m,2,100,890.0m,118.625,"Flugplatz" +"Nordhorn Lingen",,DE,5227.467N,00710.950E,28.0m,5,060,900.0m,122.650,"Flugplatz" +"Nordholz Mil",,DE,5346.050N,00839.500E,21.0m,5,080,2430.0m,131.250,"Flugplatz" +"Norden Nordeich",,DE,5337.983N,00711.400E,1.0m,5,160,720.0m,121.400,"Flugplatz" +"Nordholz Spieka",,DE,5346.017N,00838.617E,21.0m,2,080,870.0m,121.025,"Flugplatz" +"Northeim",,DE,5142.383N,01002.383E,122.0m,2,110,680.0m,118.700,"Flugplatz" +"Nuernberg",,DE,4929.933N,01104.633E,314.0m,5,100,2700.0m,118.300,"Flugplatz" +"Nussbach",,DE,4832.300N,00802.283E,173.0m,3,120,200.0m,,"Landefeld" +"Oberems",,DE,5014.500N,00823.933E,403.0m,4,130,710.0m,123.350,"Flugplatz" +"Oberhinkofen",,DE,4857.100N,01208.800E,396.0m,4,050,540.0m,122.300,"Flugplatz" +"Ober Moerlen",,DE,5021.717N,00842.683E,247.0m,2,050,800.0m,122.850,"Flugplatz" +"Oberpfaffenhofen",,DE,4804.883N,01116.983E,594.0m,5,040,2280.0m,119.550,"Flugplatz" +"Oberrissdorf",,DE,5132.600N,01135.683E,224.0m,2,140,500.0m,122.200,"Flugplatz" +"Oberrot Glashofe",,DE,4900.600N,00938.333E,488.0m,3,100,250.0m,123.425,"Landefeld" +"Oberschleissheim",,DE,4814.350N,01133.550E,485.0m,5,080,800.0m,129.400,"Flugplatz" +"Obersoellbach",,DE,4911.000N,00933.550E,287.0m,3,150,260.0m,123.425,"Landefeld" +"Oberhamersbach",,DE,4821.967N,00807.033E,290.0m,3,050,250.0m,,"Landefeld" +"Oberkirch",,DE,4832.000N,00803.783E,180.0m,3,130,300.0m,,"Landefeld" +"Oberkollwangen",,DE,4840.850N,00836.917E,683.0m,3,340,260.0m,,"Landefeld" +"Obermehler Schlo",,DE,5116.067N,01038.083E,277.0m,5,110,1450.0m,122.900,"Flugplatz" +"Ochsenfurt",,DE,4940.417N,01004.267E,248.0m,2,100,510.0m,123.000,"Flugplatz" +"Ochsenhausen",,DE,4803.200N,00954.950E,650.0m,4,080,320.0m,123.500,"Flugplatz" +"Oedheim Heli Mil",,DE,4914.483N,00914.067E,156.0m,3,180,420.0m,122.000,"Landefeld" +"Oehna",,DE,5153.983N,01303.183E,85.0m,5,080,850.0m,122.500,"Flugplatz" +"Oelde Bergeler",,DE,5149.833N,00810.483E,82.0m,2,060,550.0m,122.800,"Flugplatz" +"Oerlinghausen",,DE,5155.950N,00839.717E,171.0m,5,040,800.0m,122.175,"Flugplatz" +"Oeventrop Ruhrwi",,DE,5123.767N,00808.667E,241.0m,4,120,440.0m,123.350,"Flugplatz" +"Offenbuettel Ul",,DE,5410.550N,00922.683E,3.0m,3,140,310.0m,123.425,"Landefeld" +"Offenburg",,DE,4826.883N,00755.417E,153.0m,5,020,910.0m,119.750,"Flugplatz" +"Ohlstadt",,DE,4739.467N,01114.033E,655.0m,5,040,880.0m,130.125,"Flugplatz" +"Oldenburg Hatten",,DE,5304.117N,00818.750E,9.0m,2,060,770.0m,118.175,"Flugplatz" +"Oldenburg Cls",,DE,5310.800N,00809.667E,8.0m,3,100,2110.0m,122.100,"Landefeld" +"Oppenheim",,DE,4950.467N,00822.550E,86.0m,2,020,800.0m,122.000,"Flugplatz" +"Oppershausen",,DE,5235.733N,01013.383E,43.0m,4,100,1090.0m,122.475,"Flugplatz" +"Oppingen Au",,DE,4833.400N,00949.333E,681.0m,4,100,690.0m,123.150,"Flugplatz" +"Ortenberg",,DE,4826.533N,00757.667E,159.0m,3,150,400.0m,,"Landefeld" +"Oschatz",,DE,5117.817N,01304.783E,156.0m,2,080,830.0m,122.200,"Flugplatz" +"Oschersleben",,DE,5202.283N,01112.333E,104.0m,2,110,600.0m,129.400,"Flugplatz" +"Osnabruck Atterh",,DE,5217.200N,00758.183E,83.0m,5,090,800.0m,118.675,"Flugplatz" +"Osterholz Scharm",,DE,5312.817N,00848.617E,2.0m,4,130,820.0m,130.125,"Flugplatz" +"Ottengruner Heid",,DE,5013.550N,01143.883E,575.0m,2,100,650.0m,123.000,"Flugplatz" +"Ottenberg Pilsac",,DE,4919.717N,01128.783E,552.0m,4,160,750.0m,122.200,"Flugplatz" +"Paderborn Lippst",,DE,5136.833N,00836.950E,213.0m,5,060,2180.0m,133.375,"Flugplatz" +"Paderborn HaXTer",,DE,5141.317N,00846.550E,241.0m,5,060,1190.0m,125.275,"Flugplatz" +"Paradiek Ul",,DE,5240.083N,00819.283E,39.0m,3,090,620.0m,120.975,"Landefeld" +"Parchim Kl Platz",,DE,5325.117N,01148.100E,44.0m,4,070,750.0m,123.500,"Flugplatz" +"Pasewalk",,DE,5330.317N,01356.900E,23.0m,5,090,900.0m,123.650,"Flugplatz" +"Paterzell",,DE,4750.750N,01103.667E,595.0m,5,180,480.0m,123.500,"Flugplatz" +"Pattonville",,DE,4851.850N,00913.483E,278.0m,5,100,670.0m,123.650,"Flugplatz" +"Peenemuende",,DE,5409.533N,01346.383E,3.0m,5,130,2400.0m,122.475,"Flugplatz" +"Pegnitz Zipser",,DE,4945.733N,01134.467E,543.0m,2,080,880.0m,132.025,"Flugplatz" +"Peine Glindbruch",,DE,5219.417N,01010.900E,68.0m,4,090,640.0m,123.350,"Flugplatz" +"Peissenberg Cls",,DE,4749.967N,01104.000E,606.0m,3,010,850.0m,123.500,"Landefeld" +"Peiting",,DE,4745.500N,01054.500E,745.0m,3,060,300.0m,,"Landefeld" +"Pellworm",,DE,5432.200N,00840.800E,1.0m,2,110,680.0m,123.000,"Flugplatz" +"Pennewitz",,DE,5040.167N,01103.050E,457.0m,2,060,900.0m,123.050,"Flugplatz" +"Perleberg",,DE,5304.233N,01149.083E,31.0m,4,110,1110.0m,122.300,"Flugplatz" +"Pfarrkirchen",,DE,4825.217N,01251.883E,387.0m,2,070,700.0m,119.975,"Flugplatz" +"Pfullendorf",,DE,4754.567N,00915.050E,699.0m,2,010,600.0m,123.250,"Flugplatz" +"Pieverstorf 25M",,DE,5349.100N,01108.683E,27.0m,3,080,320.0m,,"Landefeld" +"Pinnow",,DE,5336.950N,01133.767E,43.0m,2,010,800.0m,122.500,"Flugplatz" +"Pirmasens",,DE,4915.867N,00729.300E,381.0m,5,050,800.0m,122.350,"Flugplatz" +"Pirna Pratzschwi",,DE,5058.783N,01354.517E,122.0m,2,120,900.0m,118.625,"Flugplatz" +"Plaetzer Huenfel",,DE,5042.567N,00944.350E,350.0m,4,160,540.0m,122.200,"Flugplatz" +"Pleidelsheim",,DE,4857.400N,00911.517E,190.0m,4,020,480.0m,123.500,"Flugplatz" +"Plettenberg",,DE,5111.533N,00747.383E,307.0m,2,100,430.0m,122.925,"Flugplatz" +"Ploetzin Ul",,DE,5221.333N,01249.500E,50.0m,3,080,330.0m,123.425,"Landefeld" +"Poel Agrar",,DE,5400.200N,01127.750E,14.0m,3,070,300.0m,,"Landefeld" +"Pohlheim Viehhei",,DE,5031.933N,00844.033E,237.0m,4,080,870.0m,122.150,"Flugplatz" +"Poltringen",,DE,4832.817N,00856.750E,404.0m,5,170,400.0m,123.050,"Flugplatz" +"Porta Westfalica",,DE,5213.267N,00851.583E,44.0m,5,050,860.0m,122.375,"Flugplatz" +"Porta W Gras Gld",,DE,5213.333N,00851.567E,45.0m,3,060,1000.0m,122.500,"Landefeld" +"Pretzschendorf",,DE,5053.033N,01331.850E,490.0m,3,060,780.0m,123.425,"Landefeld" +"Pritzwalk Sommer",,DE,5310.800N,01211.067E,88.0m,2,080,830.0m,122.600,"Flugplatz" +"Preschen Cls",,DE,5139.817N,01438.050E,101.0m,3,060,2400.0m,,"Landefeld" +"Purkshof",,DE,5409.717N,01214.867E,21.0m,2,040,1100.0m,122.400,"Flugplatz" +"Quakenbrueck",,DE,5239.783N,00755.583E,24.0m,4,100,540.0m,122.300,"Flugplatz" +"Radevormwald Ley",,DE,5112.983N,00722.933E,390.0m,4,090,350.0m,123.475,"Flugplatz" +"Radolfzell-Stahr",,DE,4748.167N,00858.767E,421.0m,2,010,710.0m,130.125,"Flugplatz" +"Ramstein Mil",,DE,4926.217N,00736.017E,238.0m,5,080,3200.0m,133.200,"Flugplatz" +"Rastatt Baldenau",,DE,4852.467N,00812.783E,113.0m,4,050,900.0m,122.475,"Flugplatz" +"Regensburg",,DE,4908.517N,01204.917E,396.0m,5,100,640.0m,120.425,"Flugplatz" +"Reichelsheim",,DE,5020.317N,00852.717E,121.0m,5,180,1300.0m,120.425,"Flugplatz" +"Reinheim",,DE,4950.367N,00851.033E,155.0m,4,010,720.0m,124.000,"Flugplatz" +"Reinsdorf",,DE,5154.050N,01311.767E,102.0m,2,100,1280.0m,122.850,"Flugplatz" +"Reiselfingen",,DE,4751.100N,00822.283E,746.0m,4,070,610.0m,123.000,"Flugplatz" +"Reit I Winkel",,DE,4740.417N,01228.700E,689.0m,3,010,250.0m,,"Landefeld" +"Rendsburg Schach",,DE,5413.267N,00936.050E,6.0m,5,030,990.0m,123.650,"Flugplatz" +"Renneritz",,DE,5135.683N,01214.250E,91.0m,2,070,1100.0m,123.475,"Flugplatz" +"Rerik Zweedorf",,DE,5404.917N,01138.933E,9.0m,2,080,640.0m,126.500,"Flugplatz" +"Rheine Bentl Mil",,DE,5217.467N,00723.233E,40.0m,5,090,500.0m,122.100,"Flugplatz" +"Rheine Eschendor",,DE,5216.600N,00729.533E,41.0m,2,110,920.0m,122.050,"Flugplatz" +"Rheinstetten",,DE,4858.667N,00820.550E,116.0m,4,020,1030.0m,123.350,"Flugplatz" +"Riedelbach",,DE,5018.133N,00823.083E,508.0m,4,060,710.0m,130.125,"Flugplatz" +"Riedlingen",,DE,4808.667N,00928.000E,529.0m,4,040,520.0m,129.975,"Flugplatz" +"Riesa Goehlis",,DE,5117.583N,01321.433E,98.0m,5,120,1000.0m,122.600,"Flugplatz" +"Riesa Canitz",,DE,5118.183N,01313.667E,123.0m,4,090,1050.0m,123.500,"Flugplatz" +"Rinteln",,DE,5210.517N,00903.200E,55.0m,5,110,600.0m,122.925,"Flugplatz" +"Roggenhagen Ul",,DE,5340.250N,01323.983E,47.0m,3,110,550.0m,123.425,"Landefeld" +"Roitzschjora",,DE,5134.617N,01229.650E,88.0m,2,100,1200.0m,122.000,"Flugplatz" +"Rosenthal Field",,DE,4951.800N,01147.283E,457.0m,5,090,750.0m,127.450,"Flugplatz" +"Rossfeld",,DE,4830.817N,00920.067E,803.0m,4,070,420.0m,122.475,"Flugplatz" +"Rotenburg Wumme",,DE,5307.700N,00920.917E,27.0m,5,080,800.0m,122.050,"Flugplatz" +"Rothenberg",,DE,4929.150N,00856.167E,479.0m,4,090,640.0m,123.500,"Flugplatz" +"Rothenburg O D T",,DE,4923.300N,01013.100E,399.0m,5,030,950.0m,118.175,"Flugplatz" +"Roth Mil",,DE,4913.050N,01106.000E,387.0m,5,090,530.0m,122.100,"Flugplatz" +"Rothenburg Goerl",,DE,5121.833N,01457.067E,159.0m,5,180,2500.0m,123.250,"Flugplatz" +"Rottach",,DE,4740.950N,01148.150E,761.0m,3,110,260.0m,,"Landefeld" +"Rottweil Zepfenh",,DE,4811.200N,00843.383E,738.0m,5,080,800.0m,129.500,"Flugplatz" +"Rudolstadt Gros",,DE,5043.967N,01114.167E,470.0m,2,070,800.0m,118.325,"Flugplatz" +"Rudesheim",,DE,5001.017N,00753.567E,405.0m,4,360,420.0m,123.500,"Flugplatz" +"Rugen",,DE,5423.000N,01319.533E,21.0m,5,090,900.0m,123.000,"Flugplatz" +"Ruppiner Land",,DE,5247.600N,01245.650E,43.0m,5,110,900.0m,122.500,"Flugplatz" +"Saal Kreuzberg",,DE,5018.533N,01022.400E,266.0m,4,120,590.0m,122.475,"Flugplatz" +"Saarbrucken",,DE,4912.883N,00706.567E,323.0m,5,090,1990.0m,118.350,"Flugplatz" +"Saarlouis Dueren",,DE,4918.750N,00640.450E,341.0m,5,070,800.0m,122.600,"Flugplatz" +"Salzwedel",,DE,5249.683N,01118.983E,33.0m,4,090,810.0m,122.200,"Flugplatz" +"Salzgitter Drutt",,DE,5209.267N,01025.583E,98.0m,5,070,630.0m,122.850,"Flugplatz" +"Salzgitter Schaf",,DE,5201.833N,01021.783E,203.0m,2,110,950.0m,122.500,"Flugplatz" +"Saarmund",,DE,5218.500N,01306.033E,52.0m,2,090,1000.0m,123.650,"Flugplatz" +"Sauldorf Boll",,DE,4757.383N,00902.000E,650.0m,3,020,300.0m,120.975,"Landefeld" +"Saulgau",,DE,4801.767N,00930.433E,582.0m,5,120,450.0m,123.600,"Flugplatz" +"Schoenau3",,DE,4747.150N,00753.983E,536.0m,3,040,400.0m,,"Landefeld" +"Schaefhalde Stei",,DE,4841.550N,01006.017E,628.0m,4,040,770.0m,123.500,"Flugplatz" +"Schameder",,DE,5100.017N,00818.550E,550.0m,2,100,750.0m,122.025,"Flugplatz" +"Scharling",,DE,4740.150N,01144.767E,778.0m,3,090,300.0m,,"Landefeld" +"Schwann Connweil",,DE,4850.300N,00832.583E,480.0m,4,070,330.0m,122.300,"Flugplatz" +"Scheuen Celle",,DE,5240.167N,01005.333E,55.0m,4,080,1120.0m,122.200,"Flugplatz" +"Schlechtenfeld",,DE,4817.083N,00940.400E,562.0m,4,330,300.0m,123.350,"Flugplatz" +"Schleswig Kropp",,DE,5425.533N,00932.517E,15.0m,2,090,820.0m,118.675,"Flugplatz" +"Schlierstadt Sel",,DE,4926.567N,00921.750E,344.0m,2,180,580.0m,122.050,"Flugplatz" +"Schleswig Mil",,DE,5427.567N,00930.983E,21.0m,5,050,2450.0m,122.100,"Flugplatz" +"Schmallenberg",,DE,5109.700N,00815.700E,467.0m,2,090,900.0m,122.425,"Flugplatz" +"Schmidgaden",,DE,4925.767N,01205.883E,380.0m,2,120,520.0m,123.000,"Flugplatz" +"Schmoldow",,DE,5358.367N,01320.583E,24.0m,2,150,900.0m,122.850,"Flugplatz" +"Schnuckenhei Rep",,DE,5242.967N,01032.000E,106.0m,4,110,980.0m,123.475,"Flugplatz" +"Schoenhagen",,DE,5212.217N,01309.500E,40.0m,5,070,1510.0m,131.150,"Flugplatz" +"Schoenberg",,DE,4802.867N,01230.033E,543.0m,2,080,450.0m,118.550,"Flugplatz" +"Schonebeck Zackm",,DE,5159.783N,01147.383E,52.0m,2,070,800.0m,123.000,"Flugplatz" +"Schreckhof Mosba",,DE,4921.050N,00907.267E,270.0m,4,160,300.0m,123.500,"Flugplatz" +"Schwedenstebelul",,DE,5249.350N,01002.400E,71.0m,3,110,290.0m,120.975,"Landefeld" +"Schotten",,DE,5032.083N,00908.733E,500.0m,4,050,380.0m,123.500,"Flugplatz" +"Schwarzenbach So",,DE,4935.517N,00701.900E,493.0m,3,050,380.0m,123.425,"Landefeld" +"Schwarzheide",,DE,5129.383N,01352.733E,101.0m,2,080,850.0m,129.975,"Flugplatz" +"Schwaigern Stet",,DE,4908.500N,00859.250E,237.0m,3,080,350.0m,123.425,"Landefeld" +"Schwandorf",,DE,4920.433N,01211.083E,387.0m,2,110,840.0m,121.200,"Flugplatz" +"Schwerin Parchim",,DE,5325.617N,01147.000E,52.0m,5,060,3000.0m,128.900,"Flugplatz" +"Schwaebisch Hall",,DE,4907.100N,00947.033E,399.0m,5,100,1540.0m,129.225,"Flugplatz" +"Schwabmuenchen",,DE,4810.750N,01042.183E,550.0m,2,080,850.0m,122.500,"Flugplatz" +"Schwenningen A N",,DE,4803.933N,00834.267E,667.0m,5,040,800.0m,122.850,"Flugplatz" +"Schweinfurt-Sud",,DE,5000.633N,01015.083E,210.0m,2,100,980.0m,119.975,"Flugplatz" +"Schwein Mil Heli",,DE,5002.933N,01010.200E,241.0m,5,090,680.0m,122.100,"Flugplatz" +"Schwabisch-H Wec",,DE,4907.450N,00946.867E,399.0m,2,080,550.0m,129.225,"Flugplatz" +"Schoemberg",,DE,4823.550N,00824.783E,723.0m,3,130,400.0m,,"Landefeld" +"Schiltach X",,DE,4817.917N,00821.350E,336.0m,3,040,210.0m,,"Landefeld" +"Schwabach Buchen",,DE,4916.117N,01100.600E,359.0m,5,100,530.0m,135.425,"Flugplatz" +"Schwarzenbrg X",,DE,4836.167N,00822.833E,563.0m,3,060,190.0m,,"Landefeld" +"Schweighofen",,DE,4901.900N,00759.400E,149.0m,2,080,620.0m,123.000,"Flugplatz" +"Schernbach",,DE,4833.800N,00829.617E,675.0m,3,040,430.0m,,"Landefeld" +"Seedorf",,DE,5320.117N,00915.583E,17.0m,2,060,450.0m,119.650,"Flugplatz" +"Segeletz",,DE,5249.600N,01232.550E,39.0m,2,100,920.0m,123.500,"Flugplatz" +"Seissen",,DE,4824.783N,00945.983E,692.0m,4,110,540.0m,123.425,"Flugplatz" +"Sengenthal Ul",,DE,4912.917N,01124.050E,437.0m,3,120,250.0m,123.425,"Landefeld" +"Seussling Prv Ul",,DE,4947.483N,01058.233E,336.0m,3,060,260.0m,123.425,"Landefeld" +"Siegen Eisernhar",,DE,5050.250N,00800.850E,390.0m,4,090,720.0m,123.375,"Flugplatz" +"Siegerland",,DE,5042.467N,00804.983E,601.0m,5,130,1620.0m,120.375,"Flugplatz" +"Sierksdorf Hof A",,DE,5404.033N,01044.567E,28.0m,2,030,500.0m,122.000,"Flugplatz" +"Siewisch Ul",,DE,5141.250N,01412.517E,89.0m,2,080,510.0m,123.425,"Flugplatz" +"Singhofen",,DE,5016.217N,00751.217E,302.0m,4,040,800.0m,123.150,"Flugplatz" +"Sinsheim",,DE,4914.833N,00853.633E,159.0m,2,120,1020.0m,122.475,"Flugplatz" +"Sommerda",,DE,5111.917N,01111.467E,137.0m,2,070,920.0m,124.000,"Flugplatz" +"Soest Bad Sassen",,DE,5134.683N,00812.850E,120.0m,2,070,820.0m,122.600,"Flugplatz" +"Sonnen",,DE,4840.950N,01341.683E,824.0m,5,020,650.0m,122.050,"Flugplatz" +"Sontra Dornberg",,DE,5105.250N,00954.933E,403.0m,4,120,500.0m,123.500,"Flugplatz" +"Spangdahlem Mil",,DE,4958.567N,00641.867E,362.0m,5,050,3180.0m,122.200,"Flugplatz" +"Sperenberg Cls",,DE,5208.233N,01318.100E,46.0m,3,090,1240.0m,,"Landefeld" +"Speyer",,DE,4918.283N,00827.100E,95.0m,5,160,1670.0m,118.075,"Flugplatz" +"Spitzingsee",,DE,4739.150N,01153.400E,1051.0m,3,130,300.0m,,"Landefeld" +"Spremberg Welzow",,DE,5134.617N,01408.217E,116.0m,5,030,2000.0m,134.850,"Flugplatz" +"Sprossen",,DE,5102.600N,01213.983E,206.0m,2,090,740.0m,120.975,"Flugplatz" +"Steinberg 0725",,DE,5257.333N,00733.717E,28.0m,3,070,250.0m,123.500,"Landefeld" +"Stade",,DE,5333.667N,00929.917E,19.0m,5,110,650.0m,123.000,"Flugplatz" +"Stadtlohn Vreden",,DE,5159.750N,00650.433E,49.0m,5,110,1240.0m,119.200,"Flugplatz" +"Stauffenbuehl",,DE,5109.550N,01002.833E,277.0m,4,020,820.0m,123.500,"Flugplatz" +"St Blasien",,DE,4746.517N,00806.733E,801.0m,3,140,250.0m,,"Landefeld" +"Stechow Ferchesa",,DE,5239.050N,01229.283E,42.0m,2,040,610.0m,122.200,"Flugplatz" +"Steinberg Wessel",,DE,5205.017N,01001.100E,180.0m,4,090,720.0m,123.500,"Flugplatz" +"Stendal Borstel",,DE,5237.733N,01149.200E,55.0m,5,080,1990.0m,122.400,"Flugplatz" +"Steinberg Surwol",,DE,5257.383N,00733.417E,29.0m,4,090,860.0m,123.500,"Flugplatz" +"Stillberghof",,DE,4843.850N,01050.117E,510.0m,4,090,710.0m,123.475,"Flugplatz" +"St Michaelisdon",,DE,5358.700N,00908.733E,37.0m,5,070,700.0m,122.500,"Flugplatz" +"Stoelln Rhinow",,DE,5244.450N,01223.467E,40.0m,2,080,840.0m,122.000,"Flugplatz" +"Stolberg Diepenl",,DE,5046.233N,00616.917E,259.0m,4,030,770.0m,123.500,"Flugplatz" +"St Peter Ording",,DE,5418.533N,00841.200E,3.0m,5,070,670.0m,129.775,"Flugplatz" +"Stralsund",,DE,5420.150N,01302.617E,15.0m,2,050,900.0m,118.625,"Flugplatz" +"Strausberg",,DE,5234.800N,01354.933E,78.0m,5,050,1200.0m,123.050,"Flugplatz" +"Straubing",,DE,4854.050N,01231.033E,320.0m,5,090,1350.0m,127.150,"Flugplatz" +"Strassham Ul",,DE,4810.800N,01155.633E,514.0m,3,030,400.0m,123.425,"Landefeld" +"Stude Bernsteins",,DE,5233.817N,01041.050E,73.0m,4,110,920.0m,123.150,"Flugplatz" +"Stuttgart",,DE,4841.400N,00913.317E,390.0m,5,070,3340.0m,119.050,"Flugplatz" +"Suhl Goldlauter",,DE,5037.933N,01043.550E,588.0m,2,100,570.0m,124.550,"Flugplatz" +"Sultmer Berg",,DE,5143.767N,00959.533E,222.0m,4,180,550.0m,123.150,"Flugplatz" +"Sulz Ul",,DE,4820.700N,00838.200E,536.0m,3,040,310.0m,123.425,"Landefeld" +"Sylt",,DE,5454.700N,00820.550E,15.0m,5,140,2120.0m,119.750,"Flugplatz" +"Tannheim",,DE,4800.600N,01005.950E,561.0m,2,090,1020.0m,122.825,"Flugplatz" +"Tarmstedt",,DE,5315.083N,00906.517E,41.0m,4,060,700.0m,123.150,"Flugplatz" +"Tauberbischofshe",,DE,4938.867N,00937.967E,285.0m,4,120,740.0m,122.200,"Flugplatz" +"Tauberbisch Wies",,DE,4939.000N,00938.683E,171.0m,3,150,360.0m,,"Landefeld" +"Taucha",,DE,5123.717N,01232.283E,149.0m,2,070,600.0m,122.400,"Flugplatz" +"Teisendorf Pank",,DE,4749.583N,01250.700E,578.0m,4,150,250.0m,123.500,"Flugplatz" +"Teldau Ul",,DE,5319.700N,01049.983E,5.0m,3,040,320.0m,123.425,"Landefeld" +"Thalmaessing Wai",,DE,4903.850N,01112.567E,577.0m,2,170,410.0m,123.650,"Flugplatz" +"Thannhausen",,DE,4817.400N,01026.517E,491.0m,2,080,500.0m,118.175,"Flugplatz" +"Tirschenreuth",,DE,4952.417N,01219.450E,499.0m,4,080,520.0m,123.500,"Flugplatz" +"Titschendor2 Rwy",,DE,5023.550N,01131.317E,638.0m,3,180,600.0m,122.300,"Landefeld" +"Titisee",,DE,4754.017N,00809.717E,857.0m,3,060,200.0m,,"Landefeld" +"Titschendorf",,DE,5023.833N,01131.367E,650.0m,4,010,480.0m,122.300,"Flugplatz" +"Torgau Beilrode",,DE,5134.267N,01303.133E,82.0m,2,080,800.0m,122.300,"Flugplatz" +"Traben Trarbach",,DE,4958.067N,00706.700E,275.0m,2,180,750.0m,123.000,"Flugplatz" +"Treuchtlingen Bu",,DE,4859.750N,01053.100E,412.0m,2,150,640.0m,122.600,"Flugplatz" +"Trier Foehren",,DE,4951.850N,00647.267E,204.0m,5,040,1200.0m,122.050,"Flugplatz" +"Troestau",,DE,5001.200N,01155.867E,561.0m,4,130,400.0m,123.150,"Flugplatz" +"Trollenberg",,DE,4821.617N,00827.000E,653.0m,3,110,400.0m,,"Landefeld" +"Tutow",,DE,5355.317N,01313.133E,6.0m,5,170,1200.0m,130.125,"Flugplatz" +"Uebersberg",,DE,4827.483N,00917.800E,784.0m,4,080,950.0m,123.150,"Flugplatz" +"Uehrde Ul",,DE,5206.417N,01045.333E,153.0m,3,130,500.0m,123.425,"Landefeld" +"Uelzen",,DE,5259.017N,01027.933E,75.0m,5,080,800.0m,130.900,"Flugplatz" +"Uetersen Heist",,DE,5338.800N,00942.233E,5.0m,2,090,1100.0m,122.700,"Flugplatz" +"Uetersen Segelfl",,DE,5338.967N,00942.350E,5.0m,4,090,1140.0m,123.475,"Flugplatz" +"Ummern",,DE,5237.200N,01024.617E,71.0m,4,130,560.0m,123.500,"Flugplatz" +"Unterbuchen",,DE,4747.017N,01129.133E,635.0m,3,040,300.0m,,"Landefeld" +"Unterwoessen",,DE,4743.783N,01226.283E,565.0m,5,060,800.0m,122.300,"Flugplatz" +"Unterschuepf",,DE,4930.950N,00940.150E,346.0m,2,080,670.0m,122.600,"Flugplatz" +"Unterschwaningen",,DE,4905.167N,01038.083E,476.0m,3,080,300.0m,120.975,"Landefeld" +"Urspring",,DE,4833.233N,00954.167E,642.0m,4,150,610.0m,123.500,"Flugplatz" +"Uslar",,DE,5139.733N,00936.317E,260.0m,4,070,550.0m,129.975,"Flugplatz" +"Utscheid",,DE,4959.867N,00620.583E,421.0m,4,060,720.0m,123.350,"Flugplatz" +"Vaihingen",,DE,4856.183N,00858.817E,312.0m,4,090,1000.0m,129.400,"Flugplatz" +"Varrelbusch",,DE,5254.500N,00802.600E,37.0m,2,090,850.0m,123.000,"Flugplatz" +"Verden Scharnh",,DE,5257.917N,00916.967E,42.0m,2,130,510.0m,122.400,"Flugplatz" +"Vettweiss Soller",,DE,5044.850N,00634.033E,159.0m,3,150,380.0m,120.975,"Landefeld" +"Vielbrunn",,DE,4943.183N,00904.933E,459.0m,4,170,680.0m,123.150,"Flugplatz" +"Vilsbiburg",,DE,4825.583N,01220.733E,442.0m,2,030,450.0m,123.000,"Flugplatz" +"Vilseck Mil",,DE,4938.017N,01146.033E,412.0m,5,100,1080.0m,122.100,"Flugplatz" +"Vilshofen",,DE,4838.083N,01311.800E,302.0m,5,120,1130.0m,119.175,"Flugplatz" +"Vinsebeck Frankn",,DE,5150.683N,00900.817E,247.0m,4,180,510.0m,122.200,"Flugplatz" +"Volkleshofen",,DE,4900.567N,00921.267E,396.0m,4,080,680.0m,130.125,"Flugplatz" +"Vogelsberg Wiese",,DE,4823.750N,00826.950E,680.0m,3,290,250.0m,,"Landefeld" +"Vogtareuth",,DE,4756.767N,01212.283E,471.0m,5,060,590.0m,121.025,"Flugplatz" +"Vorderriss",,DE,4733.550N,01126.267E,810.0m,3,170,300.0m,,"Landefeld" +"Wackersberg",,DE,4744.100N,01133.100E,731.0m,3,100,400.0m,,"Landefeld" +"Wachtersberg Hub",,DE,4836.900N,00845.333E,591.0m,4,070,600.0m,123.475,"Flugplatz" +"Wahlstedt",,DE,5358.167N,01013.300E,40.0m,2,110,800.0m,121.025,"Flugplatz" +"Wasserkuppe",,DE,5029.933N,00957.217E,898.0m,5,060,670.0m,118.650,"Flugplatz" +"Waldeck",,DE,5113.550N,00903.317E,405.0m,4,010,560.0m,123.475,"Flugplatz" +"Walldorf",,DE,4918.283N,00839.550E,103.0m,2,180,500.0m,118.275,"Flugplatz" +"Wallduern",,DE,4934.900N,00924.133E,402.0m,5,060,820.0m,122.750,"Flugplatz" +"Walldorf Ul",,DE,5036.867N,01021.933E,361.0m,3,040,700.0m,123.425,"Landefeld" +"Walsrode Luisenh",,DE,5253.300N,00936.050E,57.0m,4,080,640.0m,123.500,"Flugplatz" +"Waltrop Ul",,DE,5138.400N,00725.567E,50.0m,3,120,370.0m,123.425,"Landefeld" +"WalXHeim Untersc",,DE,4857.217N,01019.517E,509.0m,3,090,300.0m,120.975,"Landefeld" +"Wangerooge",,DE,5346.867N,00755.233E,3.0m,5,100,850.0m,122.400,"Flugplatz" +"Wangen Kissleg",,DE,4745.400N,00951.367E,640.0m,4,120,770.0m,123.500,"Flugplatz" +"Wanlo Niersquell",,DE,5106.067N,00623.617E,74.0m,4,080,540.0m,121.175,"Flugplatz" +"Warburg Heinber",,DE,5129.833N,00905.250E,172.0m,4,130,900.0m,123.500,"Flugplatz" +"Waren Vielist",,DE,5334.067N,01239.117E,85.0m,2,040,800.0m,130.325,"Flugplatz" +"Warbelow Cls",,DE,5359.717N,01242.633E,20.0m,3,070,700.0m,122.100,"Landefeld" +"Warngau Tannried",,DE,4749.467N,01142.250E,723.0m,5,020,550.0m,123.050,"Flugplatz" +"Wasentegernbach",,DE,4816.400N,01213.117E,463.0m,3,060,260.0m,120.975,"Landefeld" +"Wegscheid",,DE,4739.833N,01134.233E,711.0m,3,080,300.0m,,"Landefeld" +"Wehr",,DE,4738.633N,00754.550E,392.0m,3,020,250.0m,,"Landefeld" +"Weidberg Kaltenw",,DE,5036.550N,01005.283E,619.0m,3,140,400.0m,123.425,"Landefeld" +"Weiden Opf",,DE,4940.733N,01207.000E,405.0m,5,140,570.0m,120.250,"Flugplatz" +"Weimar Umpferst",,DE,5057.900N,01124.000E,299.0m,2,100,670.0m,122.400,"Flugplatz" +"Weinheim Bergst",,DE,4934.017N,00836.650E,96.0m,2,170,770.0m,123.600,"Flugplatz" +"Weipertshofen",,DE,4905.183N,01007.483E,440.0m,4,110,470.0m,123.350,"Flugplatz" +"Weissenhorn",,DE,4817.367N,01008.417E,500.0m,2,080,650.0m,119.425,"Flugplatz" +"Weissenburg Wuel",,DE,4901.550N,01101.117E,615.0m,5,050,590.0m,123.050,"Flugplatz" +"Weilerswist",,DE,5043.200N,00651.033E,137.0m,3,040,320.0m,123.425,"Landefeld" +"Welzheim",,DE,4852.583N,00939.217E,518.0m,4,080,520.0m,123.150,"Flugplatz" +"Wenzendorf",,DE,5320.183N,00946.700E,66.0m,4,040,390.0m,123.500,"Flugplatz" +"Weper",,DE,5142.750N,00948.167E,360.0m,4,350,450.0m,123.500,"Flugplatz" +"Werdohl Kuentrop",,DE,5117.817N,00749.050E,307.0m,2,070,810.0m,118.000,"Flugplatz" +"Werneuchen",,DE,5237.917N,01346.467E,79.0m,5,080,1490.0m,122.600,"Flugplatz" +"Werneck Ul",,DE,4959.300N,01000.583E,281.0m,3,070,210.0m,120.975,"Landefeld" +"Wershofen Eifel",,DE,5027.100N,00647.067E,476.0m,2,070,630.0m,122.400,"Flugplatz" +"Wertheim Ul",,DE,4943.550N,00930.367E,304.0m,3,070,260.0m,120.975,"Landefeld" +"Wesel Romerwardt",,DE,5139.767N,00635.750E,21.0m,2,090,720.0m,122.025,"Flugplatz" +"Weser Wuemme",,DE,5303.233N,00912.517E,18.0m,2,180,850.0m,122.600,"Flugplatz" +"Westhausen",,DE,5018.250N,01040.817E,301.0m,3,140,300.0m,,"Landefeld" +"Westerstede Feld",,DE,5317.317N,00755.850E,8.0m,5,060,570.0m,123.650,"Flugplatz" +"Wiefelstede Conn",,DE,5319.283N,00804.400E,7.0m,2,120,600.0m,126.500,"Flugplatz" +"Wiesbaden Mil",,DE,5002.983N,00819.517E,140.0m,5,070,2140.0m,122.100,"Flugplatz" +"Wildberg Bodense",,DE,4736.017N,00944.517E,520.0m,4,030,490.0m,118.550,"Flugplatz" +"Wilhelmshavn Ma",,DE,5330.133N,00803.133E,6.0m,5,020,1450.0m,129.250,"Flugplatz" +"Wildbergkengel",,DE,4838.200N,00843.833E,509.0m,4,080,600.0m,123.000,"Flugplatz" +"Wilsche",,DE,5231.483N,01027.683E,60.0m,2,090,500.0m,129.975,"Flugplatz" +"Winzeln Schrambe",,DE,4816.750N,00825.700E,670.0m,5,140,700.0m,123.650,"Flugplatz" +"Wipperfurth Neye",,DE,5107.483N,00722.333E,265.0m,2,100,600.0m,122.400,"Flugplatz" +"Wismar",,DE,5354.883N,01130.083E,12.0m,2,080,640.0m,123.050,"Flugplatz" +"Wittstock Berlin",,DE,5313.550N,01234.067E,79.0m,4,050,700.0m,122.200,"Flugplatz" +"Wittstock Cls",,DE,5312.150N,01231.367E,71.0m,3,080,2400.0m,,"Landefeld" +"Wittmundhafe Mil",,DE,5332.867N,00740.050E,9.0m,5,080,2450.0m,118.725,"Flugplatz" +"Witzenhausen",,DE,5121.000N,00949.483E,204.0m,4,350,400.0m,123.500,"Flugplatz" +"Woermlitz Ul",,DE,5210.200N,01149.667E,72.0m,3,080,580.0m,123.425,"Landefeld" +"Worishofen",,DE,4801.617N,01036.133E,616.0m,4,080,630.0m,123.350,"Flugplatz" +"Wolfhagen Graner",,DE,5118.433N,00910.517E,314.0m,2,150,500.0m,127.450,"Flugplatz" +"Worms",,DE,4936.383N,00822.100E,91.0m,5,060,800.0m,124.600,"Flugplatz" +"Wurzburg",,DE,4949.067N,00953.850E,297.0m,5,110,670.0m,122.175,"Flugplatz" +"Wuerzbach",,DE,4843.117N,00838.283E,684.0m,3,050,400.0m,,"Landefeld" +"Wunstorf Mil",,DE,5227.433N,00925.633E,58.0m,5,080,1870.0m,122.100,"Flugplatz" +"Wustweiler Cls",,DE,4924.633N,00703.300E,368.0m,3,070,360.0m,122.475,"Landefeld" +"Wyk Auf Foehr",,DE,5441.117N,00831.917E,9.0m,2,020,660.0m,118.250,"Flugplatz" +"Zellhausen",,DE,5001.233N,00859.017E,113.0m,4,170,860.0m,122.300,"Flugplatz" +"Zell Haidberg",,DE,5008.217N,01147.667E,583.0m,2,060,800.0m,123.375,"Flugplatz" +"Zerbst",,DE,5200.133N,01209.167E,80.0m,5,070,750.0m,123.050,"Flugplatz" +"Zierenberg Dornb",,DE,5121.750N,00920.383E,423.0m,4,170,380.0m,122.300,"Flugplatz" +"Zschorna",,DE,5123.783N,01249.400E,132.0m,3,160,280.0m,123.425,"Landefeld" +"Zweibruecken",,DE,4912.567N,00724.033E,345.0m,5,030,2670.0m,123.825,"Flugplatz" +"Zwickau",,DE,5042.067N,01227.167E,316.0m,2,060,800.0m,122.900,"Flugplatz" + diff --git a/tests/test_utils.py b/tests/test_utils.py index fa5986b..ac33231 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,8 @@ import unittest import unittest.mock as mock -from ogn.utils import get_ddb, get_trackable, get_country_code, haversine_distance +from ogn.utils import get_ddb, get_trackable, get_country_code, haversine_distance,\ + get_airports from ogn.model import AddressOrigin @@ -45,6 +46,10 @@ class TestStringMethods(unittest.TestCase): country_code = get_country_code(latitude, longitude) self.assertEqual(country_code, None) + def test_get_airports(self): + airports = get_airports('tests/Germany.cup') + self.assertGreater(len(airports), 100) + @mock.patch('ogn.utils.Nominatim') def test_gec_country_code_exception(self, nominatim_mock): from geopy.exc import GeocoderTimedOut From 84cb2d264fcd051c76a79e39fc75456c17f51b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Sun, 24 Apr 2016 19:34:25 +0200 Subject: [PATCH 2/8] From lat/lon to POINT Flake8 suggestions Add shapely Fixed update_receivers migrate table takeoff_landing --- .../277aca1b810_migrate_to_postgis.py | 85 +++++++++++++++++++ ogn/collect/logbook.py | 15 ++-- ogn/collect/receiver.py | 23 +++-- ogn/commands/logbook.py | 19 ++--- ogn/gateway/process.py | 14 ++- ogn/model/__init__.py | 2 + ogn/model/airport.py | 7 +- ogn/model/beacon.py | 17 +++- ogn/model/geo.py | 15 ++++ ogn/model/receiver.py | 20 ++++- ogn/utils.py | 17 ++-- setup.py | 2 + 12 files changed, 180 insertions(+), 56 deletions(-) create mode 100644 alembic/versions/277aca1b810_migrate_to_postgis.py create mode 100644 ogn/model/geo.py diff --git a/alembic/versions/277aca1b810_migrate_to_postgis.py b/alembic/versions/277aca1b810_migrate_to_postgis.py new file mode 100644 index 0000000..edfcf7c --- /dev/null +++ b/alembic/versions/277aca1b810_migrate_to_postgis.py @@ -0,0 +1,85 @@ +"""Migrate to PostGIS + +Revision ID: 277aca1b810 +Revises: 3a0765c9a2 +Create Date: 2016-04-23 08:01:49.059187 + +""" + +# revision identifiers, used by Alembic. +revision = '277aca1b810' +down_revision = '3a0765c9a2' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa +import geoalchemy2 as ga + +UPGRADE_QUERY = """ +UPDATE {table_name} +SET + location = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326); +""" + +DOWNGRADE_QUERY = """ +UPDATE {table_name} +SET + latitude = ST_Y(ST_TRANSFORM(location, 4326)), + longitude = ST_X(ST_TRANSFORM(location, 4326)); +""" + +def upgrade(): + #CREATE EXTENSION IF NOT EXISTS postgis + op.add_column('airport', sa.Column('location', ga.Geometry('POINT', srid=4326))) + op.execute(UPGRADE_QUERY.format(table_name='airport')) + op.drop_column('airport', 'latitude') + op.drop_column('airport', 'longitude') + + op.add_column('aircraft_beacon', sa.Column('location', ga.Geometry('POINT', srid=4326))) + op.execute(UPGRADE_QUERY.format(table_name='aircraft_beacon')) + op.drop_column('aircraft_beacon', 'latitude') + op.drop_column('aircraft_beacon', 'longitude') + + op.add_column('receiver_beacon', sa.Column('location', ga.Geometry('POINT', srid=4326))) + op.execute(UPGRADE_QUERY.format(table_name='receiver_beacon')) + op.drop_column('receiver_beacon', 'latitude') + op.drop_column('receiver_beacon', 'longitude') + + op.add_column('receiver', sa.Column('location', ga.Geometry('POINT', srid=4326))) + op.execute(UPGRADE_QUERY.format(table_name='receiver')) + op.drop_column('receiver', 'latitude') + op.drop_column('receiver', 'longitude') + + op.add_column('takeoff_landing', sa.Column('location', ga.Geometry('POINT', srid=4326))) + op.execute(UPGRADE_QUERY.format(table_name='takeoff_landing')) + op.drop_column('takeoff_landing', 'latitude') + op.drop_column('takeoff_landing', 'longitude') + + +def downgrade(): + #DROP EXTENSION postgis + op.add_column('airport', sa.Column('latitude', sa.FLOAT)) + op.add_column('airport', sa.Column('longitude', sa.FLOAT)) + op.execute(DOWNGRADE_QUERY.format(table_name='airport')) + op.drop_column('airport', 'location') + + op.add_column('aircraft_beacon', sa.Column('latitude', sa.FLOAT)) + op.add_column('aircraft_beacon', sa.Column('longitude', sa.FLOAT)) + op.execute(DOWNGRADE_QUERY.format(table_name='aircraft_beacon')) + op.drop_column('aircraft_beacon', 'location') + + op.add_column('receiver_beacon', sa.Column('latitude', sa.FLOAT)) + op.add_column('receiver_beacon', sa.Column('longitude', sa.FLOAT)) + op.execute(DOWNGRADE_QUERY.format(table_name='receiver_beacon')) + op.drop_column('receiver_beacon', 'location') + + op.add_column('receiver', sa.Column('latitude', sa.FLOAT)) + op.add_column('receiver', sa.Column('longitude', sa.FLOAT)) + op.execute(DOWNGRADE_QUERY.format(table_name='receiver')) + op.drop_column('receiver', 'location') + + op.add_column('takeoff_landing', sa.Column('latitude', sa.FLOAT)) + op.add_column('takeoff_landing', sa.Column('longitude', sa.FLOAT)) + op.execute(DOWNGRADE_QUERY.format(table_name='takeoff_landing')) + op.drop_column('takeoff_landing', 'location') diff --git a/ogn/collect/logbook.py b/ogn/collect/logbook.py index a748821..99b5889 100644 --- a/ogn/collect/logbook.py +++ b/ogn/collect/logbook.py @@ -41,13 +41,9 @@ def compute_takeoff_and_landing(): AircraftBeacon.timestamp, func.lag(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_prev'), func.lead(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_next'), - AircraftBeacon.latitude, - func.lag(AircraftBeacon.latitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('latitude_prev'), - func.lead(AircraftBeacon.latitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('latitude_next'), - AircraftBeacon.longitude, - func.lag(AircraftBeacon.longitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('longitude_prev'), - func.lead(AircraftBeacon.longitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('longitude_next'), - AircraftBeacon.ground_speed, + AircraftBeacon.location_wkt, + func.lag(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_prev'), + func.lead(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_next'), AircraftBeacon.track, func.lag(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('track_prev'), func.lead(AircraftBeacon.track).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('track_next'), @@ -65,8 +61,7 @@ def compute_takeoff_and_landing(): takeoff_landing_query = app.session.query( sq.c.address, sq.c.timestamp, - sq.c.latitude, - sq.c.longitude, + sq.c.location, sq.c.track, sq.c.ground_speed, sq.c.altitude, @@ -82,7 +77,7 @@ def compute_takeoff_and_landing(): .order_by(func.date(sq.c.timestamp), sq.c.timestamp) # ... and save them - ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.timestamp, TakeoffLanding.latitude, TakeoffLanding.longitude, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query) + ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.timestamp, TakeoffLanding.location_wkt, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query) result = app.session.execute(ins) counter = result.rowcount app.session.commit() diff --git a/ogn/collect/receiver.py b/ogn/collect/receiver.py index e7a3565..e986597 100644 --- a/ogn/collect/receiver.py +++ b/ogn/collect/receiver.py @@ -1,6 +1,6 @@ from sqlalchemy.sql import func, null from sqlalchemy.sql.functions import coalesce -from sqlalchemy import and_, or_ +from sqlalchemy import and_, not_ from celery.utils.log import get_task_logger @@ -26,8 +26,7 @@ def update_receivers(): .subquery() receivers_to_update = app.session.query(ReceiverBeacon.name, - ReceiverBeacon.latitude, - ReceiverBeacon.longitude, + ReceiverBeacon.location_wkt, ReceiverBeacon.altitude, last_receiver_beacon_sq.columns.lastseen, ReceiverBeacon.version, @@ -39,11 +38,10 @@ def update_receivers(): # set country code to None if lat or lon changed count = app.session.query(Receiver) \ .filter(and_(Receiver.name == receivers_to_update.columns.name, - or_(Receiver.latitude != receivers_to_update.columns.latitude, - Receiver.longitude != receivers_to_update.columns.longitude))) \ - .update({"latitude": receivers_to_update.columns.latitude, - "longitude": receivers_to_update.columns.longitude, - "country_code": null()}) + not_(func.ST_Equals(Receiver.location_wkt, receivers_to_update.columns.location)))) \ + .update({"location_wkt": receivers_to_update.columns.location, + "country_code": null()}, + synchronize_session=False) logger.info("Count of receivers who changed lat or lon: {}".format(count)) @@ -59,8 +57,7 @@ def update_receivers(): # add new receivers empty_sq = app.session.query(ReceiverBeacon.name, - ReceiverBeacon.latitude, - ReceiverBeacon.longitude, + ReceiverBeacon.location_wkt, ReceiverBeacon.altitude, last_receiver_beacon_sq.columns.lastseen, ReceiverBeacon.version, ReceiverBeacon.platform) \ @@ -73,8 +70,7 @@ def update_receivers(): for receiver_beacon in empty_sq.all(): receiver = Receiver() receiver.name = receiver_beacon.name - receiver.latitude = receiver_beacon.latitude - receiver.longitude = receiver_beacon.longitude + receiver.location_wkt = receiver_beacon.location_wkt receiver.altitude = receiver_beacon.altitude receiver.firstseen = None receiver.lastseen = receiver_beacon.lastseen @@ -103,7 +99,8 @@ def update_receivers(): .order_by(Receiver.name) for receiver in unknown_country_query.all(): - receiver.country_code = get_country_code(receiver.latitude, receiver.longitude) + location = receiver.location + receiver.country_code = get_country_code(location.latitude, location.longitude) if receiver.country_code is not None: logger.info("Updated country_code for {} to {}".format(receiver.name, receiver.country_code)) diff --git a/ogn/commands/logbook.py b/ogn/commands/logbook.py index 10a5237..18847d5 100644 --- a/ogn/commands/logbook.py +++ b/ogn/commands/logbook.py @@ -3,7 +3,7 @@ from datetime import timedelta from sqlalchemy.sql import func, null -from sqlalchemy import and_, or_, between +from sqlalchemy import and_, or_ from sqlalchemy.sql.expression import true, false, label from ogn.model import Device, TakeoffLanding, Airport @@ -28,21 +28,15 @@ def compute(): def show(airport_name): """Show a logbook for .""" airport = session.query(Airport) \ - .filter(or_(Airport.name==airport_name)) \ + .filter(Airport.name == airport_name) \ .first() if (airport is None): print('Airport "{}" not found.'.format(airport_name)) return - latitude = float(airport.latitude) - longitude = float(airport.longitude) - altitude = float(airport.altitude) - latmin = latitude - 0.05 - latmax = latitude + 0.05 - lonmin = longitude - 0.05 - lonmax = longitude + 0.05 - max_altitude = altitude + 200 + delta_altitude = 200 + delta_radius = 10 # make a query with current, previous and next "takeoff_landing" event, so we can find complete flights sq = session.query( @@ -91,9 +85,8 @@ def show(airport_name): TakeoffLanding.address, TakeoffLanding.timestamp)) .label('is_takeoff_next')) \ - .filter(and_(between(TakeoffLanding.latitude, latmin, latmax), - between(TakeoffLanding.longitude, lonmin, lonmax))) \ - .filter(TakeoffLanding.altitude < max_altitude) \ + .filter(func.ST_DFullyWithin(TakeoffLanding.location_wkt, Airport.location_wkt, delta_radius)) \ + .filter(TakeoffLanding.altitude < Airport.altitude + delta_altitude) \ .subquery() # find complete flights (with takeoff and landing) with duration < 1 day diff --git a/ogn/gateway/process.py b/ogn/gateway/process.py index 690b3b9..61828d0 100644 --- a/ogn/gateway/process.py +++ b/ogn/gateway/process.py @@ -1,11 +1,19 @@ import logging from ogn.commands.dbutils import session -from ogn.model import AircraftBeacon, ReceiverBeacon +from ogn.model import AircraftBeacon, ReceiverBeacon, Location from ogn.parser import parse_aprs, parse_ogn_receiver_beacon, parse_ogn_aircraft_beacon, ParseError logger = logging.getLogger(__name__) +def replace_lonlat_with_wkt(message): + location = Location(message['longitude'], message['latitude']) + message['location_wkt'] = location.to_wkt() + del message['latitude'] + del message['longitude'] + return message + + def process_beacon(raw_message): if raw_message[0] == '#': return @@ -25,9 +33,11 @@ def process_beacon(raw_message): # /o: ? if message['symboltable'] == "I" and message['symbolcode'] == '&': message.update(parse_ogn_receiver_beacon(message['comment'])) + message = replace_lonlat_with_wkt(message) beacon = ReceiverBeacon(**message) else: message.update(parse_ogn_aircraft_beacon(message['comment'])) + message = replace_lonlat_with_wkt(message) beacon = AircraftBeacon(**message) session.add(beacon) session.commit() @@ -35,3 +45,5 @@ def process_beacon(raw_message): except ParseError as e: logger.error('Received message: {}'.format(raw_message)) logger.error('Drop packet, {}'.format(e.message)) + except TypeError as e: + logger.error('TypeError: {}'.format(raw_message)) diff --git a/ogn/model/__init__.py b/ogn/model/__init__.py index e5fd495..8ff0c22 100644 --- a/ogn/model/__init__.py +++ b/ogn/model/__init__.py @@ -9,3 +9,5 @@ from .receiver_beacon import ReceiverBeacon from .receiver import Receiver from .takeoff_landing import TakeoffLanding from .airport import Airport + +from .geo import Location diff --git a/ogn/model/airport.py b/ogn/model/airport.py index cb3f1e2..16730a4 100644 --- a/ogn/model/airport.py +++ b/ogn/model/airport.py @@ -1,4 +1,5 @@ from sqlalchemy import Column, String, Integer, Float, SmallInteger +from geoalchemy2.types import Geometry from .base import Base @@ -8,14 +9,14 @@ class Airport(Base): id = Column(Integer, primary_key=True) + location_wkt = Column('location', Geometry('POINT', srid=4326)) + altitude = Column(Integer) + name = Column(String, index=True) code = Column(String(5)) country_code = Column(String(2)) style = Column(SmallInteger) description = Column(String) - latitude = Column(Float) - longitude = Column(Float) - altitude = Column(Integer) runway_direction = Column(Integer) runway_length = Column(Integer) frequency = Column(Float) diff --git a/ogn/model/beacon.py b/ogn/model/beacon.py index 8a7503d..168a5ea 100644 --- a/ogn/model/beacon.py +++ b/ogn/model/beacon.py @@ -1,21 +1,32 @@ from sqlalchemy import Column, String, Integer, Float, DateTime from sqlalchemy.ext.declarative import AbstractConcreteBase +from geoalchemy2.types import Geometry +from geoalchemy2.shape import to_shape from .base import Base +from .geo import Location class Beacon(AbstractConcreteBase, Base): id = Column(Integer, primary_key=True) # APRS data + location_wkt = Column('location', Geometry('POINT', srid=4326)) + altitude = Column(Integer) + name = Column(String) receiver_name = Column(String(9)) timestamp = Column(DateTime, index=True) - latitude = Column(Float) symboltable = None - longitude = Column(Float) symbolcode = None track = Column(Integer) ground_speed = Column(Float) - altitude = Column(Integer) comment = None + + @property + def location(self): + if self.location_wkt is None: + return None + + coords = to_shape(self.location_wkt) + return Location(lat=coords.y, lon=coords.x) diff --git a/ogn/model/geo.py b/ogn/model/geo.py new file mode 100644 index 0000000..649fc7d --- /dev/null +++ b/ogn/model/geo.py @@ -0,0 +1,15 @@ +class Location: + """Represents a location in WGS84""" + + def __init__(self, lon, lat): + self.longitude = lon + self.latitude = lat + + def to_wkt(self): + return 'SRID=4326;POINT({0} {1})'.format(self.longitude, self.latitude) + + def __str__(self): + return '{0: 7.4f}, {1:8.4f}'.format(self.latitude, self.longitude) + + def as_dict(self): + return {'latitude': round(self.latitude, 8), 'longitude': round(self.longitude, 8)} diff --git a/ogn/model/receiver.py b/ogn/model/receiver.py index 5683a43..fb29a47 100644 --- a/ogn/model/receiver.py +++ b/ogn/model/receiver.py @@ -1,18 +1,30 @@ -from sqlalchemy import Column, String, Integer, Float, DateTime +from sqlalchemy import Column, String, Integer, DateTime +from geoalchemy2.types import Geometry +from geoalchemy2.shape import to_shape from .base import Base +from .geo import Location class Receiver(Base): __tablename__ = "receiver" id = Column(Integer, primary_key=True) - name = Column(String(9)) - latitude = Column(Float) - longitude = Column(Float) + + location_wkt = Column('location', Geometry('POINT', srid=4326)) altitude = Column(Integer) + + name = Column(String(9)) firstseen = Column(DateTime, index=True) lastseen = Column(DateTime, index=True) country_code = Column(String(2)) version = Column(String) platform = Column(String) + + @property + def location(self): + if self.location_wkt is None: + return None + + coords = to_shape(self.location_wkt) + return Location(lat=coords.y, lon=coords.x) diff --git a/ogn/utils.py b/ogn/utils.py index 0741502..d4e352b 100644 --- a/ogn/utils.py +++ b/ogn/utils.py @@ -2,7 +2,7 @@ import requests import csv from io import StringIO -from .model import Device, AddressOrigin, Airport +from .model import Device, AddressOrigin, Airport, Location from geopy.geocoders import Nominatim from geopy.exc import GeopyError @@ -83,22 +83,22 @@ def get_airports(cupfile): airport.country_code = waypoint['country'] airport.style = waypoint['style'] airport.description = waypoint['description'] - airport.latitude = waypoint['latitude'] - airport.longitude = waypoint['longitude'] + location = Location(waypoint['longitude'], waypoint['latitude']) + airport.location_wkt = location.to_wkt() airport.altitude = waypoint['elevation']['value'] if (waypoint['elevation']['unit'] == 'ft'): - airport.altitude = airport.altitude*feet2m + airport.altitude = airport.altitude * feet2m airport.runway_direction = waypoint['runway_direction'] airport.runway_length = waypoint['runway_length']['value'] if (waypoint['runway_length']['unit'] == 'nm'): - airport.altitude = airport.altitude*nm2m + airport.altitude = airport.altitude * nm2m elif (waypoint['runway_length']['unit'] == 'ml'): - airport.altitude = airport.altitude*mi2m + airport.altitude = airport.altitude * mi2m airport.frequency = waypoint['frequency'] airports.append(airport) - except Exception: - print('Failed to parse line: {}'.format(line)) + except AttributeError as e: + print('Failed to parse line: {} {}'.format(line, e)) return airports @@ -115,4 +115,3 @@ def haversine_distance(location0, location1): phi = degrees(atan2(sin(lon0 - lon1) * cos(lat1), cos(lat0) * sin(lat1) - sin(lat0) * cos(lat1) * cos(lon0 - lon1))) return distance, phi - diff --git a/setup.py b/setup.py index b4fa439..7f9e911 100644 --- a/setup.py +++ b/setup.py @@ -38,6 +38,8 @@ setup( 'celery[redis]>=3.1,<3.2', 'alembic==0.8.3', 'aerofiles==0.3', + 'geoalchemy2==0.3.0', + 'shapely==1.5.15', 'ogn-client==0.3.0' ], extras_require={ From f812b0af4ddae9b0a416bb5dbb5787e87fe656ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Thu, 28 Apr 2016 12:38:48 +0200 Subject: [PATCH 3/8] Fixed logbook.show Cosmetics --- ogn/collect/database.py | 3 ++- ogn/collect/logbook.py | 12 ++++++++++-- ogn/commands/logbook.py | 3 ++- ogn/commands/showreceiver.py | 5 +++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ogn/collect/database.py b/ogn/collect/database.py index 4697fe5..c62fc2b 100644 --- a/ogn/collect/database.py +++ b/ogn/collect/database.py @@ -34,5 +34,6 @@ def import_file(path='tests/custom_ddb.txt'): """Import registered devices from a local file.""" logger.info("Import registered devices from '{}'...".format(path)) - counter = update_devices(app.session, AddressOrigin.user_defined, get_ddb(path)) + counter = update_devices(app.session, AddressOrigin.user_defined, + get_ddb(path)) logger.info("Imported {} devices.".format(counter)) diff --git a/ogn/collect/logbook.py b/ogn/collect/logbook.py index 99b5889..4595e97 100644 --- a/ogn/collect/logbook.py +++ b/ogn/collect/logbook.py @@ -41,6 +41,12 @@ def compute_takeoff_and_landing(): AircraftBeacon.timestamp, func.lag(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_prev'), func.lead(AircraftBeacon.timestamp).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('timestamp_next'), + AircraftBeacon.name, + func.lag(AircraftBeacon.name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('name_prev'), + func.lead(AircraftBeacon.name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('name_next'), + AircraftBeacon.receiver_name, + func.lag(AircraftBeacon.receiver_name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('receiver_name_prev'), + func.lead(AircraftBeacon.receiver_name).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('receiver_name_next'), AircraftBeacon.location_wkt, func.lag(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_prev'), func.lead(AircraftBeacon.location_wkt).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('location_wkt_next'), @@ -60,6 +66,8 @@ def compute_takeoff_and_landing(): # find takeoffs and landings (look at the trigger_speed) takeoff_landing_query = app.session.query( sq.c.address, + sq.c.name, + sq.c.receiver_name, sq.c.timestamp, sq.c.location, sq.c.track, @@ -76,8 +84,8 @@ def compute_takeoff_and_landing(): sq.c.ground_speed_next < landing_speed))) \ .order_by(func.date(sq.c.timestamp), sq.c.timestamp) - # ... and save them - ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.timestamp, TakeoffLanding.location_wkt, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query) + # ... and save the + ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.name, TakeoffLanding.receiver_name, TakeoffLanding.timestamp, TakeoffLanding.location_wkt, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query) result = app.session.execute(ins) counter = result.rowcount app.session.commit() diff --git a/ogn/commands/logbook.py b/ogn/commands/logbook.py index 18847d5..720574e 100644 --- a/ogn/commands/logbook.py +++ b/ogn/commands/logbook.py @@ -36,7 +36,7 @@ def show(airport_name): return delta_altitude = 200 - delta_radius = 10 + delta_radius = 0.01 # degree! # make a query with current, previous and next "takeoff_landing" event, so we can find complete flights sq = session.query( @@ -87,6 +87,7 @@ def show(airport_name): .label('is_takeoff_next')) \ .filter(func.ST_DFullyWithin(TakeoffLanding.location_wkt, Airport.location_wkt, delta_radius)) \ .filter(TakeoffLanding.altitude < Airport.altitude + delta_altitude) \ + .filter(Airport.name == airport.name) \ .subquery() # find complete flights (with takeoff and landing) with duration < 1 day diff --git a/ogn/commands/showreceiver.py b/ogn/commands/showreceiver.py index 1d8c374..9a30512 100644 --- a/ogn/commands/showreceiver.py +++ b/ogn/commands/showreceiver.py @@ -18,8 +18,9 @@ def list_all(): sq = session.query(distinct(ReceiverBeacon.name).label('name'), func.max(ReceiverBeacon.timestamp).label('lastseen'), - func.count(ReceiverBeacon.name).label('messages_count') - ).filter(ReceiverBeacon.timestamp > timestamp_24h_ago).group_by(ReceiverBeacon.name).subquery() + func.count(ReceiverBeacon.name).label('messages_count')) \ + .filter(ReceiverBeacon.timestamp > timestamp_24h_ago) \ + .group_by(ReceiverBeacon.name).subquery() query = session.query(Receiver, sq.c.messages_count).\ filter(Receiver.name == sq.c.name).\ From e1da7dcfaca2f6c4d093a96d9b468879fde77785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Thu, 28 Apr 2016 16:39:02 +0200 Subject: [PATCH 4/8] Update commands --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ef6572..363b547 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ available commands: [db] drop Drop all tables. + import_airports Import airports from a ".cup" file import_ddb Import registered devices from the DDB. import_file Import registered devices from a local file. init Initialize the database. @@ -100,7 +101,7 @@ available commands: [logbook] compute Compute takeoffs and landings. - show Show a logbook for located at given position. + show Show a logbook for . [show.devices] stats Show some stats on registered devices. From b5f111c2572cec69ab77369a33390fdb50823af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Thu, 28 Apr 2016 20:36:56 +0200 Subject: [PATCH 5/8] Remove obsolete pre postgis stuff Removed obsolete test --- ..._remove_unnecessary_pre_postgis_columns.py | 34 +++++++++++ config/default.py | 19 +++---- ogn/collect/celery.py | 1 - ogn/collect/heatmap.py | 57 ------------------- ogn/model/aircraft_beacon.py | 7 --- ogn/utils.py | 14 ----- tests/test_utils.py | 28 +-------- 7 files changed, 42 insertions(+), 118 deletions(-) create mode 100644 alembic/versions/2004ce1566c_remove_unnecessary_pre_postgis_columns.py delete mode 100644 ogn/collect/heatmap.py diff --git a/alembic/versions/2004ce1566c_remove_unnecessary_pre_postgis_columns.py b/alembic/versions/2004ce1566c_remove_unnecessary_pre_postgis_columns.py new file mode 100644 index 0000000..af6d523 --- /dev/null +++ b/alembic/versions/2004ce1566c_remove_unnecessary_pre_postgis_columns.py @@ -0,0 +1,34 @@ +"""remove unnecessary pre postgis columns + +Revision ID: 2004ce1566c +Revises: 277aca1b810 +Create Date: 2016-04-28 18:24:14.912833 + +""" + +# revision identifiers, used by Alembic. +revision = '2004ce1566c' +down_revision = '277aca1b810' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa +import geoalchemy2 as ga + + +def upgrade(): + # POSTGIS is fast enough, so lets forget radius, theta and phi + op.drop_column('aircraft_beacon', 'radius') + op.drop_column('aircraft_beacon', 'theta') + op.drop_column('aircraft_beacon', 'phi') + + # ... and flight_state is not used + op.drop_column('aircraft_beacon', 'flight_state') + + +def downgrade(): + op.add_column('aircraft_beacon', sa.Column('radius', sa.Float)) + op.add_column('aircraft_beacon', sa.Column('theta', sa.Float)) + op.add_column('aircraft_beacon', sa.Column('phi', sa.Float)) + op.add_column('aircraft_beacon', sa.Column('flight_state', sa.SmallInteger)) diff --git a/config/default.py b/config/default.py index 5ef98b6..bc4ab82 100644 --- a/config/default.py +++ b/config/default.py @@ -11,19 +11,14 @@ CELERYBEAT_SCHEDULE = { 'task': 'ogn.collect.database.import_ddb', 'schedule': timedelta(minutes=15), }, - 'update-receiver-distance': { - 'task': 'ogn.collect.heatmap.update_beacon_receiver_distance_all', - 'schedule': timedelta(minutes=5), + 'update-logbook': { + 'task': 'ogn.collect.logbook.compute_takeoff_and_landing', + 'schedule': timedelta(minutes=15), + }, + 'update-receiver-table': { + 'task': 'ogn.collect.receiver.update_receivers', + 'schedule': timedelta(minutes=15), }, -# Only supported with postgresql backend -# 'update-logbook': { -# 'task': 'ogn.collect.logbook.compute_takeoff_and_landing', -# 'schedule': timedelta(minutes=15), -# }, -# 'update-receiver-table': { -# 'task': 'ogn.collect.receiver.update_receivers', -# 'schedule': timedelta(minutes=5), -# }, } CELERY_TIMEZONE = 'UTC' diff --git a/ogn/collect/celery.py b/ogn/collect/celery.py index aa45ad8..859b157 100644 --- a/ogn/collect/celery.py +++ b/ogn/collect/celery.py @@ -26,7 +26,6 @@ def close_db(signal, sender): app = Celery('ogn.collect', include=["ogn.collect.database", - "ogn.collect.heatmap", "ogn.collect.logbook", "ogn.collect.receiver" ]) diff --git a/ogn/collect/heatmap.py b/ogn/collect/heatmap.py deleted file mode 100644 index 7c165ca..0000000 --- a/ogn/collect/heatmap.py +++ /dev/null @@ -1,57 +0,0 @@ -from math import atan2, pi, sqrt - -from sqlalchemy import and_, desc, distinct -from sqlalchemy.sql import null - -from celery import group -from celery.utils.log import get_task_logger -from ogn.collect.celery import app - -from ogn.model import AircraftBeacon, ReceiverBeacon -from ogn.utils import haversine_distance - -logger = get_task_logger(__name__) - - -@app.task -def update_beacon_receiver_distance(name): - """ - Calculate the distance between the receiver and its received aircrafts - and write this data into each aircraft_beacon. - """ - - last_receiver_beacon = app.session.query(ReceiverBeacon) \ - .filter(ReceiverBeacon.name == name) \ - .order_by(desc(ReceiverBeacon.timestamp)) \ - .first() - - if (last_receiver_beacon is None): - return - - aircraft_beacons_query = app.session.query(AircraftBeacon) \ - .filter(and_(AircraftBeacon.timestamp > last_receiver_beacon.timestamp, - AircraftBeacon.receiver_name == name, - AircraftBeacon.radius == null())) - - for aircraft_beacon in aircraft_beacons_query.all(): - location0 = (last_receiver_beacon.latitude, last_receiver_beacon.longitude) - location1 = (aircraft_beacon.latitude, aircraft_beacon.longitude) - alt0 = last_receiver_beacon.altitude - alt1 = aircraft_beacon.altitude - - (flat_distance, phi) = haversine_distance(location0, location1) - theta = atan2(alt1 - alt0, flat_distance) * 180 / pi - distance = sqrt(flat_distance**2 + (alt1 - alt0)**2) - - aircraft_beacon.radius = distance - aircraft_beacon.theta = theta - aircraft_beacon.phi = phi - - app.session.commit() - logger.warning("Updated receiver {}.".format(name)) - - -@app.task -def update_beacon_receiver_distance_all(): - group(update_beacon_receiver_distance(receiver_name) - for receiver_name in app.session.query(distinct(ReceiverBeacon.name)).all()).apply_async() diff --git a/ogn/model/aircraft_beacon.py b/ogn/model/aircraft_beacon.py index 02677ef..d69121e 100644 --- a/ogn/model/aircraft_beacon.py +++ b/ogn/model/aircraft_beacon.py @@ -24,13 +24,6 @@ class AircraftBeacon(Beacon): flightlevel = Column(Float) - # Calculated values - radius = Column(Float) - theta = Column(Float) - phi = Column(Float) - - flight_state = Column(SmallInteger) - def __repr__(self): return "" % ( self.name, diff --git a/ogn/utils.py b/ogn/utils.py index d4e352b..c97d299 100644 --- a/ogn/utils.py +++ b/ogn/utils.py @@ -101,17 +101,3 @@ def get_airports(cupfile): print('Failed to parse line: {} {}'.format(line, e)) return airports - - -def haversine_distance(location0, location1): - from math import asin, sqrt, sin, cos, atan2, radians, degrees - - lat0 = radians(location0[0]) - lon0 = radians(location0[1]) - lat1 = radians(location1[0]) - lon1 = radians(location1[1]) - - distance = 6366000 * 2 * asin(sqrt((sin((lat0 - lat1) / 2))**2 + cos(lat0) * cos(lat1) * (sin((lon0 - lon1) / 2))**2)) - phi = degrees(atan2(sin(lon0 - lon1) * cos(lat1), cos(lat0) * sin(lat1) - sin(lat0) * cos(lat1) * cos(lon0 - lon1))) - - return distance, phi diff --git a/tests/test_utils.py b/tests/test_utils.py index ac33231..e4c5954 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,8 +1,7 @@ import unittest import unittest.mock as mock -from ogn.utils import get_ddb, get_trackable, get_country_code, haversine_distance,\ - get_airports +from ogn.utils import get_ddb, get_trackable, get_country_code, get_airports from ogn.model import AddressOrigin @@ -58,28 +57,3 @@ class TestStringMethods(unittest.TestCase): instance.reverse.side_effect = GeocoderTimedOut('Too busy') country_code = get_country_code(0, 0) self.assertIsNone(country_code) - - def test_haversine_distance(self): - # delta: one latitude degree - location0 = (0, 0) - location1 = (-1, 0) - - (distance, phi) = haversine_distance(location0, location1) - self.assertAlmostEqual(distance, 60 * 1852, -2) - self.assertEqual(phi, 180) - - # delta: one longitude degree at the equator - location0 = (0, 0) - location1 = (0, -1) - - (distance, phi) = haversine_distance(location0, location1) - self.assertAlmostEqual(distance, 60 * 1852, -2) - self.assertEqual(phi, 90) - - # delta: 29000m - location0 = (48.865, 9.2225) - location1 = (48.74435, 9.578) - - (distance, phi) = haversine_distance(location0, location1) - self.assertAlmostEqual(distance, 29265.6035812215, -1) - self.assertAlmostEqual(phi, -117.1275408121, 5) From dbda5a9c4b621f5f794417509aea9f2be7d209e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Gru=CC=88ndger?= Date: Fri, 29 Apr 2016 14:03:21 +0200 Subject: [PATCH 6/8] Speed up takeoff / landing detection --- ogn/collect/logbook.py | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/ogn/collect/logbook.py b/ogn/collect/logbook.py index 4595e97..9e99d7c 100644 --- a/ogn/collect/logbook.py +++ b/ogn/collect/logbook.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import timedelta from celery.utils.log import get_task_logger from ogn.collect.celery import app @@ -16,24 +16,33 @@ logger = get_task_logger(__name__) def compute_takeoff_and_landing(): logger.info("Compute takeoffs and landings.") - takeoff_speed = 30 - landing_speed = 30 + # takeoff / landing detection is based on 3 consecutive points + takeoff_speed = 55 # takeoff detection: 1st point below, 2nd and 3rd above this limit + landing_speed = 40 # landing detection: 1st point above, 2nd and 3rd below this limit + duration = 100 # the points must not exceed this duration + radius = 0.05 # the points must not exceed this radius (degree!) around the 2nd point # calculate the time where the computation starts last_takeoff_landing_query = app.session.query(func.max(TakeoffLanding.timestamp)) - last_takeoff_landing = last_takeoff_landing_query.one()[0] - if last_takeoff_landing is None: + begin_computation = last_takeoff_landing_query.one()[0] + if begin_computation is None: # if the table is empty - last_takeoff_landing = datetime(2015, 1, 1, 0, 0, 0) + last_takeoff_landing_query = app.session.query(func.min(AircraftBeacon.timestamp)) + begin_computation = last_takeoff_landing_query.one()[0] + if begin_computation is None: + return 0 else: - # we get the beacons async. to be safe we delete takeoffs/landings from last 5 minutes and recalculate from then - # alternative: takeoff/landing has a primary key (timestamp,address) - last_takeoff_landing = last_takeoff_landing - timedelta(minutes=5) + # we get the beacons async. to be safe we delete takeoffs/landings from last 24 hours and recalculate from then + begin_computation = begin_computation - timedelta(hours=24) app.session.query(TakeoffLanding) \ - .filter(TakeoffLanding.timestamp > last_takeoff_landing) \ + .filter(TakeoffLanding.timestamp >= begin_computation) \ .delete() + end_computation = begin_computation + timedelta(days=30) - # make a query with current, previous and next position, so we can detect takeoffs and landings + logger.debug("Calculate takeoffs and landings between {} and {}" + .format(begin_computation, end_computation)) + + # make a query with current, previous and next position sq = app.session.query( AircraftBeacon.address, func.lag(AircraftBeacon.address).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('address_prev'), @@ -59,11 +68,12 @@ def compute_takeoff_and_landing(): AircraftBeacon.altitude, func.lag(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('altitude_prev'), func.lead(AircraftBeacon.altitude).over(order_by=and_(AircraftBeacon.address, AircraftBeacon.timestamp)).label('altitude_next')) \ - .filter(AircraftBeacon.timestamp > last_takeoff_landing) \ + .filter(AircraftBeacon.timestamp >= begin_computation) \ + .filter(AircraftBeacon.timestamp <= end_computation) \ .order_by(func.date(AircraftBeacon.timestamp), AircraftBeacon.address, AircraftBeacon.timestamp) \ .subquery() - # find takeoffs and landings (look at the trigger_speed) + # find takeoffs and landings takeoff_landing_query = app.session.query( sq.c.address, sq.c.name, @@ -82,9 +92,12 @@ def compute_takeoff_and_landing(): and_(sq.c.ground_speed_prev > landing_speed, # landing sq.c.ground_speed < landing_speed, sq.c.ground_speed_next < landing_speed))) \ + .filter(sq.c.timestamp_next - sq.c.timestamp_prev < timedelta(seconds=duration)) \ + .filter(and_(func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_prev, radius), + func.ST_DFullyWithin(sq.c.location, sq.c.location_wkt_next, radius))) \ .order_by(func.date(sq.c.timestamp), sq.c.timestamp) - # ... and save the + # ... and save them ins = insert(TakeoffLanding).from_select((TakeoffLanding.address, TakeoffLanding.name, TakeoffLanding.receiver_name, TakeoffLanding.timestamp, TakeoffLanding.location_wkt, TakeoffLanding.track, TakeoffLanding.ground_speed, TakeoffLanding.altitude, TakeoffLanding.is_takeoff), takeoff_landing_query) result = app.session.execute(ins) counter = result.rowcount From c9c464986c9e103bed3649ce7342dfbbb77a020d Mon Sep 17 00:00:00 2001 From: Meisterschueler Date: Wed, 18 May 2016 13:27:10 +0200 Subject: [PATCH 7/8] Create and drop PostGIS extension --- alembic/versions/277aca1b810_migrate_to_postgis.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alembic/versions/277aca1b810_migrate_to_postgis.py b/alembic/versions/277aca1b810_migrate_to_postgis.py index edfcf7c..645e159 100644 --- a/alembic/versions/277aca1b810_migrate_to_postgis.py +++ b/alembic/versions/277aca1b810_migrate_to_postgis.py @@ -30,7 +30,7 @@ SET """ def upgrade(): - #CREATE EXTENSION IF NOT EXISTS postgis + op.execute("CREATE EXTENSION IF NOT EXISTS postgis;"); op.add_column('airport', sa.Column('location', ga.Geometry('POINT', srid=4326))) op.execute(UPGRADE_QUERY.format(table_name='airport')) op.drop_column('airport', 'latitude') @@ -58,7 +58,6 @@ def upgrade(): def downgrade(): - #DROP EXTENSION postgis op.add_column('airport', sa.Column('latitude', sa.FLOAT)) op.add_column('airport', sa.Column('longitude', sa.FLOAT)) op.execute(DOWNGRADE_QUERY.format(table_name='airport')) @@ -83,3 +82,5 @@ def downgrade(): op.add_column('takeoff_landing', sa.Column('longitude', sa.FLOAT)) op.execute(DOWNGRADE_QUERY.format(table_name='takeoff_landing')) op.drop_column('takeoff_landing', 'location') + + op.execute("DROP EXTENSION postgis;"); From 81b80559e4a9a57a817ba5a1917740b759fa079f Mon Sep 17 00:00:00 2001 From: Meisterschueler Date: Wed, 18 May 2016 13:30:47 +0200 Subject: [PATCH 8/8] Drop get_airports "Test" --- tests/test_utils.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index e4c5954..afa313c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,7 @@ import unittest import unittest.mock as mock -from ogn.utils import get_ddb, get_trackable, get_country_code, get_airports +from ogn.utils import get_ddb, get_trackable, get_country_code from ogn.model import AddressOrigin @@ -45,10 +45,6 @@ class TestStringMethods(unittest.TestCase): country_code = get_country_code(latitude, longitude) self.assertEqual(country_code, None) - def test_get_airports(self): - airports = get_airports('tests/Germany.cup') - self.assertGreater(len(airports), 100) - @mock.patch('ogn.utils.Nominatim') def test_gec_country_code_exception(self, nominatim_mock): from geopy.exc import GeocoderTimedOut