From 73373420d3ec95a671ed46b8ce5ffb862b81b34c Mon Sep 17 00:00:00 2001 From: Kilian Hofmann Date: Sat, 19 Jul 2025 15:14:46 +0200 Subject: [PATCH] Fix more CF --- md11-nav-data/src/components/Map.tsx | 5 ++++ .../src/components/ProcedureSelect.tsx | 4 +++ .../parser/pathGenerators/generateRFArc.ts | 19 +++++-------- .../pathGenerators/generateTangentArc.ts | 2 +- md11-nav-data/src/parser/terminators/CF.ts | 27 ++++++++++++++----- md11-nav-data/src/parser/terminators/IF.ts | 1 + md11-nav-data/src/parser/terminators/RF.ts | 1 + md11-nav-data/src/parser/terminators/TF.ts | 6 +++-- md11-nav-data/src/parser/utils/extensions.ts | 10 +++---- md11-nav-data/src/types/navdata.d.ts | 1 + 10 files changed, 48 insertions(+), 28 deletions(-) diff --git a/md11-nav-data/src/components/Map.tsx b/md11-nav-data/src/components/Map.tsx index cea15a7..e11dcfb 100644 --- a/md11-nav-data/src/components/Map.tsx +++ b/md11-nav-data/src/components/Map.tsx @@ -91,6 +91,11 @@ export const Map: FC = ({ airport, chart, procedures }) => { shape: 'triangle', radius: 6, }); + else if (properties.isInitial) + return L.shapeMarker(latlng, { + shape: 'arrowhead', + radius: 6, + }); return L.shapeMarker(latlng, { shape: 'star-4', diff --git a/md11-nav-data/src/components/ProcedureSelect.tsx b/md11-nav-data/src/components/ProcedureSelect.tsx index d2e8228..d9f2209 100644 --- a/md11-nav-data/src/components/ProcedureSelect.tsx +++ b/md11-nav-data/src/components/ProcedureSelect.tsx @@ -145,10 +145,12 @@ export const ProcedureSelect: FC = ({ key={terminal.ID} className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100" onClick={() => { + setInFlight(terminal.ID); parser.loadTerminal(terminal.ID).then(() => { setSelectedTerminal(terminal); const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); handleSelection(Array.from(transitions), terminal); + setInFlight(undefined); }); }} disabled={!!inFlight} @@ -167,10 +169,12 @@ export const ProcedureSelect: FC = ({ key={terminal.ID} className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100" onClick={() => { + setInFlight(terminal.ID); parser.loadTerminal(terminal.ID).then(() => { setSelectedTerminal(terminal); const transitions = new Set(parser.procedures.map((proc) => proc.Transition)); handleSelection(Array.from(transitions), terminal); + setInFlight(undefined); }); }} disabled={!!inFlight} diff --git a/md11-nav-data/src/parser/pathGenerators/generateRFArc.ts b/md11-nav-data/src/parser/pathGenerators/generateRFArc.ts index a2a9956..0be50d6 100644 --- a/md11-nav-data/src/parser/pathGenerators/generateRFArc.ts +++ b/md11-nav-data/src/parser/pathGenerators/generateRFArc.ts @@ -1,4 +1,5 @@ import computeDestinationPoint from 'geolib/es/computeDestinationPoint'; +import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing'; import getPreciseDistance from 'geolib/es/getPreciseDistance'; /** @@ -6,7 +7,8 @@ import getPreciseDistance from 'geolib/es/getPreciseDistance'; * @param crsIntoOrigin Course into arc origin point * @param start Arc origin point * @param center Arc center point - * @param turnDir + * @param end Arc end point + * @param turnDir Turn Direction * @returns Line segments */ export const generateRFArc = ( @@ -14,6 +16,7 @@ export const generateRFArc = ( crsIntoOrigin: number, start: NavFix, center: NavFix, + end: NavFix, turnDir: TurnDirection ) => { const line: LineSegment[] = [[start.longitude, start.latitude]]; @@ -26,20 +29,10 @@ export const generateRFArc = ( turnDir = prov > 0 ? 'L' : 'R'; } - let crsOrthogonalOnOrigin; - let crsOrthogonalOnEndpoint; - if (turnDir === 'R') { - crsOrthogonalOnOrigin = (crsIntoOrigin + 90).normaliseDegrees(); - crsOrthogonalOnEndpoint = (crsIntoEndpoint + 90).normaliseDegrees(); - } else { - crsOrthogonalOnOrigin = (crsIntoOrigin - 90).normaliseDegrees(); - crsOrthogonalOnEndpoint = (crsIntoEndpoint - 90).normaliseDegrees(); - } - + let crsOrthogonalOnOrigin = getGreatCircleBearing(center, start); + const crsOrthogonalOnEndpoint = getGreatCircleBearing(center, end); const arcRad = getPreciseDistance(center, start); - crsOrthogonalOnOrigin = crsOrthogonalOnOrigin.reciprocalCourse(); - crsOrthogonalOnEndpoint = crsOrthogonalOnEndpoint.reciprocalCourse(); // Start turn immediately if (turnDir === 'R') { crsOrthogonalOnOrigin += crsOrthogonalOnOrigin < 1 ? crsOrthogonalOnOrigin : 1; diff --git a/md11-nav-data/src/parser/pathGenerators/generateTangentArc.ts b/md11-nav-data/src/parser/pathGenerators/generateTangentArc.ts index d49c0c7..9ab45bd 100644 --- a/md11-nav-data/src/parser/pathGenerators/generateTangentArc.ts +++ b/md11-nav-data/src/parser/pathGenerators/generateTangentArc.ts @@ -63,7 +63,7 @@ export const generateTangentArc = ( intcArcOnCrsIntoEndpoint, crsOrthogonalOnEndpoint ); - if (Math.abs(crsOrthogonalOnEndpoint - crsOrthogonalOnOrigin) <= 0.1 && arcCenter) + if (!crsOrthogonalOnEndpoint.equal(crsOrthogonalOnOrigin) && arcCenter) arcRad = getPreciseDistance(arcCenter, start); else { arcRad = getPreciseDistance(start, end) / 2; diff --git a/md11-nav-data/src/parser/terminators/CF.ts b/md11-nav-data/src/parser/terminators/CF.ts index a2aaf31..33c423f 100644 --- a/md11-nav-data/src/parser/terminators/CF.ts +++ b/md11-nav-data/src/parser/terminators/CF.ts @@ -3,6 +3,7 @@ import getGreatCircleBearing from 'geolib/es/getGreatCircleBearing'; import getPreciseDistance from 'geolib/es/getPreciseDistance'; import Parser from '../parser'; import { generateTangentArc } from '../pathGenerators/generateTangentArc'; +import { computeIntersection } from '../utils/computeIntersection'; import { computeSpeed } from '../utils/computeSpeed'; import { computeTurnRate } from '../utils/computeTurnRate'; @@ -28,7 +29,6 @@ export const TerminatorsCF = ( IsFAF: leg.IsFAF, IsMAP: leg.IsMAP, }; - const crsToIntercept = leg.Course.toTrue(targetFix); // Compute overfly arc let arc1: LineSegment[] | null = null; @@ -59,7 +59,13 @@ export const TerminatorsCF = ( if (endDist <= 25 || (endCrs <= crsIntoEndpoint + 1 && endCrs >= crsIntoEndpoint - 1)) arc = arc1; } - if (!arc && previousFix.isFlyOver && (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsToIntercept))) { + const intercept = computeIntersection(previousFix, lastCourse, targetFix, crsIntoEndpoint.reciprocalCourse()); + if ( + !arc && + previousFix.isFlyOver && + (!lastCourse.equal(crsIntoEndpoint) || !lastCourse.equal(crsIntoEndpoint)) && + !(intercept?.latitude === targetFix.latitude && intercept.longitude === targetFix.longitude) + ) { const turnRate = computeTurnRate(speed, Parser.AC_BANK); let updatedCrsToIntercept = getGreatCircleBearing(previousFix, targetFix); @@ -72,19 +78,26 @@ export const TerminatorsCF = ( // Generate arc let lastDistance = getPreciseDistance(previousFix, targetFix); - while (!updatedCrsToIntercept.equal(crsToIntercept)) { + const reversal = Math.abs(lastCourse - crsIntoEndpoint) >= 90; + while (!updatedCrsToIntercept.equal(crsIntoEndpoint)) { let interceptAngle = 0; - if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsToIntercept); - else interceptAngle = Math.abs(crsToIntercept - lastCourse); + if (leg.TurnDir === 'R') interceptAngle = Math.abs(lastCourse - crsIntoEndpoint); + else interceptAngle = Math.abs(crsIntoEndpoint - lastCourse); let time = 0; const increment = 0.1; if (interceptAngle < 44.9 || interceptAngle >= 45.1) { if (leg.TurnDir === 'R') { - lastCourse = (lastCourse + increment).normaliseDegrees(); + lastCourse = + reversal || updatedCrsToIntercept >= crsIntoEndpoint + ? (lastCourse + increment).normaliseDegrees() + : lastCourse; time = increment / turnRate; } else { - lastCourse = (lastCourse - increment).normaliseDegrees(); + lastCourse = + reversal || updatedCrsToIntercept <= crsIntoEndpoint + ? (lastCourse - increment).normaliseDegrees() + : lastCourse; time = increment / turnRate; } } else time = increment / turnRate; diff --git a/md11-nav-data/src/parser/terminators/IF.ts b/md11-nav-data/src/parser/terminators/IF.ts index 66d8e74..0de2aa8 100644 --- a/md11-nav-data/src/parser/terminators/IF.ts +++ b/md11-nav-data/src/parser/terminators/IF.ts @@ -12,6 +12,7 @@ export const TerminatorsIF = (leg: IFTerminalEntry, waypoint?: Waypoint): NavFix altitudeConstraint: leg.Alt, IsFAF: leg.IsFAF, IsMAP: leg.IsMAP, + isInitial: true, }; return targetFix; diff --git a/md11-nav-data/src/parser/terminators/RF.ts b/md11-nav-data/src/parser/terminators/RF.ts index f29d3bb..3af3112 100644 --- a/md11-nav-data/src/parser/terminators/RF.ts +++ b/md11-nav-data/src/parser/terminators/RF.ts @@ -26,6 +26,7 @@ export const TerminatorsRF = ( lastCourse, previousFix, { latitude: leg.CenterLat, longitude: leg.CenterLon }, + targetFix, leg.TurnDir ); diff --git a/md11-nav-data/src/parser/terminators/TF.ts b/md11-nav-data/src/parser/terminators/TF.ts index 789c3e7..007a73b 100644 --- a/md11-nav-data/src/parser/terminators/TF.ts +++ b/md11-nav-data/src/parser/terminators/TF.ts @@ -80,10 +80,12 @@ export const TerminatorsTF = ( const increment = 0.1; if (interceptAngle < 44.9 || interceptAngle >= 45.1) { if (leg.TurnDir === 'R') { - lastCourse = (lastCourse + increment).normaliseDegrees(); + lastCourse = + updatedCrsToIntercept >= crsIntoEndpoint ? (lastCourse + increment).normaliseDegrees() : lastCourse; time = increment / turnRate; } else { - lastCourse = (lastCourse - increment).normaliseDegrees(); + lastCourse = + updatedCrsToIntercept >= crsIntoEndpoint ? (lastCourse - increment).normaliseDegrees() : lastCourse; time = increment / turnRate; } } else time = increment / turnRate; diff --git a/md11-nav-data/src/parser/utils/extensions.ts b/md11-nav-data/src/parser/utils/extensions.ts index 31b8080..0240f1d 100644 --- a/md11-nav-data/src/parser/utils/extensions.ts +++ b/md11-nav-data/src/parser/utils/extensions.ts @@ -38,16 +38,16 @@ Number.prototype.toTrue = function (fix) { let lowerLatLowerLonMagVar = (magVarTable[lowerLatLowerLonOffset + 1] << 8) + magVarTable[lowerLatLowerLonOffset]; lowerLatLowerLonMagVar = (lowerLatLowerLonMagVar * 0x168) / 0x10000; - lowerLatLowerLonMagVar = lowerLatLowerLonMagVar > 180 ? lowerLatLowerLonMagVar - 460 : lowerLatLowerLonMagVar; + lowerLatLowerLonMagVar = lowerLatLowerLonMagVar > 180 ? lowerLatLowerLonMagVar - 360 : lowerLatLowerLonMagVar; let lowerLatUpperLonMagVar = (magVarTable[lowerLatUpperLonOffset + 1] << 8) + magVarTable[lowerLatUpperLonOffset]; lowerLatUpperLonMagVar = (lowerLatUpperLonMagVar * 0x168) / 0x10000; - lowerLatUpperLonMagVar = lowerLatUpperLonMagVar > 180 ? lowerLatUpperLonMagVar - 460 : lowerLatUpperLonMagVar; + lowerLatUpperLonMagVar = lowerLatUpperLonMagVar > 180 ? lowerLatUpperLonMagVar - 360 : lowerLatUpperLonMagVar; let upperLatLowerLonMagVar = (magVarTable[upperLatLowerLonOffset + 1] << 8) + magVarTable[upperLatLowerLonOffset]; upperLatLowerLonMagVar = (upperLatLowerLonMagVar * 0x168) / 0x10000; - upperLatLowerLonMagVar = upperLatLowerLonMagVar > 180 ? upperLatLowerLonMagVar - 460 : upperLatLowerLonMagVar; + upperLatLowerLonMagVar = upperLatLowerLonMagVar > 180 ? upperLatLowerLonMagVar - 360 : upperLatLowerLonMagVar; let upperLatUpperLonMagVar = (magVarTable[upperLatUpperLonOffset + 1] << 8) + magVarTable[upperLatUpperLonOffset]; upperLatUpperLonMagVar = (upperLatUpperLonMagVar * 0x168) / 0x10000; - upperLatUpperLonMagVar = upperLatUpperLonMagVar > 180 ? upperLatUpperLonMagVar - 460 : upperLatUpperLonMagVar; + upperLatUpperLonMagVar = upperLatUpperLonMagVar > 180 ? upperLatUpperLonMagVar - 360 : upperLatUpperLonMagVar; const lowerLatRatioLon = lowerLatLowerLonMagVar + ratioLon * (lowerLatUpperLonMagVar - lowerLatLowerLonMagVar); const upperLatRatioLon = upperLatLowerLonMagVar + ratioLon * (upperLatUpperLonMagVar - upperLatLowerLonMagVar); @@ -60,7 +60,7 @@ Number.prototype.toMetre = function () { return (this as number) * 1852.0; }; Number.prototype.equal = function (other: number) { - return Math.abs((this as number) - other) < 0.1; + return Math.abs((this as number) - other) <= 0.1; }; String.prototype.parseAltitude = function () { diff --git a/md11-nav-data/src/types/navdata.d.ts b/md11-nav-data/src/types/navdata.d.ts index 290adab..81e16c2 100644 --- a/md11-nav-data/src/types/navdata.d.ts +++ b/md11-nav-data/src/types/navdata.d.ts @@ -91,6 +91,7 @@ export declare global { IsMAP?: boolean; // For map isIntersection?: boolean; + isInitial?: boolean; }; type LineSegment = [number, number];