Fix EDDM ILS26 OTT

This commit is contained in:
Kilian Hofmann 2025-07-18 00:33:57 +02:00
parent d102ec4834
commit 4e4b921f79
5 changed files with 61 additions and 19 deletions

View File

@ -707,4 +707,23 @@ This intercept point then becomes the origin fix of the succeeding leg.
# Other Fields # Other Fields
- `Vnav`: Angle from IAF to MAP. Useful for RNAV. - `Vnav`: Angle from IAF to MAP. Useful for RNAV.
# How to run
- `git clone https://git.hofmannnet.myhome-server.de/TFDi_MD-11_QA/NavDataExplorer.git`.
- `cd md11-nav-data`.
- `pnpm install`
For dev:
- Copy contents of `tfdidesign-aircraft-md11/Design/Primary` into ? `md11-nav-data/public/NavData`
- `cd md11-nav-data`.
- `pnpm dev`
For prod:
- `cd md11-nav-data`.
- `pnpm build`
- Verify Navdata was copied into `dist`

View File

@ -80,11 +80,11 @@ function App() {
setSelectedAirport={setSelectedAirport} setSelectedAirport={setSelectedAirport}
setSelectedRunway={setSelectedRunway} setSelectedRunway={setSelectedRunway}
setSelectedTerminal={setSelectedTerminal} setSelectedTerminal={setSelectedTerminal}
handleSelection={(selectedTransitions) => { handleSelection={(selectedTransitions, _terminal) => {
let _transitions = selectedTransitions let _transitions = selectedTransitions
.map((transition) => ({ .map((transition) => ({
name: transition, name: transition,
data: parser.parse(selectedRunway!, transition), data: parser.parse(selectedRunway!, _terminal, transition),
})) }))
.filter( .filter(
(transition) => (transition) =>

View File

@ -11,7 +11,7 @@ interface ProcedureSelectProps {
setSelectedAirport: Dispatch<SetStateAction<Airport | undefined>>; setSelectedAirport: Dispatch<SetStateAction<Airport | undefined>>;
setSelectedRunway: Dispatch<SetStateAction<Runway | undefined>>; setSelectedRunway: Dispatch<SetStateAction<Runway | undefined>>;
setSelectedTerminal: Dispatch<SetStateAction<Terminal | undefined>>; setSelectedTerminal: Dispatch<SetStateAction<Terminal | undefined>>;
handleSelection: (transitions: string[]) => void; handleSelection: (transitions: string[], terminal: Terminal) => void;
} }
export const ProcedureSelect: FC<ProcedureSelectProps> = ({ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
@ -125,7 +125,7 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser.loadTerminal(terminal.ID).then(() => { parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal); setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions)); handleSelection(Array.from(transitions), terminal);
setInFlight(undefined); setInFlight(undefined);
}); });
}} }}
@ -148,7 +148,7 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser.loadTerminal(terminal.ID).then(() => { parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal); setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions)); handleSelection(Array.from(transitions), terminal);
}); });
}} }}
disabled={!!inFlight} disabled={!!inFlight}
@ -170,7 +170,7 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
parser.loadTerminal(terminal.ID).then(() => { parser.loadTerminal(terminal.ID).then(() => {
setSelectedTerminal(terminal); setSelectedTerminal(terminal);
const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
handleSelection(Array.from(transitions)); handleSelection(Array.from(transitions), terminal);
}); });
}} }}
disabled={!!inFlight} disabled={!!inFlight}

View File

@ -88,7 +88,7 @@ class Parser {
).json()) as TerminalEntry[]; ).json()) as TerminalEntry[];
}; };
public parse = (runway: Runway, transition: string) => { public parse = (runway: Runway, terminal: Terminal, transition: string) => {
// Private functions // Private functions
/** /**
* @param line Line segments * @param line Line segments
@ -123,15 +123,19 @@ class Parser {
const navFixes: NavFix[] = []; const navFixes: NavFix[] = [];
const lineSegments: { line: LineSegment[]; [x: string]: unknown }[] = []; const lineSegments: { line: LineSegment[]; [x: string]: unknown }[] = [];
// Initials let lastCourse = 0;
navFixes.push({
latitude: runway.Latitude, // RWY as origin for Departures
longitude: runway.Longitude, if (terminal.Proc === 2) {
altitude: runway.Elevation, navFixes.push({
speed: 0, latitude: runway.Latitude,
name: runway.Ident, longitude: runway.Longitude,
}); altitude: runway.Elevation,
let lastCourse = runway.TrueHeading; speed: 0,
name: runway.Ident,
});
lastCourse = runway.TrueHeading;
}
const legOptions = { isMAP: false }; const legOptions = { isMAP: false };
const procedure = this._procedures.filter( const procedure = this._procedures.filter(
({ Transition }) => !Transition || Transition === transition || Transition === 'ALL' ({ Transition }) => !Transition || Transition === transition || Transition === 'ALL'
@ -143,9 +147,28 @@ class Parser {
const leg = procedure[index]; const leg = procedure[index];
leg.Alt = leg.IsMAP ? String(runway.Elevation + 200).padStart(5, '0') : leg.Alt; leg.Alt = leg.IsMAP ? String(runway.Elevation + 200).padStart(5, '0') : leg.Alt;
const waypoint = this.waypoints.find(({ ID }) => ID === leg.WptID);
if (terminal.Proc !== 2 && navFixes.length === 0) {
if (!leg.WptLat || !leg.WptLon)
throw new Error('Non departure procedure has first leg that has no defined starting point. Cannot render.');
navFixes.push({
latitude: leg.WptLat,
longitude: leg.WptLon,
altitude: leg.Alt ? leg.Alt.parseAltitude() : runway.Elevation,
speed: leg.SpeedLimit ? leg.SpeedLimit : Parser.AC_SPEED,
name: waypoint?.Ident,
speedConstraint: leg.SpeedLimit,
altitudeConstraint: leg.Alt,
IsFAF: leg.IsFAF,
IsMAP: leg.IsMAP,
});
}
const previousFix = navFixes.at(-1)!; const previousFix = navFixes.at(-1)!;
legOptions.isMAP ||= previousFix.IsMAP ?? false; legOptions.isMAP ||= previousFix.IsMAP ?? false;
const waypoint = this.waypoints.find(({ ID }) => ID === leg.WptID);
switch (leg.TrackCode) { switch (leg.TrackCode) {
case 'AF': { case 'AF': {

View File

@ -41,7 +41,7 @@ export const TerminatorsFD = (
// Compute intercept of crs from arc end and distance // Compute intercept of crs from arc end and distance
const targetFix: NavFix = { const targetFix: NavFix = {
...computeDestinationPoint(arcEnd, remainingDistance, lastCourse), ...computeDestinationPoint(arcEnd, remainingDistance, crsIntoEndpoint),
name: leg.Distance.toString(), name: leg.Distance.toString(),
isFlyOver: true, isFlyOver: true,
altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude, altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,