|
@@ -0,0 +1,147 @@
|
|
|
+#!/usr/bin/env python
|
|
|
+
|
|
|
+import sys
|
|
|
+
|
|
|
+from aman.types.ArrivalRoute import ArrivalRoute
|
|
|
+from aman.types.Exception import FormatError, InputError
|
|
|
+from aman.types.Waypoint import Waypoint
|
|
|
+
|
|
|
+class SctEseFormat:
|
|
|
+ def readFile(filename : str):
|
|
|
+ fileBlocks = {}
|
|
|
+ block = None
|
|
|
+
|
|
|
+ # read the file line by line and create segments based on []-entries
|
|
|
+ with open(filename) as file:
|
|
|
+ for line in file:
|
|
|
+ line = line.strip()
|
|
|
+
|
|
|
+ # found a new segment
|
|
|
+ if line.startswith('['):
|
|
|
+ block = line[1:-1]
|
|
|
+ fileBlocks.setdefault(block, [])
|
|
|
+ # append the last backend
|
|
|
+ elif None != block and 0 != len(line):
|
|
|
+ fileBlocks[block].append(line)
|
|
|
+
|
|
|
+ return fileBlocks
|
|
|
+
|
|
|
+ def parseWaypoint(waypoint : str, nameIdx : int, latitudeIdx : int, longitudeIdx : int):
|
|
|
+ split = list(filter(None, waypoint.split(' ')))
|
|
|
+ if len(split) <= longitudeIdx:
|
|
|
+ raise FormatError('Invalid waypoint format: ' + waypoint)
|
|
|
+ return Waypoint(split[nameIdx], Waypoint.dms2dd(split[latitudeIdx]), Waypoint.dms2dd(split[longitudeIdx]))
|
|
|
+
|
|
|
+ def extractWaypoints(self, sctFilepath : str):
|
|
|
+ config = SctEseFormat.readFile(sctFilepath)
|
|
|
+ foundAirports = False
|
|
|
+ foundVOR = False
|
|
|
+ foundNDB = False
|
|
|
+ foundFix = False
|
|
|
+
|
|
|
+ for key in config:
|
|
|
+ if 'VOR' == key:
|
|
|
+ foundVOR = True
|
|
|
+ elif 'NDB' == key:
|
|
|
+ foundNDB = True
|
|
|
+ elif 'FIXES' == key:
|
|
|
+ foundFix = True
|
|
|
+ elif 'AIRPORT' == key:
|
|
|
+ foundAirports = True
|
|
|
+
|
|
|
+ if False == foundVOR:
|
|
|
+ raise FormatError('Unable to find VOR-entries in the sector file')
|
|
|
+ if False == foundNDB:
|
|
|
+ raise FormatError('Unable to find NDB-entries in the sector file')
|
|
|
+ if False == foundFix:
|
|
|
+ raise FormatError('Unable to find FIX-entries in the sector file')
|
|
|
+ if False == foundAirports:
|
|
|
+ raise FormatError('Unable to find AIRPORT-entries in the sector file')
|
|
|
+
|
|
|
+ # extract all waypoints
|
|
|
+ for waypoint in config['VOR']:
|
|
|
+ waypoint = SctEseFormat.parseWaypoint(waypoint, 0, 2, 3)
|
|
|
+ self.waypoints.setdefault(waypoint.name, []).append(waypoint)
|
|
|
+ for waypoint in config['NDB']:
|
|
|
+ waypoint = SctEseFormat.parseWaypoint(waypoint, 0, 1, 2)
|
|
|
+ self.waypoints.setdefault(waypoint.name, []).append(waypoint)
|
|
|
+ for waypoint in config['FIXES']:
|
|
|
+ waypoint = SctEseFormat.parseWaypoint(waypoint, 0, 1, 2)
|
|
|
+ self.waypoints.setdefault(waypoint.name, []).append(waypoint)
|
|
|
+
|
|
|
+ # extract the airports
|
|
|
+ for airport in config['AIRPORT']:
|
|
|
+ airport = SctEseFormat.parseWaypoint(airport,0, 2, 3)
|
|
|
+ self.airports.setdefault(airport.name, []).append(airport)
|
|
|
+
|
|
|
+ def parseArrivalRoute(self, route : str, airport : Waypoint):
|
|
|
+ # split the route and validate that it is a STAR for the airport
|
|
|
+ split = route.split(':')
|
|
|
+ if 5 != len(split) or 'STAR' != split[0] or split[1] != airport.name:
|
|
|
+ return None
|
|
|
+
|
|
|
+ # find all waypoints
|
|
|
+ waypoints = []
|
|
|
+ route = list(filter(None, split[4].split(' ')))
|
|
|
+ for waypoint in route:
|
|
|
+ # find the waypoint in the route
|
|
|
+ coordinates = self.waypoints[waypoint]
|
|
|
+ # no waypoint with this name defined
|
|
|
+ if None == coordinates:
|
|
|
+ raise FormatError('Unable to find waypoint ' + waypoint)
|
|
|
+ # multiple waypoints, but use Haversine distance to distinct between candidates
|
|
|
+ elif 1 != len(coordinates):
|
|
|
+ minDistance = sys.float_info.max
|
|
|
+ nearest = None
|
|
|
+
|
|
|
+ # we assume that waypoints with the same name are not close each other
|
|
|
+ for coordinate in coordinates:
|
|
|
+ distance = coordinate.haversine(airport)
|
|
|
+ # found a closer waypoint
|
|
|
+ if minDistance > distance:
|
|
|
+ minDistance = distance
|
|
|
+ nearest = coordinate
|
|
|
+
|
|
|
+ if None == nearest:
|
|
|
+ raise InputError('Unable to find a close waypoint for ' + waypoint)
|
|
|
+
|
|
|
+ waypoints.append(nearest)
|
|
|
+ # extend the list of waypoints
|
|
|
+ else:
|
|
|
+ waypoints.append(coordinates[0])
|
|
|
+
|
|
|
+ # create the arrival route
|
|
|
+ return ArrivalRoute(split[3], split[2], waypoints)
|
|
|
+
|
|
|
+ def extractArrivalRoutes(self, eseFilepath : str, airport : str, allowedRoutes : list):
|
|
|
+ config = SctEseFormat.readFile(eseFilepath)
|
|
|
+ foundSidsStars = False
|
|
|
+
|
|
|
+ # search the airport in the extracted list
|
|
|
+ if not airport in self.airports:
|
|
|
+ raise InputError(airport + 'in self.airports', 'Unable to find the requested airport')
|
|
|
+ airport = self.airports[airport][0]
|
|
|
+
|
|
|
+ for key in config:
|
|
|
+ if 'SIDSSTARS' == key:
|
|
|
+ foundSidsStars = True
|
|
|
+
|
|
|
+ if False == foundSidsStars:
|
|
|
+ raise FormatError('Unable to find SIDSSTARS-entries in the sector file')
|
|
|
+
|
|
|
+ # parse all arrival routes
|
|
|
+ for line in config['SIDSSTARS']:
|
|
|
+ route = self.parseArrivalRoute(line, airport)
|
|
|
+ if None != route and route.name in allowedRoutes:
|
|
|
+ self.arrivalRoutes.setdefault(route.name, []).append(route)
|
|
|
+
|
|
|
+ def __init__(self, sctFilepath : str, eseFilepath : str, airport : str, allowedRoutes : list):
|
|
|
+ self.arrivalRoutes = {}
|
|
|
+ self.waypoints = {}
|
|
|
+ self.airports = {}
|
|
|
+
|
|
|
+ self.extractWaypoints(sctFilepath)
|
|
|
+ print('Extracted ' + str(len(self.waypoints)) + ' waypoints')
|
|
|
+
|
|
|
+ self.extractArrivalRoutes(eseFilepath, airport, allowedRoutes)
|
|
|
+ print('Extracted ' + str(len(self.arrivalRoutes)) + ' arrival routes for ' + airport)
|