Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fmgc): transition names and final approach slope #7637

Merged
merged 4 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
## 0.10.0

1. [ADIRU] Implemented wind speed computation from TAS/GS/HDG - @tracernz (Mike)
1. [FMGC] Show proper transition names and final approach slope from AAU1 - @tracernz (Mike)

## 0.9.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class CDUAvailableDeparturesPage {
mcdu.onRightInput[i + 1] = () => {
mcdu.setDepartureTransitionIndex(transIndex, () => {
CDUAvailableDeparturesPage.ShowPage(mcdu, airport, pageCurrent, true);
}).catch(console.error);
});
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ class CDUFlightPlanPage {
}
distance = distance.toString();

const gp = wp.additionalData.verticalAngle ? `${wp.additionalData.verticalAngle.toFixed(1)}°` : undefined;

let speedConstraint = "---";
if (wp.speedConstraint > 10 && ident !== "MANUAL") {
speedConstraint = `{magenta}*{end}${wp.speedConstraint.toFixed(0)}`;
Expand Down Expand Up @@ -419,6 +421,7 @@ class CDUFlightPlanPage {
ident: ident,
color: color,
distance: distance,
gp,
spdColor: spdColor,
speedConstraint: speedConstraint,
altColor: altColor,
Expand Down Expand Up @@ -782,10 +785,11 @@ function renderFixTableHeader(isFlying) {
}

function renderFixHeader(rowObj, showNm = false, showDist = true, showFix = true) {
const { fixAnnotation, color, distance, bearingTrack } = rowObj;
const { fixAnnotation, color, distance, gp, bearingTrack } = rowObj;
const distUnit = showNm && !gp;
return [
`${(showFix) ? fixAnnotation.padEnd(7, "\xa0").padStart(8, "\xa0") : ""}`,
`${ showDist ? (showNm ? distance + "NM" : distance) : ''}${'\xa0'.repeat(showNm ? 3 : 5)}[color]${color}`,
`${ showDist ? (distUnit ? distance + "NM" : distance) : ''}{white}${(gp ? gp : '').padStart(distUnit ? 3 : 5, '\xa0')}{end}[color]${color}`,
`{${color}}${bearingTrack}{end}\xa0`,
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,9 @@ class AirportInfo extends WayPointInfo {
approach.transitions = [];
for (let i = 0; i < approachData.transitions.length; i++) {
const transition = new Transition();
transition.name = approachData.transitions[i].legs[0].fixIcao.substr(7, 5);
transition.name = approachData.transitions[i].name.trim().length > 0
? approachData.transitions[i].name
: WayPoint.formatIdentFromIcao(approachData.transitions[i].legs[0].fixIcao);
transition.waypoints = [];
for (let j = 0; j < approachData.transitions[i].legs.length; j++) {
const wp = new WayPoint(this.instrument);
Expand Down Expand Up @@ -592,7 +594,9 @@ class AirportInfo extends WayPointInfo {
}
for (let j = 0; j < this.departures[i].enRouteTransitions.length; j++) {
const legsCount = this.departures[i].enRouteTransitions[j].legs.length;
this.departures[i].enRouteTransitions[j].name = this.departures[i].enRouteTransitions[j].legs[legsCount - 1].fixIcao.substr(7, 5);
this.departures[i].enRouteTransitions[j].name = this.departures[i].enRouteTransitions[j].name.trim().length > 0
? this.departures[i].enRouteTransitions[j].name
: WayPoint.formatIdentFromIcao(this.departures[i].enRouteTransitions[j].legs[legsCount - 1].fixIcao);
}
}
this.arrivals = data.arrivals;
Expand All @@ -612,7 +616,9 @@ class AirportInfo extends WayPointInfo {
}
}
for (let j = 0; j < this.arrivals[i].enRouteTransitions.length; j++) {
this.arrivals[i].enRouteTransitions[j].name = this.arrivals[i].enRouteTransitions[j].legs[0].fixIcao.substr(7, 5);
this.arrivals[i].enRouteTransitions[j].name = this.arrivals[i].enRouteTransitions[j].name.trim().length > 0
? this.arrivals[i].enRouteTransitions[j].name
: WayPoint.formatIdentFromIcao(this.arrivals[i].enRouteTransitions[j].legs[0].fixIcao);
}
}
}
Expand Down
75 changes: 1 addition & 74 deletions src/fmgc/src/flightplanning/LegsProcedure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ export class LegsProcedure {
mappedLeg.additionalData.theta = currentLeg.theta;
mappedLeg.additionalData.thetaTrue = A32NX_Util.magneticToTrue(currentLeg.theta, magCorrection);
mappedLeg.additionalData.annotation = currentAnnotation;
mappedLeg.additionalData.verticalAngle = currentLeg.verticalAngle ? currentLeg.verticalAngle - 360 : undefined;
}

this._currentIndex++;
Expand Down Expand Up @@ -620,78 +621,4 @@ export class LegsProcedure {

return waypoint;
}

public async calculateApproachData(runway: OneWayRunway): Promise<void> {
await this.ensureFacilitiesLoaded();

// our fallback for threshold crossing altitude is threshold + 50 feet
let threshCrossAlt = runway.thresholdElevation + 15.24;

// see if we have a runway fix, to give us coded TCH
// it can either be the MAP, or be before the MAP (MAP must be last leg of final approach)
// TCH altitude must be coded in altitude1 according to ARINC
for (let i = this._legs.length - 1; i > 0; i--) {
const leg = this._legs[i];
// TODO check it's the same runway for robustness?
if (leg.fixIcao.charAt(0) === 'R') {
threshCrossAlt = leg.altitude1;
break;
}
}

// MSFS does not give the coded descent angle
// we do our best to calculate one...
let fafAlt;
let fafIndex;
let fafToTcaDist = 0;
let lastLegPoint;

for (let i = 0; i < this._legs.length; i++) {
const leg = this._legs[i];
let termPoint;
if (leg.fixIcao.charAt(0) === 'R') {
termPoint = runway.thresholdCoordinates;
} else {
const fix = this._facilities.get(leg.fixIcao);
termPoint = new LatLongAlt(fix.lat, fix.lon);
}

if (leg.fixTypeFlags & FixTypeFlags.FAF) {
if (leg.altDesc === AltitudeDescriptor.Empty) {
// this is illegal by ARINC
break;
}

fafIndex = i;
// MSFS codes the wrong altDesc... but the right data...
fafAlt = leg.altitude2 > 0 ? leg.altitude2 : leg.altitude1;
} else if (fafIndex !== undefined) {
if (leg.distance > 0) {
fafToTcaDist += leg.distance;
} else {
// assume a straight leg
fafToTcaDist += 1852 * Avionics.Utils.computeGreatCircleDistance(lastLegPoint, termPoint);
}
}

if (leg.fixIcao.charAt(0) === 'R') {
break;
}

lastLegPoint = termPoint;
}

if (fafIndex !== undefined && fafAlt > 0 && fafToTcaDist > 0) {
let glideAngle = Math.atan((fafAlt - threshCrossAlt) / fafToTcaDist) * 180 / Math.PI;
// arinc specifics < 3 degrees is rounded up to 3 degrees when calculating glide angle from alt sources
// we do the same if we have invalid data..
if (!Number.isFinite(glideAngle) || glideAngle < 3 || glideAngle > 10) {
glideAngle = 3;
}

for (let i = fafIndex + 1; i < this._legs.length; i++) {
this._legs[i].verticalAngle = glideAngle;
}
}
}
}
4 changes: 0 additions & 4 deletions src/fmgc/src/flightplanning/ManagedFlightPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1150,10 +1150,6 @@ export class ManagedFlightPlan {

const procedure = new LegsProcedure(legs, this.getWaypoint(_startIndex - 1), this._parentInstrument, airportMagVar, this.procedureDetails.approachType, legAnnotations);

if (runway) {
procedure.calculateApproachData(runway);
}

let waypointIndex = _startIndex;
// console.log('MFP: buildApproach - ADDING WAYPOINTS ------------------------');
while (procedure.hasNext()) {
Expand Down
16 changes: 8 additions & 8 deletions src/fmgc/src/flightplanning/RawDataMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ export class RawDataMapper {

info.approaches = facility.approaches;
info.approaches.forEach((approach) => approach.name = normaliseApproachName(approach.name));
info.approaches.forEach((approach) => approach.transitions.forEach((trans) => trans.name = trans.legs[0].fixIcao.substring(7, 12).trim()));
info.approaches.forEach((approach) => approach.transitions.forEach((trans) => trans.name.trim().length === 0 && (trans.name = WayPoint.formatIdentFromIcao(trans.legs[0].fixIcao))));
info.approaches.forEach((approach) => approach.runway = approach.runway.trim());

info.departures = facility.departures;
info.departures.forEach((departure) => departure.runwayTransitions.forEach((trans) => trans.name = RawDataMapper.generateRunwayTransitionName(trans)));
info.departures.forEach((departure) => departure.enRouteTransitions.forEach((trans) => trans.name = RawDataMapper.generateDepartureEnRouteTransitionName(trans)));
info.departures.forEach((departure) => departure.enRouteTransitions.forEach((trans) => trans.name.trim().length === 0 && (trans.name = RawDataMapper.generateDepartureEnRouteTransitionName(trans))));

info.arrivals = facility.arrivals;
info.arrivals.forEach((arrival) => arrival.runwayTransitions.forEach((trans) => trans.name = RawDataMapper.generateRunwayTransitionName(trans)));
info.arrivals.forEach((arrival) => arrival.enRouteTransitions.forEach((trans) => trans.name = RawDataMapper.generateArrivalTransitionName(trans)));
info.arrivals.forEach((arrival) => arrival.enRouteTransitions.forEach((trans) => trans.name.trim().length === 0 && (trans.name = RawDataMapper.generateArrivalTransitionName(trans))));

info.runways = facility.runways;

Expand Down Expand Up @@ -130,7 +130,7 @@ export class RawDataMapper {
* @param runwayTransition The runway transition to generate the name for.
* @returns The runway transition name.
*/
public static generateRunwayTransitionName(runwayTransition: RunwayTransition): string {
public static generateRunwayTransitionName(runwayTransition: RawRunwayTransition): string {
let name = `RW${runwayTransition.runwayNumber}`;

switch (runwayTransition.runwayDesignation) {
Expand All @@ -153,16 +153,16 @@ export class RawDataMapper {
* @param enrouteTransition The enroute transition to generate a name for.
* @returns The generated transition name.
*/
public static generateArrivalTransitionName(enrouteTransition: EnrouteTransition): string {
return enrouteTransition.legs[0].fixIcao.substring(7, 12).trim();
public static generateArrivalTransitionName(enrouteTransition: RawEnRouteTransition): string {
return WayPoint.formatIdentFromIcao(enrouteTransition.legs[0].fixIcao);
}

/**
* Generates a departure transition name from a provided departure enroute transition.
* @param enrouteTransition The enroute transition to generate a name for.
* @returns The generated transition name.
*/
public static generateDepartureEnRouteTransitionName(enrouteTransition: EnrouteTransition): string {
return enrouteTransition.legs[enrouteTransition.legs.length - 1].fixIcao.substring(7, 12).trim();
public static generateDepartureEnRouteTransitionName(enrouteTransition: RawEnRouteTransition): string {
return WayPoint.formatIdentFromIcao(enrouteTransition.legs[enrouteTransition.legs.length - 1].fixIcao);
}
}
2 changes: 2 additions & 0 deletions src/fmgc/src/types/fstypes/FSTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ declare global {
trueDegrees: boolean;
turnDirection: TurnDirection;
type: LegType;
/** glide path angle + 360 */
verticalAngle?: number;
__Type: 'JS_Leg';
}

Expand Down