149 lines
3.9 KiB
TypeScript
149 lines
3.9 KiB
TypeScript
import "./utils/extensions.ts";
|
|
import { handleTurnAtFix } from "./utils/handleTurnAtFix.ts";
|
|
import * as geolib from "geolib";
|
|
import geojson from "geojson";
|
|
|
|
class Parser {
|
|
private static _instance: Parser;
|
|
|
|
private waypoints: Waypoint[];
|
|
private runways: Runway[];
|
|
private terminals: Terminal[];
|
|
|
|
public static AC_SPEED = 250;
|
|
|
|
private constructor(
|
|
waypoints: Waypoint[],
|
|
runways: Runway[],
|
|
terminals: Terminal[]
|
|
) {
|
|
this.waypoints = waypoints;
|
|
this.runways = runways;
|
|
this.terminals = terminals;
|
|
}
|
|
|
|
public static instance = async () => {
|
|
if (!Parser._instance) {
|
|
const waypoints = await (await fetch("navdata/Waypoints.json")).json();
|
|
const runways = await (await fetch("navdata/Runways.json")).json();
|
|
const terminals = await (await fetch("navdata/Terminals.json")).json();
|
|
|
|
Parser._instance = new Parser(waypoints, runways, terminals);
|
|
}
|
|
|
|
return Parser._instance;
|
|
};
|
|
|
|
public parse = async (terminalID: number) => {
|
|
// Private functions
|
|
/**
|
|
* @param line Line segments
|
|
*/
|
|
const updateLastCourse = (line: LineSegment[]) => {
|
|
lastCourse = geolib.getGreatCircleBearing(
|
|
{
|
|
latitude: line.at(-2)![1],
|
|
longitude: line.at(-2)![0],
|
|
},
|
|
{
|
|
latitude: line.at(-1)![1],
|
|
longitude: line.at(-1)![0],
|
|
}
|
|
);
|
|
};
|
|
|
|
// Get Procedure main
|
|
const terminal = this.terminals.find(({ ID }) => ID === terminalID);
|
|
if (!terminal) throw new Error("Procedure does not exists");
|
|
// Get runway this procedure is for
|
|
const runway = this.runways.find(({ ID }) => ID === terminal.RwyID);
|
|
if (!runway) throw new Error("Procedure links to non existent Runway");
|
|
// Load procedure
|
|
const procedure = (await (
|
|
await fetch(`navdata/TermID_${terminalID}.json`)
|
|
).json()) as TerminalEntry[];
|
|
|
|
// Output variables
|
|
const navFixes: NavFix[] = [];
|
|
const lineSegments: { line: LineSegment[] }[] = [];
|
|
|
|
// Initials
|
|
navFixes.push({
|
|
latitude: runway.Latitude,
|
|
longitude: runway.Longitude,
|
|
altitude: runway.Elevation,
|
|
speed: 0,
|
|
name: runway.Ident,
|
|
});
|
|
let lastCourse = runway.TrueHeading;
|
|
|
|
// Main
|
|
for (let index = 0; index < procedure.length; index++) {
|
|
const leg = procedure[index];
|
|
const previousFix = navFixes.at(-1)!;
|
|
const waypoint = this.waypoints.filter(({ ID }) => ID === leg.WptID)[0];
|
|
|
|
switch (leg.TrackCode) {
|
|
case "AF":
|
|
case "CA":
|
|
case "CD":
|
|
break;
|
|
case "CF": {
|
|
const _leg = leg as CFTerminalEntry;
|
|
const targetFix: NavFix = {
|
|
latitude: _leg.WptLat,
|
|
longitude: _leg.WptLon,
|
|
name: waypoint?.Ident ?? undefined,
|
|
"marker-color": _leg.IsFlyOver ? "#ff0000" : undefined,
|
|
isFlyOver: _leg.IsFlyOver,
|
|
altitude: previousFix.altitude,
|
|
};
|
|
navFixes.push(targetFix);
|
|
|
|
const line = handleTurnAtFix(
|
|
_leg.Course.toTrue(previousFix),
|
|
_leg.Course.toTrue(previousFix),
|
|
lastCourse,
|
|
previousFix,
|
|
targetFix,
|
|
_leg.TurnDir
|
|
);
|
|
|
|
lineSegments.push({ line });
|
|
updateLastCourse(lineSegments.at(-1)!.line);
|
|
break;
|
|
}
|
|
case "CI":
|
|
case "CR":
|
|
case "DF":
|
|
case "FA":
|
|
case "FC":
|
|
case "FD":
|
|
case "FM":
|
|
case "HA":
|
|
case "HF":
|
|
case "HM":
|
|
case "IF":
|
|
case "PI":
|
|
case "RF":
|
|
case "TF":
|
|
case "VA":
|
|
case "VD":
|
|
case "VI":
|
|
case "VM":
|
|
case "VR":
|
|
default:
|
|
console.error("Unknown TrackCode", leg.TrackCode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return geojson.parse([...navFixes, ...lineSegments], {
|
|
Point: ["latitude", "longitude"],
|
|
LineString: "line",
|
|
});
|
|
};
|
|
}
|
|
|
|
export default Parser;
|