|
@@ -0,0 +1,92 @@
|
|
|
|
+import { Inbound } from '../inbound/models/inbound.model';
|
|
|
|
+import { Airport } from '../airport/models/airport.model';
|
|
|
|
+import { WGS84 } from 'src/math';
|
|
|
|
+
|
|
|
|
+export class RunwayPlanner {
|
|
|
|
+ static timeIndependentRunway(airport: Airport, inbound: Inbound): string {
|
|
|
|
+ if (airport.activeRunways.length === 0) return undefined;
|
|
|
|
+
|
|
|
|
+ const shallRunway: string[] = [undefined, undefined];
|
|
|
|
+ const shouldRunway: string[] = [undefined, undefined];
|
|
|
|
+ const mayRunway: string[] = [undefined, undefined];
|
|
|
|
+
|
|
|
|
+ // collect candidates based on aircraft type and assigned stand
|
|
|
|
+ airport.planning.assignments.forEach((assignment) => {
|
|
|
|
+ const aircraftTypeBound =
|
|
|
|
+ assignment.aircrafts.find(
|
|
|
|
+ (element) => element === inbound.aircraft.type,
|
|
|
|
+ ) !== undefined;
|
|
|
|
+ const standBound =
|
|
|
|
+ assignment.assignedStands.find(
|
|
|
|
+ (element) => element === inbound.controllerData.plannedStand,
|
|
|
|
+ ) !== undefined;
|
|
|
|
+
|
|
|
|
+ if (aircraftTypeBound) {
|
|
|
|
+ switch (assignment.type) {
|
|
|
|
+ case 'SHALL':
|
|
|
|
+ shallRunway[0] = assignment.runway;
|
|
|
|
+ break;
|
|
|
|
+ case 'SHOULD':
|
|
|
|
+ shouldRunway[0] = assignment.runway;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ mayRunway[0] = assignment.runway;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ } else if (standBound) {
|
|
|
|
+ switch (assignment.type) {
|
|
|
|
+ case 'SHALL':
|
|
|
|
+ shallRunway[1] = assignment.runway;
|
|
|
|
+ break;
|
|
|
|
+ case 'SHOULD':
|
|
|
|
+ shouldRunway[1] = assignment.runway;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ mayRunway[1] = assignment.runway;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // select based on shall-should-may order
|
|
|
|
+ if (shallRunway[0] !== undefined || shallRunway[1] !== undefined) {
|
|
|
|
+ return shallRunway[0] !== undefined ? shallRunway[0] : shallRunway[1];
|
|
|
|
+ } else if (shouldRunway[0] !== undefined || shouldRunway[1] !== undefined) {
|
|
|
|
+ return shouldRunway[0] !== undefined ? shouldRunway[0] : shouldRunway[1];
|
|
|
|
+ } else if (mayRunway[0] !== undefined || mayRunway[1] !== undefined) {
|
|
|
|
+ return mayRunway[0] !== undefined ? mayRunway[0] : mayRunway[1];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // as a fallback use the closest runway
|
|
|
|
+ let closestDistance = 10000000.0;
|
|
|
|
+ let closestRunway: string = undefined;
|
|
|
|
+
|
|
|
|
+ airport.activeRunways.forEach((identifier) => {
|
|
|
|
+ const runway = airport.runways.find(
|
|
|
|
+ (element) => element.identifier === identifier,
|
|
|
|
+ );
|
|
|
|
+ if (runway !== undefined) {
|
|
|
|
+ const distance = WGS84.distance(
|
|
|
|
+ { lat: runway.threshold.latitude, lon: runway.threshold.longitude },
|
|
|
|
+ {
|
|
|
|
+ lat: inbound.flightState.position.latitude,
|
|
|
|
+ lon: inbound.flightState.position.longitude,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ if (closestDistance > distance) {
|
|
|
|
+ closestDistance = distance;
|
|
|
|
+ closestRunway = identifier;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ if (closestRunway !== undefined) {
|
|
|
|
+ return closestRunway;
|
|
|
|
+ } else if (airport.activeRunways.length !== 0) {
|
|
|
|
+ return airport.activeRunways[0];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return undefined;
|
|
|
|
+ }
|
|
|
|
+}
|