Fix more CF

This commit is contained in:
Kilian Hofmann 2025-07-19 15:14:46 +02:00
parent e9bab0306f
commit 73373420d3
10 changed files with 48 additions and 28 deletions

View File

@ -91,6 +91,11 @@ export const Map: FC<MapProps> = ({ 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',

View File

@ -145,10 +145,12 @@ export const ProcedureSelect: FC<ProcedureSelectProps> = ({
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<ProcedureSelectProps> = ({
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}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -26,6 +26,7 @@ export const TerminatorsRF = (
lastCourse,
previousFix,
{ latitude: leg.CenterLat, longitude: leg.CenterLon },
targetFix,
leg.TurnDir
);

View File

@ -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;

View File

@ -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 () {

View File

@ -91,6 +91,7 @@ export declare global {
IsMAP?: boolean;
// For map
isIntersection?: boolean;
isInitial?: boolean;
};
type LineSegment = [number, number];