diff --git a/src/planner/runwayplanner.ts b/src/planner/runwayplanner.ts new file mode 100644 index 0000000..a91c203 --- /dev/null +++ b/src/planner/runwayplanner.ts @@ -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; + } +}