From 31150adb9e8d2e2ea5eed000c2114cfbc628db90 Mon Sep 17 00:00:00 2001 From: Sven Czarnian Date: Mon, 30 Aug 2021 21:57:56 +0200 Subject: [PATCH] add a parser to read SCT/ESE-files --- aman/formats/SctEseFormat.py | 147 +++++++++++++++++++++++++++++++++++ aman/formats/__init__.py | 0 setup.py | 1 + 3 files changed, 148 insertions(+) create mode 100644 aman/formats/SctEseFormat.py create mode 100644 aman/formats/__init__.py diff --git a/aman/formats/SctEseFormat.py b/aman/formats/SctEseFormat.py new file mode 100644 index 0000000..3bebe77 --- /dev/null +++ b/aman/formats/SctEseFormat.py @@ -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) diff --git a/aman/formats/__init__.py b/aman/formats/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/setup.py b/setup.py index c55f7d7..78258ad 100644 --- a/setup.py +++ b/setup.py @@ -75,6 +75,7 @@ setup( 'aman', 'aman.com', 'aman.config', + 'aman.formats', 'aman.tools', 'aman.types' ],