Browse Source

add a parser to read SCT/ESE-files

Sven Czarnian 3 years ago
parent
commit
31150adb9e
3 changed files with 148 additions and 0 deletions
  1. 147 0
      aman/formats/SctEseFormat.py
  2. 0 0
      aman/formats/__init__.py
  3. 1 0
      setup.py

+ 147 - 0
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)

+ 0 - 0
aman/formats/__init__.py


+ 1 - 0
setup.py

@@ -75,6 +75,7 @@ setup(
         'aman',
         'aman.com',
         'aman.config',
+        'aman.formats',
         'aman.tools',
         'aman.types'
     ],