2019-12-29 21:37:52 +00:00
# A3XX FMGC Flightplan Driver
2022-01-17 11:43:31 +00:00
# Copyright (c) 2022 Josh Davidson (Octal450) and Jonathan Redpath (legoboyvdlp)
2019-12-29 21:37:52 +00:00
var wpDep = nil;
var wpArr = nil;
var pos = nil;
var geoPosPrev = geo.Coord.new();
var currentLegCourseDist = nil;
var courseDistanceFrom = nil;
var sizeWP = nil;
var magTrueError = 0;
2020-05-30 19:03:43 +00:00
var storeCourse = nil;
2019-12-29 21:37:52 +00:00
2020-05-15 16:09:00 +00:00
var DEBUG_DISCONT = 0;
2020-04-19 09:24:06 +00:00
2020-01-05 20:21:28 +00:00
# Props.getNode
2019-12-29 21:37:52 +00:00
var magHDG = props.globals.getNode("/orientation/heading-magnetic-deg", 1);
var trueHDG = props.globals.getNode("/orientation/heading-deg", 1);
2020-01-05 20:21:28 +00:00
var flightPlanController = {
2020-04-28 23:41:08 +00:00
flightplans: [createFlightplan(), createFlightplan(), createFlightplan(), nil],
2020-01-05 20:21:28 +00:00
temporaryFlag: [0, 0],
# These flags are only for the main flgiht-plan
2022-01-17 11:43:31 +00:00
active: props.globals.initNode("/autopilot/route-manager/active", 0, "BOOL"),
changed: props.globals.initNode("/autopilot/route-manager/flightplan-changed", 0, "BOOL"),
2020-01-05 20:21:28 +00:00
currentToWpt: nil, # container for the current TO waypoint ghost
2022-01-17 11:43:31 +00:00
currentToWptIndex: props.globals.initNode("/autopilot/route-manager/current-wp", 1, "INT"),
2020-04-23 17:21:59 +00:00
currentToWptIndexTemp: 0,
2022-01-17 11:43:31 +00:00
currentToWptIndexTemp2: 0,
currentToWptID: props.globals.initNode("/autopilot/route-manager/wp[0]/id", "", "STRING"),
courseToWpt: props.globals.initNode("/autopilot/route-manager/wp[0]/true-bearing-deg", 0, "DOUBLE"),
courseMagToWpt: props.globals.initNode("/autopilot/route-manager/wp[0]/bearing-deg", 0, "DOUBLE"),
distToWpt: props.globals.initNode("/autopilot/route-manager/wp[0]/dist", 0, "DOUBLE"),
2020-04-27 13:58:38 +00:00
wptType: nil,
2020-04-23 17:21:59 +00:00
wptTypeNoAdvanceDelete: 0,
2020-01-05 20:21:28 +00:00
2022-01-17 11:43:31 +00:00
# Temporary flightplan will use flightplan[0] and flightplan[1]
num: [props.globals.initNode("/FMGC/flightplan[0]/num", 0, "INT"), props.globals.initNode("/FMGC/flightplan[1]/num", 0, "INT"), props.globals.initNode("/autopilot/route-manager/route/num", 0, "INT")],
2020-01-05 20:21:28 +00:00
arrivalIndex: [0, 0, 0],
2022-01-17 11:43:31 +00:00
arrivalDist: props.globals.getNode("/autopilot/route-manager/distance-remaining-nm"),
2020-03-24 16:46:27 +00:00
fromWptTime: nil,
fromWptAlt: nil,
_timeTemp: nil,
_altTemp: nil,
2022-01-17 11:43:31 +00:00
decelPoint: nil,
2020-01-05 20:21:28 +00:00
2020-05-21 20:02:28 +00:00
init: func() {
me.resetFlightplan(2);
me.insertPPOS(2);
me.addDiscontinuity(1, 2, 1);
me.flightPlanChanged(2);
2022-01-17 11:43:31 +00:00
me.flightplans[2].activate();
2020-05-21 20:02:28 +00:00
},
2019-12-29 21:37:52 +00:00
reset: func() {
2020-01-05 20:21:28 +00:00
me.temporaryFlag[0] = 0;
me.temporaryFlag[1] = 0;
me.resetFlightplan(0);
me.resetFlightplan(1);
me.resetFlightplan(2);
2022-01-17 11:43:31 +00:00
me.decelPoint = nil;
setprop("/instrumentation/nd/symbols/decel/show", 0);
me.flightplans[2].activate();
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
resetFlightplan: func(n) {
me.flightplans[n].cleanPlan();
me.flightplans[n].departure = nil;
me.flightplans[n].destination = nil;
2020-06-12 15:16:44 +00:00
mcdu.isNoTransArr[n] = 0;
mcdu.isNoTransDep[n] = 0;
mcdu.isNoSid[n] = 0;
mcdu.isNoStar[n] = 0;
mcdu.isNoVia[n] = 0;
2022-01-17 11:43:31 +00:00
me.arrivalIndex[n] = 0; # reset arrival index calculations
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
createTemporaryFlightPlan: func(n) {
2020-01-07 20:48:27 +00:00
me.resetFlightplan(n);
2020-01-05 20:21:28 +00:00
me.flightplans[n] = me.flightplans[2].clone();
me.temporaryFlag[n] = 1;
2020-03-28 15:53:50 +00:00
if (canvas_mcdu.myDirTo[n] != nil) {
canvas_mcdu.myDirTo[n].updateTmpy();
}
2020-05-04 10:48:22 +00:00
if (canvas_mcdu.myHold[n] != nil) {
canvas_mcdu.myHold[n].updateTmpy();
}
if (canvas_mcdu.myAirways[n] != nil) {
canvas_mcdu.myAirways[n].updateTmpy();
}
2020-06-10 02:42:30 +00:00
fmgc.windController.createTemporaryWinds(n);
2020-06-10 21:44:04 +00:00
me.flightPlanChanged(n);
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
2020-04-28 23:41:08 +00:00
loadFlightPlan: func(path) {
2022-01-17 14:44:39 +00:00
call(func {
me.flightplans[3] = createFlightplan(path);
}, nil, var err = []);
2020-04-28 23:41:08 +00:00
if (size(err) or me.flightplans[3] == nil) {
print(err[0]);
print("Load failed.");
}
me.destroyTemporaryFlightPlan(3, 1);
},
2022-01-17 11:43:31 +00:00
destroyTemporaryFlightPlan: func(n, a) { # a = 1 activate, a = 0 erase, s = 0 don't call flightplan changed
2020-01-05 20:21:28 +00:00
if (a == 1) {
2020-01-07 20:48:27 +00:00
flightPlanTimer.stop();
me.resetFlightplan(2);
2020-01-05 20:21:28 +00:00
me.flightplans[2] = me.flightplans[n].clone();
2022-01-17 11:43:31 +00:00
me.flightplans[2].activate();
2020-06-17 09:38:21 +00:00
if (n != 3) {
if (mcdu.isNoSid[n] == 1) {
mcdu.isNoSid[2] = 1;
} else {
mcdu.isNoSid[2] = 0;
}
if (mcdu.isNoStar[n] == 1) {
mcdu.isNoStar[2] = 1;
} else {
mcdu.isNoStar[2] = 0;
}
if (mcdu.isNoVia[n] == 1) {
mcdu.isNoVia[2] = 1;
} else {
mcdu.isNoVia[2] = 0;
}
if (mcdu.isNoTransDep[n] == 1) {
mcdu.isNoTransDep[2] = 1;
} else {
mcdu.isNoTransDep[2] = 0;
}
if (mcdu.isNoTransArr[n] == 1) {
mcdu.isNoTransArr[2] = 1;
} else {
mcdu.isNoTransArr[2] = 0;
}
2020-06-07 12:29:56 +00:00
}
2020-01-05 20:21:28 +00:00
me.flightPlanChanged(2);
2020-01-07 20:48:27 +00:00
flightPlanTimer.start();
2019-12-29 21:37:52 +00:00
}
2022-01-17 11:43:31 +00:00
if (n == 3) {
me.flightPlanChanged(n);
return;
}
2020-01-05 20:21:28 +00:00
me.temporaryFlag[n] = 0;
2022-01-17 11:43:31 +00:00
me.flightPlanChanged(2);
me.resetFlightplan(n);
2020-03-28 15:53:50 +00:00
if (canvas_mcdu.myDirTo[n] != nil) {
canvas_mcdu.myDirTo[n].updateTmpy();
}
2022-01-18 11:51:22 +00:00
if (me.DirToIndex != nil) {
me.currentToWptIndex.setValue(me.DirToIndex);
me.DirToIndex = nil;
}
2020-06-10 02:42:30 +00:00
fmgc.windController.destroyTemporaryWinds(n, a);
2020-06-10 21:44:04 +00:00
me.flightPlanChanged(n);
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
updateAirports: func(dep, arr, plan) {
me.resetFlightplan(plan);
me.flightplans[plan].departure = airportinfo(dep);
me.flightplans[plan].destination = airportinfo(arr);
if (plan == 2) {
2022-01-17 11:43:31 +00:00
if (me.temporaryFlag[0]) { me.destroyTemporaryFlightPlan(0, 0); }
if (me.temporaryFlag[1]) { me.destroyTemporaryFlightPlan(1, 0); }
2020-06-22 23:07:00 +00:00
me.arrivalIndex = [0, 0, 0]; # reset arrival index calculations
2019-12-29 21:37:52 +00:00
}
2020-04-19 09:29:34 +00:00
me.addDiscontinuity(1, plan);
2020-04-28 11:35:23 +00:00
# reset mcdu if it exists
2020-05-14 19:02:18 +00:00
if (canvas_mcdu.myFpln[0] != nil) { canvas_mcdu.myFpln[0].scroll = 0; }
if (canvas_mcdu.myFpln[1] != nil) { canvas_mcdu.myFpln[1].scroll = 0; }
2020-04-28 11:35:23 +00:00
if (canvas_mcdu.myArrival[0] != nil) { canvas_mcdu.myArrival[0].reset(); }
if (canvas_mcdu.myArrival[1] != nil) { canvas_mcdu.myArrival[1].reset(); }
if (canvas_mcdu.myDeparture[0] != nil) { canvas_mcdu.myDeparture[0].reset(); }
if (canvas_mcdu.myDeparture[1] != nil) { canvas_mcdu.myDeparture[1].reset(); }
2020-01-05 20:21:28 +00:00
me.flightPlanChanged(plan);
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
2020-05-16 14:48:26 +00:00
calculateTimeAltitudeOnSequence: func() {
2020-03-24 16:46:27 +00:00
me._timeTemp = math.round(getprop("/sim/time/utc/minute") + (getprop("/sim/time/utc/second") / 60));
if (me._timeTemp < 10) {
me._timeTemp = "0" ~ me._timeTemp;
}
me.fromWptTime = getprop("/sim/time/utc/hour") ~ me._timeTemp;
me._altTemp = getprop("/systems/navigation/adr/output/baro-alt-corrected-1-capt");
2020-05-16 14:48:26 +00:00
if (me._altTemp > fmgc.FMGCInternal.transAlt) {
2020-03-24 16:46:27 +00:00
me.fromWptAlt = "FL" ~ math.round(me._altTemp / 100);
} else {
if (me._altTemp > 0) {
me.fromWptAlt = math.round(me._altTemp);
} else {
me.fromWptAlt = "M" ~ math.round(me._altTemp);
}
}
2020-05-16 14:48:26 +00:00
},
autoSequencing: func() {
2022-01-17 11:43:31 +00:00
if (!me.active.getBoolValue()) { return; }
2020-05-16 14:48:26 +00:00
me.calculateTimeAltitudeOnSequence();
2020-03-24 16:46:27 +00:00
2020-04-23 17:21:59 +00:00
# Advancing logic
me.currentToWptIndexTemp = me.currentToWptIndex.getValue();
2022-01-19 11:04:37 +00:00
# TODO - after sequencing discontinuity, FPLN should show PPOS then DISCONTINUITY
# Clearing that discontinuity is not allowed, you must exit using DIRTO, or else using NAV ARM and overfly
# TODO - triple click - confirm, is it only with DES disengage, or also with the NAV loss?
2022-01-17 11:43:31 +00:00
2022-01-19 11:04:37 +00:00
if (me.flightplans[2].getWP(me.currentToWptIndexTemp + 1).wp_type == "discontinuity") {
fmgc.Input.lat.setValue(3);
} else {
me.currentToWptIndex.setValue(me.currentToWptIndexTemp + 1);
if (me.num[2].getValue() > 2 and me.currentToWptIndexTemp >= 1) {
for (var i = 0; i <= 2; i += 1) {
if (i == 2 or me.temporaryFlag[i]) {
me.flightplans[i].getWP(me.currentToWptIndexTemp - 1).hidden = 1;
}
2020-04-23 17:21:59 +00:00
}
2019-12-29 21:37:52 +00:00
}
}
},
2020-01-05 20:21:28 +00:00
2022-01-12 11:53:57 +00:00
# changeOverflyType - toggle flyby type of passed waypoint
# args: index, plan, computer
# index: index to toggle
# plan: plan on which operation is performed
# If the passed waypoint exists, toggle its flyover attribute
changeOverFlyType: func(index, plan) {
wp = me.flightplans[plan].getWP(index);
if (wp == nil or wp.wp_name == "DISCONTINUITY" or wp.wp_name == "VECTORS") { return 1; };
wp.fly_type = (wp.fly_type == "flyBy") ? "flyOver" : "flyBy";
return 2;
},
2020-04-26 13:52:07 +00:00
# for these two remember to call flightPlanChanged. We are assuming this is called from a function which will all flightPlanChanged itself.
2020-05-17 13:27:28 +00:00
# addDiscontinuity - insert discontinuity at passed index
# args: index, plan
2022-01-17 11:43:31 +00:00
# index: index to add at
# plan: plan to add to
2020-05-17 13:27:28 +00:00
# Check if a discontinuity already exists either immediately before or at that index
# If it does, don't add another one
# Optional flag DEBUG_DISCONT to disable discontinuities totally
2020-05-21 20:02:28 +00:00
addDiscontinuity: func(index, plan, force = 0) {
2020-04-19 09:24:06 +00:00
if (DEBUG_DISCONT) { return; }
2020-05-21 20:02:28 +00:00
if (force) {
me.flightplans[plan].insertWP(createDiscontinuity(), index);
}
2020-06-02 15:37:30 +00:00
if (me.flightplans[plan].getWP(index) != nil) { # index is not nil
if (me.flightplans[plan].getWP(index - 1) != nil) { # index -1 is also not nil
if (me.flightplans[plan].getWP(index).wp_name != "DISCONTINUITY" and me.flightplans[plan].getWP(index - 1).wp_name != "DISCONTINUITY") {
me.flightplans[plan].insertWP(createDiscontinuity(), index);
}
} else { # -1 is nil
if (me.flightplans[plan].getWP(index).wp_name != "DISCONTINUITY") {
me.flightplans[plan].insertWP(createDiscontinuity(), index);
}
2020-03-29 18:54:26 +00:00
}
2020-06-02 15:37:30 +00:00
} elsif (me.flightplans[plan].getWP(index - 1) != nil) { # index is nil, -1 is not
if (me.flightplans[plan].getWP(index - 1).wp_name != "DISCONTINUITY") {
2020-03-29 18:54:26 +00:00
me.flightplans[plan].insertWP(createDiscontinuity(), index);
}
2020-06-02 15:37:30 +00:00
} else { # both are nil??
2022-01-17 11:43:31 +00:00
debug.dump("Error in discontinuities; won't try to add one");
2020-03-29 18:54:26 +00:00
}
2020-01-05 20:21:28 +00:00
},
2020-04-26 13:52:07 +00:00
# insertTP - insert PPOS waypoint denoted "T-P" at specified index
# args: n, index
2022-01-17 11:43:31 +00:00
# n: flightplan to which the PPOS waypoint will be inserted
# index: index which the waypoint will be at.
2020-04-26 13:52:07 +00:00
2022-01-17 11:43:31 +00:00
insertTP: func(n, index) {
2020-04-26 13:52:07 +00:00
me.flightplans[n].insertWP(createWP(geo.aircraft_position(), "T-P"), index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(n, index, 0, "T-P");
2020-03-31 15:33:28 +00:00
},
2020-05-21 20:02:28 +00:00
insertPPOS: func(n, index = 0) {
me.flightplans[n].insertWP(createWP(geo.aircraft_position(), "PPOS"), index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(n, index, 0, "PPOS");
2020-05-21 20:02:28 +00:00
},
2022-01-17 11:43:31 +00:00
2020-04-26 13:52:07 +00:00
# childWPBearingDistance - return waypoint at bearing and distance from specified waypoint ghost
# args: wpt, bearing, dist, name, typeStr
2022-01-17 11:43:31 +00:00
# wpt: waypoint ghost
# bearing: bearing of waypoint to be created from specified waypoint
# distance: distance of waypoint to be created from specified waypoint, nautical miles
# name: name of waypoint to be created
# typeStr: optional argument to be passed to createWP, must be one of "sid", "star" "approach" "missed" or "pseudo"
2020-04-26 13:52:07 +00:00
2020-05-17 00:37:42 +00:00
childWPBearingDistance: func(wpt, bearing, dist) {
2020-05-14 19:02:18 +00:00
var coordinates = greatCircleMove(wpt.lat, wpt.lon, num(bearing), num(dist));
2020-05-17 00:37:42 +00:00
return coordinates;
2020-04-24 09:34:28 +00:00
},
2020-04-26 13:52:07 +00:00
# insertNOSID - create default SID and add to flightplan
# args: n: plan on which the SID will be created
# The default SID is a leg from departure runway to a point 2.5 miles on the runway extended centreline
# if NO SID has already been inserted, we will not insert another one.
2020-04-24 11:23:33 +00:00
insertNOSID: func(n) {
var wptStore = me.flightplans[n].getWP(0);
if (wptStore.wp_type == "runway") {
2020-04-24 11:44:39 +00:00
if (me.flightplans[n].getWP(1).id == "1500") { # check if we have NO SID already loaded
2020-04-24 11:23:33 +00:00
me.deleteWP(1, n, 1);
}
2020-04-26 13:52:07 +00:00
2020-04-24 11:23:33 +00:00
# fudge the altitude since we cannot create a hdgtoAlt from nasal. Assume 600 feet per mile - 2.5 miles
2022-01-17 11:43:31 +00:00
me.flightplans[n].insertWP(createWP(me.childWPBearingDistance(wptStore, me.flightplans[n].departure_runway.heading, 2.5 + (me.flightplans[n].departure_runway.length * M2NM)), "1500", "sid"), 1);
me.flightplans[n].getWP(1).fly_type = "flyOver";
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(n, 1, 0, "1500");
2020-04-24 11:23:33 +00:00
}
me.flightPlanChanged(n);
},
2020-04-26 13:52:07 +00:00
# insertNOSTAR - create default STAR and add to flightplan
# args: n: plan on which the STAR will be created
# The default STAR is a leg from departure runway to a point 5 miles on the runway extended centreline
# if NO STAR has already been inserted, we will not insert another one.
2020-04-24 09:34:28 +00:00
insertNOSTAR: func(n) {
var wptStore = me.flightplans[n].getWP(me.arrivalIndex[n]);
if (wptStore.wp_type == "runway") {
if (me.flightplans[n].getWP(me.arrivalIndex[n] - 1).id == "CF") { # check if we have NO STAR already loaded
me.deleteWP(me.arrivalIndex[n] - 1, n, 1);
}
var hdg = me.flightplans[n].destination_runway.heading + 180;
if (hdg > 360) {
hdg = hdg - 360;
}
2020-05-17 00:37:42 +00:00
me.flightplans[n].insertWP(createWP(me.childWPBearingDistance(wptStore, hdg, 5), "CF", "star"), me.arrivalIndex[n]);
2022-01-17 11:43:31 +00:00
me.flightplans[n].getWP(me.arrivalIndex[n]).fly_type = "flyOver";
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(n, me.arrivalIndex[n], 0, "CF");
2020-04-24 09:34:28 +00:00
}
me.flightPlanChanged(n);
},
2020-04-26 13:52:07 +00:00
# directTo - create leg direct from present position to a specified waypoint
# args: waypointGhost, plan
2022-01-17 11:43:31 +00:00
# waypointGost: waypoint ghost of the waypoint
# plan: plan on which the direct to leg will be created
2020-04-26 13:52:07 +00:00
# We first insert a PPOS waypoint at index 1
# We check if the flightplan already contains the waypoint passed to the function
# If it exists, we delete intermediate waypoints
# If it does not, we insert the waypoint at index 2 and add a discontinuity at index 3
# In either case, we delete the current FROM waypoint, index 0, and call flightPlanChanged to recalculate
# We attempt to get the distance from the aircraft current position to the chosen waypoint and update mcdu with it
2022-01-18 11:51:22 +00:00
DirToIndex: nil,
2020-03-31 15:33:28 +00:00
directTo: func(waypointGhost, plan) {
if (me.flightplans[plan].indexOfWP(waypointGhost) == -1) {
2022-01-17 11:43:31 +00:00
me.insertTP(plan, me.currentToWptIndex.getValue());
2020-05-17 13:27:28 +00:00
# use createWP here as createWPFrom doesn't accept waypoints
# createWPFrom worked before... but be sure!
2022-01-17 11:43:31 +00:00
me.flightplans[plan].insertWP(createWP(waypointGhost, waypointGhost.id), me.currentToWptIndex.getValue() + 1);
fmgc.windController.insertWind(plan, me.currentToWptIndex.getValue() + 1, 0, waypointGhost.id);
me.addDiscontinuity(me.currentToWptIndex.getValue() + 2, plan);
2022-01-18 11:51:22 +00:00
me.DirToIndex = me.currentToWptIndex.getValue() + 1;
2020-03-31 15:33:28 +00:00
} else {
2020-04-26 13:52:07 +00:00
# we want to delete the intermediate waypoints up to but not including the waypoint. Leave index 0, we delete it later.
# example - waypoint dirto is index 5, we want to delete indexes 1 -> 4. 5 - 1 = 4.
# so four individual deletions. Delete index 1 four times.
2022-01-17 11:43:31 +00:00
var indexWP = me.flightplans[plan].indexOfWP(waypointGhost);
me.insertTP(plan, indexWP - 1);
for (var i = 0; i < indexWP - 1; i = i + 1) {
if (me.temporaryFlag[0]) {
me.deleteWP(i, 0, 1);
}
if (me.temporaryFlag[1]) {
me.deleteWP(i, 0, 1);
}
me.deleteWP(i, 2, 1);
2020-04-07 15:59:43 +00:00
}
2020-03-31 15:33:28 +00:00
}
2020-03-31 15:48:36 +00:00
var curAircraftPosDirTo = geo.aircraft_position();
2022-01-17 11:43:31 +00:00
canvas_mcdu.myDirTo[plan].updateDist(me.flightplans[plan].getWP(me.currentToWptIndex.getValue() + 1).courseAndDistanceFrom(curAircraftPosDirTo)[1]);
2020-05-15 20:52:48 +00:00
me.flightPlanChanged(plan);
2020-03-29 18:54:26 +00:00
},
2020-04-11 17:12:18 +00:00
deleteWP: func(index, n, a = 0, s = 0) { # a = 1, means adding a waypoint via deleting intermediate. s = 1, means autosequencing
2022-01-17 11:43:31 +00:00
var wp = me.flightplans[n].getWP(index);
if (((s == 0 and left(wp.wp_name, 4) != FMGCInternal.depApt and left(wp.wp_name, 4) != FMGCInternal.arrApt) or (s == 1)) and me.flightplans[n].getPlanSize() > 2) {
2020-01-11 13:30:08 +00:00
if (me.flightplans[n].getWP(index).id != "DISCONTINUITY" and a == 0) { # if it is a discont, don't make a new one
2020-01-07 20:48:27 +00:00
me.flightplans[n].deleteWP(index);
2020-06-10 02:42:30 +00:00
fmgc.windController.deleteWind(n, index);
2020-02-03 19:16:05 +00:00
if (me.flightplans[n].getWP(index) != nil and s == 0) {
2020-01-23 14:14:48 +00:00
if (me.flightplans[n].getWP(index).id != "DISCONTINUITY") { # else, if the next one isn't a discont, add one
me.addDiscontinuity(index, n);
}
2020-01-05 20:21:28 +00:00
}
2019-12-29 21:37:52 +00:00
} else {
2020-01-07 20:48:27 +00:00
me.flightplans[n].deleteWP(index);
2020-06-10 02:42:30 +00:00
fmgc.windController.deleteWind(n, index);
2019-12-29 21:37:52 +00:00
}
2022-01-17 11:43:31 +00:00
2022-01-17 14:44:39 +00:00
me.flightPlanChanged(n);
2020-01-11 13:30:08 +00:00
canvas_nd.A3XXRouteDriver.triggerSignal("fp-removed");
2020-01-07 20:48:27 +00:00
return 2;
} else {
return 1;
2020-01-05 20:21:28 +00:00
}
},
2020-05-17 13:27:28 +00:00
# deleteTillIndex - helper that deletes waypoints up to a passed waypoint already in flightplan
# uses a while loop to delete a certain number of waypoints between passed index and
# index of waypoint alredy in flightplan
deleteTillIndex: func(wpGhost, index, plan) {
var numToDel = me.flightplans[plan].indexOfWP(wpGhost) - index;
while (numToDel > 0) {
me.deleteWP(index, plan, 1);
numToDel -= 1;
}
return 2;
},
2020-05-14 19:02:18 +00:00
# createDuplicateNames - helper to spawn DUPLICATENAMES page
# args: ghostContainer, index, flag, plan
# ghostContainer: vector of fgPositioned ghosts
# index: index
# flag: is it a navaids DUPLICATENAMES page or not?
# plan: plan
# flagPBD: do we return back to PBD handler or to default waypoint handler?
2021-01-28 18:57:20 +00:00
# flagPROG: do we return back to PROG handler or to default waypoint handler (only if flagPBD false)
2020-05-14 19:02:18 +00:00
2021-01-28 18:57:20 +00:00
createDuplicateNames: func(ghostContainer, index, flag, plan, flagPBD = 0, bearing = -999, distance = -99, flagPROG = 0) {
2020-05-14 19:02:18 +00:00
if (canvas_mcdu.myDuplicate[plan] != nil) {
canvas_mcdu.myDuplicate[plan].del();
}
canvas_mcdu.myDuplicate[plan] = nil;
2021-01-28 18:57:20 +00:00
canvas_mcdu.myDuplicate[plan] = mcdu.duplicateNamesPage.new(ghostContainer, index, flag, plan, flagPBD, bearing, distance, flagPROG);
2020-05-14 19:02:18 +00:00
setprop("MCDU[" ~ plan ~ "]/page", "DUPLICATENAMES");
},
2020-01-05 20:21:28 +00:00
insertAirport: func(text, index, plan, override = 0, overrideIndex = -1) {
if (index == 0) {
return 1;
}
var airport = findAirportsByICAO(text);
if (size(airport) == 0) {
return 0;
}
if (size(airport) == 1 or override) {
2020-05-17 14:34:46 +00:00
var indexToInsert = -1;
if (override) {
indexToInsert = overrideIndex;
2019-12-29 21:37:52 +00:00
} else {
2020-05-17 14:34:46 +00:00
indexToInsert = 0;
}
var indexPresent = me.flightplans[plan].indexOfWP(airport[indexToInsert]);
2022-01-17 11:43:31 +00:00
if (indexPresent == -1 or indexPresent > me.arrivalIndex[plan]) {
2020-05-17 14:34:46 +00:00
me.flightplans[plan].insertWP(createWPFrom(airport[indexToInsert]), index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(plan, index, 0, text);
2020-05-17 14:34:46 +00:00
me.addDiscontinuity(index + 1, plan);
me.flightPlanChanged(plan);
return 2;
} else {
return me.deleteTillIndex(airport[indexToInsert], index, plan);
2019-12-29 21:37:52 +00:00
}
2020-01-05 20:21:28 +00:00
} elsif (size(airport) >= 1) {
2020-05-14 19:02:18 +00:00
me.createDuplicateNames(airport, index, 0, plan);
2020-01-11 13:30:08 +00:00
return 2;
2019-12-29 21:37:52 +00:00
}
},
2020-01-05 20:21:28 +00:00
2020-05-17 16:53:43 +00:00
insertFix: func(text, index, plan, override = 0, overrideIndex = -1) {
2020-01-05 20:21:28 +00:00
if (index == 0) {
2019-12-29 21:37:52 +00:00
return 1;
}
2020-01-05 20:21:28 +00:00
var fix = findFixesByID(text);
if (size(fix) == 0) {
2019-12-29 21:37:52 +00:00
return 0;
2020-01-05 20:21:28 +00:00
}
if (size(fix) == 1 or override) {
2020-05-17 14:34:46 +00:00
var indexToInsert = -1;
if (override) {
indexToInsert = overrideIndex;
2020-01-05 20:21:28 +00:00
} else {
2020-05-17 14:34:46 +00:00
indexToInsert = 0;
}
var indexPresent = me.flightplans[plan].indexOfWP(fix[indexToInsert]);
2022-01-17 11:43:31 +00:00
if (indexPresent == -1 or indexPresent > me.arrivalIndex[plan]) {
2020-05-17 14:34:46 +00:00
me.flightplans[plan].insertWP(createWPFrom(fix[indexToInsert]), index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(plan, index, 1, text);
2020-05-17 14:34:46 +00:00
me.addDiscontinuity(index + 1, plan);
me.flightPlanChanged(plan);
return 2;
} else {
return me.deleteTillIndex(fix[indexToInsert], index, plan);
2020-01-05 20:21:28 +00:00
}
2020-01-07 20:48:27 +00:00
} elsif (size(fix) >= 1) {
2020-05-14 19:02:18 +00:00
me.createDuplicateNames(fix, index, 0, plan);
2020-01-11 13:30:08 +00:00
return 2;
2019-12-29 21:37:52 +00:00
}
},
2020-01-05 20:21:28 +00:00
2020-01-11 13:30:08 +00:00
insertNavaid: func(text, index, plan, override = 0, overrideIndex = -1) {
if (index == 0) {
return 1;
}
2020-01-05 20:21:28 +00:00
var navaid = findNavaidsByID(text);
if (size(navaid) == 0) {
2019-12-29 21:37:52 +00:00
return 0;
2020-01-05 20:21:28 +00:00
}
2020-01-11 13:30:08 +00:00
2020-01-05 20:21:28 +00:00
if (size(navaid) == 1 or override) {
2020-05-17 14:34:46 +00:00
var indexToInsert = -1;
if (override) {
indexToInsert = overrideIndex;
2019-12-29 21:37:52 +00:00
} else {
2020-05-17 14:34:46 +00:00
indexToInsert = 0;
}
var indexPresent = me.flightplans[plan].indexOfWP(navaid[indexToInsert]);
2022-01-17 11:43:31 +00:00
if (indexPresent == -1 or indexPresent > me.arrivalIndex[plan]) {
2020-05-17 14:34:46 +00:00
me.flightplans[plan].insertWP(createWPFrom(navaid[indexToInsert]), index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(plan, index, 1, text);
2020-05-17 14:34:46 +00:00
me.addDiscontinuity(index + 1, plan);
me.flightPlanChanged(plan);
return 2;
} else {
return me.deleteTillIndex(navaid[indexToInsert], index, plan);
2019-12-29 21:37:52 +00:00
}
2020-01-07 20:48:27 +00:00
} elsif (size(navaid) >= 1) {
2020-05-14 19:02:18 +00:00
me.createDuplicateNames(navaid, index, 1, plan);
return 2;
}
},
2020-05-17 13:27:28 +00:00
insertDBWP: func(wpGhost, index, plan) {
if (index == 0 or wpGhost == nil) {
2020-01-11 13:30:08 +00:00
return 1;
}
2022-01-17 11:43:31 +00:00
var indexCurr = me.flightplans[plan].indexOfWP(wpGhost);
if (indexCurr == -1 or indexCurr > me.arrivalIndex[plan]) {
2020-05-17 13:27:28 +00:00
# use createWP here as createWPFrom doesn't accept waypoints
me.flightplans[plan].insertWP(createWP(wpGhost, wpGhost.wp_name), index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(plan, index, 1, wpGhost.wp_name);
2020-03-29 18:54:26 +00:00
me.addDiscontinuity(index + 1, plan);
2020-01-11 13:30:08 +00:00
me.flightPlanChanged(plan);
return 2;
} else {
2020-05-17 13:27:28 +00:00
return me.deleteTillIndex(wpGhost, index, plan);
2020-01-11 13:30:08 +00:00
}
},
2020-05-17 16:53:43 +00:00
insertLatLonFix: func(text, index, plan) {
2020-01-05 20:21:28 +00:00
if (index == 0) {
2019-12-29 21:37:52 +00:00
return 1;
}
2020-01-05 20:21:28 +00:00
2020-05-17 16:53:43 +00:00
var lat = split("/", text)[0];
var lon = split("/", text)[1];
var latDecimal = mcdu.stringToDegrees(lat, "lat");
var lonDecimal = mcdu.stringToDegrees(lon, "lon");
if (latDecimal > 90 or latDecimal < -90 or lonDecimal > 180 or lonDecimal < -180) {
return 1;
2020-01-05 20:21:28 +00:00
}
2020-05-17 16:53:43 +00:00
var waypoint = pilotWaypoint.new({lat: latDecimal, lon: lonDecimal}, "LL");
var addDb = WaypointDatabase.addWP(waypoint);
if (addDb != 2) {
return addDb;
2020-05-14 19:02:18 +00:00
}
2020-05-17 16:53:43 +00:00
me.flightplans[plan].insertWP(waypoint.wpGhost, index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(plan, index, 1, "LL");
2020-05-17 16:53:43 +00:00
me.addDiscontinuity(index + 1, plan);
me.flightPlanChanged(plan);
return 2;
2020-05-14 19:02:18 +00:00
},
# getWPforPBD - parse scratchpad text to find waypoint ghost for PBD
# args: text, index, plan
2022-01-17 11:43:31 +00:00
# text: scratchpad text
# index: index at which waypoint will be inserted
# plan: plan to which waypoint will be inserted
2020-05-14 19:02:18 +00:00
# return:
2022-01-17 11:43:31 +00:00
# 0: not in database
# 1: notAllowed
# 2: o.k.
2020-05-14 19:02:18 +00:00
getWPforPBD: func(text, index, plan, override = 0, overrideIndex = -1) {
if (index == 0) {
return 1;
}
var textSplit = split("/", text);
if (size(split(".", textSplit[2])) != 1 or size(textSplit[1]) < 2 or size(textSplit[1]) > 3) {
return 1;
}
var wpGhost = nil;
var wpGhostContainer = nil;
var type = nil;
if (size(textSplit[0]) == 5) {
wpGhostContainer = findFixesByID(textSplit[0]);
if (size(wpGhostContainer) == 0) {
return 0;
}
type = "fix";
} elsif (size(textSplit[0]) == 4) {
wpGhostContainer = findAirportsByICAO(textSplit[0]);
if (size(wpGhostContainer) == 0) {
return 0;
}
type = "airport";
} elsif (size(textSplit[0]) == 3 or size(textSplit[0]) == 2) {
wpGhostContainer = findNavaidsByID(textSplit[0]);
if (size(wpGhostContainer) == 0) {
return 0;
}
type = "navaid";
} else {
return 1;
}
2020-05-17 00:37:42 +00:00
if (size(wpGhostContainer) == 1 or override) {
2020-05-14 19:02:18 +00:00
if (!override) {
wpGhost = wpGhostContainer[0];
} else {
wpGhost = wpGhostContainer[overrideIndex];
}
} else {
if (type == "navaid") {
2021-01-28 18:57:20 +00:00
me.createDuplicateNames(wpGhostContainer, index, 1, plan, 1, num(textSplit[1]), num(textSplit[2]), 0);
2020-05-14 19:02:18 +00:00
} else {
2021-01-28 18:57:20 +00:00
me.createDuplicateNames(wpGhostContainer, index, 0, plan, 1, num(textSplit[1]), num(textSplit[2]), 0);
2020-01-11 13:30:08 +00:00
}
return 2;
2019-12-29 21:37:52 +00:00
}
2020-05-14 19:02:18 +00:00
var localMagvar = magvar(wpGhost.lat, wpGhost.lon);
2020-05-17 20:36:42 +00:00
return me.insertPlaceBearingDistance(wpGhost, textSplit[1] + localMagvar, textSplit[2], index, plan); # magnetic to true? I don't know. But this works!
2020-05-14 19:02:18 +00:00
},
2020-06-10 02:42:30 +00:00
getNavCount: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
if (me.flightplans[plan].getWP(wpt).wp_type == "navaid") {
count += 1;
}
}
return count;
},
getDepartureCount: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
if (me.flightplans[plan].getWP(wpt).wp_role == "sid") {
count += 1;
}
}
return count;
},
getArrivalCount: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
if (me.flightplans[plan].getWP(wpt).wp_role == "star" or me.flightplans[plan].getWP(wpt).wp_role == "approach" or me.flightplans[plan].getWP(wpt).wp_role == "missed") {
count += 1;
}
}
return count;
},
2020-05-14 19:02:18 +00:00
2022-01-17 11:43:31 +00:00
getPlanSizeNoDiscont: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
if (me.flightplans[plan].getWP(wpt).wp_name != "DISCONTINUITY") {
count += 1;
}
}
return count;
},
2022-01-17 14:44:39 +00:00
calculateDecelPoint: func() {
if (me.getPlanSizeNoDiscont(2) <= 1 or fmgc.FMGCInternal.decel) {
2022-01-17 11:43:31 +00:00
setprop("/instrumentation/nd/symbols/decel/show", 0);
return;
}
me.indexDecel = 0;
2022-01-17 14:44:39 +00:00
for (var wpt = 0; wpt < me.flightplans[2].getPlanSize(); wpt += 1) {
if (me.flightplans[2].getWP(wpt).wp_role == "approach") {
2022-01-17 11:43:31 +00:00
me.indexDecel = wpt;
break;
}
2022-01-17 14:44:39 +00:00
if (wpt == me.flightplans[2].getPlanSize()) {
2022-01-17 11:43:31 +00:00
me.indexDecel = me.arrivalIndex - 2;
break;
}
}
2022-01-17 14:44:39 +00:00
me.dist = me.flightplans[2].getWP(me.indexDecel).leg_distance - 7;
2022-01-17 11:43:31 +00:00
if (me.dist < 0) {
me.dist = 0.1;
}
2022-01-17 14:44:39 +00:00
me.decelPoint = me.flightplans[2].pathGeod(me.indexDecel - 1, me.dist);
2022-01-17 11:43:31 +00:00
2022-01-17 14:44:39 +00:00
setprop("/instrumentation/nd/symbols/decel/latitude-deg", me.decelPoint.lat);
setprop("/instrumentation/nd/symbols/decel/longitude-deg", me.decelPoint.lon);
setprop("/instrumentation/nd/symbols/decel/show", 1);
2022-01-17 11:43:31 +00:00
me.indexTemp = me.indexDecel;
me.distTemp = 7;
2022-01-17 14:44:39 +00:00
if (me.flightplans[2].getWP(me.indexTemp).leg_distance < 7) {
2022-01-17 11:43:31 +00:00
while (me.distTemp > 0 and me.indexTemp > 0) {
2022-01-17 14:44:39 +00:00
me.distTemp -= me.flightplans[2].getWP(me.indexTemp).leg_distance;
2022-01-17 11:43:31 +00:00
me.indexTemp -= 1;
}
me.indexTemp += 1;
}
setprop("/instrumentation/nd/symbols/decel/index", me.indexTemp);
},
2020-05-14 19:02:18 +00:00
# insertPlaceBearingDistance - insert PBD waypoint at specified index,
# at some specified bearing, distance from a specified location
# args: wp, index, plan
2022-01-17 11:43:31 +00:00
# wpt: waypoint ghost
# index: index to insert at in plan
# plan: plan to insert to
2020-05-14 19:02:18 +00:00
insertPlaceBearingDistance: func(wp, bearing, distance, index, plan) {
2020-05-17 00:37:42 +00:00
var waypoint = pilotWaypoint.new(me.childWPBearingDistance(wp, bearing, distance), "PBD");
var addDb = WaypointDatabase.addWP(waypoint);
if (addDb != 2) {
return addDb;
}
2020-05-17 20:36:42 +00:00
2020-05-17 00:37:42 +00:00
me.flightplans[plan].insertWP(waypoint.wpGhost, index);
2020-06-10 02:42:30 +00:00
fmgc.windController.insertWind(plan, index, 0, "PBD");
2020-05-14 19:02:18 +00:00
me.addDiscontinuity(index + 1, plan);
me.flightPlanChanged(plan);
2020-05-17 00:37:42 +00:00
return 2;
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
2020-05-17 00:37:42 +00:00
scratchpad: func(text, index, plan) { # return 0 not in database, 1 not allowed, 2 success, 3 = not allowed due to dir to, 4 = database full
2020-03-28 15:53:50 +00:00
if (mcdu.dirToFlag) {
2020-03-29 15:55:30 +00:00
return 3;
2020-03-28 15:53:50 +00:00
}
2022-01-17 11:43:31 +00:00
if (!me.temporaryFlag[plan]) {
2020-01-07 20:48:27 +00:00
if (text == "CLR" and me.flightplans[2].getWP(index).wp_name == "DISCONTINUITY") {
2022-01-18 12:25:01 +00:00
if (me.flightplans[2].getPlanSize() == 3 and me.flightplans[2].departure_runway == nil and me.flightplans[2].destination_runway == nil and index == 1) {
return 1;
}
2020-01-07 20:48:27 +00:00
var thePlan = 2;
} else {
fmgc.flightPlanController.createTemporaryFlightPlan(plan);
var thePlan = plan;
}
} else {
var thePlan = plan;
}
2020-05-17 00:37:42 +00:00
# check waypoints database here
2020-05-17 13:27:28 +00:00
var wpFromDB = WaypointDatabase.getWP(text);
if (wpFromDB != nil) {
return me.insertDBWP(wpFromDB, index, thePlan);
}
2020-05-17 00:37:42 +00:00
2020-05-14 19:02:18 +00:00
if (size(split("/", text)) == 3) {
return me.getWPforPBD(text, index, thePlan);
2022-01-12 11:53:57 +00:00
} elsif (text == "@") {
return me.changeOverFlyType(index, thePlan);
2020-05-14 19:02:18 +00:00
} elsif (text == "CLR") {
2020-01-11 13:30:08 +00:00
return me.deleteWP(index, thePlan, 0);
2020-04-30 18:35:46 +00:00
} elsif (size(text) > 12) {
2020-01-11 13:30:08 +00:00
return me.insertLatLonFix(text, index, thePlan);
2020-01-05 20:21:28 +00:00
} elsif (size(text) == 5) {
2020-01-07 20:48:27 +00:00
return me.insertFix(text, index, thePlan);
2020-01-05 20:21:28 +00:00
} elsif (size(text) == 4) {
2020-01-07 20:48:27 +00:00
return me.insertAirport(text, index, thePlan);
2020-01-05 20:21:28 +00:00
} elsif (size(text) == 3 or size(text) == 2) {
2020-01-07 20:48:27 +00:00
return me.insertNavaid(text, index, thePlan);
2020-01-05 20:21:28 +00:00
} else {
return 1;
}
},
2022-01-17 14:44:39 +00:00
flightPlanChanged: func(n) {
me.updatePlans(1);
2020-06-10 02:42:30 +00:00
fmgc.windController.updatePlans();
2022-01-17 11:43:31 +00:00
2020-05-18 19:18:17 +00:00
# push update to fuel
2020-10-03 09:59:43 +00:00
if (fmgc.FMGCInternal.blockConfirmed) {
fmgc.FMGCInternal.fuelCalculating = 0;
2020-10-03 11:34:29 +00:00
fmgc.fuelCalculating.setValue(0);
2020-10-03 09:59:43 +00:00
fmgc.FMGCInternal.fuelCalculating = 1;
2020-10-03 11:34:29 +00:00
fmgc.fuelCalculating.setValue(1);
2020-05-18 19:18:17 +00:00
}
2021-06-06 21:21:58 +00:00
if (n == 2) flightPlanController.changed.setBoolValue(1);
2020-01-11 13:30:08 +00:00
canvas_nd.A3XXRouteDriver.triggerSignal("fp-added");
2019-12-29 21:37:52 +00:00
},
2020-01-05 20:21:28 +00:00
2022-01-17 11:43:31 +00:00
# runDecel - used to ensure that only flightplanchanged will update the decel point
2022-01-17 14:44:39 +00:00
updatePlans: func(runDecel = 0) {
2022-01-17 11:43:31 +00:00
if (fmgc.FMGCInternal.toFromSet and me.flightplans[2].departure != nil and me.flightplans[2].destination != nil) { # check if flightplan exists
if (!me.active.getBoolValue()) {
if (me.currentToWptIndex.getValue() < 1) {
var errs = [];
call(func {
me.currentToWptIndex.setValue(1);
2022-01-19 11:04:37 +00:00
}, nil, nil, nil, errs);
2022-01-17 11:43:31 +00:00
if (size(errs) != 0) { debug.printerror(errs); }
}
me.active.setValue(1);
}
} elsif (me.active.getBoolValue()) {
me.active.setValue(0);
}
2020-01-05 20:21:28 +00:00
for (var n = 0; n <= 2; n += 1) {
for (var wpt = 0; wpt < me.flightplans[n].getPlanSize(); wpt += 1) { # Iterate through the waypoints and update their data
var waypointHashStore = me.flightplans[n].getWP(wpt);
2022-01-17 11:43:31 +00:00
if (left(waypointHashStore.wp_name, 4) == fmgc.FMGCInternal.arrApt and wpt != 0) {
2020-07-10 19:28:17 +00:00
if (me.arrivalIndex[n] != wpt) {
me.arrivalIndex[n] = wpt;
2020-01-16 21:02:35 +00:00
if (canvas_mcdu.myFpln[0] != nil) {
canvas_mcdu.myFpln[0].destInfo();
}
if (canvas_mcdu.myFpln[1] != nil) {
canvas_mcdu.myFpln[1].destInfo();
}
2020-01-07 20:48:27 +00:00
}
2020-01-05 20:21:28 +00:00
}
2022-01-17 11:43:31 +00:00
}
2022-01-17 14:44:39 +00:00
}
2022-01-17 11:43:31 +00:00
2022-01-17 14:44:39 +00:00
if (runDecel) {
me.calculateDecelPoint();
2019-12-29 21:37:52 +00:00
}
2020-06-22 23:07:00 +00:00
2020-01-05 20:21:28 +00:00
for (var i = 0; i <= 1; i += 1) {
2020-01-07 20:48:27 +00:00
if (canvas_mcdu.myFpln[i] != nil) {
canvas_mcdu.myFpln[i].updatePlan();
2019-12-29 21:37:52 +00:00
}
2020-03-28 15:53:50 +00:00
if (canvas_mcdu.myDirTo[i] != nil) {
canvas_mcdu.myDirTo[i].updateFromFpln();
}
2019-12-29 21:37:52 +00:00
}
},
};
2022-01-17 11:43:31 +00:00
var flightPlanTimer = maketimer(0.1, flightPlanController, flightPlanController.updatePlans);