import re
latLongRE = re.compile(r'\s*(\d+)-(\d{2})-(\d{2}.\d{3,8})([NS])\s*(\d+)-(\d{2})-(\d{2}.\d{3,8})([EW])')
statesAbbreviationsToExclude = ['AK', 'HI']
navaidsToInclude = ['VOR', 'NDB']
airwayFixTypes = frozenset(['CN', 'NDB/DME', 'NDB', 'MIL-REP-PT', 'REP-PT', 'RNAV', 'VOR', 'VOR/DME', 'VORTAC'])
airwayTypes = frozenset(['J', 'T', 'Q', 'V'])
class WaypointData:
def __init__(self):
self.waypoints = []
self.allNames = set()
def parseLatLongDMS(self, latLongString):
match = latLongRE.match(latLongString)
latitude = float(match.group(1)) + (float(match.group(2)) * 60 + float(match.group(3))) / 3600
if match.group(4) == 'S':
latitude = -latitude
longitude = float(match.group(5)) + (float(match.group(6)) * 60 + float(match.group(7))) / 3600
if match.group(8) == 'W':
longitude = -longitude
return (latitude, longitude)
def parseAirportData(self, airportFile):
file = open(airportFile, 'r')
for line in file:
if line[0:3] != 'APT':
continue
if line[48:50] in statesAbbreviationsToExclude:
continue
facilityType = line[14:27].rstrip().title()
latLong = self.parseLatLongDMS(line[523:538] + line[550:565])
description = line[133:183].rstrip().title() + ' ' + facilityType + ', ' + line[93:133].rstrip().title() + ', ' + line[48:50]
description = description.replace('"', '\\"');
name = line[1210:1217].rstrip()
if not len(name):
name = line[27:31].rstrip()
if name in self.allNames:
print('Duplicate airport waypoint name {0}'.format(name))
continue
self.allNames.add(name)
self.waypoints.append((name, facilityType, description, latLong[0], latLong[1]))
file.close()
def parseNavAidData(self, navaidFile):
file = open(navaidFile, 'r')
self.ndbs = []
for line in file:
if line[0:4] != 'NAV1':
continue
if line[144:147] == 'AIN':
continue
if not line[8:11] in navaidsToInclude:
continue
facilityType = line[8:28].rstrip()
latLong = self.parseLatLongDMS(line[371:385] + line[396:410])
name = line[4:8].rstrip()
description = line[42:72].rstrip().title() + ' ' + line[8:28].rstrip()
if line[8:11] == 'NDB':
self.ndbs.append((name, facilityType, description, latLong[0], latLong[1]))
else:
self.allNames.add(name)
self.waypoints.append((name, facilityType, description, latLong[0], latLong[1]))
for ndb in self.ndbs:
if ndb[0] not in self.allNames:
self.allNames.add(ndb[0])
self.waypoints.append(ndb)
file.close()
def parseFixData(self, fixFile):
file = open(fixFile, 'r')
for line in file:
if line[0:4] != 'FIX1':
continue
if line[4] < 'A' or line[4] > 'Z':
continue
facilityType = 'Intersection'
latLong = self.parseLatLongDMS(line[66:80] + line[80:94])
name = line[4:34].rstrip()
description = name + ' Intersection'
if name in self.allNames:
print('Duplicate fix name {0}'.format(name))
continue
self.allNames.add(name)
self.waypoints.append((name, facilityType, description, latLong[0], latLong[1], ''))
file.close()
def outputWaypointFile(self, outputFilename):
sortedWaypoints = sorted(self.waypoints, key=lambda waypoint: waypoint[0])
outputFile = open(outputFilename, 'w+')
outputFile.write('var _faaWaypoints = {\n');
isFirst = True
for waypoint in sortedWaypoints:
if isFirst:
isFirst = False
else:
outputFile.write(',\n');
outputFile.write(' "{0}":{{ "name":"{0}", "type":"{1}", "description":"{2}", "latitude":{3}, "longitude":{4}}}'.format(waypoint[0], waypoint[1], waypoint[2], waypoint[3], waypoint[4]))
outputFile.write('\n};\n');
class AirwayData:
def __init__(self):
self.airways = []
def parseAirwayData(self, airwayFile):
file = open(airwayFile, 'r')
self.currentAirway = ''
self.airwayPoints = []
for line in file:
airway = line[4:8].rstrip()
if airway != self.currentAirway:
if self.currentAirway != '':
self.airways.append((self.currentAirway, self.airwayPoints))
self.currentAirway = ''
self.airwayPoints = []
if line[0:4] != 'AWY2':
continue
if line[4] not in airwayTypes:
continue
if line[9] != ' ':
continue
if line[45:64].rstrip() not in airwayFixTypes:
continue
if self.currentAirway == '':
self.currentAirway = airway
if line[64:79].rstrip() == 'FIX':
self.airwayPoints.append(line[15:45].rstrip())
else:
self.airwayPoints.append(line[116:120].rstrip())
if self.currentAirway != '':
self.airways.append((self.currentAirway, self.airwayPoints))
file.close()
def outputAirwayFile(self, outputFilename):
sortedAirways = sorted(self.airways, key=lambda airways: airways[0])
outputFile = open(outputFilename, 'w+')
outputFile.write('var _faaAirways = {\n');
isFirst = True
for airway in sortedAirways:
if isFirst:
isFirst = False
else:
outputFile.write(',\n');
outputFile.write(' "{0}":{{ "name":"{0}", "fixes":['.format(airway[0]))
isFirstFix = True
for fix in airway[1]:
if isFirstFix:
isFirstFix = False
else:
outputFile.write(', ');
outputFile.write('"{0}"'.format(fix))
outputFile.write(']}')
outputFile.write('\n};\n');
def main():
waypoints = WaypointData()
waypoints.parseAirportData('APT.txt')
waypoints.parseNavAidData('NAV.txt')
waypoints.parseFixData('FIX.txt')
waypoints.outputWaypointFile('waypoints.js')
airways = AirwayData()
airways.parseAirwayData('AWY.txt')
airways.outputAirwayFile('airways.js')
if __name__ == "__main__":
main()