Skip to content

Commit c75d4fa

Browse files
agutherBlueberryKingtracernzbeheh
authored
feat: vertical navigation v1 (flybywiresim#7080)
* feat: vertical navigation v1 flybywiresim#7080 * fix(nd): vnav uses groundSpeed * Fix vertical angle missing on leg * Start using VNAV speed predictions * Trigger path recomputation for speed limit edits * Use INIT FUEL PRED for dest EFOB estimate * Start moving profile building out of VnavDriver * Change profile references * Fix intercept checkpoint not showing up * Fix continue descent not showing up * Fix FCU alt arrow not showing up * Use proper dep/dest elevations * Fix rebase issue * Intercept MCDU with descent profile * Fix tactical path constraint handling edge case * Fix level segments violating alt constraint * Fix update rate of yoyo * Fix descent SPD LIM PWP missing * Fix speed change dot missing * Re-add EXP CLB prediction * Refactor to use variables from observer * Fix level off arrow in selected modes * Fix tactical predictions in HDG * Fix SPD LIM interpolation * Predict approach path in tactical profiles * Consider discontinuities in speed predictions * Use new thr red/acc alt variables * Add comments about configuration options * Fix alt constraint violation * Add changelog entry * Rename PopUp to PopUpDialog * Remove unused comment * Remove old file * Consolidate fundamental prediction code * Fix missing callback after rebase * Fix build after removed file * Remove unused import * Fix my own code review comments * Implement first round of review suggestions * Implement more code review suggestions * Use subjects for everything * Fix typos * Fix CSS issues again * Refactor step altitude implementation * Fix step altitude bugs * Ignore steps before T/C and after T/D * Use AP's pressure alt variable --------- Co-authored-by: BBK <[email protected]> Co-authored-by: Michael Corcoran <[email protected]> Co-authored-by: Benedict Etzel <[email protected]>
1 parent 627b556 commit c75d4fa

File tree

101 files changed

+10385
-1355
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+10385
-1355
lines changed

.github/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@
125125
1. [HYD] Adjusted low speed pumps efficiency / cargo doors refactor - @Crocket63 (crocket)
126126
1. [ECAM/SD] Limit PRESS page gauges to correct range - @tracernz (Mike)
127127
1. [FMGC/PFD] Implemented FMGC exposure of the Minimums to the PFD - @MikioDK (Yekouri#1836)
128-
128+
1. [FMS] Implement vertical navigation functions - @BlueberryKing (BlueberryKing)
129+
1. [EFB] Added pause at T/D function - @2hwk (2Cas#1022)
129130

130131
## 0.9.0
131132

fbw-a32nx/docs/a320-simvars.md

+33
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,35 @@
13371337
- Bool
13381338
- Indicates if the SET HOLD SPEED message is shown on the PFD
13391339

1340+
- A32NX_PFD_MSG_TD_REACHED
1341+
- Bool
1342+
- Indicates if the T/D REACHED message is shown on the PFD
1343+
1344+
- A32NX_PFD_LINEAR_DEVIATION_ACTIVE
1345+
- Bool
1346+
- Indicates if the linear deviation is shown on the PFD
1347+
1348+
- A32NX_PFD_TARGET_ALTITUDE
1349+
- Feet
1350+
- Indicates the current target altitude in the DES mode. This is an indicated altitude and not a pressure altitude
1351+
- This is used to compute a linear deviation
1352+
1353+
- A32NX_PFD_VERTICAL_PROFILE_LATCHED
1354+
- Boolean
1355+
- Indicates whether to show the latch symbol on the PFD with the deviation indicator
1356+
1357+
- A32NX_PFD_SHOW_SPEED_MARGINS
1358+
- Boolean
1359+
- Indicates whether speed margins are shown on the PFD in DES mode.
1360+
1361+
- A32NX_PFD_UPPER_SPEED_MARGIN
1362+
- Knots
1363+
- Indicates the speed for the upper speed margin limit in DES mode
1364+
1365+
- A32NX_PFD_LOWER_SPEED_MARGIN
1366+
- Knots
1367+
- Indicates the speed for the lower speed margin limit in DES mode
1368+
13401369
- A32NX_ISIS_LS_ACTIVE
13411370
- Bool
13421371
- Indicates whether LS scales are shown on the ISIS
@@ -1875,6 +1904,10 @@ In the variables below, {number} should be replaced with one item in the set: {
18751904
- 1 - captain's side FMGC
18761905
- 2 - f/o's side FMGC
18771906

1907+
- A32NX_FM_VNAV_TRIGGER_STEP_DELETED
1908+
- Bool
1909+
- Indicates whether to trigger a step deleted message on the MCDU
1910+
18781911
## Autopilot System
18791912

18801913
- A32NX_FMA_LATERAL_MODE

fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Utils/NXSystemMessages.js

+3
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ const NXSystemMessages = {
9696
vToDisagree: new TypeIIMessage("V1/VR/V2 DISAGREE", true),
9797
waitForSystemResponse: new TypeIMessage("WAIT FOR SYSTEM RESPONSE"),
9898
xxxIsDeselected: new TypeIMessage("XXXX IS DESELECTED", false, "XXXX"),
99+
stepAboveMaxFl: new TypeIIMessage("STEP ABOVE MAX FL"),
100+
stepAhead: new TypeIIMessage("STEP AHEAD"),
101+
stepDeleted: new TypeIIMessage("STEP DELETED"),
99102
};
100103

101104
const NXFictionalMessages = {

fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Utils/NXUnits.js

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class NXUnits {
2222
return NXUnits.metricWeight ? value : value / 0.4535934;
2323
}
2424

25+
static poundsToUser(value) {
26+
return NXUnits.metricWeight ? value / 2.204625 : value;
27+
}
28+
2529
static userWeightUnit() {
2630
return NXUnits.metricWeight ? 'KG' : 'LBS'; // EIS uses S suffix on LB
2731
}

fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU.html

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_NavaidPage.js"></script>
157157
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_NewWaypoint.js"></script>
158158
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_PilotsWaypoint.js"></script>
159+
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_StepAltsPage.js"></script>
159160
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_VerticalRevisionPage.js"></script>
160161
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_HoldAtPage.js"></script>
161162
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_SecFplnMain.js"></script>

fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_FlightPlanPage.js

+190-143
Large diffs are not rendered by default.

fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_MainDisplay.js

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class A320_Neo_CDU_MainDisplay extends FMCMainDisplay {
117117
AOCRcvdMsgs: 74,
118118
AOCSentMsgs: 75,
119119
AOCFreeText: 76,
120+
StepAltsPage: 77,
120121
};
121122

122123
this.mcduServerClient = undefined;

fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_PerformancePage.js

+175-27
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,31 @@ class CDUPerformancePage {
378378
const isSelected = Simplane.getAutoPilotAirspeedSelected();
379379
const actModeCell = isSelected ? "SELECTED" : "MANAGED";
380380
const costIndexCell = isFinite(mcdu.costIndex) ? mcdu.costIndex.toFixed(0) + "[color]cyan" : "[][color]cyan";
381+
382+
// Predictions to altitude
383+
const vnavDriver = mcdu.guidanceController.vnavDriver;
384+
385+
const cruiseAltitude = mcdu.cruiseFlightLevel * 100;
386+
const fcuAltitude = SimVar.GetSimVarValue("AUTOPILOT ALTITUDE LOCK VAR:3", "feet");
387+
const altitudeToPredict = Math.min(cruiseAltitude, fcuAltitude);
388+
389+
const predToCell = CDUPerformancePage.formatAltitudeOrLevel(altitudeToPredict, mcdu.flightPlanManager.getOriginTransitionAltitude()) + "[color]cyan";
390+
391+
let predToDistanceCell = "---";
392+
let predToTimeCell = "----";
393+
394+
let expeditePredToDistanceCell = "---";
395+
let expeditePredToTimeCell = "----";
396+
397+
if (vnavDriver) {
398+
[predToDistanceCell, predToTimeCell] = CDUPerformancePage.getTimeAndDistancePredictionsFromGeometryProfile(vnavDriver.mcduProfile, altitudeToPredict, mcdu.flightPhaseManager.phase >= FmgcFlightPhases.TAKEOFF);
399+
400+
if (isPhaseActive) {
401+
const expediteProfile = vnavDriver.expediteProfile;
402+
[expeditePredToDistanceCell, expeditePredToTimeCell] = CDUPerformancePage.getTimeAndDistancePredictionsFromGeometryProfile(expediteProfile, altitudeToPredict, mcdu.flightPhaseManager.phase >= FmgcFlightPhases.TAKEOFF, true);
403+
}
404+
}
405+
381406
let managedSpeedCell = "";
382407
if (isPhaseActive) {
383408
if (mcdu.managedSpeedTarget === mcdu.managedSpeedClimb) {
@@ -388,7 +413,7 @@ class CDUPerformancePage {
388413
managedSpeedCell = "{small}" + mcdu.managedSpeedTarget.toFixed(0) + "{end}";
389414
}
390415
} else {
391-
managedSpeedCell = (isSelected ? "*" : "") + mcdu.managedSpeedClimb > mcdu.managedSpeedLimit ? mcdu.managedSpeedLimit.toFixed(0) : mcdu.managedSpeedClimb.toFixed(0);
416+
managedSpeedCell = (isSelected ? "*" : "") + mcdu.managedSpeedClimb > mcdu.climbSpeedLimit ? mcdu.climbSpeedLimit.toFixed(0) : mcdu.managedSpeedClimb.toFixed(0);
392417

393418
mcdu.onLeftInput[3] = (value, scratchpadCallback) => {
394419
if (mcdu.trySetPreSelectedClimbSpeed(value)) {
@@ -441,16 +466,16 @@ class CDUPerformancePage {
441466
};
442467
mcdu.setTemplate([
443468
["CLB[color]" + titleColor],
444-
["ACT MODE", "EFOB", timeLabel],
445-
[actModeCell + "[color]green", "6.0[color]green", "----[color]green"],
469+
["ACT MODE"],
470+
[actModeCell + "[color]green"],
446471
["\xa0CI"],
447-
[costIndexCell + "[color]cyan"],
448-
["\xa0MANAGED"],
449-
["\xa0" + managedSpeedCell + "[color]green"],
472+
[costIndexCell + "[color]cyan", predToCell, "\xa0\xa0\xa0{small}PRED TO{end}"],
473+
["\xa0MANAGED", "DIST", timeLabel],
474+
["\xa0" + managedSpeedCell + "[color]green", !isSelected ? predToDistanceCell : "", !isSelected ? predToTimeCell : ""],
450475
["\xa0" + selectedSpeedTitle],
451-
["\xa0" + selectedSpeedCell + "[color]cyan"],
452-
[""],
476+
["\xa0" + selectedSpeedCell, isSelected ? predToDistanceCell : "", isSelected ? predToTimeCell : ""],
453477
[""],
478+
isPhaseActive ? ["\xa0{small}EXPEDITE{end}[color]green", expeditePredToDistanceCell, expeditePredToTimeCell] : [""],
454479
bottomRowLabels,
455480
bottomRowCells
456481
]);
@@ -473,15 +498,19 @@ class CDUPerformancePage {
473498
const isPhaseActive = mcdu.flightPhaseManager.phase === FmgcFlightPhases.CRUISE;
474499
const titleColor = isPhaseActive ? "green" : "white";
475500
const isSelected = Simplane.getAutoPilotAirspeedSelected();
476-
const isFlying = false;
501+
const isFlying = mcdu.flightPhaseManager.phase >= FmgcFlightPhases.TAKEOFF;
477502
const actModeCell = isSelected ? "SELECTED" : "MANAGED";
478503
const costIndexCell = isFinite(mcdu.costIndex) ? mcdu.costIndex.toFixed(0) + "[color]cyan" : "[][color]cyan";
479-
let managedSpeedCell = "";
504+
let managedSpeedCell = "---/---";
480505
const managedSpeed = isPhaseActive ? mcdu.managedSpeedTarget : mcdu.managedSpeedCruise;
481506
if (isFinite(managedSpeed)) {
482-
managedSpeedCell = (isSelected ? "*" : "") + managedSpeed.toFixed(0);
507+
managedSpeedCell = managedSpeed.toFixed(0) + "[color]green";
508+
}
509+
const preselTitle = isPhaseActive ? "" : "\xa0PRESEL";
510+
let preselCell = "";
511+
if (!isPhaseActive) {
512+
preselCell = (isFinite(mcdu.preSelectedCrzSpeed) ? Math.round(mcdu.preSelectedCrzSpeed).toFixed(0) : "\xa0*[ ]") + "[color]cyan";
483513
}
484-
const [selectedSpeedTitle, selectedSpeedCell] = CDUPerformancePage.getSelectedTitleAndValue(isPhaseActive, isSelected, mcdu.preSelectedCrzSpeed);
485514
mcdu.onLeftInput[1] = (value, scratchpadCallback) => {
486515
if (mcdu.tryUpdateCostIndex(value)) {
487516
CDUPerformancePage.ShowCRZPage(mcdu);
@@ -493,6 +522,13 @@ class CDUPerformancePage {
493522
if (isFlying) {
494523
timeLabel = "UTC";
495524
}
525+
const [destEfobCell, destTimeCell] = CDUPerformancePage.formatDestEfobAndTime(mcdu, isFlying);
526+
const [toUtcLabel, toDistLabel] = isFlying ? ["UTC", "DIST"] : ["", ""];
527+
const [toReasonCell, toDistCell, toTimeCell] = isFlying ? CDUPerformancePage.formatToReasonDistanceAndTime(mcdu) : ["", "", ""];
528+
const desCabinRateCell = "{small}-350{end}";
529+
const shouldShowStepAltsOption = mcdu._cruiseEntered && mcdu._cruiseFlightLevel
530+
&& (mcdu.flightPhaseManager.phase < FmgcFlightPhases.DESCENT || mcdu.flightPhaseManager.phase > FmgcFlightPhases.GOAROUND);
531+
496532
const bottomRowLabels = ["\xa0PREV", "NEXT\xa0"];
497533
const bottomRowCells = ["<PHASE", "PHASE>"];
498534
mcdu.leftInputDelay[5] = () => {
@@ -526,6 +562,18 @@ class CDUPerformancePage {
526562
CDUPerformancePage.ShowCLBPage(mcdu);
527563
};
528564
}
565+
mcdu.onRightInput[3] = () => {
566+
// DES CABIN RATE
567+
mcdu.setScratchpadMessage(NXFictionalMessages.notYetImplemented);
568+
};
569+
if (shouldShowStepAltsOption) {
570+
CDUStepAltsPage.Return = () => {
571+
CDUPerformancePage.ShowCRZPage(mcdu, false);
572+
};
573+
mcdu.onRightInput[4] = () => {
574+
CDUStepAltsPage.ShowPage(mcdu);
575+
};
576+
}
529577
mcdu.rightInputDelay[5] = () => {
530578
return mcdu.getDelaySwitchPage();
531579
};
@@ -534,16 +582,16 @@ class CDUPerformancePage {
534582
};
535583
mcdu.setTemplate([
536584
["CRZ[color]" + titleColor],
537-
["ACT MODE", "EFOB", timeLabel],
538-
[actModeCell + "[color]green", "6.0[color]green", "----[color]green"],
585+
["ACT MODE", "DEST EFOB", timeLabel],
586+
[actModeCell + "[color]green", destEfobCell, destTimeCell],
539587
["\xa0CI"],
540-
[costIndexCell + "[color]cyan"],
541-
["\xa0MANAGED"],
542-
["\xa0" + managedSpeedCell + "[color]green"],
543-
["\xa0" + selectedSpeedTitle],
544-
["\xa0" + selectedSpeedCell + "[color]cyan"],
545-
["", "DES CABIN RATE>"],
546-
["", "-350FT/MIN[color]green"],
588+
[costIndexCell + "[color]cyan", toReasonCell],
589+
["\xa0MANAGED", toDistLabel, toUtcLabel],
590+
["\xa0" + managedSpeedCell, toDistCell, toTimeCell],
591+
[preselTitle, "DES CABIN RATE"],
592+
[preselCell, `\xa0{cyan}${desCabinRateCell}{end}{white}{small}FT/MN{end}{end}`],
593+
[""],
594+
["", shouldShowStepAltsOption ? "STEP ALTS>" : ""],
547595
bottomRowLabels,
548596
bottomRowCells
549597
]);
@@ -565,7 +613,7 @@ class CDUPerformancePage {
565613
};
566614
const isPhaseActive = mcdu.flightPhaseManager.phase === FmgcFlightPhases.DESCENT;
567615
const titleColor = isPhaseActive ? "green" : "white";
568-
const isFlying = false;
616+
const isFlying = mcdu.flightPhaseManager.phase >= FmgcFlightPhases.TAKEOFF;
569617
const isSelected = Simplane.getAutoPilotAirspeedSelected();
570618
const actModeCell = isSelected ? "SELECTED" : "MANAGED";
571619
const costIndexCell = isFinite(mcdu.costIndex) ? mcdu.costIndex.toFixed(0) + "[color]cyan" : "[][color]cyan";
@@ -579,6 +627,8 @@ class CDUPerformancePage {
579627
if (isFlying) {
580628
timeLabel = "UTC";
581629
}
630+
const [destEfobCell, destTimeCell] = CDUPerformancePage.formatDestEfobAndTime(mcdu, isFlying);
631+
582632
const bottomRowLabels = ["\xa0PREV", "NEXT\xa0"];
583633
const bottomRowCells = ["<PHASE", "PHASE>"];
584634
mcdu.leftInputDelay[5] = () => {
@@ -627,14 +677,14 @@ class CDUPerformancePage {
627677
};
628678
mcdu.setTemplate([
629679
["DES[color]" + titleColor],
630-
["ACT MODE", "EFOB", timeLabel],
631-
[actModeCell + "[color]green", "6.0[color]green", "----[color]green"],
680+
["ACT MODE", "DEST EFOB", timeLabel],
681+
[actModeCell + "[color]green", destEfobCell, destTimeCell],
632682
["\xa0CI"],
633683
[costIndexCell + "[color]cyan"],
634684
["\xa0MANAGED"],
635685
["\xa0" + managedSpeedCell + "[color]green"],
636686
["\xa0" + selectedSpeedTitle],
637-
["\xa0" + selectedSpeedCell + "[color]cyan"],
687+
["\xa0" + selectedSpeedCell],
638688
[""],
639689
[""],
640690
bottomRowLabels,
@@ -977,10 +1027,108 @@ class CDUPerformancePage {
9771027

9781028
static getSelectedTitleAndValue(_isPhaseActive, _isSelected, _preSel) {
9791029
if (_isPhaseActive) {
980-
return _isSelected ? ["SELECTED", "" + Math.round(Simplane.getAutoPilotMachModeActive() ? SimVar.GetGameVarValue('FROM MACH TO KIAS', 'number', Simplane.getAutoPilotMachHoldValue()) : Simplane.getAutoPilotAirspeedHoldValue())] : ["", ""];
1030+
return _isSelected
1031+
? ["SELECTED", "" + Math.round(Simplane.getAutoPilotMachModeActive()
1032+
? SimVar.GetGameVarValue('FROM MACH TO KIAS', 'number', Simplane.getAutoPilotMachHoldValue())
1033+
: Simplane.getAutoPilotAirspeedHoldValue()) + "[color]green"]
1034+
: ["", ""];
9811035
} else {
982-
return ["PRESEL", isFinite(_preSel) ? "" + _preSel : "*[ ]"];
1036+
return ["PRESEL", (isFinite(_preSel) ? "" + _preSel : "*[ ]") + "[color]cyan"];
1037+
}
1038+
}
1039+
static formatAltitudeOrLevel(altitudeToFormat, transitionAltitude) {
1040+
if (transitionAltitude >= 100 && altitudeToFormat > transitionAltitude) {
1041+
return `FL${(altitudeToFormat / 100).toFixed(0).toString().padStart(3,"0")}`;
1042+
}
1043+
1044+
return (10 * Math.round(altitudeToFormat / 10)).toFixed(0).toString().padStart(5,"\xa0");
1045+
}
1046+
static getTimeAndDistancePredictionsFromGeometryProfile(geometryProfile, altitudeToPredict, isFlying, printSmall = false) {
1047+
let predToDistanceCell = "---";
1048+
let predToTimeCell = "----";
1049+
1050+
if (!geometryProfile || !geometryProfile.isReadyToDisplay) {
1051+
return [predToTimeCell, predToDistanceCell];
9831052
}
1053+
1054+
const predictions = geometryProfile.computePredictionToFcuAltitude(altitudeToPredict);
1055+
1056+
if (predictions) {
1057+
if (Number.isFinite(predictions.distanceFromStart)) {
1058+
if (printSmall) {
1059+
predToDistanceCell = "{small}" + predictions.distanceFromStart.toFixed(0) + "{end}[color]green";
1060+
} else {
1061+
predToDistanceCell = predictions.distanceFromStart.toFixed(0) + "[color]green";
1062+
}
1063+
}
1064+
1065+
if (Number.isFinite(predictions.secondsFromPresent)) {
1066+
const utcTime = SimVar.GetGlobalVarValue("ZULU TIME", "seconds");
1067+
1068+
const predToTimeCellText = isFlying
1069+
? FMCMainDisplay.secondsToUTC(utcTime + predictions.secondsFromPresent)
1070+
: FMCMainDisplay.minutesTohhmm(predictions.secondsFromPresent);
1071+
1072+
if (printSmall) {
1073+
predToTimeCell = "{small}" + predToTimeCellText + "{end}[color]green";
1074+
} else {
1075+
predToTimeCell = predToTimeCellText + "[color]green";
1076+
}
1077+
}
1078+
}
1079+
1080+
return [predToDistanceCell, predToTimeCell];
1081+
}
1082+
static formatDestEfobAndTime(mcdu, isFlying) {
1083+
const destinationPrediction = mcdu.guidanceController.vnavDriver.getDestinationPrediction();
1084+
1085+
let destEfobCell = "---.-";
1086+
let destTimeCell = "----";
1087+
1088+
if (destinationPrediction) {
1089+
if (Number.isFinite(destinationPrediction.estimatedFuelOnBoard)) {
1090+
destEfobCell = (NXUnits.poundsToUser(destinationPrediction.estimatedFuelOnBoard) / 1000).toFixed(1) + "[color]green";
1091+
}
1092+
1093+
if (Number.isFinite(destinationPrediction.secondsFromPresent)) {
1094+
const utcTime = SimVar.GetGlobalVarValue("ZULU TIME", "seconds");
1095+
1096+
const predToTimeCellText = isFlying
1097+
? FMCMainDisplay.secondsToUTC(utcTime + destinationPrediction.secondsFromPresent)
1098+
: FMCMainDisplay.secondsTohhmm(destinationPrediction.secondsFromPresent);
1099+
1100+
destTimeCell = predToTimeCellText + "[color]green";
1101+
}
1102+
}
1103+
1104+
return [destEfobCell, destTimeCell];
1105+
}
1106+
static formatToReasonDistanceAndTime(mcdu) {
1107+
const toPrediction = mcdu.guidanceController.vnavDriver.getPerfCrzToPrediction();
1108+
1109+
let reasonCell = "(T/D)";
1110+
let distCell = "---";
1111+
let timeCell = "----";
1112+
1113+
if (toPrediction) {
1114+
if (Number.isFinite(toPrediction.distanceFromPresentPosition)) {
1115+
distCell = Math.round(toPrediction.distanceFromPresentPosition) + "[color]green";
1116+
}
1117+
1118+
if (Number.isFinite(toPrediction.secondsFromPresent)) {
1119+
const utcTime = SimVar.GetGlobalVarValue("ZULU TIME", "seconds");
1120+
1121+
timeCell = FMCMainDisplay.secondsToUTC(utcTime + toPrediction.secondsFromPresent) + "\xa0[color]green";
1122+
}
1123+
1124+
if (toPrediction.reason === "StepClimb") {
1125+
reasonCell = "(S/C)";
1126+
} else if (toPrediction.reason === "StepDescent") {
1127+
reasonCell = "(S/D)";
1128+
}
1129+
}
1130+
1131+
return ["{small}TO{end}\xa0{green}" + reasonCell + "{end}", distCell, timeCell];
9841132
}
9851133
}
9861134
CDUPerformancePage._timer = 0;

0 commit comments

Comments
 (0)